audio_raw_stream.c 7.6 KB

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