diff options
Diffstat (limited to 'examples/src/audio')
| -rw-r--r-- | examples/src/audio/audio_raw_stream.c | 109 |
1 files changed, 80 insertions, 29 deletions
diff --git a/examples/src/audio/audio_raw_stream.c b/examples/src/audio/audio_raw_stream.c index 80c83e9..7eee46f 100644 --- a/examples/src/audio/audio_raw_stream.c +++ b/examples/src/audio/audio_raw_stream.c @@ -7,7 +7,7 @@ * This example has been created using raylib 1.6 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2018 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox) * ********************************************************************************************/ @@ -15,8 +15,9 @@ #include <stdlib.h> // Required for: malloc(), free() #include <math.h> // Required for: sinf() +#include <string.h> // Required for: memcpy() -#define MAX_SAMPLES 22050 +#define MAX_SAMPLES 512 #define MAX_SAMPLES_PER_UPDATE 4096 int main() @@ -33,20 +34,28 @@ int main() // Init raw audio stream (sample rate: 22050, sample size: 16bit-short, channels: 1-mono) AudioStream stream = InitAudioStream(22050, 16, 1); - // Generate samples data from sine wave + // Buffer for the single cycle waveform we are synthesizing short *data = (short *)malloc(sizeof(short)*MAX_SAMPLES); - - // TODO: Review data generation, it seems data is discontinued for loop, - // for that reason, there is a clip everytime audio stream is looped... - for (int i = 0; i < MAX_SAMPLES; i++) - { - data[i] = (short)(sinf(((2*PI*(float)i)/2)*DEG2RAD)*32000); - } + + // Frame buffer, describing the waveform when repeated over the course of a frame + short *writeBuf = (short *)malloc(sizeof(short)*MAX_SAMPLES_PER_UPDATE); PlayAudioStream(stream); // Start processing stream buffer (no data loaded currently) - int totalSamples = MAX_SAMPLES; - int samplesLeft = totalSamples; + // Position read in to determine next frequency + Vector2 mousePosition = { -100.0f, -100.0f }; + + // Cycles per second (hz) + float frequency = 440.0f; + + // Previous value, used to test if sine needs to be rewritten, and to smoothly modulate frequency + float oldFrequency = 1.0f; + + // Cursor to read and copy the samples of the sine wave buffer + int readCursor = 0; + + // Computed size in samples of the sine wave + int waveLength = 1; Vector2 position = { 0, 0 }; @@ -59,22 +68,63 @@ int main() // Update //---------------------------------------------------------------------------------- + // Sample mouse input. + mousePosition = GetMousePosition(); + + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + float fp = (float)(mousePosition.y); + frequency = 40.0f + (float)(fp); + } + + // Rewrite the sine wave. + // Compute two cycles to allow the buffer padding, simplifying any modulation, resampling, etc. + if (frequency != oldFrequency) + { + // Compute wavelength. Limit size in both directions. + int oldWavelength = waveLength; + waveLength = (int)(22050/frequency); + if (waveLength > MAX_SAMPLES/2) waveLength = MAX_SAMPLES/2; + if (waveLength < 1) waveLength = 1; + + // Write sine wave. + for (int i = 0; i < waveLength*2; i++) + { + data[i] = (short)(sinf(((2*PI*(float)i/waveLength)))*32000); + } + + // Scale read cursor's position to minimize transition artifacts + readCursor = (int)(readCursor * ((float)waveLength / (float)oldWavelength)); + oldFrequency = frequency; + } + // Refill audio stream if required - // NOTE: Every update we check if stream data has been already consumed and we update - // buffer with new data from the generated samples, we upload data at a rate (MAX_SAMPLES_PER_UPDATE), - // but notice that at some point we update < MAX_SAMPLES_PER_UPDATE data... if (IsAudioBufferProcessed(stream)) { - int numSamples = 0; - if (samplesLeft >= MAX_SAMPLES_PER_UPDATE) numSamples = MAX_SAMPLES_PER_UPDATE; - else numSamples = samplesLeft; - - UpdateAudioStream(stream, data + (totalSamples - samplesLeft), numSamples); + // Synthesize a buffer that is exactly the requested size + int writeCursor = 0; - samplesLeft -= numSamples; + while (writeCursor < MAX_SAMPLES_PER_UPDATE) + { + // Start by trying to write the whole chunk at once + int writeLength = MAX_SAMPLES_PER_UPDATE-writeCursor; + + // Limit to the maximum readable size + int readLength = waveLength-readCursor; + + if (writeLength > readLength) writeLength = readLength; + + // Write the slice + memcpy(writeBuf + writeCursor, data + readCursor, writeLength*sizeof(short)); + + // Update cursors and loop audio + readCursor = (readCursor + writeLength) % waveLength; + + writeCursor += writeLength; + } - // Reset samples feeding (loop audio) - if (samplesLeft <= 0) samplesLeft = totalSamples; + // Copy finished frame to audio stream + UpdateAudioStream(stream, writeBuf, MAX_SAMPLES_PER_UPDATE); } //---------------------------------------------------------------------------------- @@ -84,13 +134,14 @@ int main() ClearBackground(RAYWHITE); - DrawText("SINE WAVE SHOULD BE PLAYING!", 240, 140, 20, LIGHTGRAY); + DrawText(FormatText("sine frequency: %i",(int)frequency), GetScreenWidth() - 220, 10, 20, RED); + DrawText("click mouse button to change frequency", 10, 10, 20, DARKGRAY); - // NOTE: Draw a part of the sine wave (only screen width, proportional values) - for (int i = 0; i < GetScreenWidth(); i++) + // Draw the current buffer state proportionate to the screen + for (int i = 0; i < screenWidth; i++) { position.x = i; - position.y = 250 + 50*data[i]/32000; + position.y = 250 + 50*data[i*MAX_SAMPLES/screenWidth]/32000; DrawPixelV(position, RED); } @@ -102,13 +153,13 @@ int main() // De-Initialization //-------------------------------------------------------------------------------------- free(data); // Unload sine wave data + free(writeBuf); // Unload write buffer CloseAudioStream(stream); // Close raw audio stream and delete buffers from RAM - CloseAudioDevice(); // Close audio device (music streaming is automatically stopped) CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; -}
\ No newline at end of file +} |
