NAudio to split mp3 file - c#

I am very new to audio or mp3 stuff, was looking for a way to have a feature to split an mp3 file in C#, asp.net. After googling for a good 3-day without much of a great help, I am hoping that somebody here can point me to a right direction.
Can I use NAudio to accomplish this? Is there any sample code for that? Thanks in advance.

My final solution to split mp3 file in c# is to use NAudio. Here is a sample script for that, hope it helps someone in the community:
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();
}
Thanks to Mark Heath's suggestion for this.
The namespace required is NAudio.Wave.

An MP3 File is made up of a sequence of MP3 frames (plus often ID3 tags on the beginning and end). The cleanest way to split an MP3 file then is to copy a certain number of frames into a new file (and optionally bring the ID3 tags along too if that is important).
NAudio's MP3FileReader class features a ReadNextFrame method. This returns an MP3Frame class, which contains the raw data as a byte array in the RawData property. It also includes a SampleCount property which you can use to accurately measure the duration of each MP3 Frame.

The previous answers helped me get started. NAudio is the way to go.
For my PodcastTool I needed to to split podcasts at 2 minute intervals to make seeking to a specific place faster.
Here's the code to split an mp3 every N seconds:
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();
}

these would be helpful Alvas Audio (commercial) and ffmpeg

If you want to split podcasts, copy the tracks to an audio device (swimming headers in my case) and include a little audio header made from the Text To Speech service from Google to identify the tracks. (e.g. "History of the world in a hundred objects. Episode 15. Track 1 of 4") you could check a little bash script https://github.com/pulijon/cpodcast/blob/main/cutpodcast.bash
It is prepared to add the audio header in Spanish. For other languages you should change the option -l and the string of header
gtts-cli "Corte $((10#$ntrack)) de $((10#$numtracks)). $5 " -l es --output pre_$track

Related

Adding Beep or Silence for a given duration in an Audio file || NAudio || C#

I am using NAudio to record and play the audio file. Now, I want to add silence or beep in an audio file for a given duration. Could you please suggest the NAudio provider name in order to achieve it?
To generate a beep, take a look at SignalGenerator, which can generate a sine wave. There is a Take extension method to limit the duration of the beep. For silence, you can use the same technique, except with SilenceProvider.
Here's a simple example of two beeps with silence between them:
var beep1 = (new SignalGenerator(){ Frequency = 1000, Gain = 0.2}).Take(TimeSpan.FromSeconds(2));
var silence = new SilenceProvider(beep1.WaveFormat).ToSampleProvider().Take(TimeSpan.FromSeconds(2));
var beep2 = (new SignalGenerator() { Frequency = 1500, Gain = 0.2 }).Take(TimeSpan.FromSeconds(2));
var concat = beep1.FollowedBy(silence).FollowedBy(beep2);
using (var wo = new WaveOutEvent())
{
wo.Init(concat);
wo.Play();
while(wo.PlaybackState == PlaybackState.Playing)
{
Thread.Sleep(500);
}
}

Mix audio read from two source files

I want to mix audio read from two files (1 mp3 and 1 wav(recorded voice) file) into one file (mp3 or wav).
I have read many relevant answers but non helped me to get what I wanted.
Like this code below generate a steam as output. I do not know how to call this function properly and how to get the Output stream as an mp3/wav file at the end.
public static void Combine(string[] inputFiles, Stream output)
{
foreach (string file in inputFiles)
{
Mp3FileReader reader = new Mp3FileReader(file);
if ((output.Position == 0) && (reader.Id3v2Tag != null))
{
output.Write(reader.Id3v2Tag.RawData, 0, reader.Id3v2Tag.RawData.Length);
}
Mp3Frame frame;
while ((frame = reader.ReadNextFrame()) != null)
{
output.Write(frame.RawData, 0, frame.RawData.Length);
}
}
}
It looks like you took the code from http://mark-dot-net.blogspot.com/2010/11/merging-mp3-files-with-naudio-in-c-and.html. Check out http://markheath.net/post/mixing-and-looping-with-naudio as well. This talks about looping as well as mixing. Since you're not looping, you don't need that part.
Note that the example there sends the audio to the speaker. However, you can always replace that output with a (e.g.) WaveFileWriter.
Note also that the MixingWaveProvider32 requires that all inputs be in the same WaveFormat. If that's not the case, then you'll need to use a resampler. Luckily, there's http://mark-dot-net.blogspot.com/2014/05/how-to-resample-audio-with-naudio.html to help you out there as well.

Why does my re-recorded audio file play back with chipmunk voice?

I use NAudio 1.72 project to record new audio files and edit existing wav files. I noticed that whenever I open a 172kbps wav file and record part of the file, playback sounds like a chipmunk.
The newly recorded wav files show a bit rate of 128kbps. And I don't find the chipmunk issue with wav files of 128kbps. Does anyone think its a problem because bit rates don't match?
How do I resolve this?
Please note: I am coding in C#, use NAudio project reference to record and edit wav files. I use WPF mediaelement to play back any wav file.
Well, after a bit of exploration, i found this somewhat helpful. Still i am afraid i have regression issues. Still working on making the below strategy work better.
Although below method converts a 176kbps wav file to 128kbps and plays well, the application crashes.
private string OpenMedia(string filename)
{
using (var reader = new WaveFileReader(filename))
{
int bitrate = reader.WaveFormat.AverageBytesPerSecond * 8;
if (bitrate > 128000)
{
MessageBox.Show("This wav file has a bit rate higher than 128 kbps : " +
bitrate);
int channel = reader.WaveFormat.Channels;
if (channel > 1)
{
MessageBox.Show("This wav file was not created in Mono channel : " +
channel);
}
int samplerate = reader.WaveFormat.SampleRate;
if (samplerate > 8000)
{
MessageBox.Show("This wav file has a sample rate > 8000 : " + samplerate);
var newFormat = new WaveFormat(8000, 16, 1);
using (var conversionStream = new WaveFormatConversionStream(newFormat,
reader))
{
WaveFileWriter.CreateWaveFile(filename, conversionStream);
}
}
}
}
return filename;
}

