mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 22:20:21 +00:00
Merge branch 'wav_loader'
This commit is contained in:
commit
18f78613ae
@ -453,7 +453,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 \
|
||||
|
@ -28,6 +28,15 @@
|
||||
#include <altivec.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <memalign.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 +74,237 @@ 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)
|
||||
memalign_free(chunk->upsample_buf);
|
||||
|
||||
if (chunk->float_buf)
|
||||
memalign_free(chunk->float_buf);
|
||||
|
||||
if (chunk->float_resample_buf)
|
||||
memalign_free(chunk->float_resample_buf);
|
||||
|
||||
if (chunk->resample_buf)
|
||||
memalign_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));
|
||||
int sample_size;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* numsamples does not know or care about multiple channels, but we need space for 2 */
|
||||
chunk->upsample_buf = (int16_t*)memalign_alloc(128, chunk->rwav->numsamples * 2 * sizeof(int16_t));
|
||||
|
||||
sample_size = chunk->rwav->bitspersample / 8;
|
||||
|
||||
if (sample_size == 1)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < chunk->rwav->numsamples; i++)
|
||||
{
|
||||
uint8_t *sample = ((uint8_t*)chunk->rwav->samples) +
|
||||
(i * chunk->rwav->numchannels);
|
||||
|
||||
chunk->upsample_buf[i * 2] = (int16_t)((sample[0] - 128) << 8);
|
||||
|
||||
if (chunk->rwav->numchannels == 1)
|
||||
chunk->upsample_buf[(i * 2) + 1] = (int16_t)((sample[0] - 128) << 8);
|
||||
else if (chunk->rwav->numchannels == 2)
|
||||
chunk->upsample_buf[(i * 2) + 1] = (int16_t)((sample[1] - 128) << 8);
|
||||
}
|
||||
}
|
||||
else if (sample_size == 2)
|
||||
{
|
||||
if (chunk->rwav->numchannels == 1)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < chunk->rwav->numsamples; i++)
|
||||
{
|
||||
int16_t sample = ((int16_t*)chunk->rwav->samples)[i];
|
||||
|
||||
chunk->upsample_buf[i * 2] = sample;
|
||||
chunk->upsample_buf[(i * 2) + 1] = sample;
|
||||
}
|
||||
}
|
||||
else if (chunk->rwav->numchannels == 2)
|
||||
memcpy(chunk->upsample_buf, chunk->rwav->samples, chunk->rwav->subchunk2size);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
if (sample_rate != chunk->rwav->samplerate)
|
||||
{
|
||||
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*)memalign_alloc(128, chunk->rwav->numsamples * 2 * chunk->ratio * sizeof(float));
|
||||
|
||||
/* why is *3 needed instead of just *2? does the sinc driver require more space than we know about? */
|
||||
chunk->float_resample_buf = (float*)memalign_alloc(128, chunk->rwav->numsamples * 3 * chunk->ratio * sizeof(float));
|
||||
|
||||
convert_s16_to_float(chunk->float_buf, chunk->upsample_buf, chunk->rwav->numsamples * 2, 1.0);
|
||||
|
||||
info.data_in = (const float*)chunk->float_buf;
|
||||
info.data_out = chunk->float_resample_buf;
|
||||
/* a 'frame' consists of two channels, so we set this to the number of samples irrespective of channel count */
|
||||
info.input_frames = chunk->rwav->numsamples;
|
||||
info.ratio = chunk->ratio;
|
||||
|
||||
chunk->resampler->process(chunk->resampler_data, &info);
|
||||
|
||||
/* number of output_frames does not increase with multiple channels, but assume we need space for 2 */
|
||||
chunk->resample_buf = (int16_t*)memalign_alloc(128, info.output_frames * 2 * sizeof(int16_t));
|
||||
chunk->resample_len = info.output_frames;
|
||||
convert_float_to_s16(chunk->resample_buf, chunk->float_resample_buf, info.output_frames * 2);
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
**/
|
||||
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;
|
||||
|
||||
if (chunk->resample)
|
||||
sample = (uint8_t*)chunk->resample_buf +
|
||||
(sample_size * index * chunk->rwav->numchannels) + (channel * sample_size);
|
||||
else
|
||||
sample = (uint8_t*)chunk->upsample_buf +
|
||||
(sample_size * index * chunk->rwav->numchannels) + (channel * sample_size);
|
||||
|
||||
sample_out = (int16_t)*sample;
|
||||
|
||||
return sample_out;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no other filetypes supported yet */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t* audio_mix_get_chunk_samples(audio_chunk_t *chunk)
|
||||
{
|
||||
if (!chunk)
|
||||
return 0;
|
||||
|
||||
if (chunk->rwav)
|
||||
{
|
||||
int16_t *sample;
|
||||
|
||||
if (chunk->resample)
|
||||
sample = chunk->resample_buf;
|
||||
else
|
||||
sample = chunk->upsample_buf;
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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,28 @@ 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);
|
||||
|
||||
int16_t* audio_mix_get_chunk_samples(audio_chunk_t *chunk);
|
||||
|
||||
int audio_mix_get_chunk_num_channels(audio_chunk_t *chunk);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user