【问题标题】:android audioRecord- apply gain with variationandroid audioRecord-应用增益变化
【发布时间】:2012-05-14 07:09:25
【问题描述】:

我想为我的录音应用增益(PCM 16 位)。为此,我有以下代码:

for (int i=0; i<buffer.length/2; i++)
{ // 16bit sample size                      
  short curSample = getShort(buffer[i*2], buffer[i*2+1]);
  if(rGain != 1){
  //apply gain
  curSample *= rGain;
  //convert back from short sample that was "gained" to byte data
  byte[] a = getByteFromShort(curSample);
  buffer[i*2] = a[0];
  buffer[i*2 + 1] = a[1];
}

如果像这样应用(将每个样本与分数相乘),播放时我会中断(像旧对讲机一样听)。是否有一些公式可以改变每个样本的增益因子?我假设样本范围有一些 maxValue 和 minValue(我猜是 [-32768, +32767]),并且在某些公式中使用这些值,我可以得到一个可变的增益因子以应用于当前样本。

//编辑: 添加了

if (curSample>32767) {curSample=32767;}
if (curSample<-32768) {curSample=-32768;}

完整方法

aRecorder.read(buffer, 0, buffer.length);
for (int i=0; i<buffer.length/2; i++)
                    { // 16bit sample size                      
                        short curSample = getShort(buffer[i*2], buffer[i*2+1]);
                        if(rGain != 1){
                            //apply gain
                            curSample *= rGain;
                            if (curSample>32767) {curSample=32767;}
                            if (curSample<-32768) {curSample=-32768;}
                            //convert back from short sample that was "gained" to byte data
                            byte[] a = getByteFromShort(curSample);
                            buffer[i*2] = a[0];
                            buffer[i*2 + 1] = a[1];
                        }

但仍然听到奇怪的声音(噪音 + 像旧对讲机一样中断)。

任何帮助将不胜感激,

谢谢。

【问题讨论】:

  • 是的,rGain 假设为 2,但我不想将样本 1789 乘以 2,样本 4 乘以 2。我认为样本 1789 应该乘以小于 2 的值。
  • 仍然不明白你是否想要一个随机(任何)值,或者乘数之间的某种相关性
  • rGain 是从用户选择(seekBar)中获得的,我希望根据每个样本的值对其应用变化。我认为较高的样本值应乘以小于 rGain 的值(以避免中断),并且应将较小的样本值乘以 rGain。请参阅另一篇帖子:stackoverflow.com/questions/10449963/… - “为防止输出不连续,请确保从头到尾平滑地改变乘法因子。”
  • 那么你不想要一个随机数。另外,对不起,但我无能为力。

标签: java android audio fft audio-recording


【解决方案1】:

这是最终结果...该算法与 VU 计量测量相交...忽略那部分...

final int numFrames = getNumOfFrames(source.length);
62                          final int bytesPerSample = bitsPerSamples / 8;
63                          final int emptySpace=64-bitsPerSamples;
64                          int byteIndex=0;
65                          int byteIndex2 = 0;
66                  
67                  
68                          int temp = 0;
69                          int mLeftTemp = 0;
70                          int mRightTemp = 0;
71                          int a=0;
72                          int x = 0;
73                          
74                          for(int frameIndex=0; frameIndex<numFrames; frameIndex++){
75                                  for(int c=0; c<nChannels; c++){
76                                          if(rGain != 1){
77                                                  // gain
78                                                  long accumulator=0;
79                                                  for(int b=0; b<bytesPerSample; b++){
80                                                          accumulator+=((long)(source[byteIndex++]&0xFF))<<(b*8+emptySpace);
81                                                  }
82                                                  double sample = ((double)accumulator/(double)Long.MAX_VALUE);
83                                                  sample *= rGain;                                
84                                          
85                                                  int intValue = (int)((double)sample*(double)Integer.MAX_VALUE);                         
86                                                  for(int i=0; i<bytesPerSample; i++){
87                                                          source[i+byteIndex2]=(byte)(intValue >>> ((i+2)*8) & 0xff);
88                                                  }
89                                                  byteIndex2 += bytesPerSample;   
90                                          }
91                                          
92                                          //average
93                                          if(bytesPerSample == 2){
94                                                  x = frameIndex*nChannels*bytesPerSample+(c*bytesPerSample);
95                                                  a = Math.abs((short)(((data[x+1] & 0xFF) << 8) | (data[x] & 0xFF)));
96                                          }else{
97                                                  a = Math.abs(data[frameIndex*nChannels +c]);
98                                          }
99                                          
100                                         temp += a;
101                                         mLeftTemp += (c==0)? a : 0;
102                                         mRightTemp += (c==1)? a : 0;
103                                         }//end for(channel)
104                         }//end for(frameIndex)
105                         
106                         mAverage = temp / (data.length / bytesPerSample);
107 //                      System.out.println("result 1 is: "+mAverage);
108 //                      System.out.println("result 2 is: "+calculateAverageValue());
109                         
110                         mLeftChannelAverage = mLeftTemp / (data.length/bytesPerSample/nChannels);
111                         mRightChannelAverage = mRightTemp / (data.length/bytesPerSample/nChannels);
112                         Amplitude ampl = new Amplitude(mAverage, mLeftChannelAverage, mRightChannelAverage);
113                         AmplitudePollAPI.getInstance().onAmplitudeReached(ampl);

【讨论】:

  • 你能解释一下你在上面的代码中试图做什么。我没有得到你。使用了不同的变量以及为什么要计算累加器。做它的实际过程或公式是什么。任何了解该过程的参考都会有所帮助。
  • 增益计算从第一条评论 (// 增益) 开始,在 // 平均评论之前结束。如您所见,我只是修改了“源”数组....
  • 转成long时使用累加器
  • Alexandru Circus 非常感谢.. :)
【解决方案2】:

您的源代码中还有另一个错误。以下行从 -32768..32767 创建样本值,这是 s 短变量的全部范围:

short curSample = getShort(buffer[i*2], buffer[i*2+1]);

当您现在应用大于 1 的增益因子时,您会“溢出”short 格式:

curSample *= rGain;

这会在平滑信号中产生令人讨厌的裂缝,例如32767 * 1.5 不是预期的 49150,而是由于“溢出”被解释为 -16386,因为您再次将结果分配给 short 变量。

这两行

if (curSample>32767) {curSample=32767;}
if (curSample<-32768) {curSample=-32768;}

不会改变任何东西,因为 curSample 永远不会大于 32767 或小于 -32768。

为避免这种情况,您必须使用临时的int 变量:

short curSample = getShort(buffer[i*2], buffer[i*2+1]);
int temp = curSample * rGain;
if (temp>=32767)
    curSample=32767;
else if (temp<=-32768)
    curSample=-32768;
else
    curSample=(short)temp;

【讨论】:

    【解决方案3】:

    更改增益时,您需要在通常大约 10 毫秒的时间内平稳地执行此操作,否则您会听到不连续的声音(即咔嗒声)。最简单的过渡是线性的,例如在 10 毫秒内从旧增益线性上升到新增益,但对于高质量音频,您应该使用升余弦转换之类的方法:

    gain(t) = gain_old + (gain_new - gain_old) * 0.5 * (1 - cos(π * (t - t0) / (t1 - t0)))
    

    其中 t0、t1 是过渡的开始时间和结束时间。

    【讨论】:

    • 谢谢。还有一个问题:gain_old 和 gain_new - 我怎样才能得到这两个?我只有 1 个增益可应用(例如:2),那么如何获得这 2 个值? new_gain 为 2(或用户选择的)且 old_gain 为 1?
    • 抱歉 - 我假设您在 更改 增益时获得了点击,即从某个初始增益值 gain_old 到某个新增益值 gain_new -即使不改变增益,你也能获得点击吗?
    • 我没有听到任何咔哒声,但是例如我说“一、二、三、四、五”,并且在播放时,每个单词都被剪切,并且播放时长小于应有的时间是。此外,当增益为 1 时,质量非常好。但是任何其他值都会导致问题,所以我认为将每个样本乘以一个固定值(!= 大于 1)并不是一个好习惯。
    • 好的 - 我唯一能想到的另一件事是您的样本可能是偏移二进制而不是二进制补码,因此当您相乘时会破坏值。
    • 是的,我的错。选择了以 PCM 8 位而不是 16 位录制的选项。直到现在,选择 16 位并应用增益都可以正常工作(没有“咔哒”声,只有少量噪音)。但是,正如您所建议的,对于高质量的音频,我需要实现升余弦过渡;我会尝试看看如何处理 old_gain 和 new_gain。谢谢您的帮助。真的很感激。
    猜你喜欢
    • 2013-07-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-31
    • 1970-01-01
    • 2012-07-02
    • 2014-12-06
    • 2011-05-08
    • 2023-03-13
    相关资源
    最近更新 更多