Files
raylib/examples/audio/audio_stream_callback.c
dan-hoang 70cb8d15e0 [examples] Add audio_stream_callback (#5638)
* Add audio_raw_stream_callback.c

* Update audio_raw_stream_callback.c to more closely follow raylib coding conventions

* Remove spaces before asterisks in comments in audio_raw_stream_callback.c

* Put SetTargetFPS(30) before while(!WindowShouldClose()) in audio_raw_stream_callback.c

* Add audio_stream_callback.c

* Delete examples/audio/audio_raw_stream_callback.c

* Delete examples/audio/audio_raw_stream_callback.png

* Update audio_raw_stream.c to more closely follow raylib coding conventions

Drawing code wasn't tabbed in

* Remove screenshot code in audio_stream_callback.c

* Update raylib version and copyright year in audio_raw_stream.c

* Update audio_stream_callback.c

Used if instead of switch to compact code; seemed more readable in this case.
2026-03-13 18:51:49 +01:00

237 lines
8.1 KiB
C

/*******************************************************************************************
*
* 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))
{
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;
}