1
0
mirror of https://github.com/libretro/RetroArch synced 2024-07-08 12:15:49 +00:00

initial resampling wav loader

This commit is contained in:
Brad Parker 2017-01-25 01:28:48 -05:00
parent e3842d4169
commit 4fae51edcb
3 changed files with 261 additions and 1 deletions

View File

@ -454,7 +454,8 @@ endif
OBJ += $(LIBRETRO_COMM_DIR)/audio/conversion/s16_to_float.o \
$(LIBRETRO_COMM_DIR)/audio/conversion/float_to_s16.o \
$(LIBRETRO_COMM_DIR)/audio/audio_mix.o
$(LIBRETRO_COMM_DIR)/audio/audio_mix.o \
$(LIBRETRO_COMM_DIR)/formats/wav/rwav.o
ifeq ($(HAVE_NEON),1)
OBJ += $(LIBRETRO_COMM_DIR)/audio/conversion/s16_to_float_neon.o \

View File

@ -28,6 +28,14 @@
#include <altivec.h>
#endif
#include <stdio.h>
#include <retro_miscellaneous.h>
#include <audio/audio_mix.h>
#include <streams/file_stream.h>
#include <audio/conversion/float_to_s16.h>
#include <audio/conversion/s16_to_float.h>
void audio_mix_volume_C(float *out, const float *in, float vol, size_t samples)
{
size_t i;
@ -65,3 +73,213 @@ void audio_mix_volume_SSE2(float *out, const float *in, float vol, size_t sample
}
#endif
void audio_mix_free_chunk(audio_chunk_t *chunk)
{
if (!chunk)
return;
if (chunk->rwav && chunk->rwav->samples)
{
/* rwav_free only frees the samples */
rwav_free(chunk->rwav);
free(chunk->rwav);
}
if (chunk->buf)
free(chunk->buf);
if (chunk->upsample_buf)
free(chunk->upsample_buf);
if (chunk->float_buf)
free(chunk->float_buf);
if (chunk->float_resample_buf)
free(chunk->float_resample_buf);
if (chunk->resample_buf)
free(chunk->resample_buf);
if (chunk->resampler && chunk->resampler_data)
chunk->resampler->free(chunk->resampler_data);
free(chunk);
}
audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate)
{
audio_chunk_t *chunk = (audio_chunk_t*)calloc(1, sizeof(*chunk));
chunk->sample_rate = sample_rate;
if (!filestream_read_file(path, &chunk->buf, &chunk->len))
{
printf("Could not open WAV file for reading.\n");
return NULL;
}
chunk->rwav = (rwav_t*)malloc(sizeof(rwav_t));
if (rwav_load(chunk->rwav, chunk->buf, chunk->len) == RWAV_ITERATE_ERROR)
{
printf("error: could not load WAV file\n");
audio_mix_free_chunk(chunk);
return NULL;
}
if (sample_rate != chunk->rwav->samplerate)
{
int sample_size = chunk->rwav->bitspersample / 8;
if (sample_size == 1)
{
unsigned i;
chunk->upsample_buf = (int16_t*)malloc(chunk->rwav->numsamples * chunk->rwav->numchannels * sizeof(int16_t));
for (i = 0; i < chunk->rwav->numsamples; i++)
{
unsigned channel;
uint8_t *sample = ((uint8_t*)chunk->rwav->samples) +
(sample_size * i * chunk->rwav->numchannels);
for (channel = 0; channel < chunk->rwav->numchannels; channel++)
{
chunk->upsample_buf[i] = (int16_t)((sample[channel] - 128) << 8);
}
}
}
else if (sample_size != 2)
{
/* we don't support any other sample size besides 8 and 16-bit yet */
printf("error: we don't support a sample size of %d\n", sample_size);
audio_mix_free_chunk(chunk);
return NULL;
}
chunk->resample = true;
chunk->ratio = (double)sample_rate / chunk->rwav->samplerate;
retro_resampler_realloc(&chunk->resampler_data,
&chunk->resampler,
NULL,
chunk->ratio);
if (chunk->resampler && chunk->resampler_data)
{
struct resampler_data info = {0};
chunk->float_buf = (float*)malloc(chunk->rwav->numsamples * chunk->rwav->numchannels * sizeof(float));
chunk->float_resample_buf = (float*)malloc((chunk->rwav->numsamples * chunk->ratio + 16) * chunk->rwav->numsamples * chunk->rwav->numchannels * sizeof(float));
if (sample_size == 1)
convert_s16_to_float(chunk->float_buf, chunk->upsample_buf, chunk->rwav->numsamples * chunk->rwav->numchannels, 1.0);
else
convert_s16_to_float(chunk->float_buf, chunk->buf, chunk->rwav->numsamples * chunk->rwav->numchannels, 1.0);
info.data_in = (const float*)chunk->float_buf;
info.data_out = chunk->float_resample_buf;
info.input_frames = chunk->rwav->numsamples;
info.ratio = chunk->ratio;
chunk->resampler->process(chunk->resampler_data, &info);
chunk->resample_buf = (int16_t*)malloc(info.output_frames * chunk->rwav->numchannels * sizeof(int16_t));
chunk->resample_len = info.output_frames;
convert_float_to_s16(chunk->resample_buf, chunk->float_resample_buf, info.output_frames * chunk->rwav->numchannels);
}
}
return chunk;
}
size_t audio_mix_get_chunk_num_samples(audio_chunk_t *chunk)
{
if (!chunk)
return 0;
if (chunk->rwav)
{
if (chunk->resample)
return chunk->resample_len;
else
return chunk->rwav->numsamples;
}
else
{
/* no other filetypes supported yet */
return 0;
}
}
/**
* audio_mix_get_chunk_sample:
* @chunk : audio chunk instance
* @channel : channel of the sample (0=left, 1=right)
* @index : index of the sample
*
* Get a sample from an audio chunk.
*
* Returns: A signed 16-bit audio sample, (if necessary) resampled into the desired output rate.
**/
int16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk, unsigned channel, size_t index)
{
if (!chunk)
return 0;
if (chunk->rwav)
{
int sample_size = chunk->rwav->bitspersample / 8;
int16_t sample_out = 0;
/* 0 is the first/left channel */
uint8_t *sample = ((uint8_t*)chunk->rwav->samples) +
(sample_size * index * chunk->rwav->numchannels) + (channel * sample_size);
if (sample_size == 1)
{
if (chunk->resample)
sample_out = chunk->resample_buf[index];
else
{
/* convert unsigned 8-bit to signed 16-bit */
sample_out = (*sample - 128) << 8;
}
}
else if (sample_size == 2)
{
if (chunk->resample)
return chunk->resample_buf[index];
else
{
/* signed 16-bit is native, pass it through */
sample_out = (uint16_t)*sample;
}
}
else
{
return 0;
}
return sample_out;
}
else
{
/* no other filetypes supported yet */
return 0;
}
}
int audio_mix_get_chunk_num_channels(audio_chunk_t *chunk)
{
if (!chunk)
return 0;
if (chunk->rwav)
return chunk->rwav->numchannels;
else
{
/* don't support other formats yet */
return 0;
}
}

