diff --git a/examples/audio/audio_raw_stream.c b/examples/audio/audio_raw_stream.c index 536f8c311..64c9b5a50 100644 --- a/examples/audio/audio_raw_stream.c +++ b/examples/audio/audio_raw_stream.c @@ -4,14 +4,14 @@ * * 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) * * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software * -* Copyright (c) 2015-2025 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox) +* Copyright (c) 2015-2026 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox) * ********************************************************************************************/ @@ -109,26 +109,26 @@ int main(void) // Draw //---------------------------------------------------------------------------------- BeginDrawing(); - ClearBackground(RAYWHITE); - - DrawText(TextFormat("sine frequency: %i", sineFrequency), screenWidth - 220, 10, 20, RED); - DrawText(TextFormat("pan: %.2f", pan), screenWidth - 220, 30, 20, RED); - DrawText("Up/down to change frequency", 10, 10, 20, DARKGRAY); - DrawText("Left/right to pan", 10, 30, 20, DARKGRAY); - - int windowStart = (GetTime() - sineStartTime)*SAMPLE_RATE; - int windowSize = 0.1f*SAMPLE_RATE; - int wavelength = SAMPLE_RATE/sineFrequency; - - // Draw a sine wave with the same frequency as the one being sent to the audio stream - for (int i = 0; i < screenWidth; i++) - { - int t0 = windowStart + i*windowSize/screenWidth; - int t1 = windowStart + (i + 1)*windowSize/screenWidth; - Vector2 startPos = { i, 250 + 50*sin(2*PI*t0/wavelength) }; - Vector2 endPos = { i + 1, 250 + 50*sin(2*PI*t1/wavelength) }; - DrawLineV(startPos, endPos, RED); - } + ClearBackground(RAYWHITE); + + DrawText(TextFormat("sine frequency: %i", sineFrequency), screenWidth - 220, 10, 20, RED); + DrawText(TextFormat("pan: %.2f", pan), screenWidth - 220, 30, 20, RED); + DrawText("Up/down to change frequency", 10, 10, 20, DARKGRAY); + DrawText("Left/right to pan", 10, 30, 20, DARKGRAY); + + int windowStart = (GetTime() - sineStartTime)*SAMPLE_RATE; + int windowSize = 0.1f*SAMPLE_RATE; + int wavelength = SAMPLE_RATE/sineFrequency; + + // Draw a sine wave with the same frequency as the one being sent to the audio stream + for (int i = 0; i < screenWidth; i++) + { + int t0 = windowStart + i*windowSize/screenWidth; + int t1 = windowStart + (i + 1)*windowSize/screenWidth; + Vector2 startPos = { i, 250 + 50*sin(2*PI*t0/wavelength) }; + Vector2 endPos = { i + 1, 250 + 50*sin(2*PI*t1/wavelength) }; + DrawLineV(startPos, endPos, RED); + } EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/examples/audio/audio_stream_callback.c b/examples/audio/audio_stream_callback.c new file mode 100644 index 000000000..e31e8e80b --- /dev/null +++ b/examples/audio/audio_stream_callback.c @@ -0,0 +1,236 @@ +/******************************************************************************************* +* +* raylib [audio] example - stream callback +* +* Example complexity rating: [★★★☆] 3/4 +* +* Example originally created with raylib 6.0, last time updated with raylib 6.0 +* +* Example created by Dan Hoang (@dan-hoang) and reviewed by +* +* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software +* +* Copyright (c) 2015-2026 +* +********************************************************************************************/ + +#include "raylib.h" +#include +#include + +#define BUFFER_SIZE 4096 +#define SAMPLE_RATE 44100 + +// This example sends a wave to the audio device +// The user gets the choice of four waves: sine, square, triangle, and sawtooth +// A stream is set up to play to the audio device +// The stream is hooked to a callback that generates a wave +// The callback used is determined by user choice +typedef enum +{ + SINE, + SQUARE, + TRIANGLE, + SAWTOOTH +} WaveType; + +int waveFrequency = 440; +int newWaveFrequency = 440; +int waveIndex = 0; + +// Buffer for keeping the last second of uploaded audio, part of which will be drawn on the screen +float buffer[SAMPLE_RATE] = {}; + +void SineCallback(void *framesOut, unsigned int frameCount) +{ + int wavelength = SAMPLE_RATE/waveFrequency; + + // Synthesize the sine wave + for (int i = 0; i < frameCount; i++) + { + ((float *)framesOut)[i] = sin(2*PI*waveIndex/wavelength); + + waveIndex++; + + if (waveIndex >= wavelength) + { + waveFrequency = newWaveFrequency; + waveIndex = 0; + } + } + + // Save the synthesized samples for later drawing + for (int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount]; + for (int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i]; +} + +void SquareCallback(void *framesOut, unsigned int frameCount) +{ + int wavelength = SAMPLE_RATE/waveFrequency; + + // Synthesize the square wave + for (int i = 0; i < frameCount; i++) + { + ((float *)framesOut)[i] = (waveIndex < wavelength/2)? 1 : -1; + waveIndex++; + + if (waveIndex >= wavelength) + { + waveFrequency = newWaveFrequency; + waveIndex = 0; + } + } + + // Save the synthesized samples for later drawing + for (int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount]; + for (int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i]; +} + +void TriangleCallback(void *framesOut, unsigned int frameCount) +{ + int wavelength = SAMPLE_RATE/waveFrequency; + + // Synthesize the triangle wave + for (int i = 0; i < frameCount; i++) + { + ((float *)framesOut)[i] = (waveIndex < wavelength/2)? (-1 + 2.0f*waveIndex/(wavelength/2)) : (1 - 2.0f*(waveIndex - wavelength/2)/(wavelength/2)); + waveIndex++; + + if (waveIndex >= wavelength) + { + waveFrequency = newWaveFrequency; + waveIndex = 0; + } + } + + // Save the synthesized samples for later drawing + for (int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount]; + for (int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i]; +} + +void SawtoothCallback(void *framesOut, unsigned int frameCount) +{ + int wavelength = SAMPLE_RATE/waveFrequency; + + // Synthesize the sawtooth wave + for (int i = 0; i < frameCount; i++) + { + ((float *)framesOut)[i] = -1 + 2.0f*waveIndex/wavelength; + waveIndex++; + + if (waveIndex >= wavelength) + { + waveFrequency = newWaveFrequency; + waveIndex = 0; + } + } + + // Save the synthesized samples for later drawing + for (int i = 0; i < SAMPLE_RATE - frameCount; i++) buffer[i] = buffer[i + frameCount]; + for (int i = 0; i < frameCount; i++) buffer[SAMPLE_RATE - frameCount + i] = ((float *)framesOut)[i]; +} + +AudioCallback waveCallbacks[] = { SineCallback, SquareCallback, TriangleCallback, SawtoothCallback }; +char *waveTypesAsString[] = { "sine", "square", "triangle", "sawtooth" }; + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [audio] example - stream callback"); + + InitAudioDevice(); + + // Set the number of samples the stream will keep in memory at a time to BUFFER_SIZE + SetAudioStreamBufferSizeDefault(BUFFER_SIZE); + + // Init raw audio stream (sample rate: 44100, sample size: 32bit-float, channels: 1-mono) + AudioStream stream = LoadAudioStream(SAMPLE_RATE, 32, 1); + PlayAudioStream(stream); + + // Configure it so that waveCallbacks[waveType] is called whenever stream is out of samples + WaveType waveType = SINE; + SetAudioStreamCallback(stream, waveCallbacks[waveType]); + + SetTargetFPS(30); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + + if (IsKeyDown(KEY_UP)) + { + newWaveFrequency += 10; + if (newWaveFrequency > 12500) newWaveFrequency = 12500; + } + + if (IsKeyDown(KEY_DOWN)) + { + newWaveFrequency -= 10; + if (newWaveFrequency < 20) newWaveFrequency = 20; + } + + if (IsKeyPressed(KEY_LEFT)) + { + if (waveType == SINE) waveType = SAWTOOTH; + else if (waveType == SQUARE) waveType = SINE; + else if (waveType == TRIANGLE) waveType = SQUARE; + else waveType = TRIANGLE; + + SetAudioStreamCallback(stream, waveCallbacks[waveType]); + } + + if (IsKeyPressed(KEY_RIGHT)) + { + if (waveType == SINE) waveType = SQUARE; + else if (waveType == SQUARE) waveType = TRIANGLE; + else if (waveType == TRIANGLE) waveType = SAWTOOTH; + else waveType = SINE; + + SetAudioStreamCallback(stream, waveCallbacks[waveType]); + } + + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + DrawText(TextFormat("frequency: %i", newWaveFrequency), screenWidth - 220, 10, 20, RED); + DrawText(TextFormat("wave type: %s", waveTypesAsString[waveType]), screenWidth - 220, 30, 20, RED); + DrawText("Up/down to change frequency", 10, 10, 20, DARKGRAY); + DrawText("Left/right to change wave type", 10, 30, 20, DARKGRAY); + + // Draw the last 10 ms of uploaded audio + for (int i = 0; i < screenWidth; i++) + { + Vector2 startPos = { i, 250 - 50*buffer[SAMPLE_RATE - SAMPLE_RATE/100 + i*SAMPLE_RATE/100/screenWidth] }; + Vector2 endPos = { i + 1, 250 - 50*buffer[SAMPLE_RATE - SAMPLE_RATE/100 + (i + 1)*SAMPLE_RATE/100/screenWidth] }; + DrawLineV(startPos, endPos, RED); + } + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadAudioStream(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; +} diff --git a/examples/audio/audio_stream_callback.png b/examples/audio/audio_stream_callback.png new file mode 100644 index 000000000..12305744e Binary files /dev/null and b/examples/audio/audio_stream_callback.png differ