为啥将拆分为 wav 文件的旋律转换为拆分的 mp3 会在片段边界处产生不好的声音?
Posted
技术标签:
【中文标题】为啥将拆分为 wav 文件的旋律转换为拆分的 mp3 会在片段边界处产生不好的声音?【英文标题】:Why converting splitted onto wav files melody into splitted mp3 gives bad sound at fragments borders?为什么将拆分为 wav 文件的旋律转换为拆分的 mp3 会在片段边界处产生不好的声音? 【发布时间】:2015-12-29 11:54:30 【问题描述】:我有一个录音程序,可以从麦克风录制声音,然后将其拆分为 WAV 单秒片段,然后将每个 WAV 转换为 MP3。
将所有 WAV 文件连接在一起时,我得到了正常的旋律。 将所有 MP3 文件连接在一起时,我的旋律很糟糕。
怎么了?我虽然 wav -> mp3 转换不应该在文件中添加或删除任何块。 这是在wav和mp3版本中创建单秒片段的代码:
public void CreateWavAndMp3(string wav_path, string mp3_path, WaveFormat recordingFormat)
WaveFileWriter wav_writer = new WaveFileWriter(wav_path, recordingFormat);
List<byte> complete_chunk = new List<byte>(); //to store chunks one after another
for (int i = 0; i < this.Chunks.Count; i++) //here I have raw bytes stored in List<byte[]>. I just do it that way and since WAV files are fine it's no matter
complete_chunk.AddRange(this.Chunks[i]);
long maxFileLength = recordingFormat.AverageBytesPerSecond * 60;
var toWrite = (int)Math.Min(maxFileLength - wav_writer.Length, complete_chunk.Count);
if (toWrite > 0)
wav_writer.Write(complete_chunk.ToArray(), 0, complete_chunk.Count); //write wav based on stored chunks
wav_writer.Dispose(); //wav file written
//mp3 junk
WaveLib.WaveStream InStr = new WaveLib.WaveStream(wav_path);
Yeti.MMedia.Mp3.Mp3Writer mp3Writer;
Yeti.MMedia.Mp3.Mp3WriterConfig m_Config = new Yeti.MMedia.Mp3.Mp3WriterConfig(InStr.Format);
FileStream Mp3FS = new FileStream(mp3_path, FileMode.Create, FileAccess.Write);
mp3Writer = new Yeti.MMedia.Mp3.Mp3Writer(Mp3FS, m_Config);
byte[] mp3buff = new byte[mp3Writer.OptimalBufferSize];
int read = 0;
long total = InStr.Length;
while ((read = InStr.Read(mp3buff, 0, mp3buff.Length)) > 0)
mp3Writer.Write(mp3buff, 0, read);
InStr.Dispose();
mp3Writer.Dispose();
测试声音文件:https://www.dropbox.com/s/e43hh4y3oli13f4/livestream.7z?dl=0 这样你也能听到。尝试加入电影制作器等中的所有文件。
【问题讨论】:
我认为 mp3 编写器在每个Write
方法调用之后都会在末尾添加一个填充。它甚至可以将前导空格放在第一个块上。我认为在这种情况下,最好将每个波块合并为一个,然后将它们全部转换在一起。
@TaW - 我不知道我在哪里拆分...我有 OnDataAvailable
事件,它给了我一些原始字节。我将此字节添加到Single-second
类中,并检查第二个是否已经过去。如果通过,那么我将下一个字节写入新的Single-second
类,您看到了该类创建 wav 和 mp3 的方法。
@WutipongWongsakuldej - 可悲的是,分割碎片是其工作原理的主要思想。我有直播应用程序,允许管理员向所有连接的浏览器广播他的声音。它接收声音片段并一个接一个地播放。
所以您接收多个波形并将其录制到一个 mp3 文件中,而不知道它何时会结束,对吗?我认为,如果您能找到不发生填充的帧大小(在实际存在的情况下),那么您就可以开始了。您可以将它们记录到单独的文件中,然后在会话结束后将它们组合在一起。
@WutipongWongsakuldej - 你是对的......无论如何确定什么填充是没有蛮力的?
【参考方案1】:
您遇到了与 MP3 编码方式有关的问题。编解码器本身的一部分在每个文件的开头和结尾添加了填充。这是无法避免的。如果您想将它们首尾相连,则需要使用不同的格式。
一些音乐播放器通过计算添加了多少静音来解决这个问题。但即使这也可能因编解码器而异。如果您想深入了解技术细节,请查看本文档的第 2 部分:http://lame.sourceforge.net/tech-FAQ.txt
(tl;dr:该文档说“576 个样本”,16 位立体声是每个样本 4 个字节。)
另一个不存在此问题的有损编解码器是 OGG。 “Vorbis”是一个 NuGet 包,据说支持使用这种格式。
【讨论】:
呃,mp3 是 IE html5audio
标签支持的唯一编解码器,但感谢您提供信息。我会考虑如何处理填充。
你知道如何计算增加了多少静音吗?
它可能因编解码器而异。我猜您将无法对其进行解码并以编程方式自己查看数据(如果您使用的是 HTML5。)这意味着您所能做的就是做出有根据的猜测。如果你有一个不错的音频编辑器(Audacity、Audition 等)并且你知道 MP3 都来自同一个编解码器,你可以在音频编辑器中打开结果 MP3 并放大到足以测量静音之前的数量声音开始。
另外,如果您需要 IE 支持,并且不介意将 IE9 设为最低,您可以同时提供 AAC 和 OGG 格式。它们是有损格式,但应该足够了。在这两种格式之间,您应该拥有完整的浏览器支持。
谢谢。 Audacity 是一个很好的解决方案。我将在 JS 中使用计时器并开始主动播放下一个片段。以上是关于为啥将拆分为 wav 文件的旋律转换为拆分的 mp3 会在片段边界处产生不好的声音?的主要内容,如果未能解决你的问题,请参考以下文章