aboutsummaryrefslogtreecommitdiff
path: root/src/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio.c')
-rw-r--r--src/audio.c156
1 files changed, 93 insertions, 63 deletions
diff --git a/src/audio.c b/src/audio.c
index 4b8641ab..3bace5f7 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -183,7 +183,7 @@ void CloseAudioDevice(void)
alcMakeContextCurrent(NULL);
alcDestroyContext(context);
alcCloseDevice(device);
-
+
TraceLog(INFO, "Audio device closed successfully");
}
@@ -217,7 +217,7 @@ Sound LoadSound(char *fileName)
else TraceLog(WARNING, "[%s] Sound extension not recognized, it can't be loaded", fileName);
Sound sound = LoadSoundFromWave(wave);
-
+
// Sound is loaded, we can unload wave
UnloadWave(wave);
@@ -233,17 +233,29 @@ Sound LoadSoundFromWave(Wave wave)
if (wave.data != NULL)
{
ALenum format = 0;
- // The OpenAL format is worked out by looking at the number of channels and the bits per sample
+
+ // The OpenAL format is worked out by looking at the number of channels and the sample size (bits per sample)
if (wave.channels == 1)
{
- if (wave.bitsPerSample == 8 ) format = AL_FORMAT_MONO8;
- else if (wave.bitsPerSample == 16) format = AL_FORMAT_MONO16;
+ switch (wave.sampleSize)
+ {
+ case 8: format = AL_FORMAT_MONO8; break;
+ case 16: format = AL_FORMAT_MONO16; break;
+ case 32: format = AL_FORMAT_MONO_FLOAT32; break;
+ default: TraceLog(WARNING, "Wave sample size not supported: %i", wave.sampleSize); break;
+ }
}
else if (wave.channels == 2)
{
- if (wave.bitsPerSample == 8 ) format = AL_FORMAT_STEREO8;
- else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16;
+ switch (wave.sampleSize)
+ {
+ case 8: format = AL_FORMAT_STEREO8; break;
+ case 16: format = AL_FORMAT_STEREO16; break;
+ case 32: format = AL_FORMAT_STEREO_FLOAT32; break;
+ default: TraceLog(WARNING, "Wave sample size not supported: %i", wave.sampleSize); break;
+ }
}
+ else TraceLog(WARNING, "Wave number of channels not supported: %i", wave.channels);
// Create an audio source
ALuint source;
@@ -260,16 +272,19 @@ Sound LoadSoundFromWave(Wave wave)
ALuint buffer;
alGenBuffers(1, &buffer); // Generate pointer to buffer
+ unsigned int dataSize = wave.sampleCount*wave.sampleSize/8; // Size in bytes
+
// Upload sound data to buffer
- alBufferData(buffer, format, wave.data, wave.dataSize, wave.sampleRate);
+ alBufferData(buffer, format, wave.data, dataSize, wave.sampleRate);
// Attach sound buffer to source
alSourcei(source, AL_BUFFER, buffer);
- TraceLog(INFO, "[SND ID %i][BUFR ID %i] Sound data loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", source, buffer, wave.sampleRate, wave.bitsPerSample, wave.channels);
+ TraceLog(INFO, "[SND ID %i][BUFR ID %i] Sound data loaded successfully (SampleRate: %i, SampleSize: %i, Channels: %i)", source, buffer, wave.sampleRate, wave.sampleSize, wave.channels);
sound.source = source;
sound.buffer = buffer;
+ sound.format = format;
}
return sound;
@@ -341,8 +356,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
fread(&reserved, 1, 1, rresFile); // <reserved>
wave.sampleRate = sampleRate;
- wave.dataSize = infoHeader.srcSize;
- wave.bitsPerSample = bps;
+ wave.sampleSize = bps;
wave.channels = (short)channels;
unsigned char *data = malloc(infoHeader.size);
@@ -354,7 +368,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
free(data);
sound = LoadSoundFromWave(wave);
-
+
// Sound is loaded, we can unload wave data
UnloadWave(wave);
}
@@ -396,6 +410,33 @@ void UnloadSound(Sound sound)
TraceLog(INFO, "[SND ID %i][BUFR ID %i] Unloaded sound data from RAM", sound.source, sound.buffer);
}
+// Update sound buffer with new data
+// NOTE: data must match sound.format
+void UpdateSound(Sound sound, void *data, int numSamples)
+{
+ ALint sampleRate, sampleSize, channels;
+ alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate);
+ alGetBufferi(sound.buffer, AL_BITS, &sampleSize); // It could also be retrieved from sound.format
+ alGetBufferi(sound.buffer, AL_CHANNELS, &channels); // It could also be retrieved from sound.format
+
+ TraceLog(DEBUG, "UpdateSound() : AL_FREQUENCY: %i", sampleRate);
+ TraceLog(DEBUG, "UpdateSound() : AL_BITS: %i", sampleSize);
+ TraceLog(DEBUG, "UpdateSound() : AL_CHANNELS: %i", channels);
+
+ unsigned int dataSize = numSamples*sampleSize/8; // Size of data in bytes
+
+ alSourceStop(sound.source); // Stop sound
+ alSourcei(sound.source, AL_BUFFER, 0); // Unbind buffer from sound to update
+ //alDeleteBuffers(1, &sound.buffer); // Delete current buffer data
+ //alGenBuffers(1, &sound.buffer); // Generate new buffer
+
+ // Upload new data to sound buffer
+ alBufferData(sound.buffer, sound.format, data, dataSize, sampleRate);
+
+ // Attach sound buffer to source again
+ alSourcei(sound.source, AL_BUFFER, sound.buffer);
+}
+
// Play a sound
void PlaySound(Sound sound)
{
@@ -493,13 +534,13 @@ Music LoadMusicStream(char *fileName)
TraceLog(DEBUG, "[%s] OGG sample rate: %i", fileName, info.sample_rate);
TraceLog(DEBUG, "[%s] OGG channels: %i", fileName, info.channels);
TraceLog(DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required);
-
+
}
}
else if (strcmp(GetExtension(fileName), "xm") == 0)
{
int result = jar_xm_create_context_from_file(&music->ctxXm, 48000, fileName);
-
+
if (!result) // XM context created successfully
{
jar_xm_set_max_loop_count(music->ctxXm, 0); // Set infinite number of loops
@@ -510,7 +551,7 @@ Music LoadMusicStream(char *fileName)
music->samplesLeft = music->totalSamples;
music->ctxType = MUSIC_MODULE_XM;
music->loop = true;
-
+
TraceLog(DEBUG, "[%s] XM number of samples: %i", fileName, music->totalSamples);
TraceLog(DEBUG, "[%s] XM track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f);
}
@@ -542,11 +583,11 @@ Music LoadMusicStream(char *fileName)
void UnloadMusicStream(Music music)
{
CloseAudioStream(music->stream);
-
+
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg);
else if (music->ctxType == MUSIC_MODULE_XM) jar_xm_free_context(music->ctxXm);
else if (music->ctxType == MUSIC_MODULE_MOD) jar_mod_unload(&music->ctxMod);
-
+
free(music);
}
@@ -584,58 +625,58 @@ void UpdateMusicStream(Music music)
// Determine if music stream is ready to be written
alGetSourcei(music->stream.source, AL_BUFFERS_PROCESSED, &processed);
-
+
int numBuffersToProcess = processed;
-
+
if (processed > 0)
{
bool active = true;
short pcm[AUDIO_BUFFER_SIZE];
float pcmf[AUDIO_BUFFER_SIZE];
-
- int numSamples = 0; // Total size of data steamed in L+R samples for xm floats,
+
+ int numSamples = 0; // Total size of data steamed in L+R samples for xm floats,
// individual L or R for ogg shorts
for (int i = 0; i < numBuffersToProcess; i++)
{
switch (music->ctxType)
{
- case MUSIC_AUDIO_OGG:
+ case MUSIC_AUDIO_OGG:
{
if (music->samplesLeft >= AUDIO_BUFFER_SIZE) numSamples = AUDIO_BUFFER_SIZE;
else numSamples = music->samplesLeft;
-
+
// NOTE: Returns the number of samples to process (should be the same as numSamples -> it is)
int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, pcm, numSamples);
// TODO: Review stereo channels Ogg, not enough samples served!
UpdateAudioStream(music->stream, pcm, numSamplesOgg*music->stream.channels);
music->samplesLeft -= (numSamplesOgg*music->stream.channels);
-
+
} break;
- case MUSIC_MODULE_XM:
+ case MUSIC_MODULE_XM:
{
if (music->samplesLeft >= AUDIO_BUFFER_SIZE/2) numSamples = AUDIO_BUFFER_SIZE/2;
else numSamples = music->samplesLeft;
-
+
// NOTE: Output buffer is 2*numsamples elements (left and right value for each sample)
jar_xm_generate_samples(music->ctxXm, pcmf, numSamples);
UpdateAudioStream(music->stream, pcmf, numSamples*2); // Using 32bit PCM data
music->samplesLeft -= numSamples;
-
+
//TraceLog(INFO, "Samples left: %i", music->samplesLeft);
-
+
} break;
- case MUSIC_MODULE_MOD:
+ case MUSIC_MODULE_MOD:
{
if (music->samplesLeft >= AUDIO_BUFFER_SIZE/2) numSamples = AUDIO_BUFFER_SIZE/2;
else numSamples = music->samplesLeft;
-
+
// NOTE: Output buffer size is nbsample*channels (default: 48000Hz, 16bit, Stereo)
- jar_mod_fillbuffer(&music->ctxMod, pcm, numSamples, 0);
+ jar_mod_fillbuffer(&music->ctxMod, pcm, numSamples, 0);
UpdateAudioStream(music->stream, pcm, numSamples*2);
music->samplesLeft -= numSamples;
-
+
} break;
default: break;
}
@@ -646,15 +687,15 @@ void UpdateMusicStream(Music music)
break;
}
}
-
+
// Reset audio stream for looping
if (!active && music->loop)
{
// Restart music context (if required)
- //if (music->ctxType == MUSIC_MODULE_XM)
+ //if (music->ctxType == MUSIC_MODULE_XM)
if (music->ctxType == MUSIC_MODULE_MOD) jar_mod_seek_start(&music->ctxMod);
else if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_seek_start(music->ctxOgg);
-
+
// Reset samples left to total samples
music->samplesLeft = music->totalSamples;
}
@@ -700,7 +741,7 @@ void SetMusicPitch(Music music, float pitch)
float GetMusicTimeLength(Music music)
{
float totalSeconds = (float)music->totalSamples/music->stream.sampleRate;
-
+
return totalSeconds;
}
@@ -719,7 +760,7 @@ float GetMusicTimePlayed(Music music)
AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels)
{
AudioStream stream = { 0 };
-
+
stream.sampleRate = sampleRate;
stream.sampleSize = sampleSize;
stream.channels = channels;
@@ -778,7 +819,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
}
alSourceQueueBuffers(stream.source, MAX_STREAM_BUFFERS, stream.buffers);
-
+
TraceLog(INFO, "[AUD ID %i] Audio stream loaded successfully", stream.source);
return stream;
@@ -793,9 +834,9 @@ void CloseAudioStream(AudioStream stream)
// Flush out all queued buffers
int queued = 0;
alGetSourcei(stream.source, AL_BUFFERS_QUEUED, &queued);
-
+
ALuint buffer = 0;
-
+
while (queued > 0)
{
alSourceUnqueueBuffers(stream.source, 1, &buffer);
@@ -805,7 +846,7 @@ void CloseAudioStream(AudioStream stream)
// Delete source and buffers
alDeleteSources(1, &stream.source);
alDeleteBuffers(MAX_STREAM_BUFFERS, stream.buffers);
-
+
TraceLog(INFO, "[AUD ID %i] Unloaded audio stream data", stream.source);
}
@@ -815,14 +856,14 @@ void UpdateAudioStream(AudioStream stream, void *data, int numSamples)
{
ALuint buffer = 0;
alSourceUnqueueBuffers(stream.source, 1, &buffer);
-
+
// Check if any buffer was available for unqueue
if (alGetError() != AL_INVALID_VALUE)
{
if (stream.sampleSize == 8) alBufferData(buffer, stream.format, (unsigned char *)data, numSamples*sizeof(unsigned char), stream.sampleRate);
else if (stream.sampleSize == 16) alBufferData(buffer, stream.format, (short *)data, numSamples*sizeof(short), stream.sampleRate);
else if (stream.sampleSize == 32) alBufferData(buffer, stream.format, (float *)data, numSamples*sizeof(float), stream.sampleRate);
-
+
alSourceQueueBuffers(stream.source, 1, &buffer);
}
}
@@ -948,18 +989,18 @@ static Wave LoadWAV(const char *fileName)
else
{
// Allocate memory for data
- wave.data = (unsigned char *)malloc(sizeof(unsigned char) * waveData.subChunkSize);
+ wave.data = (unsigned char *)malloc(sizeof(unsigned char)*waveData.subChunkSize);
// Read in the sound data into the soundData variable
fread(wave.data, waveData.subChunkSize, 1, wavFile);
// Now we set the variables that we need later
- wave.dataSize = waveData.subChunkSize;
+ wave.sampleCount = waveData.subChunkSize;
wave.sampleRate = waveFormat.sampleRate;
+ wave.sampleSize = waveFormat.bitsPerSample;
wave.channels = waveFormat.numChannels;
- wave.bitsPerSample = waveFormat.bitsPerSample;
- TraceLog(INFO, "[%s] WAV file loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", fileName, wave.sampleRate, wave.bitsPerSample, wave.channels);
+ TraceLog(INFO, "[%s] WAV file loaded successfully (SampleRate: %i, SampleSize: %i, Channels: %i)", fileName, wave.sampleRate, wave.sampleSize, wave.channels);
}
}
}
@@ -988,35 +1029,24 @@ static Wave LoadOGG(char *fileName)
stb_vorbis_info info = stb_vorbis_get_info(oggFile);
wave.sampleRate = info.sample_rate;
- wave.bitsPerSample = 16;
+ wave.sampleSize = 16; // 16 bit per sample (short)
wave.channels = info.channels;
- TraceLog(DEBUG, "[%s] Ogg sample rate: %i", fileName, info.sample_rate);
- TraceLog(DEBUG, "[%s] Ogg channels: %i", fileName, info.channels);
-
int totalSamplesLength = (stb_vorbis_stream_length_in_samples(oggFile)*info.channels);
-
- wave.dataSize = totalSamplesLength*sizeof(short); // Size must be in bytes
-
- TraceLog(DEBUG, "[%s] Samples length: %i", fileName, totalSamplesLength);
-
float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile);
- TraceLog(DEBUG, "[%s] Total seconds: %f", fileName, totalSeconds);
-
if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio lenght is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds);
int totalSamples = totalSeconds*info.sample_rate*info.channels;
+ wave.sampleCount = totalSamples;
- TraceLog(DEBUG, "[%s] Total samples calculated: %i", fileName, totalSamples);
-
- wave.data = malloc(sizeof(short)*totalSamplesLength);
+ wave.data = (short *)malloc(totalSamplesLength*sizeof(short));
- int samplesObtained = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, wave.data, totalSamplesLength);
+ int samplesObtained = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, (short *)wave.data, totalSamplesLength);
TraceLog(DEBUG, "[%s] Samples obtained: %i", fileName, samplesObtained);
- TraceLog(INFO, "[%s] OGG file loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", fileName, wave.sampleRate, wave.bitsPerSample, wave.channels);
+ TraceLog(INFO, "[%s] OGG file loaded successfully (SampleRate: %i, SampleSize: %i, Channels: %i)", fileName, wave.sampleRate, wave.sampleSize, wave.channels);
stb_vorbis_close(oggFile);
}