New example : Audio/mixed processor
This commit is contained in:
parent
5bed8af6d4
commit
a9a0a28119
3 changed files with 155 additions and 0 deletions
155
examples/audio/mixed_processor/main.go
Normal file
155
examples/audio/mixed_processor/main.go
Normal file
|
@ -0,0 +1,155 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - Mixed audio processing
|
||||
*
|
||||
* Example originally created with raylib 4.2, last time updated with raylib 4.2
|
||||
*
|
||||
* Example contributed by hkc (@hatkidchan) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2023 hkc (@hatkidchan)
|
||||
*
|
||||
********************************************************************************************/
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
const (
|
||||
screenWidth = 800
|
||||
screenHeight = 450
|
||||
)
|
||||
|
||||
var exponent float32 = 1.0 // Audio exponentiation value
|
||||
var averageVolume [400]float32 // Average volume history
|
||||
|
||||
func main() {
|
||||
rl.InitWindow(screenWidth, screenHeight, "raylib [audio] example - processing mixed output")
|
||||
|
||||
rl.InitAudioDevice() // Initialize audio device
|
||||
rl.AttachAudioMixedProcessor(ProcessAudio)
|
||||
|
||||
music := rl.LoadMusicStream("country.mp3")
|
||||
sound := rl.LoadSound("coin.wav")
|
||||
|
||||
rl.PlayMusicStream(music)
|
||||
|
||||
rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second
|
||||
|
||||
// Main game loop
|
||||
for !rl.WindowShouldClose() { // Detect window close button or ESC key
|
||||
rl.UpdateMusicStream(music) // Update music buffer with new stream data
|
||||
|
||||
// Modify processing variables
|
||||
if rl.IsKeyPressed(rl.KeyLeft) {
|
||||
exponent -= 0.05
|
||||
}
|
||||
if rl.IsKeyPressed(rl.KeyRight) {
|
||||
exponent += 0.05
|
||||
}
|
||||
if rl.IsKeyPressed(rl.KeyDown) {
|
||||
exponent -= 0.25
|
||||
}
|
||||
if rl.IsKeyPressed(rl.KeyUp) {
|
||||
exponent += 0.25
|
||||
}
|
||||
|
||||
// Make sure that exponent stays between 0.5 and 3
|
||||
exponent = clamp(exponent, 0.5, 3)
|
||||
|
||||
if rl.IsKeyPressed(rl.KeySpace) {
|
||||
rl.PlaySound(sound)
|
||||
}
|
||||
|
||||
// Draw
|
||||
rl.BeginDrawing()
|
||||
|
||||
rl.ClearBackground(rl.RayWhite)
|
||||
|
||||
rl.DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, rl.LightGray)
|
||||
|
||||
rl.DrawText(fmt.Sprintf("EXPONENT = %.2f", exponent), 215, 180, 20, rl.LightGray)
|
||||
|
||||
rl.DrawRectangle(199, 199, 402, 34, rl.LightGray)
|
||||
for i := int32(0); i < 400; i++ {
|
||||
rl.DrawLine(201+i, 232-int32(averageVolume[i]*32), 201+i, 232, rl.Maroon)
|
||||
}
|
||||
rl.DrawRectangleLines(199, 199, 402, 34, rl.Gray)
|
||||
|
||||
rl.DrawText("PRESS SPACE TO PLAY OTHER SOUND", 200, 250, 20, rl.LightGray)
|
||||
rl.DrawText("USE LEFT AND RIGHT ARROWS TO ALTER DISTORTION", 140, 280, 20, rl.LightGray)
|
||||
|
||||
rl.EndDrawing()
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
rl.UnloadMusicStream(music) // Unload music stream buffers from RAM
|
||||
rl.DetachAudioMixedProcessor(ProcessAudio) // Disconnect audio processor
|
||||
rl.CloseAudioDevice() // Close audio device (music streaming is automatically stopped)
|
||||
|
||||
rl.CloseWindow() // Close window and OpenGL context
|
||||
}
|
||||
|
||||
// ProcessAudio is the audio processing function
|
||||
func ProcessAudio(buffer []float32, frames int) {
|
||||
var average float32 // Temporary average volume
|
||||
maxFrame := frames / 2
|
||||
|
||||
// Each frame has 2 samples (left and right),
|
||||
// so we should loop `frames / 2` times
|
||||
for frame := 0; frame < maxFrame; frame++ {
|
||||
left := &buffer[frame*2+0] // Left channel
|
||||
right := &buffer[frame*2+1] // Right channel
|
||||
|
||||
// Modify left and right channel samples with exponent
|
||||
*left = pow(abs(*left), exponent) * sgn(*left)
|
||||
*right = pow(abs(*right), exponent) * sgn(*right)
|
||||
|
||||
// Accumulating average volume
|
||||
average += abs(*left) / float32(maxFrame)
|
||||
average += abs(*right) / float32(maxFrame)
|
||||
}
|
||||
|
||||
// Shift average volume history buffer to the left
|
||||
for i := 0; i < 399; i++ {
|
||||
averageVolume[i] = averageVolume[i+1]
|
||||
}
|
||||
|
||||
// Add the new average value
|
||||
averageVolume[399] = average
|
||||
}
|
||||
|
||||
// Helper functions to make the code shorter
|
||||
// (using less type conversions)
|
||||
// (Golang: Please make the `math` package generic! This is ridiculous :-)
|
||||
func abs(value float32) float32 {
|
||||
return float32(math.Abs(float64(value)))
|
||||
}
|
||||
|
||||
func pow(value, exponent float32) float32 {
|
||||
return float32(math.Pow(float64(value), float64(exponent)))
|
||||
}
|
||||
|
||||
func sgn(value float32) float32 {
|
||||
if value < 0 {
|
||||
return -1
|
||||
} else if value > 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func clamp(value, min, max float32) float32 {
|
||||
if value < min {
|
||||
return min
|
||||
}
|
||||
if value > max {
|
||||
return max
|
||||
}
|
||||
return value
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue