mirror of
https://github.com/libretro/RetroArch
synced 2025-02-28 12:40:23 +00:00
Some cleanups for audio mixer
This commit is contained in:
parent
c8dfdaa5ff
commit
4e0c24acbe
@ -38,13 +38,12 @@
|
|||||||
#define __forceinline __inline__ __attribute__((__always_inline__,__gnu_inline__))
|
#define __forceinline __inline__ __attribute__((__always_inline__,__gnu_inline__))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "stb_vorbis.c"
|
#include "../deps/stb/stb_vorbis.h"
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define AUDIO_MIXER_MAX_VOICES 8
|
#define AUDIO_MIXER_MAX_VOICES 8
|
||||||
#define AUDIO_MIXER_TEMP_OGG_BUFFER 8192
|
#define AUDIO_MIXER_TEMP_OGG_BUFFER 8192
|
||||||
|
|
||||||
|
|
||||||
#define AUDIO_MIXER_TYPE_NONE 0
|
#define AUDIO_MIXER_TYPE_NONE 0
|
||||||
#define AUDIO_MIXER_TYPE_WAV 1
|
#define AUDIO_MIXER_TYPE_WAV 1
|
||||||
#define AUDIO_MIXER_TYPE_OGG 2
|
#define AUDIO_MIXER_TYPE_OGG 2
|
||||||
@ -102,20 +101,21 @@ struct audio_mixer_voice_t
|
|||||||
} types;
|
} types;
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned s_rate;
|
|
||||||
static audio_mixer_voice_t s_voices[AUDIO_MIXER_MAX_VOICES];
|
static audio_mixer_voice_t s_voices[AUDIO_MIXER_MAX_VOICES];
|
||||||
|
static unsigned s_rate = 0;
|
||||||
|
|
||||||
static bool wav2float(const rwav_t* wav, float** pcm, size_t* samples_out)
|
static bool wav2float(const rwav_t* wav, float** pcm, size_t* samples_out)
|
||||||
{
|
{
|
||||||
float* f;
|
|
||||||
float sample;
|
|
||||||
const uint8_t* u8;
|
|
||||||
const int16_t* s16;
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
float sample = 0.0f;
|
||||||
|
const uint8_t* u8 = NULL;
|
||||||
|
const int16_t* s16 = NULL;
|
||||||
|
float* f = NULL;
|
||||||
|
|
||||||
/* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes */
|
/* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes */
|
||||||
*samples_out = wav->numsamples * 2;
|
*samples_out = wav->numsamples * 2;
|
||||||
f = (float*)memalign_alloc(16, ((*samples_out + 15) & ~15) * sizeof(float));
|
f = (float*)memalign_alloc(16,
|
||||||
|
((*samples_out + 15) & ~15) * sizeof(float));
|
||||||
|
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
return false;
|
return false;
|
||||||
@ -184,7 +184,8 @@ static bool wav2float(const rwav_t* wav, float** pcm, size_t* samples_out)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool one_shot_resample(const float* in, size_t samples_in, unsigned rate, float** out, size_t* samples_out)
|
static bool one_shot_resample(const float* in, size_t samples_in,
|
||||||
|
unsigned rate, float** out, size_t* samples_out)
|
||||||
{
|
{
|
||||||
void* data = NULL;
|
void* data = NULL;
|
||||||
const retro_resampler_t* resampler = NULL;
|
const retro_resampler_t* resampler = NULL;
|
||||||
@ -196,7 +197,8 @@ static bool one_shot_resample(const float* in, size_t samples_in, unsigned rate,
|
|||||||
|
|
||||||
/* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes */
|
/* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes */
|
||||||
*samples_out = samples_in * ratio;
|
*samples_out = samples_in * ratio;
|
||||||
*out = (float*)memalign_alloc(16, ((*samples_out + 15) & ~15) * sizeof(float));
|
*out = (float*)memalign_alloc(16,
|
||||||
|
((*samples_out + 15) & ~15) * sizeof(float));
|
||||||
|
|
||||||
if (*out == NULL)
|
if (*out == NULL)
|
||||||
return false;
|
return false;
|
||||||
@ -231,17 +233,17 @@ void audio_mixer_done(void)
|
|||||||
|
|
||||||
audio_mixer_sound_t* audio_mixer_load_wav(const char* path)
|
audio_mixer_sound_t* audio_mixer_load_wav(const char* path)
|
||||||
{
|
{
|
||||||
/* Raw WAV bytes */
|
|
||||||
void* buffer;
|
|
||||||
ssize_t size;
|
|
||||||
/* WAV data */
|
/* WAV data */
|
||||||
rwav_t wav;
|
rwav_t wav;
|
||||||
|
/* Raw WAV bytes */
|
||||||
|
void* buffer = NULL;
|
||||||
|
ssize_t size = 0;
|
||||||
/* WAV samples converted to float */
|
/* WAV samples converted to float */
|
||||||
float* pcm;
|
float* pcm = NULL;
|
||||||
float* resampled;
|
float* resampled = NULL;
|
||||||
size_t samples;
|
size_t samples = 0;
|
||||||
/* Result */
|
/* Result */
|
||||||
audio_mixer_sound_t* sound;
|
audio_mixer_sound_t* sound = NULL;
|
||||||
|
|
||||||
if (filestream_read_file(path, &buffer, &size) == 0)
|
if (filestream_read_file(path, &buffer, &size) == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -259,7 +261,8 @@ audio_mixer_sound_t* audio_mixer_load_wav(const char* path)
|
|||||||
|
|
||||||
if (wav.samplerate != s_rate)
|
if (wav.samplerate != s_rate)
|
||||||
{
|
{
|
||||||
if (!one_shot_resample(pcm, samples, wav.samplerate, &resampled, &samples))
|
if (!one_shot_resample(pcm, samples,
|
||||||
|
wav.samplerate, &resampled, &samples))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
memalign_free((void*)pcm);
|
memalign_free((void*)pcm);
|
||||||
@ -284,9 +287,9 @@ audio_mixer_sound_t* audio_mixer_load_wav(const char* path)
|
|||||||
|
|
||||||
audio_mixer_sound_t* audio_mixer_load_ogg(const char* path)
|
audio_mixer_sound_t* audio_mixer_load_ogg(const char* path)
|
||||||
{
|
{
|
||||||
void* buffer;
|
|
||||||
ssize_t size;
|
ssize_t size;
|
||||||
audio_mixer_sound_t* sound;
|
void* buffer = NULL;
|
||||||
|
audio_mixer_sound_t* sound = NULL;
|
||||||
|
|
||||||
if (filestream_read_file(path, &buffer, &size) == 0)
|
if (filestream_read_file(path, &buffer, &size) == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -316,7 +319,9 @@ void audio_mixer_destroy(audio_mixer_sound_t* sound)
|
|||||||
free(sound);
|
free(sound);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool audio_mixer_play_wav(audio_mixer_sound_t* sound, audio_mixer_voice_t* voice, bool repeat, float volume, audio_mixer_stop_cb_t stop_cb)
|
static bool audio_mixer_play_wav(audio_mixer_sound_t* sound,
|
||||||
|
audio_mixer_voice_t* voice, bool repeat, float volume,
|
||||||
|
audio_mixer_stop_cb_t stop_cb)
|
||||||
{
|
{
|
||||||
voice->type = AUDIO_MIXER_TYPE_WAV;
|
voice->type = AUDIO_MIXER_TYPE_WAV;
|
||||||
voice->repeat = repeat;
|
voice->repeat = repeat;
|
||||||
@ -328,28 +333,34 @@ static bool audio_mixer_play_wav(audio_mixer_sound_t* sound, audio_mixer_voice_t
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool audio_mixer_play_ogg(audio_mixer_sound_t* sound, audio_mixer_voice_t* voice, bool repeat, float volume, audio_mixer_stop_cb_t stop_cb)
|
static bool audio_mixer_play_ogg(
|
||||||
|
audio_mixer_sound_t* sound,
|
||||||
|
audio_mixer_voice_t* voice,
|
||||||
|
bool repeat, float volume,
|
||||||
|
audio_mixer_stop_cb_t stop_cb)
|
||||||
{
|
{
|
||||||
int res;
|
|
||||||
stb_vorbis_info info;
|
stb_vorbis_info info;
|
||||||
float ratio;
|
int res = 0;
|
||||||
unsigned samples;
|
float ratio = 0.0f;
|
||||||
|
unsigned samples = 0;
|
||||||
|
|
||||||
voice->repeat = repeat;
|
voice->repeat = repeat;
|
||||||
voice->volume = volume;
|
voice->volume = volume;
|
||||||
voice->sound = sound;
|
voice->sound = sound;
|
||||||
voice->stop_cb = stop_cb;
|
voice->stop_cb = stop_cb;
|
||||||
|
|
||||||
voice->types.ogg.stream = stb_vorbis_open_memory((const unsigned char*)sound->types.ogg.data, sound->types.ogg.size, &res, NULL);
|
voice->types.ogg.stream = stb_vorbis_open_memory(
|
||||||
|
(const unsigned char*)sound->types.ogg.data,
|
||||||
|
sound->types.ogg.size, &res, NULL);
|
||||||
|
|
||||||
if (voice->types.ogg.stream == NULL)
|
if (voice->types.ogg.stream == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
info = stb_vorbis_get_info(voice->types.ogg.stream);
|
info = stb_vorbis_get_info(voice->types.ogg.stream);
|
||||||
|
|
||||||
|
/* Only stereo supported for now */
|
||||||
if (info.channels != 2)
|
if (info.channels != 2)
|
||||||
{
|
{
|
||||||
/* Only stereo supported for now */
|
|
||||||
stb_vorbis_close(voice->types.ogg.stream);
|
stb_vorbis_close(voice->types.ogg.stream);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -358,15 +369,18 @@ static bool audio_mixer_play_ogg(audio_mixer_sound_t* sound, audio_mixer_voice_t
|
|||||||
{
|
{
|
||||||
voice->types.ogg.ratio = ratio = (double)s_rate / (double)info.sample_rate;
|
voice->types.ogg.ratio = ratio = (double)s_rate / (double)info.sample_rate;
|
||||||
|
|
||||||
if (!retro_resampler_realloc(&voice->types.ogg.resampler_data, &voice->types.ogg.resampler, NULL, ratio))
|
if (!retro_resampler_realloc(&voice->types.ogg.resampler_data,
|
||||||
|
&voice->types.ogg.resampler, NULL, ratio))
|
||||||
{
|
{
|
||||||
stb_vorbis_close(voice->types.ogg.stream);
|
stb_vorbis_close(voice->types.ogg.stream);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
samples = voice->types.ogg.buf_samples = (unsigned)(AUDIO_MIXER_TEMP_OGG_BUFFER * ratio);
|
samples =
|
||||||
voice->types.ogg.buffer = (float*)memalign_alloc(16, ((samples + 15) & ~15) * sizeof(float));
|
voice->types.ogg.buf_samples = (unsigned)(AUDIO_MIXER_TEMP_OGG_BUFFER * ratio);
|
||||||
|
voice->types.ogg.buffer = (float*)memalign_alloc(16,
|
||||||
|
((samples + 15) & ~15) * sizeof(float));
|
||||||
|
|
||||||
if (voice->types.ogg.buffer == NULL)
|
if (voice->types.ogg.buffer == NULL)
|
||||||
{
|
{
|
||||||
@ -380,10 +394,11 @@ static bool audio_mixer_play_ogg(audio_mixer_sound_t* sound, audio_mixer_voice_t
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat, float volume, audio_mixer_stop_cb_t stop_cb)
|
audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat,
|
||||||
|
float volume, audio_mixer_stop_cb_t stop_cb)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
audio_mixer_voice_t* voice;
|
audio_mixer_voice_t* voice = NULL;
|
||||||
bool res = false;
|
bool res = false;
|
||||||
|
|
||||||
for (i = 0, voice = s_voices; i < AUDIO_MIXER_MAX_VOICES; i++, voice++)
|
for (i = 0, voice = s_voices; i < AUDIO_MIXER_MAX_VOICES; i++, voice++)
|
||||||
@ -399,7 +414,9 @@ audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat, f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res ? voice : NULL;
|
if (res)
|
||||||
|
return voice;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_mixer_stop(audio_mixer_voice_t* voice)
|
void audio_mixer_stop(audio_mixer_voice_t* voice)
|
||||||
@ -409,12 +426,13 @@ void audio_mixer_stop(audio_mixer_voice_t* voice)
|
|||||||
|
|
||||||
static void mix_wav(float* buffer, size_t num_frames, audio_mixer_voice_t* voice)
|
static void mix_wav(float* buffer, size_t num_frames, audio_mixer_voice_t* voice)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
unsigned buf_free = num_frames * 2;
|
unsigned buf_free = num_frames * 2;
|
||||||
const audio_mixer_sound_t* sound = voice->sound;
|
const audio_mixer_sound_t* sound = voice->sound;
|
||||||
unsigned pcm_available = sound->types.wav.frames * 2 - voice->types.wav.position;
|
unsigned pcm_available = sound->types.wav.frames
|
||||||
|
* 2 - voice->types.wav.position;
|
||||||
const float* pcm = sound->types.wav.pcm + voice->types.wav.position;
|
const float* pcm = sound->types.wav.pcm + voice->types.wav.position;
|
||||||
float volume = voice->volume;
|
float volume = voice->volume;
|
||||||
int i;
|
|
||||||
|
|
||||||
again:
|
again:
|
||||||
if (pcm_available < buf_free)
|
if (pcm_available < buf_free)
|
||||||
@ -450,19 +468,21 @@ again:
|
|||||||
|
|
||||||
static void mix_ogg(float* buffer, size_t num_frames, audio_mixer_voice_t* voice)
|
static void mix_ogg(float* buffer, size_t num_frames, audio_mixer_voice_t* voice)
|
||||||
{
|
{
|
||||||
unsigned buf_free = num_frames * 2;
|
int i;
|
||||||
const audio_mixer_sound_t* sound = voice->sound;
|
|
||||||
float temp_buffer[AUDIO_MIXER_TEMP_OGG_BUFFER];
|
float temp_buffer[AUDIO_MIXER_TEMP_OGG_BUFFER];
|
||||||
unsigned temp_samples;
|
unsigned buf_free = num_frames * 2;
|
||||||
|
unsigned temp_samples = 0;
|
||||||
float volume = voice->volume;
|
float volume = voice->volume;
|
||||||
struct resampler_data info = {0};
|
struct resampler_data info = {0};
|
||||||
float* pcm;
|
float* pcm = NULL;
|
||||||
int i;
|
const audio_mixer_sound_t* sound = voice->sound;
|
||||||
|
|
||||||
if (voice->types.ogg.position == voice->types.ogg.samples)
|
if (voice->types.ogg.position == voice->types.ogg.samples)
|
||||||
{
|
{
|
||||||
again:
|
again:
|
||||||
temp_samples = stb_vorbis_get_samples_float_interleaved(voice->types.ogg.stream, 2, temp_buffer, AUDIO_MIXER_TEMP_OGG_BUFFER) * 2;
|
temp_samples = stb_vorbis_get_samples_float_interleaved(
|
||||||
|
voice->types.ogg.stream, 2, temp_buffer,
|
||||||
|
AUDIO_MIXER_TEMP_OGG_BUFFER) * 2;
|
||||||
|
|
||||||
if (temp_samples == 0)
|
if (temp_samples == 0)
|
||||||
{
|
{
|
||||||
@ -517,9 +537,9 @@ static void mix_ogg(float* buffer, size_t num_frames, audio_mixer_voice_t* voice
|
|||||||
void audio_mixer_mix(float* buffer, size_t num_frames)
|
void audio_mixer_mix(float* buffer, size_t num_frames)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
audio_mixer_voice_t* voice;
|
size_t j = 0;
|
||||||
size_t j;
|
float* sample = NULL;
|
||||||
float* sample;
|
audio_mixer_voice_t* voice = NULL;
|
||||||
|
|
||||||
for (i = 0, voice = s_voices; i < AUDIO_MIXER_MAX_VOICES; i++, voice++)
|
for (i = 0, voice = s_voices; i < AUDIO_MIXER_MAX_VOICES; i++, voice++)
|
||||||
{
|
{
|
||||||
|
@ -16,9 +16,11 @@
|
|||||||
#ifndef __AUDIO_MIXER__H
|
#ifndef __AUDIO_MIXER__H
|
||||||
#define __AUDIO_MIXER__H
|
#define __AUDIO_MIXER__H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#include <boolean.h>
|
#include <boolean.h>
|
||||||
#include <retro_common_api.h>
|
#include <retro_common_api.h>
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
RETRO_BEGIN_DECLS
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
11
audio/stb_vorbis.c → deps/stb/stb_vorbis.h
vendored
11
audio/stb_vorbis.c → deps/stb/stb_vorbis.h
vendored
@ -3935,8 +3935,10 @@ static int start_decoder(vorb *f)
|
|||||||
for (j=0; j < g->values; ++j)
|
for (j=0; j < g->values; ++j)
|
||||||
g->sorted_order[j] = (uint8) p[j].y;
|
g->sorted_order[j] = (uint8) p[j].y;
|
||||||
// precompute the neighbors
|
// precompute the neighbors
|
||||||
for (j=2; j < g->values; ++j) {
|
for (j=2; j < g->values; ++j)
|
||||||
int low,hi;
|
{
|
||||||
|
int low = 0;
|
||||||
|
int hi = 0;
|
||||||
neighbors(g->Xlist, j, &low,&hi);
|
neighbors(g->Xlist, j, &low,&hi);
|
||||||
g->neighbors[j][0] = low;
|
g->neighbors[j][0] = low;
|
||||||
g->neighbors[j][1] = hi;
|
g->neighbors[j][1] = hi;
|
||||||
@ -4536,11 +4538,12 @@ static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last)
|
|||||||
// doing needless I/O would be crazy!
|
// doing needless I/O would be crazy!
|
||||||
static int vorbis_analyze_page(stb_vorbis *f, ProbedPage *z)
|
static int vorbis_analyze_page(stb_vorbis *f, ProbedPage *z)
|
||||||
{
|
{
|
||||||
uint8 header[27], lacing[255];
|
uint8 lacing[255];
|
||||||
uint8 packet_type[255];
|
uint8 packet_type[255];
|
||||||
int num_packet, packet_start;
|
int num_packet, packet_start;
|
||||||
int i,len;
|
int i,len;
|
||||||
uint32 samples;
|
uint32 samples;
|
||||||
|
uint8 header[27] = {0};
|
||||||
|
|
||||||
// record where the page starts
|
// record where the page starts
|
||||||
z->page_start = stb_vorbis_get_file_offset(f);
|
z->page_start = stb_vorbis_get_file_offset(f);
|
||||||
@ -5175,7 +5178,7 @@ static void convert_samples_short(int buf_c, short **buffer, int b_offset, int d
|
|||||||
|
|
||||||
int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples)
|
int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples)
|
||||||
{
|
{
|
||||||
float **output;
|
float **output = {NULL};
|
||||||
int len = stb_vorbis_get_frame_float(f, NULL, &output);
|
int len = stb_vorbis_get_frame_float(f, NULL, &output);
|
||||||
if (len > num_samples) len = num_samples;
|
if (len > num_samples) len = num_samples;
|
||||||
if (len)
|
if (len)
|
Loading…
x
Reference in New Issue
Block a user