混合来自 MP3 文件的两个音频样本

Posted

技术标签:

【中文标题】混合来自 MP3 文件的两个音频样本【英文标题】:Mixing two audio samples from MP3 files 【发布时间】:2015-10-04 19:45:19 【问题描述】:

我在将两个不同的音频样本混合为一个时遇到问题,只需将两个音频样本的字节相加即可。

当我尝试在媒体播放器中打开混合.mp3 文件时,经过以下过程,它显示:

Windows Media Player 在播放文件时遇到问题。

这是我用来混合音频文件的代码:

byte[] bytes1,bytes2,final;
int length1,length2,max;

// Getting byte[] of audio file
using ( BinaryReader b = new BinaryReader(File.Open("background.mp3" , FileMode.Open)) )

    length1 = (int)b.BaseStream.Length;
    bytes1 = b.ReadBytes(length1);


using ( BinaryReader b = new BinaryReader(File.Open("voice.mp3" , FileMode.Open)) )

    length2 = (int)b.BaseStream.Length;
    bytes2 = b.ReadBytes(length2);


// Getting max length
if(length1 > length2)
    max = length1;
else
    max = length2;


// Initializing output byte[] of max length
final = new byte[max];

// Adding byte1 and byte2 and copying into final
for (int i=0;i<max;i++)

    byte b1 , b2;

    if(i < length1)
        b1 = bytes1[i];
    else
        b1 = 0;
    

    if ( i < length2 )
        b2 = bytes2[i];
    
    else
        b2 = 0;
    

    final[i] = (byte)(b1 + b2);


// Writing final[] as an mp3 file
File.WriteAllBytes("mixed.mp3" , final);

注意:我尝试混合两个相同的文件,并且成功了,也就是说,媒体播放器没有抛出任何错误并且可以正确播放。

【问题讨论】:

你的底注是什么意思?你的意思是代码现在可以工作了? 这是不可能的。 Mp3 不是行波数据。像这样添加字节会 100% 损坏数据。不确定它是如何为您工作的 解码,计算,记住裁剪(0..255),再次编码。您现在所做的无法正常工作,因为:mp3 已压缩(除非它仅包含幅度数据……我不是专家),您还必须考虑在文件级别工作时不应更改的所有元数据的标题。 @TaLha Khan 我的回答对你有用吗? @EmpereurAiman 没有。你的答案和我正在做的一样,我的意思是附加字节。 【参考方案1】:

这很可能是因为您不是decoding 混合MP3 文件之前并且你“只是将”样本“添加”在一起,这将导致clipping;您应该首先使用library 将 MP3 文件解码为 PCM,然后您可以混合它们。

要正确混合您应该做的样品:

final[i] = (byte)(b1 / 2 + b2 / 2);

否则您的计算将溢出(另外,我通常建议在操作之前将您的音频标准化为floats)。还应该注意的是,您正在混合 MP3 文件中的 所有 字节,即,您正在弄乱标题(因此 WMP 拒绝播放您的“混合”文件)。您应该只混合文件的实际音频数据(样本),而不是整个文件。

我使用 NAudio 库提供了一个(已注释的)工作示例1(它将混合音频导出到 wav 文件以避免进一步复杂化):

// You can get the library via NuGet if preferred.
using NAudio.Wave;

...

var fileA = new AudioFileReader("Input path 1");

// Calculate our buffer size, since we're normalizing our samples to floats
// we'll need to account for that by dividing the file's audio byte count
// by its bit depth / 8.
var bufferA = new float[fileA.Length / (fileA.WaveFormat.BitsPerSample / 8)];

// Now let's populate our buffer with samples.
fileA.Read(bufferA, 0, bufferA.Length);

// Do it all over again for the other file.
var fileB = new AudioFileReader("Input path 2");
var bufferB = new float[fileB.Length / (fileB.WaveFormat.BitsPerSample / 8)];
fileB.Read(bufferB, 0, bufferB.Length);

// Calculate the largest file (simpler than using an 'if').
var maxLen = (long)Math.Max(bufferA.Length, bufferB.Length);
var final = new byte[maxLen];

// For now, we'll just save our mixed data to a wav file.
// (Things can get a little complicated when encoding to MP3.)
using (var writer = new WaveFileWriter("Output path", fileA.WaveFormat))

    for (var i = 0; i < maxLen; i++)
    
        float a, b;

        if (i < bufferA.Length)
        
            // Reduce the amplitude of the sample by 2
            // to avoid clipping.
            a = bufferA[i] / 2;
        
        else
        
            a = 0;
        

        if (i < bufferB.Length)
        
            b = bufferB[i] / 2;
        
        else
        
            b = 0;
        

        writer.WriteSample(a + b);
    


1 输入文件必须具有相同的采样率、位深度和通道数才能正常工作。

【讨论】:

以上是关于混合来自 MP3 文件的两个音频样本的主要内容,如果未能解决你的问题,请参考以下文章

核心音频指导/入门

如何使用 NAudio 从 mp3 中获取音频样本数据

合并iPhone上的音频文件

如何在 C# 中分层两个音频文件?

MP3 样本大小?

混合 PCM 音频样本