我正在为libretro核心编写一个非常简单的前端,并且我正在攻击音频部分,这是最难的(我以前从未处理过任何与声音相关的事情,所以我很可能完全错了)。
它的工作方式是,libretro 核心定期调用一个原型函数,因为我必须自己实现:
typedef size_t (*retro_audio_sample_batch_t)(const int16_t *data, size_t count);
data
参数是隔行扫描立体数据的数组(){ Left, Right, Left, ...}
,count
是样本数(所以数组元素计数实际上是count * 2)。
这是我目前对这些数据所做的事情:
- 当 libretro 核心向我发送样品时
- 我只是将它们连接到音频缓冲区
- 当 SDL 调用我的音频回调方法时,
- 我从音频缓冲区复制尽可能多的请求和可用到流缓冲区
- 如果没有足够的数据可用,我用 0 填充流缓冲区的其余部分
- 如果我的缓冲区的数据比请求的多,我只需删除我刚刚播放的内容并保留其余部分
但是,我得到的不正确。尽管有些可辨认,但声音却是乱码,充满了噪音。我不确定我可能缺少什么:似乎 RetroArch 前端(libretro 核心的官方前端)正在进行某种重新采样,但我不知道它是什么。是否需要重新采样?我的问题可以来自那里吗?
这是我的完整代码,部分转载如下:
static int16_t * g_audio_samples = NULL;
static size_t g_audio_sample_count = 0;
static void audio_write( int16_t const * samples, size_t count )
{
SDL_LockAudio( );
int16_t * previous_samples = g_audio_samples;
size_t previous_count = g_audio_sample_count;
g_audio_sample_count = previous_count + count;
g_audio_samples = calloc( g_audio_sample_count * 2, sizeof( int16_t ) );
for ( size_t index = 0; index < previous_count; ++ index )
g_audio_samples[ index ] = previous_samples[ index ];
for ( size_t index = 0; index < count; ++ index )
g_audio_samples[ previous_count + index ] = samples[ index ];
free( previous_samples );
SDL_UnlockAudio( );
}
static void audio_callback( void * userdata, Uint8 * stream, int length )
{
int16_t * available_samples = g_audio_samples;
size_t available_sample_count = g_audio_sample_count;
size_t requested_sample_count = length / 2;
size_t requested_byte_length = requested_sample_count * 2;
size_t providen_sample_count = requested_sample_count < available_sample_count ? requested_sample_count : available_sample_count;
size_t providen_byte_length = providen_sample_count * 2;
memcpy( stream, available_samples, providen_byte_length );
memset( stream + providen_byte_length, 0, requested_byte_length - providen_byte_length );
g_audio_samples = NULL;
g_audio_sample_count = 0;
if ( providen_sample_count < available_sample_count )
audio_write( available_samples + providen_sample_count, available_sample_count - providen_sample_count );
free( available_samples );
}
size_t bridge_virtjs_audio_push_sample_batch( int16_t const * samples, size_t count )
{
audio_write( samples, count );
return count;
}