diff --git a/src/audio.c b/src/audio.c index ea14d77d..11d0d6b9 100644 --- a/src/audio.c +++ b/src/audio.c @@ -126,9 +126,8 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -static Wave LoadWAV(const char *fileName); // Load WAV file -static Wave LoadOGG(char *fileName); // Load OGG file -static void UnloadWave(Wave wave); // Unload wave data +static Wave LoadWAV(const char *fileName); // Load WAV file +static Wave LoadOGG(const char *fileName); // Load OGG file #if defined(AUDIO_STANDALONE) const char *GetExtension(const char *fileName); // Get the extension for a filename @@ -206,20 +205,39 @@ bool IsAudioDeviceReady(void) // Module Functions Definition - Sounds loading and playing (.WAV) //---------------------------------------------------------------------------------- -// Load sound to memory -// NOTE: The entire file is loaded to memory to be played (no-streaming) -Sound LoadSound(char *fileName) +// Load wave data from file into RAM +Wave LoadWave(const char *fileName) { Wave wave = { 0 }; if (strcmp(GetExtension(fileName), "wav") == 0) wave = LoadWAV(fileName); else if (strcmp(GetExtension(fileName), "ogg") == 0) wave = LoadOGG(fileName); - else TraceLog(WARNING, "[%s] Sound extension not recognized, it can't be loaded", fileName); + else TraceLog(WARNING, "[%s] File extension not recognized, it can't be loaded", fileName); + return wave; +} + +// Load wave data from float array data (32bit) +Wave LoadWaveEx(float *data, int sampleRate, int sampleSize, int channels) +{ + Wave wave; + + wave.data = data; + + WaveFormat(&wave, sampleRate, sampleSize, channels); + + return wave; +} + +// Load sound to memory +// NOTE: The entire file is loaded to memory to be played (no-streaming) +Sound LoadSound(const char *fileName) +{ + Wave wave = LoadWave(fileName); + Sound sound = LoadSoundFromWave(wave); - - // Sound is loaded, we can unload wave - UnloadWave(wave); + + UnloadWave(wave); // Sound is loaded, we can unload wave return sound; } @@ -401,6 +419,14 @@ Sound LoadSoundFromRES(const char *rresName, int resId) return sound; } +// Unload Wave data +void UnloadWave(Wave wave) +{ + free(wave.data); + + TraceLog(INFO, "Unloaded wave data from RAM"); +} + // Unload sound void UnloadSound(Sound sound) { @@ -504,12 +530,102 @@ void SetSoundPitch(Sound sound, float pitch) alSourcef(sound.source, AL_PITCH, pitch); } +// Convert wave data to desired format +void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) +{ + if (wave->sampleSize != sampleSize) + { + float *samples = GetWaveData(*wave); //Color *pixels = GetImageData(*image); + + free(wave->data); + + //image->format = newFormat; + + if (sampleSize == 8) + { + wave->data = (unsigned char *)malloc(wave->sampleCount*sizeof(unsigned char)); + + for (int i = 0; i < wave->sampleCount; i++) + { + ((unsigned char *)wave->data)[i] = (unsigned char)((float)samples[i]); // TODO: review conversion + } + } + else if (sampleSize == 16) + { + wave->data = (short *)malloc(wave->sampleCount*sizeof(short)); + + for (int i = 0; i < wave->sampleCount; i++) + { + ((short *)wave->data)[i] = (short)((float)samples[i]); // TODO: review conversion + } + } + else if (sampleSize == 32) + { + wave->data = (float *)malloc(wave->sampleCount*sizeof(float)); + + for (int i = 0; i < wave->sampleCount; i++) + { + ((float *)wave->data)[i] = (float)samples[i]; // TODO: review conversion + } + } + else TraceLog(WARNING, "Wave formatting: Sample size not supported"); + } + + // TODO: Consider channels (mono vs stereo) +} + +// Copy a wave to a new wave +Wave WaveCopy(Wave wave) +{ + Wave newWave; + + if (wave.sampleSize == 8) newWave.data = (unsigned char *)malloc(wave.sampleCount*sizeof(unsigned char)); + else if (wave.sampleSize == 16) newWave.data = (short *)malloc(wave.sampleCount*sizeof(short)); + else if (wave.sampleSize == 32) newWave.data = (float *)malloc(wave.sampleCount*sizeof(float)); + else TraceLog(WARNING, "Wave sample size not supported for copy"); + + if (newWave.data != NULL) + { + // NOTE: Size must be provided in bytes + memcpy(newWave.data, wave.data, wave.sampleCount); + + newWave.sampleCount = wave.sampleCount; + newWave.sampleRate = wave.sampleRate; + newWave.sampleSize = wave.sampleSize; + newWave.channels = wave.channels; + } + + return newWave; +} + +// Crop a wave to defined samples range +// NOTE: Security check in case of out-of-range +void WaveCrop(Wave *wave, int initSample, int finalSample) +{ + // TODO: Crop wave to a samples range +} + +// Get samples data from wave as a floats array +float *GetWaveData(Wave wave) +{ + float *samples = (float *)malloc(wave.sampleCount*sizeof(float)); + + for (int i = 0; i < wave.sampleCount; i++) + { + if (wave.sampleSize == 8) samples[i] = (float)((unsigned char *)wave.data)[i]; // TODO: review conversion + else if (wave.sampleSize == 16) samples[i] = (float)((short *)wave.data)[i]; // TODO: review conversion + else if (wave.sampleSize == 32) samples[i] = ((float *)wave.data)[i]; // TODO: review conversion + } + + return samples; +} + //---------------------------------------------------------------------------------- // Module Functions Definition - Music loading and stream playing (.OGG) //---------------------------------------------------------------------------------- // Load music stream from file -Music LoadMusicStream(char *fileName) +Music LoadMusicStream(const char *fileName) { Music music = (MusicData *)malloc(sizeof(MusicData)); @@ -1013,7 +1129,7 @@ static Wave LoadWAV(const char *fileName) // Load OGG file into Wave structure // NOTE: Using stb_vorbis library -static Wave LoadOGG(char *fileName) +static Wave LoadOGG(const char *fileName) { Wave wave; @@ -1054,14 +1170,6 @@ static Wave LoadOGG(char *fileName) return wave; } -// Unload Wave data -static void UnloadWave(Wave wave) -{ - free(wave.data); - - TraceLog(INFO, "Unloaded wave data from RAM"); -} - // Some required functions for audio standalone module version #if defined(AUDIO_STANDALONE) // Get the extension for a filename diff --git a/src/raylib.h b/src/raylib.h index dff69705..ae3de038 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -484,13 +484,6 @@ typedef struct Ray { Vector3 direction; // Ray direction } Ray; -// Sound source type -typedef struct Sound { - unsigned int source; // OpenAL audio source id - unsigned int buffer; // OpenAL audio buffer id - int format; // OpenAL audio format specifier -} Sound; - // Wave type, defines audio wave data typedef struct Wave { unsigned int sampleCount; // Number of samples @@ -500,6 +493,13 @@ typedef struct Wave { void *data; // Buffer data pointer } Wave; +// Sound source type +typedef struct Sound { + unsigned int source; // OpenAL audio source id + unsigned int buffer; // OpenAL audio buffer id + int format; // OpenAL audio format specifier +} Sound; + // Music type (file streaming from memory) // NOTE: Anything longer than ~10 seconds should be streamed typedef struct MusicData *Music; @@ -909,10 +909,13 @@ RLAPI void InitAudioDevice(void); // Initial RLAPI void CloseAudioDevice(void); // Close the audio device and context (and music stream) RLAPI bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully -RLAPI Sound LoadSound(char *fileName); // Load sound to memory +RLAPI Wave LoadWave(const char *fileName); // Load wave data from file into RAM +RLAPI Wave LoadWaveEx(float *data, int sampleRate, int sampleSize, int channels); // Load wave data from float array data (32bit) +RLAPI Sound LoadSound(const char *fileName); // Load sound to memory RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data RLAPI Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource) RLAPI void UpdateSound(Sound sound, void *data, int numSamples); // Update sound buffer with new data +RLAPI void UnloadWave(Wave wave); RLAPI void UnloadSound(Sound sound); // Unload sound RLAPI void PlaySound(Sound sound); // Play a sound RLAPI void PauseSound(Sound sound); // Pause a sound @@ -921,8 +924,11 @@ RLAPI void StopSound(Sound sound); // Stop pl RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) - -RLAPI Music LoadMusicStream(char *fileName); // Load music stream from file +RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format +RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave +RLAPI void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range +RLAPI float *GetWaveData(Wave wave); // Get samples data from wave as a floats array +RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file RLAPI void UnloadMusicStream(Music music); // Unload music stream RLAPI void PlayMusicStream(Music music); // Start music playing (open stream) RLAPI void UpdateMusicStream(Music music); // Updates buffers for music streaming