| @ -0,0 +1,179 @@ | |||
| /******************************************************************************************* | |||
| * | |||
| * raylib [audio] example - Music stream processing effects | |||
| * | |||
| * Example originally created with raylib 4.2, last time updated with raylib 4.2 | |||
| * | |||
| * 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 Ramon Santamaria (@raysan5) | |||
| * | |||
| ********************************************************************************************/ | |||
| #include "raylib.h" | |||
| #include <stdlib.h> // Required for: NULL | |||
| // Required delay effect variables | |||
| static float *delayBuffer = NULL; | |||
| static unsigned int delayBufferSize = 0; | |||
| static unsigned int delayReadIndex = 2; | |||
| static unsigned int delayWriteIndex = 0; | |||
| //------------------------------------------------------------------------------------ | |||
| // Module Functions Declaration | |||
| //------------------------------------------------------------------------------------ | |||
| static void AudioProcessEffectLPF(void *buffer, unsigned int frames); // Audio effect: lowpass filter | |||
| static void AudioProcessEffectDelay(void *buffer, unsigned int frames); // Audio effect: delay | |||
| //------------------------------------------------------------------------------------ | |||
| // Program main entry point | |||
| //------------------------------------------------------------------------------------ | |||
| int main(void) | |||
| { | |||
| // Initialization | |||
| //-------------------------------------------------------------------------------------- | |||
| const int screenWidth = 800; | |||
| const int screenHeight = 450; | |||
| InitWindow(screenWidth, screenHeight, "raylib [audio] example - stream effects"); | |||
| InitAudioDevice(); // Initialize audio device | |||
| Music music = LoadMusicStream("resources/country.mp3"); | |||
| // Allocate buffer for the delay effect | |||
| delayBufferSize = 48000*2; // 1 second delay (device sampleRate*channels) | |||
| delayBuffer = (float *)RL_CALLOC(delayBufferSize, sizeof(float)); | |||
| PlayMusicStream(music); | |||
| float timePlayed = 0.0f; // Time played normalized [0.0f..1.0f] | |||
| bool pause = false; // Music playing paused | |||
| bool enableEffectLPF = false; // Enable effect low-pass-filter | |||
| bool enableEffectDelay = false; // Enable effect delay (1 second) | |||
| SetTargetFPS(60); // Set our game to run at 60 frames-per-second | |||
| //-------------------------------------------------------------------------------------- | |||
| // Main game loop | |||
| while (!WindowShouldClose()) // Detect window close button or ESC key | |||
| { | |||
| // Update | |||
| //---------------------------------------------------------------------------------- | |||
| UpdateMusicStream(music); // Update music buffer with new stream data | |||
| // Restart music playing (stop and play) | |||
| if (IsKeyPressed(KEY_SPACE)) | |||
| { | |||
| StopMusicStream(music); | |||
| PlayMusicStream(music); | |||
| } | |||
| // Pause/Resume music playing | |||
| if (IsKeyPressed(KEY_P)) | |||
| { | |||
| pause = !pause; | |||
| if (pause) PauseMusicStream(music); | |||
| else ResumeMusicStream(music); | |||
| } | |||
| // Add/Remove effect: lowpass filter | |||
| if (IsKeyPressed(KEY_F)) | |||
| { | |||
| enableEffectLPF = !enableEffectLPF; | |||
| if (enableEffectLPF) AttachAudioStreamProcessor(music.stream, AudioProcessEffectLPF); | |||
| else DetachAudioStreamProcessor(music.stream, AudioProcessEffectLPF); | |||
| } | |||
| // Add/Remove effect: delay | |||
| if (IsKeyPressed(KEY_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(RAYWHITE); | |||
| DrawText("MUSIC SHOULD BE PLAYING!", 245, 150, 20, LIGHTGRAY); | |||
| DrawRectangle(200, 180, 400, 12, LIGHTGRAY); | |||
| DrawRectangle(200, 180, (int)(timePlayed*400.0f), 12, MAROON); | |||
| DrawRectangleLines(200, 180, 400, 12, GRAY); | |||
| DrawText("PRESS SPACE TO RESTART MUSIC", 215, 230, 20, LIGHTGRAY); | |||
| DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 260, 20, LIGHTGRAY); | |||
| DrawText(TextFormat("PRESS F TO TOGGLE LPF EFFECT: %s", enableEffectLPF? "ON" : "OFF"), 200, 320, 20, GRAY); | |||
| DrawText(TextFormat("PRESS D TO TOGGLE DELAY EFFECT: %s", enableEffectDelay? "ON" : "OFF"), 180, 350, 20, GRAY); | |||
| EndDrawing(); | |||
| //---------------------------------------------------------------------------------- | |||
| } | |||
| // De-Initialization | |||
| //-------------------------------------------------------------------------------------- | |||
| UnloadMusicStream(music); // Unload music stream buffers from RAM | |||
| CloseAudioDevice(); // Close audio device (music streaming is automatically stopped) | |||
| RL_FREE(delayBuffer); // Free delay buffer | |||
| CloseWindow(); // Close window and OpenGL context | |||
| //-------------------------------------------------------------------------------------- | |||
| return 0; | |||
| } | |||
| //------------------------------------------------------------------------------------ | |||
| // Module Functions Definition | |||
| //------------------------------------------------------------------------------------ | |||
| // Audio effect: lowpass filter | |||
| static void AudioProcessEffectLPF(void *buffer, unsigned int frames) | |||
| { | |||
| static float low[2] = { 0.0f, 0.0f }; | |||
| static const float cutoff = 70.0f / 44100.0f; // 70 Hz lowpass filter | |||
| const float k = cutoff / (cutoff + 0.1591549431f); // RC filter formula | |||
| for (unsigned int i = 0; i < frames*2; i += 2) | |||
| { | |||
| float l = ((float *)buffer)[i], r = ((float *)buffer)[i + 1]; | |||
| low[0] += k * (l - low[0]); | |||
| low[1] += k * (r - low[1]); | |||
| ((float *)buffer)[i] = low[0]; | |||
| ((float *)buffer)[i + 1] = low[1]; | |||
| } | |||
| } | |||
| // Audio effect: delay | |||
| static void AudioProcessEffectDelay(void *buffer, unsigned int frames) | |||
| { | |||
| for (unsigned int i = 0; i < frames*2; i += 2) | |||
| { | |||
| float leftDelay = delayBuffer[delayReadIndex++]; // ERROR: Reading buffer -> WHY??? Maybe thread related??? | |||
| float rightDelay = delayBuffer[delayReadIndex++]; | |||
| if (delayReadIndex == delayBufferSize) delayReadIndex = 0; | |||
| ((float *)buffer)[i] = 0.5f*((float *)buffer)[i] + 0.5f*leftDelay; | |||
| ((float *)buffer)[i + 1] = 0.5f*((float *)buffer)[i + 1] + 0.5f*rightDelay; | |||
| delayBuffer[delayWriteIndex++] = ((float *)buffer)[i]; | |||
| delayBuffer[delayWriteIndex++] = ((float *)buffer)[i + 1]; | |||
| if (delayWriteIndex == delayBufferSize) delayWriteIndex = 0; | |||
| } | |||
| } | |||