| @ -0,0 +1,267 @@ | |||
| /******************************************************************************************* | |||
| * | |||
| * 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 <stdlib.h> | |||
| #include <math.h> | |||
| #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)) | |||
| { | |||
| switch (waveType) | |||
| { | |||
| case SINE: | |||
| { | |||
| waveType = SAWTOOTH; | |||
| } break; | |||
| case SQUARE: | |||
| { | |||
| waveType = SINE; | |||
| } break; | |||
| case TRIANGLE: | |||
| { | |||
| waveType = SQUARE; | |||
| } break; | |||
| case SAWTOOTH: | |||
| { | |||
| waveType = TRIANGLE; | |||
| } break; | |||
| } | |||
| SetAudioStreamCallback(stream, waveCallbacks[waveType]); | |||
| } | |||
| if (IsKeyPressed(KEY_RIGHT)) | |||
| { | |||
| switch (waveType) | |||
| { | |||
| case SINE: | |||
| { | |||
| waveType = SQUARE; | |||
| } break; | |||
| case SQUARE: | |||
| { | |||
| waveType = TRIANGLE; | |||
| } break; | |||
| case TRIANGLE: | |||
| { | |||
| waveType = SAWTOOTH; | |||
| } break; | |||
| case SAWTOOTH: | |||
| { | |||
| waveType = SINE; | |||
| } break; | |||
| } | |||
| 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 | |||
| //-------------------------------------------------------------------------------------- | |||
| TakeScreenshot("hello.png"); | |||
| 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; | |||
| } | |||