Update C sources, add new functions and rename package to
This commit is contained in:
parent
391c25482d
commit
08aa518a46
156 changed files with 34542 additions and 19573 deletions
265
raylib/audio.c
265
raylib/audio.c
|
@ -19,7 +19,7 @@
|
|||
* Required types and functions are defined in the same module.
|
||||
*
|
||||
* #define USE_OPENAL_BACKEND
|
||||
* Use OpenAL Soft audio backend usage
|
||||
* Use OpenAL Soft audio backend
|
||||
*
|
||||
* #define SUPPORT_FILEFORMAT_WAV
|
||||
* #define SUPPORT_FILEFORMAT_OGG
|
||||
|
@ -75,20 +75,19 @@
|
|||
*
|
||||
**********************************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if !defined(USE_OPENAL_BACKEND)
|
||||
#define USE_MINI_AL 1 // Set to 1 to use mini_al; 0 to use OpenAL.
|
||||
#endif
|
||||
|
||||
#if defined(AUDIO_STANDALONE)
|
||||
#include "audio.h"
|
||||
#include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end()
|
||||
#else
|
||||
#include "raylib.h"
|
||||
#include "config.h" // Defines module configuration flags
|
||||
#include "raylib.h" // Declares module functions
|
||||
#include "utils.h" // Required for: fopen() Android mapping
|
||||
#endif
|
||||
|
||||
#if !defined(USE_OPENAL_BACKEND)
|
||||
#define USE_MINI_AL 1 // Set to 1 to use mini_al; 0 to use OpenAL.
|
||||
#endif
|
||||
|
||||
#include "external/mini_al.h" // Implemented in mini_al.c. Cannot implement this here because it conflicts with Win32 APIs such as CloseWindow(), etc.
|
||||
|
||||
#if !defined(USE_MINI_AL) || (USE_MINI_AL == 0)
|
||||
|
@ -166,6 +165,7 @@
|
|||
typedef enum {
|
||||
MUSIC_AUDIO_OGG = 0,
|
||||
MUSIC_AUDIO_FLAC,
|
||||
MUSIC_AUDIO_MP3,
|
||||
MUSIC_MODULE_XM,
|
||||
MUSIC_MODULE_MOD
|
||||
} MusicContextType;
|
||||
|
@ -179,6 +179,9 @@ typedef struct MusicData {
|
|||
#if defined(SUPPORT_FILEFORMAT_FLAC)
|
||||
drflac *ctxFlac; // FLAC audio context
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||
drmp3 ctxMp3; // MP3 audio context
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_XM)
|
||||
jar_xm_context_t *ctxXm; // XM chiptune context
|
||||
#endif
|
||||
|
@ -220,6 +223,9 @@ static Wave LoadOGG(const char *fileName); // Load OGG file
|
|||
#if defined(SUPPORT_FILEFORMAT_FLAC)
|
||||
static Wave LoadFLAC(const char *fileName); // Load FLAC file
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||
static Wave LoadMP3(const char *fileName); // Load MP3 file
|
||||
#endif
|
||||
|
||||
#if defined(AUDIO_STANDALONE)
|
||||
bool IsFileExtension(const char *fileName, const char *ext); // Check file extension
|
||||
|
@ -304,7 +310,7 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameC
|
|||
(void)pDevice;
|
||||
|
||||
// Mixing is basically just an accumulation. We need to initialize the output buffer to 0.
|
||||
memset(pFramesOut, 0, frameCount*pDevice->channels*mal_get_sample_size_in_bytes(pDevice->format));
|
||||
memset(pFramesOut, 0, frameCount*pDevice->channels*mal_get_bytes_per_sample(pDevice->format));
|
||||
|
||||
// Using a mutex here for thread-safety which makes things not real-time. This is unlikely to be necessary for this project, but may
|
||||
// want to consider how you might want to avoid this.
|
||||
|
@ -338,11 +344,7 @@ static mal_uint32 OnSendAudioDataToDevice(mal_device *pDevice, mal_uint32 frameC
|
|||
framesToReadRightNow = sizeof(tempBuffer)/sizeof(tempBuffer[0])/DEVICE_CHANNELS;
|
||||
}
|
||||
|
||||
// If we're not looping, we need to make sure we flush the internal buffers of the DSP pipeline to ensure we get the
|
||||
// last few samples.
|
||||
bool flushDSP = !audioBuffer->looping;
|
||||
|
||||
mal_uint32 framesJustRead = mal_dsp_read_frames_ex(&audioBuffer->dsp, framesToReadRightNow, tempBuffer, flushDSP);
|
||||
mal_uint32 framesJustRead = (mal_uint32)mal_dsp_read(&audioBuffer->dsp, framesToReadRightNow, tempBuffer, audioBuffer->dsp.pUserData);
|
||||
if (framesJustRead > 0)
|
||||
{
|
||||
float *framesOut = (float *)pFramesOut + (framesRead*device.channels);
|
||||
|
@ -402,7 +404,7 @@ static mal_uint32 OnAudioBufferDSPRead(mal_dsp *pDSP, mal_uint32 frameCount, voi
|
|||
isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0];
|
||||
isSubBufferProcessed[1] = audioBuffer->isSubBufferProcessed[1];
|
||||
|
||||
mal_uint32 frameSizeInBytes = mal_get_sample_size_in_bytes(audioBuffer->dsp.config.formatIn)*audioBuffer->dsp.config.channelsIn;
|
||||
mal_uint32 frameSizeInBytes = mal_get_bytes_per_sample(audioBuffer->dsp.formatConverterIn.config.formatIn)*audioBuffer->dsp.formatConverterIn.config.channels;
|
||||
|
||||
// Fill out every frame until we find a buffer that's marked as processed. Then fill the remainder with 0.
|
||||
mal_uint32 framesRead = 0;
|
||||
|
@ -648,7 +650,7 @@ void SetMasterVolume(float volume)
|
|||
// Create a new audio buffer. Initially filled with silence
|
||||
AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint32 sampleRate, mal_uint32 bufferSizeInFrames, AudioBufferUsage usage)
|
||||
{
|
||||
AudioBuffer *audioBuffer = (AudioBuffer *)calloc(sizeof(*audioBuffer) + (bufferSizeInFrames*channels*mal_get_sample_size_in_bytes(format)), 1);
|
||||
AudioBuffer *audioBuffer = (AudioBuffer *)calloc(sizeof(*audioBuffer) + (bufferSizeInFrames*channels*mal_get_bytes_per_sample(format)), 1);
|
||||
if (audioBuffer == NULL)
|
||||
{
|
||||
TraceLog(LOG_ERROR, "CreateAudioBuffer() : Failed to allocate memory for audio buffer");
|
||||
|
@ -664,10 +666,13 @@ AudioBuffer *CreateAudioBuffer(mal_format format, mal_uint32 channels, mal_uint3
|
|||
dspConfig.channelsOut = DEVICE_CHANNELS;
|
||||
dspConfig.sampleRateIn = sampleRate;
|
||||
dspConfig.sampleRateOut = DEVICE_SAMPLE_RATE;
|
||||
mal_result resultMAL = mal_dsp_init(&dspConfig, OnAudioBufferDSPRead, audioBuffer, &audioBuffer->dsp);
|
||||
dspConfig.onRead = OnAudioBufferDSPRead;
|
||||
dspConfig.pUserData = audioBuffer;
|
||||
dspConfig.allowDynamicSampleRate = MAL_TRUE; // <-- Required for pitch shifting.
|
||||
mal_result resultMAL = mal_dsp_init(&dspConfig, &audioBuffer->dsp);
|
||||
if (resultMAL != MAL_SUCCESS)
|
||||
{
|
||||
TraceLog(LOG_ERROR, "LoadSoundFromWave() : Failed to create data conversion pipeline");
|
||||
TraceLog(LOG_ERROR, "CreateAudioBuffer() : Failed to create data conversion pipeline");
|
||||
free(audioBuffer);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -695,7 +700,7 @@ void DeleteAudioBuffer(AudioBuffer *audioBuffer)
|
|||
{
|
||||
if (audioBuffer == NULL)
|
||||
{
|
||||
TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer");
|
||||
TraceLog(LOG_ERROR, "DeleteAudioBuffer() : No audio buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -708,7 +713,7 @@ bool IsAudioBufferPlaying(AudioBuffer *audioBuffer)
|
|||
{
|
||||
if (audioBuffer == NULL)
|
||||
{
|
||||
TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer");
|
||||
TraceLog(LOG_ERROR, "IsAudioBufferPlaying() : No audio buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -736,7 +741,7 @@ void StopAudioBuffer(AudioBuffer *audioBuffer)
|
|||
{
|
||||
if (audioBuffer == NULL)
|
||||
{
|
||||
TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer");
|
||||
TraceLog(LOG_ERROR, "StopAudioBuffer() : No audio buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -755,7 +760,7 @@ void PauseAudioBuffer(AudioBuffer *audioBuffer)
|
|||
{
|
||||
if (audioBuffer == NULL)
|
||||
{
|
||||
TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer");
|
||||
TraceLog(LOG_ERROR, "PauseAudioBuffer() : No audio buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -767,7 +772,7 @@ void ResumeAudioBuffer(AudioBuffer *audioBuffer)
|
|||
{
|
||||
if (audioBuffer == NULL)
|
||||
{
|
||||
TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer");
|
||||
TraceLog(LOG_ERROR, "ResumeAudioBuffer() : No audio buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -779,7 +784,7 @@ void SetAudioBufferVolume(AudioBuffer *audioBuffer, float volume)
|
|||
{
|
||||
if (audioBuffer == NULL)
|
||||
{
|
||||
TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer");
|
||||
TraceLog(LOG_ERROR, "SetAudioBufferVolume() : No audio buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -791,7 +796,7 @@ void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch)
|
|||
{
|
||||
if (audioBuffer == NULL)
|
||||
{
|
||||
TraceLog(LOG_ERROR, "PlayAudioBuffer() : No audio buffer");
|
||||
TraceLog(LOG_ERROR, "SetAudioBufferPitch() : No audio buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -799,7 +804,7 @@ void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch)
|
|||
|
||||
// Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches
|
||||
// will make the sound faster; lower pitches make it slower.
|
||||
mal_uint32 newOutputSampleRate = (mal_uint32)((((float)audioBuffer->dsp.config.sampleRateOut / (float)audioBuffer->dsp.config.sampleRateIn) / pitch) * audioBuffer->dsp.config.sampleRateIn);
|
||||
mal_uint32 newOutputSampleRate = (mal_uint32)((((float)audioBuffer->dsp.src.config.sampleRateOut / (float)audioBuffer->dsp.src.config.sampleRateIn) / pitch) * audioBuffer->dsp.src.config.sampleRateIn);
|
||||
mal_dsp_set_output_sample_rate(&audioBuffer->dsp, newOutputSampleRate);
|
||||
}
|
||||
|
||||
|
@ -857,6 +862,9 @@ Wave LoadWave(const char *fileName)
|
|||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_FLAC)
|
||||
else if (IsFileExtension(fileName, ".flac")) wave = LoadFLAC(fileName);
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||
else if (IsFileExtension(fileName, ".mp3")) wave = LoadMP3(fileName);
|
||||
#endif
|
||||
else TraceLog(LOG_WARNING, "[%s] Audio fileformat not supported, it can't be loaded", fileName);
|
||||
|
||||
|
@ -915,13 +923,13 @@ Sound LoadSoundFromWave(Wave wave)
|
|||
mal_format formatIn = ((wave.sampleSize == 8) ? mal_format_u8 : ((wave.sampleSize == 16) ? mal_format_s16 : mal_format_f32));
|
||||
mal_uint32 frameCountIn = wave.sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so.
|
||||
|
||||
mal_uint32 frameCount = mal_convert_frames(NULL, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, formatIn, wave.channels, wave.sampleRate, frameCountIn);
|
||||
mal_uint32 frameCount = (mal_uint32)mal_convert_frames(NULL, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, formatIn, wave.channels, wave.sampleRate, frameCountIn);
|
||||
if (frameCount == 0) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Failed to get frame count for format conversion");
|
||||
|
||||
AudioBuffer* audioBuffer = CreateAudioBuffer(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, frameCount, AUDIO_BUFFER_USAGE_STATIC);
|
||||
if (audioBuffer == NULL) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Failed to create audio buffer");
|
||||
|
||||
frameCount = mal_convert_frames(audioBuffer->buffer, audioBuffer->dsp.config.formatIn, audioBuffer->dsp.config.channelsIn, audioBuffer->dsp.config.sampleRateIn, wave.data, formatIn, wave.channels, wave.sampleRate, frameCountIn);
|
||||
frameCount = (mal_uint32)mal_convert_frames(audioBuffer->buffer, audioBuffer->dsp.formatConverterIn.config.formatIn, audioBuffer->dsp.formatConverterIn.config.channels, audioBuffer->dsp.src.config.sampleRateIn, wave.data, formatIn, wave.channels, wave.sampleRate, frameCountIn);
|
||||
if (frameCount == 0) TraceLog(LOG_WARNING, "LoadSoundFromWave() : Format conversion failed");
|
||||
|
||||
sound.audioBuffer = audioBuffer;
|
||||
|
@ -1023,7 +1031,7 @@ void UpdateSound(Sound sound, const void *data, int samplesCount)
|
|||
StopAudioBuffer(audioBuffer);
|
||||
|
||||
// TODO: May want to lock/unlock this since this data buffer is read at mixing time.
|
||||
memcpy(audioBuffer->buffer, data, samplesCount*audioBuffer->dsp.config.channelsIn*mal_get_sample_size_in_bytes(audioBuffer->dsp.config.formatIn));
|
||||
memcpy(audioBuffer->buffer, data, samplesCount*audioBuffer->dsp.formatConverterIn.config.channels*mal_get_bytes_per_sample(audioBuffer->dsp.formatConverterIn.config.formatIn));
|
||||
#else
|
||||
ALint sampleRate, sampleSize, channels;
|
||||
alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate);
|
||||
|
@ -1049,6 +1057,89 @@ void UpdateSound(Sound sound, const void *data, int samplesCount)
|
|||
#endif
|
||||
}
|
||||
|
||||
// Export wave data to file
|
||||
void ExportWave(Wave wave, const char *fileName)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
if (IsFileExtension(fileName, ".wav"))
|
||||
{
|
||||
// Basic WAV headers structs
|
||||
typedef struct {
|
||||
char chunkID[4];
|
||||
int chunkSize;
|
||||
char format[4];
|
||||
} RiffHeader;
|
||||
|
||||
typedef struct {
|
||||
char subChunkID[4];
|
||||
int subChunkSize;
|
||||
short audioFormat;
|
||||
short numChannels;
|
||||
int sampleRate;
|
||||
int byteRate;
|
||||
short blockAlign;
|
||||
short bitsPerSample;
|
||||
} WaveFormat;
|
||||
|
||||
typedef struct {
|
||||
char subChunkID[4];
|
||||
int subChunkSize;
|
||||
} WaveData;
|
||||
|
||||
RiffHeader riffHeader;
|
||||
WaveFormat waveFormat;
|
||||
WaveData waveData;
|
||||
|
||||
// Fill structs with data
|
||||
riffHeader.chunkID[0] = 'R';
|
||||
riffHeader.chunkID[1] = 'I';
|
||||
riffHeader.chunkID[2] = 'F';
|
||||
riffHeader.chunkID[3] = 'F';
|
||||
riffHeader.chunkSize = 44 - 4 + wave.sampleCount*wave.sampleSize/8;
|
||||
riffHeader.format[0] = 'W';
|
||||
riffHeader.format[1] = 'A';
|
||||
riffHeader.format[2] = 'V';
|
||||
riffHeader.format[3] = 'E';
|
||||
|
||||
waveFormat.subChunkID[0] = 'f';
|
||||
waveFormat.subChunkID[1] = 'm';
|
||||
waveFormat.subChunkID[2] = 't';
|
||||
waveFormat.subChunkID[3] = ' ';
|
||||
waveFormat.subChunkSize = 16;
|
||||
waveFormat.audioFormat = 1;
|
||||
waveFormat.numChannels = wave.channels;
|
||||
waveFormat.sampleRate = wave.sampleRate;
|
||||
waveFormat.byteRate = wave.sampleRate*wave.sampleSize/8;
|
||||
waveFormat.blockAlign = wave.sampleSize/8;
|
||||
waveFormat.bitsPerSample = wave.sampleSize;
|
||||
|
||||
waveData.subChunkID[0] = 'd';
|
||||
waveData.subChunkID[1] = 'a';
|
||||
waveData.subChunkID[2] = 't';
|
||||
waveData.subChunkID[3] = 'a';
|
||||
waveData.subChunkSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
|
||||
|
||||
FILE *wavFile = fopen(fileName, "wb");
|
||||
|
||||
if (wavFile == NULL) return;
|
||||
|
||||
fwrite(&riffHeader, 1, sizeof(RiffHeader), wavFile);
|
||||
fwrite(&waveFormat, 1, sizeof(WaveFormat), wavFile);
|
||||
fwrite(&waveData, 1, sizeof(WaveData), wavFile);
|
||||
|
||||
fwrite(wave.data, 1, wave.sampleCount*wave.channels*wave.sampleSize/8, wavFile);
|
||||
|
||||
fclose(wavFile);
|
||||
|
||||
success = true;
|
||||
}
|
||||
else if (IsFileExtension(fileName, ".raw")) { } // TODO: Support additional file formats to export wave sample data
|
||||
|
||||
if (success) TraceLog(LOG_INFO, "Wave exported successfully: %s", fileName);
|
||||
else TraceLog(LOG_WARNING, "Wave could not be exported.");
|
||||
}
|
||||
|
||||
// Play a sound
|
||||
void PlaySound(Sound sound)
|
||||
{
|
||||
|
@ -1153,7 +1244,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
|
|||
|
||||
mal_uint32 frameCountIn = wave->sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so.
|
||||
|
||||
mal_uint32 frameCount = mal_convert_frames(NULL, formatOut, channels, sampleRate, NULL, formatIn, wave->channels, wave->sampleRate, frameCountIn);
|
||||
mal_uint32 frameCount = (mal_uint32)mal_convert_frames(NULL, formatOut, channels, sampleRate, NULL, formatIn, wave->channels, wave->sampleRate, frameCountIn);
|
||||
if (frameCount == 0)
|
||||
{
|
||||
TraceLog(LOG_ERROR, "WaveFormat() : Failed to get frame count for format conversion.");
|
||||
|
@ -1162,7 +1253,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
|
|||
|
||||
void *data = malloc(frameCount*channels*(sampleSize/8));
|
||||
|
||||
frameCount = mal_convert_frames(data, formatOut, channels, sampleRate, wave->data, formatIn, wave->channels, wave->sampleRate, frameCountIn);
|
||||
frameCount = (mal_uint32)mal_convert_frames(data, formatOut, channels, sampleRate, wave->data, formatIn, wave->channels, wave->sampleRate, frameCountIn);
|
||||
if (frameCount == 0)
|
||||
{
|
||||
TraceLog(LOG_ERROR, "WaveFormat() : Format conversion failed.");
|
||||
|
@ -1284,7 +1375,7 @@ Wave WaveCopy(Wave wave)
|
|||
void WaveCrop(Wave *wave, int initSample, int finalSample)
|
||||
{
|
||||
if ((initSample >= 0) && (initSample < finalSample) &&
|
||||
(finalSample > 0) && (finalSample < wave->sampleCount))
|
||||
(finalSample > 0) && ((unsigned int)finalSample < wave->sampleCount))
|
||||
{
|
||||
int sampleCount = finalSample - initSample;
|
||||
|
||||
|
@ -1304,9 +1395,9 @@ float *GetWaveData(Wave wave)
|
|||
{
|
||||
float *samples = (float *)malloc(wave.sampleCount*wave.channels*sizeof(float));
|
||||
|
||||
for (int i = 0; i < wave.sampleCount; i++)
|
||||
for (unsigned int i = 0; i < wave.sampleCount; i++)
|
||||
{
|
||||
for (int j = 0; j < wave.channels; j++)
|
||||
for (unsigned int j = 0; j < wave.channels; j++)
|
||||
{
|
||||
if (wave.sampleSize == 8) samples[wave.channels*i + j] = (float)(((unsigned char *)wave.data)[wave.channels*i + j] - 127)/256.0f;
|
||||
else if (wave.sampleSize == 16) samples[wave.channels*i + j] = (float)((short *)wave.data)[wave.channels*i + j]/32767.0f;
|
||||
|
@ -1325,13 +1416,14 @@ float *GetWaveData(Wave wave)
|
|||
Music LoadMusicStream(const char *fileName)
|
||||
{
|
||||
Music music = (MusicData *)malloc(sizeof(MusicData));
|
||||
bool musicLoaded = true;
|
||||
|
||||
if (IsFileExtension(fileName, ".ogg"))
|
||||
{
|
||||
// Open ogg audio stream
|
||||
music->ctxOgg = stb_vorbis_open_filename(fileName, NULL, NULL);
|
||||
|
||||
if (music->ctxOgg == NULL) TraceLog(LOG_WARNING, "[%s] OGG audio file could not be opened", fileName);
|
||||
if (music->ctxOgg == NULL) musicLoaded = false;
|
||||
else
|
||||
{
|
||||
stb_vorbis_info info = stb_vorbis_get_info(music->ctxOgg); // Get Ogg file info
|
||||
|
@ -1343,7 +1435,7 @@ Music LoadMusicStream(const char *fileName)
|
|||
music->ctxType = MUSIC_AUDIO_OGG;
|
||||
music->loopCount = -1; // Infinite loop by default
|
||||
|
||||
TraceLog(LOG_DEBUG, "[%s] FLAC total samples: %i", fileName, music->totalSamples);
|
||||
TraceLog(LOG_DEBUG, "[%s] OGG total samples: %i", fileName, music->totalSamples);
|
||||
TraceLog(LOG_DEBUG, "[%s] OGG sample rate: %i", fileName, info.sample_rate);
|
||||
TraceLog(LOG_DEBUG, "[%s] OGG channels: %i", fileName, info.channels);
|
||||
TraceLog(LOG_DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required);
|
||||
|
@ -1354,7 +1446,7 @@ Music LoadMusicStream(const char *fileName)
|
|||
{
|
||||
music->ctxFlac = drflac_open_file(fileName);
|
||||
|
||||
if (music->ctxFlac == NULL) TraceLog(LOG_WARNING, "[%s] FLAC audio file could not be opened", fileName);
|
||||
if (music->ctxFlac == NULL) musicLoaded = false;
|
||||
else
|
||||
{
|
||||
music->stream = InitAudioStream(music->ctxFlac->sampleRate, music->ctxFlac->bitsPerSample, music->ctxFlac->channels);
|
||||
|
@ -1370,6 +1462,27 @@ Music LoadMusicStream(const char *fileName)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||
else if (IsFileExtension(fileName, ".mp3"))
|
||||
{
|
||||
drmp3_init_file(&music->ctxMp3, fileName, NULL);
|
||||
|
||||
if (music->ctxMp3.framesRemaining <= 0) musicLoaded = false;
|
||||
else
|
||||
{
|
||||
music->stream = InitAudioStream(music->ctxMp3.sampleRate, 16, music->ctxMp3.channels);
|
||||
music->totalSamples = (unsigned int)music->ctxMp3.framesRemaining*music->ctxMp3.channels;
|
||||
music->samplesLeft = music->totalSamples;
|
||||
music->ctxType = MUSIC_AUDIO_MP3;
|
||||
music->loopCount = -1; // Infinite loop by default
|
||||
|
||||
TraceLog(LOG_DEBUG, "[%s] MP3 total samples: %i", fileName, music->totalSamples);
|
||||
TraceLog(LOG_DEBUG, "[%s] MP3 sample rate: %i", fileName, music->ctxMp3.sampleRate);
|
||||
//TraceLog(LOG_DEBUG, "[%s] MP3 bits per sample: %i", fileName, music->ctxMp3.bitsPerSample);
|
||||
TraceLog(LOG_DEBUG, "[%s] MP3 channels: %i", fileName, music->ctxMp3.channels);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_XM)
|
||||
else if (IsFileExtension(fileName, ".xm"))
|
||||
{
|
||||
|
@ -1389,7 +1502,7 @@ Music LoadMusicStream(const char *fileName)
|
|||
TraceLog(LOG_DEBUG, "[%s] XM number of samples: %i", fileName, music->totalSamples);
|
||||
TraceLog(LOG_DEBUG, "[%s] XM track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f);
|
||||
}
|
||||
else TraceLog(LOG_WARNING, "[%s] XM file could not be opened", fileName);
|
||||
else musicLoaded = false;
|
||||
}
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_MOD)
|
||||
|
@ -1408,10 +1521,32 @@ Music LoadMusicStream(const char *fileName)
|
|||
TraceLog(LOG_DEBUG, "[%s] MOD number of samples: %i", fileName, music->samplesLeft);
|
||||
TraceLog(LOG_DEBUG, "[%s] MOD track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f);
|
||||
}
|
||||
else TraceLog(LOG_WARNING, "[%s] MOD file could not be opened", fileName);
|
||||
else musicLoaded = false;
|
||||
}
|
||||
#endif
|
||||
else TraceLog(LOG_WARNING, "[%s] Audio fileformat not supported, it can't be loaded", fileName);
|
||||
else musicLoaded = false;
|
||||
|
||||
if (!musicLoaded)
|
||||
{
|
||||
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg);
|
||||
#if defined(SUPPORT_FILEFORMAT_FLAC)
|
||||
else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac);
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||
else if (music->ctxType == MUSIC_AUDIO_MP3) drmp3_uninit(&music->ctxMp3);
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_XM)
|
||||
else if (music->ctxType == MUSIC_MODULE_XM) jar_xm_free_context(music->ctxXm);
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_MOD)
|
||||
else if (music->ctxType == MUSIC_MODULE_MOD) jar_mod_unload(&music->ctxMod);
|
||||
#endif
|
||||
|
||||
free(music);
|
||||
music = NULL;
|
||||
|
||||
TraceLog(LOG_WARNING, "[%s] Music file could not be opened", fileName);
|
||||
}
|
||||
|
||||
return music;
|
||||
}
|
||||
|
@ -1425,6 +1560,9 @@ void UnloadMusicStream(Music music)
|
|||
#if defined(SUPPORT_FILEFORMAT_FLAC)
|
||||
else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac);
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||
else if (music->ctxType == MUSIC_AUDIO_MP3) drmp3_uninit(&music->ctxMp3);
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_XM)
|
||||
else if (music->ctxType == MUSIC_MODULE_XM) jar_xm_free_context(music->ctxXm);
|
||||
#endif
|
||||
|
@ -1516,7 +1654,10 @@ void StopMusicStream(Music music)
|
|||
{
|
||||
case MUSIC_AUDIO_OGG: stb_vorbis_seek_start(music->ctxOgg); break;
|
||||
#if defined(SUPPORT_FILEFORMAT_FLAC)
|
||||
case MUSIC_MODULE_FLAC: /* TODO: Restart FLAC context */ break;
|
||||
case MUSIC_AUDIO_FLAC: /* TODO: Restart FLAC context */ break;
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||
case MUSIC_AUDIO_MP3: /* TODO: Restart MP3 context */ break;
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_XM)
|
||||
case MUSIC_MODULE_XM: /* TODO: Restart XM context */ break;
|
||||
|
@ -1566,6 +1707,14 @@ void UpdateMusicStream(Music music)
|
|||
|
||||
} break;
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||
case MUSIC_AUDIO_MP3:
|
||||
{
|
||||
// NOTE: Returns the number of samples to process
|
||||
unsigned int numSamplesMp3 = (unsigned int)drmp3_read_f32(&music->ctxMp3, samplesCount*music->stream.channels, (float *)pcm);
|
||||
|
||||
} break;
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_XM)
|
||||
case MUSIC_MODULE_XM: jar_xm_generate_samples_16bit(music->ctxXm, pcm, samplesCount); break;
|
||||
#endif
|
||||
|
@ -1650,6 +1799,13 @@ void UpdateMusicStream(Music music)
|
|||
|
||||
} break;
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||
case MUSIC_AUDIO_MP3:
|
||||
{
|
||||
// NOTE: Returns the number of samples to process
|
||||
unsigned int numSamplesMp3 = (unsigned int)drmp3_read_f32(&music->ctxMp3, samplesCount*music->stream.channels, (float *)pcm);
|
||||
} break;
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_XM)
|
||||
case MUSIC_MODULE_XM: jar_xm_generate_samples_16bit(music->ctxXm, pcm, samplesCount); break;
|
||||
#endif
|
||||
|
@ -2239,6 +2395,33 @@ static Wave LoadFLAC(const char *fileName)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||
// Load MP3 file into Wave structure
|
||||
// NOTE: Using dr_mp3 library
|
||||
static Wave LoadMP3(const char *fileName)
|
||||
{
|
||||
Wave wave;
|
||||
|
||||
// Decode an entire MP3 file in one go
|
||||
uint64_t totalSampleCount;
|
||||
drmp3_config *config;
|
||||
wave.data = drmp3_open_and_decode_file_f32(fileName, config, &totalSampleCount);
|
||||
|
||||
wave.channels = config->outputChannels;
|
||||
wave.sampleRate = config->outputSampleRate;
|
||||
wave.sampleCount = (int)totalSampleCount/wave.channels;
|
||||
wave.sampleSize = 16;
|
||||
|
||||
// NOTE: Only support up to 2 channels (mono, stereo)
|
||||
if (wave.channels > 2) TraceLog(LOG_WARNING, "[%s] MP3 channels number (%i) not supported", fileName, wave.channels);
|
||||
|
||||
if (wave.data == NULL) TraceLog(LOG_WARNING, "[%s] MP3 data could not be loaded", fileName);
|
||||
else TraceLog(LOG_INFO, "[%s] MP3 file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo");
|
||||
|
||||
return wave;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Some required functions for audio standalone module version
|
||||
#if defined(AUDIO_STANDALONE)
|
||||
// Check file extension
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue