NAudio分割mp3文件

13

我对音频或mp3等方面非常陌生,正在寻找一种在C#、asp.net中拆分mp3文件的方法。在谷歌搜索了三天后没有多少帮助,我希望这里有人能指引我正确的方向。

我可以使用NAudio来完成吗?是否有任何示例代码可供参考?先感谢您。


可能是通过编程剪辑MP3的重复问题。 - ErikE
5个回答

13

我在C#中用NAudio实现了分割mp3文件的最终解决方案。以下是一个示例脚本,希望能对社区中的某些人有所帮助:

string strMP3Folder = "<YOUR FOLDER PATH>";
string strMP3SourceFilename = "<YOUR SOURCE MP3 FILENAMe>";
string strMP3OutputFilename = "<YOUR OUTPUT MP3 FILENAME>";

using (Mp3FileReader reader = new Mp3FileReader(strMP3Folder + strMP3SourceFilename))
{
    int count = 1;
    Mp3Frame mp3Frame = reader.ReadNextFrame();
    System.IO.FileStream _fs = new System.IO.FileStream(strMP3Folder + strMP3OutputFilename, System.IO.FileMode.Create, System.IO.FileAccess.Write);

    while (mp3Frame != null)
    {
        if (count > 500) //retrieve a sample of 500 frames
            return;

        _fs.Write(mp3Frame.RawData, 0, mp3Frame.RawData.Length);
        count = count + 1;
        mp3Frame = reader.ReadNextFrame();
     }

     _fs.Close();
}

感谢Mark Heath的建议。

所需的命名空间为NAudio.Wave。


1
为什么你要在每一帧中关闭和重新打开Filestream?这样做会影响性能。 - BrokenGlass
这只是对NAudio的一个快速测试。你是对的,不应该一直打开和关闭文件流,代码已经被编辑了。 - joe kirk
一个帧的时间有多长? - Andrey Kaplun
@AndreyKaplun 双声道音频长度(秒)=(double)frame.SampleCount / frame.SampleRate; - Brian Rak

12

一个MP3文件由一系列MP3帧组成(通常还有开头和结尾的ID3标签)。因此,最清晰的分割MP3文件的方法是将一定数量的帧复制到一个新文件中(如果重要的话,也可以将ID3标签一同复制)。

NAudio的MP3FileReader类具有一个ReadNextFrame方法。它返回一个MP3Frame类,其中包含原始数据的字节数组在RawData属性中。它还包括一个SampleCount属性,您可以使用它来准确地测量每个MP3帧的持续时间。


谢谢您的评论,我会尝试一下。稍后我会回来更新我的发现。谢谢! - joe kirk
每个mp3帧有多少毫秒?是否有公式或其他方法可以用来获取每个mp3帧的长度(以毫秒为单位)? - Desolator
1
@ermac2014 使用采样率。如果您知道每秒采样数和采样数量,则将采样数量除以采样率得到持续时间。 - Mark Heath

6
之前的回答帮助了我入门。NAudio 是正确的选择。
对于我的 PodcastTool,我需要将播客在每 2 分钟的间隔内分割,以便更快地查找到特定位置。
以下是将 mp3 按每 N 秒分割的代码:
    var mp3Path = @"C:\Users\ronnie\Desktop\mp3\dotnetrocks_0717_alan_dahl_imagethink.mp3";
    int splitLength = 120; // seconds

    var mp3Dir = Path.GetDirectoryName(mp3Path);
    var mp3File = Path.GetFileName(mp3Path);
    var splitDir = Path.Combine(mp3Dir,Path.GetFileNameWithoutExtension(mp3Path));
    Directory.CreateDirectory(splitDir);

    int splitI = 0;
    int secsOffset = 0;

    using (var reader = new Mp3FileReader(mp3Path))
    {   
        FileStream writer = null;       
        Action createWriter = new Action(() => {
            writer = File.Create(Path.Combine(splitDir,Path.ChangeExtension(mp3File,(++splitI).ToString("D4") + ".mp3")));
        });

        Mp3Frame frame;
        while ((frame = reader.ReadNextFrame()) != null)
        {           
            if (writer == null) createWriter();

            if ((int)reader.CurrentTime.TotalSeconds - secsOffset >= splitLength)
            {   
                // time for a new file
                writer.Dispose();
                createWriter();
                secsOffset = (int)reader.CurrentTime.TotalSeconds;              
            }

            writer.Write(frame.RawData, 0, frame.RawData.Length);
        }

        if(writer != null) writer.Dispose();
    }

1
修改我的示例以实现这一点不应该很困难。你试过了吗?我可以在某个时候尝试一下,只是现在不行。起始和停止修剪点的测量单位是什么? - Ronnie Overby
我一直在尝试,但还没有成功。这是我第一次使用NAudio。测量结果将是时间跨度。开始和结束时间,因此基本上是剪辑的开始和结束。 - Andre DeMattia
我尝试过了,但CurrentTime始终为零,有人知道为什么吗? - Paolo Costa

2

感谢您的评论,我会先尝试使用NAudio。 :) - joe kirk

0

如果你想要分割播客,可以将音轨复制到一个音频设备上(在我的情况下是游泳耳机),并使用 Google 的 Text To Speech 服务创建一个小的音频头来标识音轨。(例如,“一百件物品的世界历史。第15集。4个音轨之一。”)你可以查看一个小的 bash 脚本 https://github.com/pulijon/cpodcast/blob/main/cutpodcast.bash

该脚本已准备好添加西班牙语的音频头。对于其他语言,您需要更改选项 -l 和头字符串。

gtts-cli "Corte $((10#$ntrack)) de $((10#$numtracks)). $5 " -l es --output pre_$track

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接