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.

215 line
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-2023 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. audioFrequency += 1.0f;
  34. audioFrequency -= 1.0f;
  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 audio streaming");
  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. // Sample mouse input.
  85. mousePosition = GetMousePosition();
  86. if (IsMouseButtonDown(MOUSE_BUTTON_LEFT))
  87. {
  88. float fp = (float)(mousePosition.y);
  89. frequency = 40.0f + (float)(fp);
  90. float pan = (float)(mousePosition.x) / (float)screenWidth;
  91. SetAudioStreamPan(stream, pan);
  92. }
  93. // Rewrite the sine wave
  94. // Compute two cycles to allow the buffer padding, simplifying any modulation, resampling, etc.
  95. if (frequency != oldFrequency)
  96. {
  97. // Compute wavelength. Limit size in both directions.
  98. //int oldWavelength = waveLength;
  99. waveLength = (int)(22050/frequency);
  100. if (waveLength > MAX_SAMPLES/2) waveLength = MAX_SAMPLES/2;
  101. if (waveLength < 1) waveLength = 1;
  102. // Write sine wave
  103. for (int i = 0; i < waveLength*2; i++)
  104. {
  105. data[i] = (short)(sinf(((2*PI*(float)i/waveLength)))*32000);
  106. }
  107. // Make sure the rest of the line is flat
  108. for (int j = waveLength*2; j < MAX_SAMPLES; j++)
  109. {
  110. data[j] = (short)0;
  111. }
  112. // Scale read cursor's position to minimize transition artifacts
  113. //readCursor = (int)(readCursor * ((float)waveLength / (float)oldWavelength));
  114. oldFrequency = frequency;
  115. }
  116. /*
  117. // Refill audio stream if required
  118. if (IsAudioStreamProcessed(stream))
  119. {
  120. // Synthesize a buffer that is exactly the requested size
  121. int writeCursor = 0;
  122. while (writeCursor < MAX_SAMPLES_PER_UPDATE)
  123. {
  124. // Start by trying to write the whole chunk at once
  125. int writeLength = MAX_SAMPLES_PER_UPDATE-writeCursor;
  126. // Limit to the maximum readable size
  127. int readLength = waveLength-readCursor;
  128. if (writeLength > readLength) writeLength = readLength;
  129. // Write the slice
  130. memcpy(writeBuf + writeCursor, data + readCursor, writeLength*sizeof(short));
  131. // Update cursors and loop audio
  132. readCursor = (readCursor + writeLength) % waveLength;
  133. writeCursor += writeLength;
  134. }
  135. // Copy finished frame to audio stream
  136. UpdateAudioStream(stream, writeBuf, MAX_SAMPLES_PER_UPDATE);
  137. }
  138. */
  139. //----------------------------------------------------------------------------------
  140. // Draw
  141. //----------------------------------------------------------------------------------
  142. BeginDrawing();
  143. ClearBackground(RAYWHITE);
  144. DrawText(TextFormat("sine frequency: %i",(int)frequency), GetScreenWidth() - 220, 10, 20, RED);
  145. DrawText("click mouse button to change frequency or pan", 10, 10, 20, DARKGRAY);
  146. // Draw the current buffer state proportionate to the screen
  147. for (int i = 0; i < screenWidth; i++)
  148. {
  149. position.x = (float)i;
  150. position.y = 250 + 50*data[i*MAX_SAMPLES/screenWidth]/32000.0f;
  151. DrawPixelV(position, RED);
  152. }
  153. EndDrawing();
  154. //----------------------------------------------------------------------------------
  155. }
  156. // De-Initialization
  157. //--------------------------------------------------------------------------------------
  158. free(data); // Unload sine wave data
  159. free(writeBuf); // Unload write buffer
  160. UnloadAudioStream(stream); // Close raw audio stream and delete buffers from RAM
  161. CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
  162. CloseWindow(); // Close window and OpenGL context
  163. //--------------------------------------------------------------------------------------
  164. return 0;
  165. }