将数据馈送到插孔时声音失真 - .wav 二进制数据转换为数字信号?

Posted

技术标签:

【中文标题】将数据馈送到插孔时声音失真 - .wav 二进制数据转换为数字信号?【英文标题】:Distorted sound when feeding data to jack - .wav binary data into digital signals? 【发布时间】:2012-12-11 16:41:26 【问题描述】:

经过一些故障排除后,我意识到(至少我很确定)我通过 JackAudio 库向声音端口提供了错误类型的值。

这是当前正在工作但会产生令人难以置信的失真声音的回调函数。

我怀疑我必须将二进制(然后转换为十进制)数据转换为 -1 到 1 之间的float 信号。

后者怎么做?

现在我正在为它提供一个 16 位的波形音乐文件。每个样本的大小为short

static int Process( jack_nframes_t nframes, void * arg )
    

        SamplerClass * SamplerPtr = ( SamplerClass * ) arg;

        jack_default_audio_sample_t * LeftChannel, * RightChannel;

        LeftChannel = ( jack_default_audio_sample_t * ) jack_port_get_buffer( LeftChannelOutputPort, nframes );

        RightChannel = ( jack_default_audio_sample_t * ) jack_port_get_buffer( RightChannelOutputPort, nframes );

        for( unsigned int i = 0; i<nframes; i++)
        
            LeftChannel[i] = SamplerPtr->SoundFile->getSoundDataRef().at( SamplerPtr->SamplePosition ) ;
            RightChannel[i] = SamplerPtr->SoundFile->getSoundDataRef().at( SamplerPtr->SamplePosition + 1;

            SamplerPtr->SamplePosition = SamplerPtr->SamplePosition + 2;
        

        return 0;
    

getSoundDataRef() 返回一个vector&lt;short&gt;,我通过vector::at 获得样本位置。

我正在通过 SamplePtr-&gt;SamplePosition 跟踪来自公共 int 变量的样本位置;

以下是 16 位 41000Hz 立体声波样本向量内数据格式的调试输出。所以看起来分配给通道的数据是正确的。

[INFO] [ 18:48:50.492] 288756 vec index RCh >1844
[INFO] [ 18:48:50.492] 288757 vec index LCh >1401
[INFO] [ 18:48:50.492] 288758 vec index RCh >-1251

【问题讨论】:

如何存储您处理的实际数据,并将其与您期望的数据进行比较(您可以通过您正在录制的同一个声卡播放一些预先录制的 WAV 文件来做到这一点开) 您是在处理来自输入插孔的音频,还是将预先录制的音频(您知道不会失真)发送到输出插孔?如果是前者.....您是否将线路电平音频源连接到麦克风输入?或者您是否使用过高的耳机输出过度驱动线路电平输入?如果是这样,那么您的输入端口正在“削波”信号(切断波形的顶部和底部),这就是失真的原因。您能否将连接到同一音频插孔的同一音频源用作不同程序的输入而不会失真? @MatsPetersson 我以为我提到它是来自实际 .wav 文件的 wav 样本。所以是的,它是预先录制的。使用带有 jack 插件的 VLC 媒体播放器,相同的文件听起来不错。 @phonetagger 我直接从文件中读取数据,没有声音处理,只是将数据传递到输出。 那么,当您比较原始文件和代码中的内容时,有什么区别?例如,您是否有可能放大太多以至于声音剪辑? 【参考方案1】:

在 cmets 的讨论中,解决方案是将正确的数据格式传递给 Jackaudio 库 - 在这种情况下,格式是 -1.0 - 1.0 范围内的浮点数,其中原始数据是 short int,所以使用公式x = sample / 32767.0; 转换每个样本将得到所需的结果。

【讨论】:

是的,做到了。很明显的答案,但我不习惯在这么多格式之间进行转换。感谢您帮助我解决此问题! :D 我知道你已经回答了,但我希望你能帮助我提供最后一个细节。而不是循环我如何使用memcpy() 直接将样本复制到变量LeftChannel/RightChannel 中,而不必遍历每个nframe 来复制每个单独的样本? 如果你必须转换每个样本,你不能 memcpy,因为你需要做转换。如果您想做一些内联汇编程序,您可以使用 SSE 指令进行转换,但是对于解释您如何做到这一点的评论来说有点太长了。无论如何,在 44KHz 时,我认为它并没有太大的区别。 当然,STL 可能有一些聪明的功能,你可以用它来复制一个 vector 到一个 vector 只用一行 - 但它仍然需要为每个转换,所以总体工作将几乎相同 - 只是在代码中看起来不会那样...... :) 其实我可以先把数据转换成向量再存入。我可以首先做一个矢量

以上是关于将数据馈送到插孔时声音失真 - .wav 二进制数据转换为数字信号?的主要内容,如果未能解决你的问题,请参考以下文章

USB 音频,低位失真

通过板载耳机插孔使用 ALSA + Jackd2 时,Raspberry Pi 3 A+ 音频失真/尖叫

捕捉当前正在播放的声音

音频 .wav 文件的二进制分类

使用 Hopfield 神经网络读取 WAV 文件的数据部分以进行语音识别

如何将 .wav 格式的声音相互附加