播放创建的 Audio-Data 有噪音和周期性的咔哒声
Posted
技术标签:
【中文标题】播放创建的 Audio-Data 有噪音和周期性的咔哒声【英文标题】:playing created Audio-Data has noise and periodical clicking in sound 【发布时间】:2011-12-28 10:51:58 【问题描述】:我编写了一个应用程序,它播放来自硬件的声音(就像一个充满一定频率的正弦波的环形缓冲区)。一切正常,我可以正确播放创建的声音,除了周期性的点击(可能在缓冲区的末尾?)和噪音。
我初始化并运行缓冲区:
void Audiooutput::InitializeAudioParameters()
Audio_DataWritten = 0;
Audio_fragments = 4;
Audio_channels = 2;
Audio_BufferSize = 256;
Audio_Samplerate = 8000;
Audio_ResamplingFactor = 1;
Audio_Framesize = 2;
// (SND_PCM_FORMAT_S16_LE / 8);
Audio_frames = Audio_BufferSize / Audio_Framesize * Audio_fragments;
snd_pcm_uframes_t size;
err = snd_pcm_hw_params_any(pcmPlaybackHandle, hw_params);
err = snd_pcm_hw_params_set_rate_resample(pcmPlaybackHandle, hw_params, 1);
// qDebug()<<a1.sprintf(" % d \t snd_pcm_hw_params_set_rate: %s",Audio_Samplerate,snd_strerror(err));
err =
snd_pcm_hw_params_set_format(pcmPlaybackHandle, hw_params,
SND_PCM_FORMAT_S16_LE);
err =
snd_pcm_hw_params_set_channels(pcmPlaybackHandle, hw_params,
Audio_channels);
err = snd_pcm_hw_params_set_rate_near(pcmPlaybackHandle, hw_params, &Audio_Samplerate, 0);
// qDebug()<<a1.sprintf(" % d \t snd_pcm_hw_params_set_rate: %s",Audio_Samplerate,snd_strerror(err));
if ((err =
snd_pcm_hw_params_set_periods_near(pcmPlaybackHandle, hw_params,
&Audio_fragments, 0)) < 0)
qDebug() << a1.sprintf("Error setting # fragments to %d: %s\n",
Audio_fragments, snd_strerror(err));
else
qDebug() << a1.sprintf("setting # fragments to %d: %s\n",
Audio_fragments, snd_strerror(err));
err = snd_pcm_hw_params_get_buffer_size(hw_params, &size);
if ((err =
snd_pcm_hw_params_set_buffer_size_near(pcmPlaybackHandle,
hw_params,
&Audio_frames)) < 0)
qDebug() << a1.
sprintf("Error setting buffer_size %d frames: %s",
Audio_frames, snd_strerror(err));
else
qDebug() << a1.sprintf("setting Buffersize to %d --> %d: %s\n",
Audio_BufferSize, Audio_frames,
snd_strerror(err));
Audio_BufferSize = Audio_frames;
if ((err = snd_pcm_hw_params(pcmPlaybackHandle, hw_params)) < 0)
qDebug() << a1.sprintf("Error setting HW params: %s",
snd_strerror(err));
Q_ASSERT(err >= 0);
void Audiooutput::ProduceAudioOutput(int n, int mmodes, int totalMModeGates,
short *sinusValue, short *cosinusValue)
for (int audiosample = 0; audioSample < n;
audioSample += Audio_ResamplingFactor)
currentposition =
(int)(m_Audio.generalPos % (Audio_BufferSize / 2));
if (currentposition == 0)
QueueAudioBuffer();
m_Audio.currentPos = 0;
m_Audio.generalPos++;
AudioData[currentposition * 2] =
(short)(sinusValue[audioSample]);
AudioData[currentposition * 2 + 1] =
(short)(cosinusValue[audioSample]);
void Audiooutput::QueueAudioBuffer()
snd_pcm_prepare(pcmPlaybackHandle);
Audio_DataWritten +=
snd_pcm_writei(pcmPlaybackHandle, AudioData, Audio_BufferSize);
更改音频缓冲区大小或片段也会更改点击周期。 谁能帮我解决这个问题? 我还检查了第一个和最后一个值。你总是与众不同。
操作系统:Ubuntu 11
更多细节。
接收数据的数量是动态的,变化取决于不同的参数。但我总是扮演某个角色,例如128 个值或 256 或 512....
// 我从硬件(在 Timerloop 中)获取音频数据
audiobuffersize = 256;
short *AudioData = new short[256];
int generalAudioSample = 0;
void CollectDataFromHw()
...
int n = 0;
n = GetData(buf1,buf2);//buf1 = new short[MAX_SHRT]
if(n > 0)
FillAudioBuffer(n,buf1,buf2)
...
-------------------------------------------
void FillAudioBuffer(int n, short*buf1, short*buf2)
for(int audioSample = 0;audioSample < n; audioSample++)
iCurrentAudioSample = (int)(generalAudioSample % (audiobuffersize/2));
if(iCurrentAudioSample == 0)
snd_pcm_writei(pcmPlaybackHandle,AudioData,audiobuffersize );
memset(AudioData,0x00,audiobuffersize*sizeof(short));
generalAudioSample++;
AudioData[iCurrentAudioSample * 2] = (short)(buf1[audioSample];
AudioData[iCurrentAudioSample * 2 +1] = (short)(buf2[audioSample];
我也更改了音频缓冲区大小。如果我将它设置为更大的尺寸,我会有一些额外的回声点击。
任何想法? //----------------------- 问题是
snd_pcm_prepare(pcmPlaybackHandle);
此函数的每次调用都会产生点击声!
【问题讨论】:
要么编辑你的问题,要么自己添加一个答案,在 cmets 中阅读长代码块是不可能的。顺便说一句,如果你让它工作,我很感兴趣,因为我自己也有同样的问题。 :) @MartinR:为什么要将 buf1[audioSample] 和 buf2[audioSample] 的值放在 AudioData 中的连续位置? 它们是音频数据的真实和想象部分。它在我的 Windows 应用程序中也可以这样工作。如果我只写 buf1,它也会发出声音。但是点击是一样的! 【参考方案1】:无法测试源代码,但我认为你听到的高频咔嗒声是声波中的不连续性。您必须确保循环周期(或缓冲区大小)是波周期的倍数。
检查缓冲区的第一个和最后一个值是否几乎相同(例如+/- 1)。它们的距离决定了不需要的点击的幅度。
【讨论】:
第一个和最后一个值不一样!它们总是不同的。 @MartinR:好的,请按照我的建议尝试根据波长更改缓冲区大小 是的,我也这样做了,但没有任何成功 --> 查看我的新细节。【参考方案2】:解决了 缓冲区在被数据填充之前已经播放了几次。
代码中的愚蠢错误。缺少 parantez --> audio_buffersize/2 - 因此结果通常是 if(iCurrentAudioSample == 0) true !!!!!
iCurrentAudioSample = (int)(generalAudioSample % (audio_buffersize/2));
if(iCurrentAudioSample == 0)
writetoaudioStream(audiobuffer);
【讨论】:
以上是关于播放创建的 Audio-Data 有噪音和周期性的咔哒声的主要内容,如果未能解决你的问题,请参考以下文章