如何混合PCM音频源(Java)?
以下是我目前正在处理的问题:如何混合PCM音频源(Java)?,java,audio,signal-processing,pcm,mixing,Java,Audio,Signal Processing,Pcm,Mixing,以下是我目前正在处理的问题: for (int i = 0, numSamples = soundBytes.length / 2; i < numSamples; i += 2) { // Get the samples. int sample1 = ((soundBytes[i] & 0xFF) << 8) | (soundBytes[i + 1] & 0xFF); // Automatically converts to unsigne
for (int i = 0, numSamples = soundBytes.length / 2; i < numSamples; i += 2)
{
// Get the samples.
int sample1 = ((soundBytes[i] & 0xFF) << 8) | (soundBytes[i + 1] & 0xFF); // Automatically converts to unsigned int 0...65535
int sample2 = ((outputBytes[i] & 0xFF) << 8) | (outputBytes[i + 1] & 0xFF); // Automatically converts to unsigned int 0...65535
// Normalize for simplicity.
float normalizedSample1 = sample1 / 65535.0f;
float normalizedSample2 = sample2 / 65535.0f;
float normalizedMixedSample = 0.0f;
// Apply the algorithm.
if (normalizedSample1 < 0.5f && normalizedSample2 < 0.5f)
normalizedMixedSample = 2.0f * normalizedSample1 * normalizedSample2;
else
normalizedMixedSample = 2.0f * (normalizedSample1 + normalizedSample2) - (2.0f * normalizedSample1 * normalizedSample2) - 1.0f;
int mixedSample = (int)(normalizedMixedSample * 65535);
// Replace the sample in soundBytes array with this mixed sample.
soundBytes[i] = (byte)((mixedSample >> 8) & 0xFF);
soundBytes[i + 1] = (byte)(mixedSample & 0xFF);
}
for(int i=0,numSamples=soundBytes.length/2;i
据我所知,这是本页定义的算法的准确表示:
然而,仅仅是将一个声音与静默(全部为0)混合会产生一个听起来显然不正确的声音,也许最好将其描述为音调更高、声音更大
如果能帮助我确定我是否正确地实现了算法,或者我是否只需要以不同的方式(不同的算法/方法)实现算法,我将不胜感激。在链接文章中,作者假设a和B代表整个音频流。更具体地说,X表示流X中所有样本的最大abs值,其中X为A或B。因此,他的算法扫描两个流的整体,以计算每个流的最大abs样本,然后对其进行缩放,以便理论上输出峰值为1.0。为了实现此算法,您需要对数据进行多次传递,如果您的数据正在流式传输,那么它将无法工作 下面是一个我认为算法如何工作的例子。它假设示例已经转换为浮点,以避免转换代码出错的问题。我稍后会解释它的问题:
double[] samplesA = ConvertToDoubles(samples1);
double[] samplesB = ConvertToDoubles(samples2);
double A = ComputeMax(samplesA);
double B = ComputeMax(samplesB);
// Z always equals 1 which is an un-useful bit of information.
double Z = A+B-A*B;
// really need to find a value x such that xA+xB=1, which I think is:
double x = 1 / (Math.sqrt(A) * Math.sqrt(B));
// Now mix and scale the samples
double[] samples = MixAndScale(samplesA, samplesB, x);
混合和结垢:
double[] MixAndScale(double[] samplesA, double[] samplesB, double scalingFactor)
{
double[] result = new double[samplesA.length];
for (int i = 0; i < samplesA.length; i++)
result[i] = scalingFactor * (samplesA[i] + samplesB[i]);
}
double[]MixAndScale(double[]samplesA,double[]samplesB,double scalingFactor)
{
double[]结果=新的double[samplesA.length];
对于(int i=0;i
计算最大峰值:
double ComputeMaxPeak(double[] samples)
{
double max = 0;
for (int i = 0; i < samples.length; i++)
{
double x = Math.abs(samples[i]);
if (x > max)
max = x;
}
return max;
}
double ComputeMaxPeak(双[]个样本)
{
双最大值=0;
对于(int i=0;i最大值)
max=x;
}
返回最大值;
}
和转换。请注意我是如何使用short的,以便正确维护符号位的:
double[] ConvertToDouble(byte[] bytes)
{
double[] samples = new double[bytes.length/2];
for (int i = 0; i < samples.length; i++)
{
short tmp = ((short)bytes[i*2])<<8 + ((short)(bytes[i*2+1]);
samples[i] = tmp / 32767.0;
}
return samples;
}
double[]ConvertToDouble(字节[]字节)
{
double[]samples=新的double[bytes.length/2];
对于(int i=0;i short tmp=((short)bytes[i*2])尝试了这段代码。经过几次编译和缺少括号错误后,当两个音频源混合时,背景中仍然存在白噪声。还有什么遗漏吗?经过长时间处理这个问题后,我决定不使用这种转换方式,而是使用ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
,对shorts进行操作。然后返回ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN.asShortBuffer().put(shorts);
。这非常有效。