diff --git a/examples/audio/audio_raw_stream.c b/examples/audio/audio_raw_stream.c index 9b2d1022..ddf4337e 100644 --- a/examples/audio/audio_raw_stream.c +++ b/examples/audio/audio_raw_stream.c @@ -20,6 +20,35 @@ #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 frames) +{ + 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 < frames; 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 +62,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); + // Buffer for the single cycle waveform we are synthesizing short *data = (short *)malloc(sizeof(short)*MAX_SAMPLES); @@ -47,6 +78,7 @@ int main(void) // Position read in to determine next frequency Vector2 mousePosition = { -100.0f, -100.0f }; + /* // Cycles per second (hz) float frequency = 440.0f; @@ -55,6 +87,7 @@ 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; @@ -82,7 +115,7 @@ int main(void) SetAudioStreamPan(stream, pan); } - // Rewrite the sine wave. + // Rewrite the sine wave // Compute two cycles to allow the buffer padding, simplifying any modulation, resampling, etc. if (frequency != oldFrequency) { @@ -92,17 +125,18 @@ int main(void) if (waveLength > MAX_SAMPLES/2) waveLength = MAX_SAMPLES/2; if (waveLength < 1) waveLength = 1; - // Write sine wave. + // Write sine wave for (int i = 0; i < waveLength*2; i++) { 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)); + //readCursor = (int)(readCursor * ((float)waveLength / (float)oldWavelength)); oldFrequency = frequency; } + /* // Refill audio stream if required if (IsAudioStreamProcessed(stream)) { @@ -131,6 +165,7 @@ int main(void) // Copy finished frame to audio stream UpdateAudioStream(stream, writeBuf, MAX_SAMPLES_PER_UPDATE); } + */ //---------------------------------------------------------------------------------- // Draw diff --git a/src/raudio.c b/src/raudio.c index d5b13086..8118338b 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -311,9 +311,11 @@ typedef enum { AUDIO_BUFFER_USAGE_STREAM } AudioBufferUsage; -// Audio buffer structure +// Audio buffer struct struct rAudioBuffer { ma_data_converter converter; // Audio data converter + + AudioStreamCallback callback; // Audio buffer callback for buffer filling on audio threads float volume; // Audio buffer volume float pitch; // Audio buffer pitch @@ -555,10 +557,13 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam audioBuffer->volume = 1.0f; audioBuffer->pitch = 1.0f; audioBuffer->pan = 0.5f; + + audioBuffer->callback = NULL; audioBuffer->playing = false; audioBuffer->paused = false; audioBuffer->looping = false; + audioBuffer->usage = usage; audioBuffer->frameCursorPos = 0; audioBuffer->sizeInFrames = sizeInFrames; @@ -2028,6 +2033,12 @@ void SetAudioStreamBufferSizeDefault(int size) AUDIO.Buffer.defaultSize = size; } +// Audio thread callback to request new data +void SetAudioStreamCallback(AudioStream stream, AudioStreamCallback callback) +{ + if (stream.buffer != NULL) stream.buffer->callback = callback; +} + //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- @@ -2041,6 +2052,15 @@ static void OnLog(void *pUserData, ma_uint32 level, const char *pMessage) // Reads audio data from an AudioBuffer object in internal format. static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, void *framesOut, ma_uint32 frameCount) { + // Using audio buffer callback + if (audioBuffer->callback) + { + audioBuffer->callback(framesOut, frameCount); + audioBuffer->framesProcessed += frameCount; + + return frameCount; + } + ma_uint32 subBufferSizeInFrames = (audioBuffer->sizeInFrames > 1)? audioBuffer->sizeInFrames/2 : audioBuffer->sizeInFrames; ma_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames; diff --git a/src/raylib.h b/src/raylib.h index 262194fd..198cadea 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -425,6 +425,8 @@ typedef struct Wave { void *data; // Buffer data pointer } Wave; +// Opaque structs declaration +// NOTE: Actual structs are defined internally in raudio module typedef struct rAudioBuffer rAudioBuffer; // AudioStream, custom audio stream @@ -1472,6 +1474,7 @@ RLAPI RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) //------------------------------------------------------------------------------------ +typedef void (*AudioStreamCallback)(void *bufferData, unsigned int frames); // Audio device management functions RLAPI void InitAudioDevice(void); // Initialize audio device and context @@ -1539,6 +1542,7 @@ RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set vol RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) RLAPI void SetAudioStreamPan(AudioStream stream, float pan); // Set pan for audio stream (0.5 is centered) RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams +RLAPI void SetAudioStreamCallback(AudioStream stream, AudioStreamCallback callback); // Audio thread callback to request new data #if defined(__cplusplus) }