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.

214 lines
7.6 KiB

  1. /*******************************************************************************************
  2. *
  3. * raylib [audio] example - Raw audio streaming
  4. *
  5. * Example originally created with raylib 1.6, last time updated with raylib 4.2
  6. *
  7. * Example created by Ramon Santamaria (@raysan5) and reviewed by James Hofmann (@triplefox)
  8. *
  9. * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
  10. * BSD-like license that allows static linking with closed source software
  11. *
  12. * Copyright (c) 2015-2024 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox)
  13. *
  14. ********************************************************************************************/
  15. #include "raylib.h"
  16. #include <stdlib.h> // Required for: malloc(), free()
  17. #include <math.h> // Required for: sinf()
  18. #include <string.h> // Required for: memcpy()
  19. #define MAX_SAMPLES 512
  20. #define MAX_SAMPLES_PER_UPDATE 4096
  21. // Cycles per second (hz)
  22. float frequency = 440.0f;
  23. // Audio frequency, for smoothing
  24. float audioFrequency = 440.0f;
  25. // Previous value, used to test if sine needs to be rewritten, and to smoothly modulate frequency
  26. float oldFrequency = 1.0f;
  27. // Index for audio rendering
  28. float sineIdx = 0.0f;
  29. // Audio input processing callback
  30. void AudioInputCallback(void *buffer, unsigned int frames)
  31. {
  32. audioFrequency = frequency + (audioFrequency - frequency)*0.95f;
  33. float incr = audioFrequency/44100.0f;
  34. short *d = (short *)buffer;
  35. for (unsigned int i = 0; i < frames; i++)
  36. {
  37. d[i] = (short)(32000.0f*sinf(2*PI*sineIdx));
  38. sineIdx += incr;
  39. if (sineIdx > 1.0f) sineIdx -= 1.0f;
  40. }
  41. }
  42. //------------------------------------------------------------------------------------
  43. // Program main entry point
  44. //------------------------------------------------------------------------------------
  45. int main(void)
  46. {
  47. // Initialization
  48. //--------------------------------------------------------------------------------------
  49. const int screenWidth = 800;
  50. const int screenHeight = 450;
  51. InitWindow(screenWidth, screenHeight, "raylib [audio] example - raw audio streaming");
  52. InitAudioDevice(); // Initialize audio device
  53. SetAudioStreamBufferSizeDefault(MAX_SAMPLES_PER_UPDATE);
  54. // Init raw audio stream (sample rate: 44100, sample size: 16bit-short, channels: 1-mono)
  55. AudioStream stream = LoadAudioStream(44100, 16, 1);
  56. SetAudioStreamCallback(stream, AudioInputCallback);
  57. // Buffer for the single cycle waveform we are synthesizing
  58. short *data = (short *)malloc(sizeof(short)*MAX_SAMPLES);
  59. // Frame buffer, describing the waveform when repeated over the course of a frame
  60. short *writeBuf = (short *)malloc(sizeof(short)*MAX_SAMPLES_PER_UPDATE);
  61. PlayAudioStream(stream); // Start processing stream buffer (no data loaded currently)
  62. // Position read in to determine next frequency
  63. Vector2 mousePosition = { -100.0f, -100.0f };
  64. /*
  65. // Cycles per second (hz)
  66. float frequency = 440.0f;
  67. // Previous value, used to test if sine needs to be rewritten, and to smoothly modulate frequency
  68. float oldFrequency = 1.0f;
  69. // Cursor to read and copy the samples of the sine wave buffer
  70. int readCursor = 0;
  71. */
  72. // Computed size in samples of the sine wave
  73. int waveLength = 1;
  74. Vector2 position = { 0, 0 };
  75. SetTargetFPS(30); // Set our game to run at 30 frames-per-second
  76. //--------------------------------------------------------------------------------------
  77. // Main game loop
  78. while (!WindowShouldClose()) // Detect window close button or ESC key
  79. {
  80. // Update
  81. //----------------------------------------------------------------------------------
  82. // Sample mouse input.
  83. mousePosition = GetMousePosition();
  84. if (IsMouseButtonDown(MOUSE_BUTTON_LEFT))
  85. {
  86. float fp = (float)(mousePosition.y);
  87. frequency = 40.0f + (float)(fp);
  88. float pan = (float)(mousePosition.x) / (float)screenWidth;
  89. SetAudioStreamPan(stream, pan);
  90. }
  91. // Rewrite the sine wave
  92. // Compute two cycles to allow the buffer padding, simplifying any modulation, resampling, etc.
  93. if (frequency != oldFrequency)
  94. {
  95. // Compute wavelength. Limit size in both directions.
  96. //int oldWavelength = waveLength;
  97. waveLength = (int)(22050/frequency);
  98. if (waveLength > MAX_SAMPLES/2) waveLength = MAX_SAMPLES/2;
  99. if (waveLength < 1) waveLength = 1;
  100. // Write sine wave
  101. for (int i = 0; i < waveLength*2; i++)
  102. {
  103. data[i] = (short)(sinf(((2*PI*(float)i/waveLength)))*32000);
  104. }
  105. // Make sure the rest of the line is flat
  106. for (int j = waveLength*2; j < MAX_SAMPLES; j++)
  107. {
  108. data[j] = (short)0;
  109. }
  110. // Scale read cursor's position to minimize transition artifacts
  111. //readCursor = (int)(readCursor * ((float)waveLength / (float)oldWavelength));
  112. oldFrequency = frequency;
  113. }
  114. /*
  115. // Refill audio stream if required
  116. if (IsAudioStreamProcessed(stream))
  117. {
  118. // Synthesize a buffer that is exactly the requested size
  119. int writeCursor = 0;
  120. while (writeCursor < MAX_SAMPLES_PER_UPDATE)
  121. {
  122. // Start by trying to write the whole chunk at once
  123. int writeLength = MAX_SAMPLES_PER_UPDATE-writeCursor;
  124. // Limit to the maximum readable size
  125. int readLength = waveLength-readCursor;
  126. if (writeLength > readLength) writeLength = readLength;
  127. // Write the slice
  128. memcpy(writeBuf + writeCursor, data + readCursor, writeLength*sizeof(short));
  129. // Update cursors and loop audio
  130. readCursor = (readCursor + writeLength) % waveLength;
  131. writeCursor += writeLength;
  132. }
  133. // Copy finished frame to audio stream
  134. UpdateAudioStream(stream, writeBuf, MAX_SAMPLES_PER_UPDATE);
  135. }
  136. */
  137. //----------------------------------------------------------------------------------
  138. // Draw
  139. //----------------------------------------------------------------------------------
  140. BeginDrawing();
  141. ClearBackground(RAYWHITE);
  142. DrawText(TextFormat("sine frequency: %i",(int)frequency), GetScreenWidth() - 220, 10, 20, RED);
  143. DrawText("click mouse button to change frequency or pan", 10, 10, 20, DARKGRAY);
  144. // Draw the current buffer state proportionate to the screen
  145. for (int i = 0; i < screenWidth; i++)
  146. {
  147. position.x = (float)i;
  148. position.y = 250 + 50*data[i*MAX_SAMPLES/screenWidth]/32000.0f;
  149. DrawPixelV(position, RED);
  150. }
  151. EndDrawing();
  152. //----------------------------------------------------------------------------------
  153. }
  154. // De-Initialization
  155. //--------------------------------------------------------------------------------------
  156. free(data); // Unload sine wave data
  157. free(writeBuf); // Unload write buffer
  158. UnloadAudioStream(stream); // Close raw audio stream and delete buffers from RAM
  159. CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
  160. CloseWindow(); // Close window and OpenGL context
  161. //--------------------------------------------------------------------------------------
  162. return 0;
  163. }