View File

@ -27,9 +27,30 @@
#include <stdint.h>
#include <stddef.h>
#include <unistd.h>
#include <formats/rwav.h>
#include <audio/audio_resampler.h>
RETRO_BEGIN_DECLS
typedef struct
{
void *buf;
int16_t *upsample_buf;
float *float_buf;
float *float_resample_buf;
int16_t *resample_buf;
ssize_t len;
size_t resample_len;
rwav_t *rwav;
int sample_rate;
bool resample;
const retro_resampler_t *resampler;
void *resampler_data;
double ratio;
} audio_chunk_t;
#if defined(__SSE2__)
#define audio_mix_volume audio_mix_volume_SSE2
@ -41,6 +62,26 @@ void audio_mix_volume_SSE2(float *out,
void audio_mix_volume_C(float *dst, const float *src, float vol, size_t samples);
void audio_mix_free_chunk(audio_chunk_t *chunk);
audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate);
size_t audio_mix_get_chunk_num_samples(audio_chunk_t *chunk);
/**
* audio_mix_get_chunk_sample:
* @chunk : audio chunk instance
* @channel : channel of the sample (0=left, 1=right)
* @index : index of the sample
*
* Get a sample from an audio chunk.
*
* Returns: A signed 16-bit audio sample, (if necessary) resampled into the desired output rate.
**/
int16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk, unsigned channel, size_t sample);
int audio_mix_get_chunk_num_channels(audio_chunk_t *chunk);
RETRO_END_DECLS
#endif