chore: clean recommit
This commit is contained in:
parent
8024c6ac40
commit
60ad2e7fb1
122 changed files with 23950 additions and 323 deletions
222
Examples/Audio/StreamEffects.cs
Normal file
222
Examples/Audio/StreamEffects.cs
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - stream effects
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 4.2, last time updated with raylib 5.0
|
||||
*
|
||||
* 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) 2022-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
[ExcludeFromBrowser("AttachAudioStreamProcessor is unreliable on the wasm audio backend")]
|
||||
public unsafe partial class StreamEffects : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Audio / Stream Effects";
|
||||
|
||||
public string Title => "raylib [audio] example - stream effects";
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
private static float[] delayBuffer = null;
|
||||
private static uint delayBufferSize = 0;
|
||||
private static uint delayReadIndex = 2;
|
||||
private static uint delayWriteIndex = 0;
|
||||
|
||||
// Low-pass filter state (was a function-local static in the C example)
|
||||
private static readonly float[] low = { 0.0f, 0.0f };
|
||||
|
||||
private Music music;
|
||||
private float timePlayed;
|
||||
private bool pause;
|
||||
private bool enableEffectLPF;
|
||||
private bool enableEffectDelay;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice(); // Initialize audio device
|
||||
|
||||
music = LoadMusicStream("resources/audio/country.mp3");
|
||||
|
||||
// Allocate buffer for the delay effect
|
||||
delayBufferSize = 48000 * 2; // 1 second delay (device sampleRate*channels)
|
||||
delayBuffer = new float[delayBufferSize];
|
||||
delayReadIndex = 2;
|
||||
delayWriteIndex = 0;
|
||||
low[0] = 0.0f;
|
||||
low[1] = 0.0f;
|
||||
|
||||
PlayMusicStream(music);
|
||||
|
||||
timePlayed = 0.0f; // Time played normalized [0.0f..1.0f]
|
||||
pause = false; // Music playing paused
|
||||
|
||||
enableEffectLPF = false; // Enable effect low-pass-filter
|
||||
enableEffectDelay = false; // Enable effect delay (1 second)
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||
|
||||
// Restart music playing (stop and play)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
StopMusicStream(music);
|
||||
PlayMusicStream(music);
|
||||
}
|
||||
|
||||
// Pause/Resume music playing
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
pause = !pause;
|
||||
|
||||
if (pause) PauseMusicStream(music);
|
||||
else ResumeMusicStream(music);
|
||||
}
|
||||
|
||||
// Add/Remove effect: lowpass filter
|
||||
if (IsKeyPressed(KeyboardKey.F))
|
||||
{
|
||||
enableEffectLPF = !enableEffectLPF;
|
||||
if (enableEffectLPF) AttachAudioStreamProcessor(music.Stream, &AudioProcessEffectLPF);
|
||||
else DetachAudioStreamProcessor(music.Stream, &AudioProcessEffectLPF);
|
||||
}
|
||||
|
||||
// Add/Remove effect: delay
|
||||
if (IsKeyPressed(KeyboardKey.D))
|
||||
{
|
||||
enableEffectDelay = !enableEffectDelay;
|
||||
if (enableEffectDelay) AttachAudioStreamProcessor(music.Stream, &AudioProcessEffectDelay);
|
||||
else DetachAudioStreamProcessor(music.Stream, &AudioProcessEffectDelay);
|
||||
}
|
||||
|
||||
// Get normalized time played for current music stream
|
||||
timePlayed = GetMusicTimePlayed(music) / GetMusicTimeLength(music);
|
||||
|
||||
if (timePlayed > 1.0f) timePlayed = 1.0f; // Make sure time played is no longer than music
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("MUSIC SHOULD BE PLAYING!", 245, 150, 20, Color.LightGray);
|
||||
|
||||
DrawRectangle(200, 180, 400, 12, Color.LightGray);
|
||||
DrawRectangle(200, 180, (int)(timePlayed * 400.0f), 12, Color.Maroon);
|
||||
DrawRectangleLines(200, 180, 400, 12, Color.Gray);
|
||||
|
||||
DrawText("PRESS SPACE TO RESTART MUSIC", 215, 230, 20, Color.LightGray);
|
||||
DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 260, 20, Color.LightGray);
|
||||
|
||||
DrawText($"PRESS F TO TOGGLE LPF EFFECT: {(enableEffectLPF ? "ON" : "OFF")}", 200, 320, 20, Color.Gray);
|
||||
DrawText($"PRESS D TO TOGGLE DELAY EFFECT: {(enableEffectDelay ? "ON" : "OFF")}", 180, 350, 20, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadMusicStream(music); // Unload music stream buffers from RAM
|
||||
|
||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
|
||||
delayBuffer = null; // Free delay buffer
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//------------------------------------------------------------------------------------
|
||||
// Audio effect: lowpass filter
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void AudioProcessEffectLPF(void* buffer, uint frames)
|
||||
{
|
||||
const float cutoff = 70.0f / 44100.0f; // 70 Hz lowpass filter
|
||||
const float k = cutoff / (cutoff + 0.1591549431f); // RC filter formula
|
||||
|
||||
// Converts the buffer data before using it
|
||||
float* bufferData = (float*)buffer;
|
||||
for (uint i = 0; i < frames * 2; i += 2)
|
||||
{
|
||||
float l = bufferData[i];
|
||||
float r = bufferData[i + 1];
|
||||
|
||||
low[0] += k * (l - low[0]);
|
||||
low[1] += k * (r - low[1]);
|
||||
bufferData[i] = low[0];
|
||||
bufferData[i + 1] = low[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Audio effect: delay
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void AudioProcessEffectDelay(void* buffer, uint frames)
|
||||
{
|
||||
float* bufferData = (float*)buffer;
|
||||
fixed (float* delay = delayBuffer)
|
||||
{
|
||||
for (uint i = 0; i < frames * 2; i += 2)
|
||||
{
|
||||
float leftDelay = delay[delayReadIndex++]; // ERROR: Reading buffer -> WHY??? Maybe thread related???
|
||||
float rightDelay = delay[delayReadIndex++];
|
||||
|
||||
if (delayReadIndex == delayBufferSize) delayReadIndex = 0;
|
||||
|
||||
bufferData[i] = 0.5f * bufferData[i] + 0.5f * leftDelay;
|
||||
bufferData[i + 1] = 0.5f * bufferData[i + 1] + 0.5f * rightDelay;
|
||||
|
||||
delay[delayWriteIndex++] = bufferData[i];
|
||||
delay[delayWriteIndex++] = bufferData[i + 1];
|
||||
if (delayWriteIndex == delayBufferSize) delayWriteIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - stream effects");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new StreamEffects();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue