我想将增益应用于我的录音(PCM 16bit)。为此,我有以下代码:
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];
}
但仍然听到奇怪的声音(噪音+不像老式对讲机一样停止)。
任何帮助将不胜感激,
感谢。
答案 0 :(得分:2)
这是最终的结果......算法与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);
答案 1 :(得分:1)
当改变增益时,你需要在通常大约10毫秒的时间内平稳地做到这一点,否则你会听到不可思议的不连续性(即点击)。最简单的过渡是线性的,例如从旧增益到新增益的线性延迟超过10 ms,但对于高质量音频,你应该使用类似升余弦转换的东西:
gain(t) = gain_old + (gain_new - gain_old) * 0.5 * (1 - cos(π * (t - t0) / (t1 - t0)))
其中t0,t1是转换的开始,结束时间。
答案 2 :(得分:1)
您的来源中还有其他错误。以下行从-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;