如何在 SDL 中将 16 位样本拆分为 2 个字节的音频?

How do I split a 16bit sample into 2 bytes for audio in SDL?

提问人:Jake A 提问时间:11/1/2023 更新时间:11/1/2023 访问量:25

问:

以下函数填充在回调中读取的音频缓冲区。当没有声音时,它很好,但是当播放样本时,它有明显的失真。如果我尝试使用AUDIO_S8格式并删除 val 的位移,它可以正常工作,但将 8 个通道混合到一个 8 位输出听起来很糟糕,您可以想象。

// global
struct AudioBuffer{
    Uint8 *data;
    Uint32 len;
    Uint32 pos;
    bool update; // if true audio_works() fills buffer
    bool stop;
} buffer;

#define AMP_LEV 252
#define BYTES_IN_SAMPLE 2
#define CHANNELS 8

注意:隔离到通道 0 进行测试。目标是将 8 个 8 位通道混合到 1 个 16 位输出。

void AudioW::audio_works(AudioBuffer *b)
{
    int actual_pos;
    int16_t val;
    if (b->stop)
    {
        for (int c = 0; c < CHANNELS; c++)
        {
            t->channel[c].play = false;
        }
        b->stop = false;
    }
    for (int p = 0; p < b->len; p += BYTES_IN_SAMPLE)
    {
        val = 0;
        for (int c = 0; c < 1; c++) // only use channel 0
        {
            if (t->channel[c].play && t->mute[c] == false)
            {
                actual_pos = (int)t->channel[c].pos;
                if (t->sample[t->channel[c].sample].len != 0 && actual_pos < t->sample[t->channel[c].sample].len)
                {
                    val = (t->sample[t->channel[c].sample].data[actual_pos] * AMP_LEV) * t->channel[c].amplifier;
                    t->channel[c].pos += t->channel[c].pos_adv;
                    t->channel[c].pos_adv *= t->channel[c].pitch_mod;
                } else{
                    t->channel[c].play = false; // stop channel playback if sample reaches end or sample is empty
                }
            }
        }
        val = val; // with other channels: val / CHANNELS
        b->data[p] = val;
        b->data[p+1] = val >> 8;
    }
}

我想我已经将其缩小到将“val”拆分为 2 个字节的问题。 有谁知道是什么原因导致了失真?

C++ 音频 SDL-2

评论

0赞 fdcpp 11/22/2023
在这些情况下,失真几乎总是归结为整数值溢出。建议先将值转换为 ,而不是移位,然后在 之间缩放,然后将求和/缩放到整数格式的任何范围。此外,你似乎在以错误的方式转变,但也可能更合适。float±1b->data[p+1] = val << 8;(int16_t)(*b->data+p)

答: 暂无答案