You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
7.2 KiB

  1. /*******************************************************************************************
  2. *
  3. * raylib [audio] example - Music stream processing effects
  4. *
  5. * Example originally created with raylib 4.2, last time updated with raylib 5.0
  6. *
  7. * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
  8. * BSD-like license that allows static linking with closed source software
  9. *
  10. * Copyright (c) 2022-2024 Ramon Santamaria (@raysan5)
  11. *
  12. ********************************************************************************************/
  13. #include "raylib.h"
  14. #include <stdlib.h> // Required for: NULL
  15. // Required delay effect variables
  16. static float *delayBuffer = NULL;
  17. static unsigned int delayBufferSize = 0;
  18. static unsigned int delayReadIndex = 2;
  19. static unsigned int delayWriteIndex = 0;
  20. //------------------------------------------------------------------------------------
  21. // Module Functions Declaration
  22. //------------------------------------------------------------------------------------
  23. static void AudioProcessEffectLPF(void *buffer, unsigned int frames); // Audio effect: lowpass filter
  24. static void AudioProcessEffectDelay(void *buffer, unsigned int frames); // Audio effect: delay
  25. //------------------------------------------------------------------------------------
  26. // Program main entry point
  27. //------------------------------------------------------------------------------------
  28. int main(void)
  29. {
  30. // Initialization
  31. //--------------------------------------------------------------------------------------
  32. const int screenWidth = 800;
  33. const int screenHeight = 450;
  34. InitWindow(screenWidth, screenHeight, "raylib [audio] example - stream effects");
  35. InitAudioDevice(); // Initialize audio device
  36. Music music = LoadMusicStream("resources/country.mp3");
  37. // Allocate buffer for the delay effect
  38. delayBufferSize = 48000*2; // 1 second delay (device sampleRate*channels)
  39. delayBuffer = (float *)RL_CALLOC(delayBufferSize, sizeof(float));
  40. PlayMusicStream(music);
  41. float timePlayed = 0.0f; // Time played normalized [0.0f..1.0f]
  42. bool pause = false; // Music playing paused
  43. bool enableEffectLPF = false; // Enable effect low-pass-filter
  44. bool enableEffectDelay = false; // Enable effect delay (1 second)
  45. SetTargetFPS(60); // Set our game to run at 60 frames-per-second
  46. //--------------------------------------------------------------------------------------
  47. // Main game loop
  48. while (!WindowShouldClose()) // Detect window close button or ESC key
  49. {
  50. // Update
  51. //----------------------------------------------------------------------------------
  52. UpdateMusicStream(music); // Update music buffer with new stream data
  53. // Restart music playing (stop and play)
  54. if (IsKeyPressed(KEY_SPACE))
  55. {
  56. StopMusicStream(music);
  57. PlayMusicStream(music);
  58. }
  59. // Pause/Resume music playing
  60. if (IsKeyPressed(KEY_P))
  61. {
  62. pause = !pause;
  63. if (pause) PauseMusicStream(music);
  64. else ResumeMusicStream(music);
  65. }
  66. // Add/Remove effect: lowpass filter
  67. if (IsKeyPressed(KEY_F))
  68. {
  69. enableEffectLPF = !enableEffectLPF;
  70. if (enableEffectLPF) AttachAudioStreamProcessor(music.stream, AudioProcessEffectLPF);
  71. else DetachAudioStreamProcessor(music.stream, AudioProcessEffectLPF);
  72. }
  73. // Add/Remove effect: delay
  74. if (IsKeyPressed(KEY_D))
  75. {
  76. enableEffectDelay = !enableEffectDelay;
  77. if (enableEffectDelay) AttachAudioStreamProcessor(music.stream, AudioProcessEffectDelay);
  78. else DetachAudioStreamProcessor(music.stream, AudioProcessEffectDelay);
  79. }
  80. // Get normalized time played for current music stream
  81. timePlayed = GetMusicTimePlayed(music)/GetMusicTimeLength(music);
  82. if (timePlayed > 1.0f) timePlayed = 1.0f; // Make sure time played is no longer than music
  83. //----------------------------------------------------------------------------------
  84. // Draw
  85. //----------------------------------------------------------------------------------
  86. BeginDrawing();
  87. ClearBackground(RAYWHITE);
  88. DrawText("MUSIC SHOULD BE PLAYING!", 245, 150, 20, LIGHTGRAY);
  89. DrawRectangle(200, 180, 400, 12, LIGHTGRAY);
  90. DrawRectangle(200, 180, (int)(timePlayed*400.0f), 12, MAROON);
  91. DrawRectangleLines(200, 180, 400, 12, GRAY);
  92. DrawText("PRESS SPACE TO RESTART MUSIC", 215, 230, 20, LIGHTGRAY);
  93. DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 260, 20, LIGHTGRAY);
  94. DrawText(TextFormat("PRESS F TO TOGGLE LPF EFFECT: %s", enableEffectLPF? "ON" : "OFF"), 200, 320, 20, GRAY);
  95. DrawText(TextFormat("PRESS D TO TOGGLE DELAY EFFECT: %s", enableEffectDelay? "ON" : "OFF"), 180, 350, 20, GRAY);
  96. EndDrawing();
  97. //----------------------------------------------------------------------------------
  98. }
  99. // De-Initialization
  100. //--------------------------------------------------------------------------------------
  101. UnloadMusicStream(music); // Unload music stream buffers from RAM
  102. CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
  103. RL_FREE(delayBuffer); // Free delay buffer
  104. CloseWindow(); // Close window and OpenGL context
  105. //--------------------------------------------------------------------------------------
  106. return 0;
  107. }
  108. //------------------------------------------------------------------------------------
  109. // Module Functions Definition
  110. //------------------------------------------------------------------------------------
  111. // Audio effect: lowpass filter
  112. static void AudioProcessEffectLPF(void *buffer, unsigned int frames)
  113. {
  114. static float low[2] = { 0.0f, 0.0f };
  115. static const float cutoff = 70.0f / 44100.0f; // 70 Hz lowpass filter
  116. const float k = cutoff / (cutoff + 0.1591549431f); // RC filter formula
  117. // Converts the buffer data before using it
  118. float *bufferData = (float *)buffer;
  119. for (unsigned int i = 0; i < frames*2; i += 2)
  120. {
  121. const float l = bufferData[i];
  122. const float r = bufferData[i + 1];
  123. low[0] += k * (l - low[0]);
  124. low[1] += k * (r - low[1]);
  125. bufferData[i] = low[0];
  126. bufferData[i + 1] = low[1];
  127. }
  128. }
  129. // Audio effect: delay
  130. static void AudioProcessEffectDelay(void *buffer, unsigned int frames)
  131. {
  132. for (unsigned int i = 0; i < frames*2; i += 2)
  133. {
  134. float leftDelay = delayBuffer[delayReadIndex++]; // ERROR: Reading buffer -> WHY??? Maybe thread related???
  135. float rightDelay = delayBuffer[delayReadIndex++];
  136. if (delayReadIndex == delayBufferSize) delayReadIndex = 0;
  137. ((float *)buffer)[i] = 0.5f*((float *)buffer)[i] + 0.5f*leftDelay;
  138. ((float *)buffer)[i + 1] = 0.5f*((float *)buffer)[i + 1] + 0.5f*rightDelay;
  139. delayBuffer[delayWriteIndex++] = ((float *)buffer)[i];
  140. delayBuffer[delayWriteIndex++] = ((float *)buffer)[i + 1];
  141. if (delayWriteIndex == delayBufferSize) delayWriteIndex = 0;
  142. }
  143. }