how to decode mp3 file in c# using NAudio

My task is to decode a mp3 file, exclude its header, side information and the optional checksum. I just need the actual data of every frame of the mp3 file.
I have googled a lot but did't find a way !
Can any one tell me a direct way to do that. I am using NAudio to access frames using ReadNextFrame()
Any help will be appreciated.
As mentioned in http://mark-dot-net.blogspot.de/2010/11/merging-mp3-files-with-naudio-in-c-and.html you could change the code to something like that:
public static byte[] GetRawMp3Frames(string filename)
{
using(MemoryStream output = new MemoryStream()) {
Mp3FileReader reader = new Mp3FileReader(filename);
Mp3Frame frame;
while ((frame = reader.ReadNextFrame()) != null)
{
output.Write(frame.RawData, 0, frame.RawData.Length);
}
return output.ToArray();
}
}
Then you can process the frame-only bytes by doing this:
var btAllFrames = GetRawMp3Frames("MyMp3.mp3");
EDIT: Looks like this is a dupe question that was answered better here.
ORIGINAL:
Sounds like you want a full MP3 decoder that outputs the main_data chunks instead of decoding them.
Two options:
Build your own reader (complete with bit reservoir calculations for layer III), or
Remove the audio decode logic from an existing decoder and insert your output logic instead.
There are probably some tricks you can apply that would allow you to short-circuit decoding at least some of the header / side info, but that will take a thorough understanding of the specifications.
If you need a place to start for option #2, try searching for NLayer, JLayer, libmad, or "dist10 source".
Apparently NAudio uses NLayer.
This worked for me
byte[] data = File.ReadAllBytes("path/to/file.mp3");
var memStream = new System.IO.MemoryStream(results);
var mpgFile = new NLayer.MpegFile(memStream);
var samples = new float[mpgFile.Length];
mpgFile.ReadSamples(samples, 0, (int)mpgFile.Length);

C# : concatenate 2 MP3 files

I tried to concatenate 2 MP3 files using the code below. I got a new file which I can play the first half of (complete first file), but the second half is silent. The length of the new file was correct. What do I do wrong?
List<Byte[]> files = new List<byte[]>();
var tempfile = File.ReadAllBytes(Path.Combine(path, "1.mp3"));
files.Add(tempfile);
tempfile = File.ReadAllBytes(Path.Combine(path, "2.mp3"));
files.Add(tempfile);
Byte[] a=new Byte[files[0].Length+files[1].Length];
Array.Copy(files[0], a, files[0].Length);
Array.Copy(files[1], a, files[1].Length);
File.WriteAllBytes(Path.Combine(path, "3.mp3") , a);
I am willing to bet you are only hearing the second song. (and that either both files are the same length or the first is shorter)
You are copying the second song data over the first. And MP3 data is streaming so you can just append the files to each other without worrying about bitrates (while they may glitch) the bitrate should automaticly adjust.
Detail on MP3 Frame headers
... try this...
Array.Copy(files[0], 0, a, 0, files[0].Length);
Array.Copy(files[1], 0, a, files[0].Length, files[1].Length);
... or better still...
using (var fs = File.OpenWrite(Path.Combine(path, "3.mp3")))
{
var buffer = File.ReadAllBytes(Path.Combine(path, "1.mp3"));
fs.Write(buffer, 0, buffer.Length);
buffer = File.ReadAllBytes(Path.Combine(path, "2.mp3"));
fs.Write(buffer, 0, buffer.Length);
fs.Flush();
}
Simple:
public static void Combine(string[] mp3Files, string mp3OuputFile)
{
using (var w = new BinaryWriter(File.Create(mp3OuputFile)))
{
new List<string>(mp3Files).ForEach(f => w.Write(File.ReadAllBytes(f)));
}
}
Here's how you can concatenate MP3 files using NAudio:
public static void Combine(string[] inputFiles, Stream output)
{
foreach (string file in inputFiles)
{
Mp3FileReader reader = new Mp3FileReader(file);
if ((output.Position == 0) && (reader.Id3v2Tag != null))
{
output.Write(reader.Id3v2Tag.RawData,
0,
reader.Id3v2Tag.RawData.Length);
}
Mp3Frame frame;
while ((frame = reader.ReadNextFrame()) != null)
{
output.Write(frame.RawData, 0, frame.RawData.Length);
}
}
}
See here for more information.
This question has been asked before here and here. Also see reading MP3 Headers in C#, but instead of reading the header you just want to strip it off, concatenate the rest, then generate a new header for the concatenated file.
Edit: After further reading apparently it doesn't make any difference if you just concatenate the files without stripping the ID3 tags. But it still seems like a good idea to strip them out first.
Each MP3 file has a header at the beginning of the file containing the metadata of the song. At the very least you will have to remove that on the second file.
Here is a previous Stack Overflow question, How do I merge/join MP3 files with C#?.
Here's another link to Read MP3 Tag Information (ID3v1 and ID3v2), it might help you remove it.
As all knows, the Mp3 files are just some frames and you can concatenate the streams together:
public static void Concatenate(params string[] mp3filenames)
{
Stream w = File.OpenWrite("D:\\out.mp3");
foreach (string filename in mp3filenames)
File.OpenRead(filename).CopyTo(w);
w.Flush();
w.Close();
}
and hears the usage:
Concatenate("D:\\1.mp3", "D:\\2.mp3");

Categories