Split audio file into parts

I am trying to split an audio file into multiple parts.

The thing is, I have a byte array and I would like to split the WAV file into some random chunks (like 3).

Of course, I know that I cannot do something like this. But does anyone have an idea on how to do this?

byte[] result = stream.ToArray();
byte[] testing = new byte[44];

for (int ix = 0; ix < testing.Length; ix++)
{
    testing[ix] = result[ix];
}

System.IO.File.WriteAllBytes("yourfilepath_" + System.Guid.NewGuid() + ".wav", testing);

      

I would like to build this solution in C #, but I heard there is a lib called Sox and I can split it with a silence type like this:

sox in.wav out.wav silence 1 0.5 1% 1 5.0 1% : newfile : restart

      

But every time I run this command only one file is generated. (the sound file is 5 seconds long and each split file should have something in a second).

What's the best way to do this?

Many thanks!

+3


source to share


1 answer


EDIT

With SOX:

string sox = @"C:\Program Files (x86)\sox-14-4-1\sox.exe";
string inputFile = @"D:\Brothers Vibe - Rainforest.mp3";
string outputDirectory = @"D:\splittest";
string outputPrefix = "split";

int[] segments = { 10, 15, 30 };

IEnumerable<string> enumerable = segments.Select(s => "trim 0 " + s.ToString(CultureInfo.InvariantCulture));
string @join = string.Join(" : newfile : ", enumerable);
string cmdline = string.Format("\"{0}\" \"{1}%1n.wav" + "\" {2}", inputFile,
    Path.Combine(outputDirectory, outputPrefix), @join);

var processStartInfo = new ProcessStartInfo(sox, cmdline);
Process start = System.Diagnostics.Process.Start(processStartInfo);

      

If SOX complains about libmad (for MP3): copy the DLL next to it, see here

Alternatively, you can use FFMPEG in the same way:

ffmpeg -ss 0 -t 30 -i "Brothers Vibe - Rainforest.mp3" "Brothers Vibe - Rainforest.wav"

      

( see docs for all details)


You can do it easily with BASS.NET :



Below is the code below:

  • input file name
  • desired duration for each segment
  • output directory Prefix
  • for each segment file

The method checks if the file is sufficient for the specified segments, if yes, then it cuts the file to WAV with the same sampling rate, channels, bit depth.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Un4seen.Bass;
using Un4seen.Bass.Misc;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            if (!Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero))
                throw new InvalidOperationException("Couldn't initialize BASS");

            string fileName = @"D:\Brothers Vibe - Rainforest.mp3";
            var segments = new double[] {30, 15, 20};
            string[] splitAudio = SplitAudio(fileName, segments, "output", @"D:\split");
        }

        private static string[] SplitAudio(string fileName, double[] segments, string prefix, string outputDirectory)
        {
            if (fileName == null) throw new ArgumentNullException("fileName");
            if (segments == null) throw new ArgumentNullException("segments");
            if (prefix == null) throw new ArgumentNullException("prefix");
            if (outputDirectory == null) throw new ArgumentNullException("outputDirectory");
            int i = Bass.BASS_StreamCreateFile(fileName, 0, 0,
                BASSFlag.BASS_STREAM_PRESCAN | BASSFlag.BASS_STREAM_DECODE);
            if (i == 0)
                throw new InvalidOperationException("Couldn't create stream");

            double sum = segments.Sum();

            long length = Bass.BASS_ChannelGetLength(i);
            double seconds = Bass.BASS_ChannelBytes2Seconds(i, length);
            if (sum > seconds)
                throw new ArgumentOutOfRangeException("segments", "Required segments exceed file duration");
            BASS_CHANNELINFO info = Bass.BASS_ChannelGetInfo(i);

            if (!Directory.Exists(outputDirectory)) Directory.CreateDirectory(outputDirectory);

            int index = 0;
            var list = new List<string>();
            foreach (double segment in segments)
            {
                double d = segment;
                long seconds2Bytes = Bass.BASS_ChannelSeconds2Bytes(i, d);
                var buffer = new byte[seconds2Bytes];
                int getData = Bass.BASS_ChannelGetData(i, buffer, buffer.Length);
                string name = string.Format("{0}_{1}.wav", prefix, index);
                string combine = Path.Combine(outputDirectory, name);
                int bitsPerSample = info.Is8bit ? 8 : info.Is32bit ? 32 : 16;
                var waveWriter = new WaveWriter(combine, info.chans, info.freq, bitsPerSample, true);
                waveWriter.WriteNoConvert(buffer, buffer.Length);
                waveWriter.Close();
                list.Add(combine);
                index++;
            }
            bool free = Bass.BASS_StreamFree(i);

            return list.ToArray();
        }
    }
}

      

TODO

The retrieval is not optimized, if you are interested in memory usage then the function should be improved to grab parts of the segments and write them gradually to WaveWriter

.

Notes

BASS.NET has a screensaver screen, but you can request a free serial registration on its website.

Please note: install BASS.NET, then be sure to copy bass.dll from the base package next to your EXE. Also, you can use almost any audio formats, see their site for format plugins and how to load them (BASS_PluginLoad).

+3


source







All Articles