Add SetAudioStreamCallback method to fill audio streams on the audio thread.

This commit is contained in:
ptarabbia 2021-12-12 19:37:09 -05:00
parent 20f4d8c147
commit 9238d8e656
4 changed files with 69 additions and 49 deletions

View File

@ -20,6 +20,33 @@
#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;
void audioCallback(void* buffer, unsigned int nFrames, void* callbackData)
{
audioFrequency = frequency + (audioFrequency - frequency) * 0.95f;
audioFrequency += 1.0f;
audioFrequency -= 1.0f;
float incr = audioFrequency / 44100.0f;
short* d = (short*)buffer;
for (int i = 0; i < nFrames; i++)
{
d[i] = (short)(32000.0f * sinf(2 * PI * sineIdx));
sineIdx += incr;
if (sineIdx > 1.0f) sineIdx -= 1.0f;
}
}
int main(void)
{
// Initialization
@ -33,9 +60,11 @@ int main(void)
SetAudioStreamBufferSizeDefault(MAX_SAMPLES_PER_UPDATE);
// Init raw audio stream (sample rate: 22050, sample size: 16bit-short, channels: 1-mono)
// Init raw audio stream (sample rate: 44100, sample size: 16bit-short, channels: 1-mono)
AudioStream stream = LoadAudioStream(44100, 16, 1);
SetAudioStreamCallback(stream, &audioCallback, NULL);
// Buffer for the single cycle waveform we are synthesizing
short *data = (short *)malloc(sizeof(short)*MAX_SAMPLES);
@ -47,15 +76,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;
@ -78,56 +98,23 @@ int main(void)
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;
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++)
for (int i = 0; i < waveLength * 2; i++)
{
data[i] = (short)(sinf(((2*PI*(float)i/waveLength)))*32000);
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
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
@ -147,7 +134,6 @@ int main(void)
DrawPixelV(position, RED);
}
EndDrawing();
//----------------------------------------------------------------------------------
}

View File

@ -315,6 +315,9 @@ typedef enum {
struct rAudioBuffer {
ma_data_converter converter; // Audio data converter
void (*audioCallback)(void*, unsigned int); // optional callback for filling in buffer on audio threads
void* audioCallbackData; // optional data passed to callback
float volume; // Audio buffer volume
float pitch; // Audio buffer pitch
@ -396,6 +399,7 @@ void PlayAudioBuffer(AudioBuffer *buffer);
void StopAudioBuffer(AudioBuffer *buffer);
void PauseAudioBuffer(AudioBuffer *buffer);
void ResumeAudioBuffer(AudioBuffer *buffer);
void SetAudioBufferCallback(AudioBuffer* buffer, int callback(void*));
void SetAudioBufferVolume(AudioBuffer *buffer, float volume);
void SetAudioBufferPitch(AudioBuffer *buffer, float pitch);
void TrackAudioBuffer(AudioBuffer *buffer);
@ -553,6 +557,8 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
// Init audio buffer values
audioBuffer->volume = 1.0f;
audioBuffer->pitch = 1.0f;
audioBuffer->audioCallback = NULL;
audioBuffer->audioCallbackData = NULL;
audioBuffer->playing = false;
audioBuffer->paused = false;
audioBuffer->looping = false;
@ -635,6 +641,16 @@ void ResumeAudioBuffer(AudioBuffer *buffer)
if (buffer != NULL) buffer->paused = false;
}
// Audio thread callback to request new data
void SetAudioBufferCallback(AudioBuffer* buffer, void callback(void*, unsigned int, void*), void* callbackData)
{
if (buffer != NULL)
{
buffer->audioCallback = callback;
buffer->audioCallbackData = callbackData;
}
}
// Set volume for an audio buffer
void SetAudioBufferVolume(AudioBuffer *buffer, float volume)
{
@ -1040,6 +1056,9 @@ void PlaySoundMulti(Sound sound)
AUDIO.MultiChannel.pool[index]->volume = sound.stream.buffer->volume;
AUDIO.MultiChannel.pool[index]->pitch = sound.stream.buffer->pitch;
AUDIO.MultiChannel.pool[index]->audioCallback = sound.stream.buffer->audioCallback;
AUDIO.MultiChannel.pool[index]->audioCallbackData = sound.stream.buffer->audioCallbackData;
AUDIO.MultiChannel.pool[index]->looping = sound.stream.buffer->looping;
AUDIO.MultiChannel.pool[index]->usage = sound.stream.buffer->usage;
AUDIO.MultiChannel.pool[index]->isSubBufferProcessed[0] = false;
@ -1987,6 +2006,12 @@ void SetAudioStreamBufferSizeDefault(int size)
AUDIO.Buffer.defaultSize = size;
}
// Audio thread callback to request new data
void SetAudioStreamCallback(AudioStream stream, void callback(void*, unsigned int, void*), void* callbackData)
{
SetAudioBufferCallback(stream.buffer, callback, callbackData);
}
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
@ -2003,6 +2028,12 @@ static void OnLog(ma_context *pContext, ma_device *pDevice, ma_uint32 logLevel,
// Reads audio data from an AudioBuffer object in internal format.
static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, void *framesOut, ma_uint32 frameCount)
{
if (audioBuffer->audioCallback)
{
audioBuffer->audioCallback(framesOut, frameCount, audioBuffer->audioCallbackData);
return frameCount;
}
ma_uint32 subBufferSizeInFrames = (audioBuffer->sizeInFrames > 1)? audioBuffer->sizeInFrames/2 : audioBuffer->sizeInFrames;
ma_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames;
@ -2030,7 +2061,8 @@ static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer,
}
else
{
if (isSubBufferProcessed[currentSubBufferIndex]) break;
if (isSubBufferProcessed[currentSubBufferIndex])
break;
}
ma_uint32 totalFramesRemaining = (frameCount - framesRead);

View File

@ -190,6 +190,7 @@ void StopAudioStream(AudioStream stream); // Stop audio st
void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams
void SetAudioStreamCallback(AudioStream stream, void callback(void*, unsigned int, void*), void* callbackData); // Audio thread callback to request new data
#ifdef __cplusplus
}

View File

@ -1530,6 +1530,7 @@ RLAPI void StopAudioStream(AudioStream stream); // Stop au
RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams
RLAPI void SetAudioStreamCallback(AudioStream stream, void callback(void*, unsigned int, void*), void* callbackData); // Audio thread callback to request new data
#if defined(__cplusplus)
}