diff --git a/examples/audio/audio_raw_stream.c b/examples/audio/audio_raw_stream.c index 4deae2090..0195efba8 100644 --- a/examples/audio/audio_raw_stream.c +++ b/examples/audio/audio_raw_stream.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★☆] 3/4 * -* Example originally created with raylib 1.6, last time updated with raylib 4.2 +* Example originally created with raylib 1.6, last time updated with raylib 6.0 * * Example created by Ramon Santamaria (@raysan5) and reviewed by James Hofmann (@triplefox) * @@ -24,34 +24,6 @@ #define MAX_SAMPLES 512 #define MAX_SAMPLES_PER_UPDATE 4096 -// Cycles per second (hz) -float frequency = 440.0f; - -// Audio frequency, for smoothing -float audioFrequency = 440.0f; - -// Previous value, used to test if sine needs to be rewritten, and to smoothly modulate frequency -float oldFrequency = 1.0f; - -// Index for audio rendering -float sineIdx = 0.0f; - -// Audio input processing callback -void AudioInputCallback(void *buffer, unsigned int frames) -{ - audioFrequency = frequency + (audioFrequency - frequency)*0.95f; - - float incr = audioFrequency/44100.0f; - short *d = (short *)buffer; - - for (unsigned int i = 0; i < frames; i++) - { - d[i] = (short)(32000.0f*sinf(2*PI*sineIdx)); - sineIdx += incr; - if (sineIdx > 1.0f) sineIdx -= 1.0f; - } -} - //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ @@ -71,8 +43,6 @@ int main(void) // Init raw audio stream (sample rate: 44100, sample size: 16bit-short, channels: 1-mono) AudioStream stream = LoadAudioStream(44100, 16, 1); - SetAudioStreamCallback(stream, AudioInputCallback); - // Buffer for the single cycle waveform we are synthesizing short *data = (short *)malloc(sizeof(short)*MAX_SAMPLES); @@ -84,7 +54,6 @@ int main(void) // Position read in to determine next frequency Vector2 mousePosition = { -100.0f, -100.0f }; - /* // Cycles per second (hz) float frequency = 440.0f; @@ -93,7 +62,6 @@ int main(void) // 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; @@ -124,8 +92,8 @@ int main(void) if (frequency != oldFrequency) { // Compute wavelength. Limit size in both directions - //int oldWavelength = waveLength; - waveLength = (int)(22050/frequency); + int oldWavelength = waveLength; + waveLength = (int)(stream.sampleRate/frequency); if (waveLength > MAX_SAMPLES/2) waveLength = MAX_SAMPLES/2; if (waveLength < 1) waveLength = 1; @@ -141,11 +109,10 @@ int main(void) } // Scale read cursor's position to minimize transition artifacts - //readCursor = (int)(readCursor*((float)waveLength/(float)oldWavelength)); + readCursor = (int)(readCursor*((float)waveLength/(float)oldWavelength)); oldFrequency = frequency; } - /* // Refill audio stream if required if (IsAudioStreamProcessed(stream)) { @@ -174,7 +141,6 @@ int main(void) // Copy finished frame to audio stream UpdateAudioStream(stream, writeBuf, MAX_SAMPLES_PER_UPDATE); } - */ //---------------------------------------------------------------------------------- // Draw diff --git a/examples/audio/audio_raw_stream_callback.c b/examples/audio/audio_raw_stream_callback.c index 501a0c324..746b29716 100644 --- a/examples/audio/audio_raw_stream_callback.c +++ b/examples/audio/audio_raw_stream_callback.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★☆] 3/4 * -* Example originally created with raylib 1.6, last time updated with raylib 4.2 +* Example originally created with raylib 1.6, last time updated with raylib 6.0 * * Example created by Ramon Santamaria (@raysan5) and reviewed by James Hofmann (@triplefox) * @@ -19,7 +19,12 @@ #include // Required for: malloc(), free() #include // Required for: sinf() -#include // Required for: memcpy() + +enum Flags { FLAG_CHANNEL_MONO = 1u<<0, FLAG_SAMPLESIZE_SHORT = 1u<<1 }; +static unsigned int gflags = FLAG_CHANNEL_MONO | FLAG_SAMPLESIZE_SHORT; // mono + 16-bit to match initial stream specs +#define CHANNEL_MONO() ((gflags & FLAG_CHANNEL_MONO) != 0) +#define SAMPLESIZE_SHORT() ((gflags & FLAG_SAMPLESIZE_SHORT) != 0) +#define TOGGLE(K, F) do { if (IsKeyPressed(K)) { gflags ^= (F); } } while (0) #define MAX_SAMPLES 512 #define MAX_SAMPLES_PER_UPDATE 4096 @@ -37,7 +42,7 @@ float oldFrequency = 1.0f; float sineIdx = 0.0f; // Audio input processing callback -void AudioInputCallback(void *buffer, unsigned int frames) +void AudioInputCallbackMonoShort(void *buffer, unsigned int frames) { audioFrequency = frequency + (audioFrequency - frequency)*0.95f; @@ -52,6 +57,54 @@ void AudioInputCallback(void *buffer, unsigned int frames) } } +void AudioInputCallbackStereoShort(void *buffer, unsigned int frames) +{ + audioFrequency = frequency + (audioFrequency - frequency)*0.95f; + + float incr = audioFrequency/44100.0f; + short *d = (short *)buffer; + + for (unsigned int i = 0; i < frames; i++) + { + short s = (short)(32000.0f*sinf(2*PI*sineIdx)); + d[2*i + 0] = s; // L + d[2*i + 1] = s; // R + sineIdx += incr; + if (sineIdx > 1.0f) sineIdx -= 1.0f; + } +} + +void AudioInputCallbackMonoFloat(void *buffer, unsigned int frames) +{ + audioFrequency = frequency + (audioFrequency - frequency)*0.95f; + + float incr = audioFrequency/44100.0f; + float *d = (float *)buffer; + + for (unsigned int i = 0; i < frames; i++) + { + d[i] = sinf(2*PI*sineIdx); + sineIdx += incr; + if (sineIdx > 1.0f) sineIdx -= 1.0f; + } +} + +void AudioInputCallbackStereoFloat(void *buffer, unsigned int frames) +{ + audioFrequency = frequency + (audioFrequency - frequency)*0.95f; + float incr = audioFrequency/44100.0f; + float *d = (float *)buffer; + for (unsigned int i = 0; i < frames; i++) + { + float s = sinf(2*PI*sineIdx); + d[2*i + 0] = s; + d[2*i + 1] = s; + + sineIdx += incr; + if (sineIdx > 1.0f) sineIdx -= 1.0f; + } +} + //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ @@ -62,7 +115,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [audio] example - raw stream"); + InitWindow(screenWidth, screenHeight, "raylib [audio] example - raw stream with callbacks"); InitAudioDevice(); // Initialize audio device @@ -71,7 +124,9 @@ int main(void) // Init raw audio stream (sample rate: 44100, sample size: 16bit-short, channels: 1-mono) AudioStream stream = LoadAudioStream(44100, 16, 1); - SetAudioStreamCallback(stream, AudioInputCallback); + SetAudioStreamCallback(stream, AudioInputCallbackMonoShort); + unsigned int previousSampleSize = stream.sampleSize; + unsigned int previousChannels = stream.channels; // Buffer for the single cycle waveform we are synthesizing short *data = (short *)malloc(sizeof(short)*MAX_SAMPLES); @@ -84,17 +139,6 @@ int main(void) // 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; @@ -106,6 +150,32 @@ int main(void) // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key { + TOGGLE(KEY_M, FLAG_CHANNEL_MONO); + TOGGLE(KEY_F, FLAG_SAMPLESIZE_SHORT); + unsigned int nextSampleSize = (SAMPLESIZE_SHORT())? 16u : 32u; + unsigned int nextChannels = (CHANNEL_MONO())? 1u : 2u; + if (nextSampleSize != previousSampleSize || nextChannels != previousChannels) + { + StopAudioStream(stream); + UnloadAudioStream(stream); + stream = LoadAudioStream(44100, nextSampleSize, nextChannels); + // CORRECT ALIGNMENT + if (nextChannels == 1 && nextSampleSize == 16) SetAudioStreamCallback(stream, AudioInputCallbackMonoShort); + if (nextChannels == 2 && nextSampleSize == 16) SetAudioStreamCallback(stream, AudioInputCallbackStereoShort); + if (nextChannels == 1 && nextSampleSize == 32) SetAudioStreamCallback(stream, AudioInputCallbackMonoFloat); + if (nextChannels == 2 && nextSampleSize == 32) SetAudioStreamCallback(stream, AudioInputCallbackStereoFloat); + + // INCORRECT ALIGNMENT TESTS: comment and uncomment or add your own to observe common misconfigurations + // if (nextChannels == 1 && nextSampleSize == 16) SetAudioStreamCallback(stream, AudioInputCallbackStereoShort); + // if (nextChannels == 1 && nextSampleSize == 32) SetAudioStreamCallback(stream, AudioInputCallbackMonoShort); + // if (nextChannels == 2 && nextSampleSize == 32) SetAudioStreamCallback(stream, AudioInputCallbackMonoShort); + // if (nextChannels == 2 && nextSampleSize == 16) SetAudioStreamCallback(stream, AudioInputCallbackMonoFloat); + // if (nextChannels == 2 && nextSampleSize == 16) SetAudioStreamCallback(stream, AudioInputCallbackStereoFloat); + + PlayAudioStream(stream); + previousSampleSize = nextSampleSize; + previousChannels = nextChannels; + } // Update //---------------------------------------------------------------------------------- mousePosition = GetMousePosition(); @@ -124,7 +194,6 @@ int main(void) 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; @@ -140,41 +209,9 @@ int main(void) data[j] = (short)0; } - // Scale read cursor's position to minimize transition artifacts - //readCursor = (int)(readCursor*((float)waveLength/(float)oldWavelength)); oldFrequency = frequency; } - /* - // Refill audio stream if required - if (IsAudioStreamProcessed(stream)) - { - // Synthesize a buffer that is exactly the requested size - int writeCursor = 0; - - 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; - } - - // Copy finished frame to audio stream - UpdateAudioStream(stream, writeBuf, MAX_SAMPLES_PER_UPDATE); - } - */ //---------------------------------------------------------------------------------- // Draw @@ -185,6 +222,10 @@ int main(void) DrawText(TextFormat("sine frequency: %i",(int)frequency), GetScreenWidth() - 220, 10, 20, RED); DrawText("click mouse button to change frequency or pan", 10, 10, 20, DARKGRAY); + DrawText("press M to SWAP channels [ M ]:", 250, 366, 20, BLUE); + DrawText((CHANNEL_MONO())? "MONO" : "STEREO", 600, 366, 20, (CHANNEL_MONO())? GREEN : RED); + DrawText("press F to SWAP Sample Size [ F ]:", 250, 400, 20, BLUE); + DrawText((SAMPLESIZE_SHORT())? "16" : "32", 620, 400, 20, (SAMPLESIZE_SHORT())? GREEN : RED); // Draw the current buffer state proportionate to the screen for (int i = 0; i < screenWidth; i++) diff --git a/examples/audio/audio_raw_stream_callback.png b/examples/audio/audio_raw_stream_callback.png new file mode 100644 index 000000000..08ab77ac9 Binary files /dev/null and b/examples/audio/audio_raw_stream_callback.png differ diff --git a/examples/audio/audio_sound_loading.c b/examples/audio/audio_sound_loading.c index 97e26a450..997c93b19 100644 --- a/examples/audio/audio_sound_loading.c +++ b/examples/audio/audio_sound_loading.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★☆☆☆] 1/4 * -* Example originally created with raylib 1.1, last time updated with raylib 3.5 +* Example originally created with raylib 1.1, last time updated with raylib 6.0 * * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software @@ -14,6 +14,8 @@ ********************************************************************************************/ #include "raylib.h" +#include // Required for: malloc(), free() +#include // Required for: memcpy() //------------------------------------------------------------------------------------ // Program main entry point @@ -32,6 +34,17 @@ int main(void) Sound fxWav = LoadSound("resources/sound.wav"); // Load WAV audio file Sound fxOgg = LoadSound("resources/target.ogg"); // Load OGG audio file + bool soundReversed = false; + + float *soundData = malloc(sizeof(float)*fxWav.frameCount*fxWav.stream.channels); + float *scratchSoundData = malloc(sizeof(float)*fxWav.frameCount*fxWav.stream.channels); + + Wave wave = LoadWave("resources/sound.wav"); + // Sounds always have 32bit sampleSize: + WaveFormat(&wave, fxWav.stream.sampleRate, 32, fxWav.stream.channels); + memcpy(soundData, wave.data, sizeof(float)*fxWav.frameCount*fxWav.stream.channels); + UnloadWave(wave); + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -40,6 +53,18 @@ int main(void) { // Update //---------------------------------------------------------------------------------- + if (IsKeyPressed(KEY_R)) + { + soundReversed = !soundReversed; + for (unsigned int i = 0; i < fxWav.frameCount; i++) + { + unsigned int src = (soundReversed)? fxWav.frameCount - 1 - i : i; + // Sounds always have STEREO channels: + scratchSoundData[i * fxWav.stream.channels + 0] = soundData[src * fxWav.stream.channels + 0]; + scratchSoundData[i * fxWav.stream.channels + 1] = soundData[src * fxWav.stream.channels + 1]; + } + UpdateSound(fxWav, scratchSoundData, fxWav.frameCount); + } if (IsKeyPressed(KEY_SPACE)) PlaySound(fxWav); // Play WAV sound if (IsKeyPressed(KEY_ENTER)) PlaySound(fxOgg); // Play OGG sound //---------------------------------------------------------------------------------- @@ -51,7 +76,9 @@ int main(void) ClearBackground(RAYWHITE); DrawText("Press SPACE to PLAY the WAV sound!", 200, 180, 20, LIGHTGRAY); - DrawText("Press ENTER to PLAY the OGG sound!", 200, 220, 20, LIGHTGRAY); + DrawText(TextFormat("Press R to REVERSE the WAV sound : "), 120, 220, 20, LIGHTGRAY); + DrawText((soundReversed)? "BACKWARDS" : "FORWARDS", 525, 220, 20, (soundReversed)? MAROON : DARKGREEN); + DrawText("Press ENTER to PLAY the OGG sound!", 200, 260, 20, LIGHTGRAY); EndDrawing(); //---------------------------------------------------------------------------------- @@ -59,6 +86,8 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- + free(soundData); + free(scratchSoundData); UnloadSound(fxWav); // Unload sound data UnloadSound(fxOgg); // Unload sound data diff --git a/examples/audio/audio_sound_loading.png b/examples/audio/audio_sound_loading.png index 24071ce3c..64b463f6c 100644 Binary files a/examples/audio/audio_sound_loading.png and b/examples/audio/audio_sound_loading.png differ