I am trying to merge two mp3 files together from a specific point time in the first mp3 file to a specific point in time for the 2nd mp3 (in C#)
When I say specific point in time, I want to copy everything from the first mp3 file 10 sec after it has played and then the entire mp3. Then I want to merge this together with the 2nd mp3 first 20 seconds. How do I do this?
Just to merge the two files together I am doing as follows:
using (var fs = File.OpenWrite("combined.mp3"))
{
var buffer = File.ReadAllBytes("test1.mp3");
fs.Write(buffer, 0, buffer.Length);
buffer = File.ReadAllBytes("test.mp3");
fs.Write(buffer, 0, buffer.Length); fs.Flush();
}
The above code was found somewhere here on Stackoverflow. I know that I am not removing the header from the 2nd file, but this kinda works anyways. (If you can tell me how to remove the header this will be appreciated).
Is there a way to find out how many bytes each second is (or how many frames) in the mp3 files?
Due to the format of my mp3 files I cannot use NAudio.NET. NAudio gives me an error when I try to play these on these mp3 files (Not a recognised MP3 header).
1) It is desirable to learn at least basics of MP3 file structrure and legal MP3 file tags (ID3v1/v2 and possibly Xing VBR Header).
Look for example at the following links:
http://www.mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm
http://www.codeproject.com/KB/audio-video/mpegaudioinfo.aspx
http://www.developerfusion.com/code/4684/read-mp3-tag-information-id3v1-and-id3v2/
http://www.id3.org/
2) To count exact duration of continuous part in a MP3 file you will need to count number of MP3 frames in this part. Duration of a MP3 frame is always 1152 samples for MPEG1 Layer 3, and 576 samples for other versions of MPEG.
3) To position to a specific point in a MP3 file you can use one of the following:
If the file has a small size you can simply count frames from begginning of MP3 data.
If you deal with a CBR file you can simply calculate offset of the desired position.
If you deal with a VBR file and the file has a VBR header, you can get from the header a starting position and count frames to the desired position.
"If you can tell me how to remove the header this will be appreciated" - you need to cut off ID3 tags and probably VBR header.
"Is there a way to find out how many bytes each second is (or how many frames) in the mp3 files?" - for CBR this can be easily calculated from bitrate.
Note, you should perform all operations on the frame boundaries.
Related
Doing my first steps in Audio prog and using NAudio, I'm trying to have a simple app that grabs a WAV file and getting 20ms of audio data each time till EOF. However I'm getting a bit confused with the buffer arrays and probably conversions.
Is there a simple way someone can post in here?
Moreover I got confused with the following:
When using AudioFileReader readertest = new AudioFileReader(fileName) I'm getting different metadata like bitrate of 32 and length of ~700000.
However, when using the NAudio - WaveFileReader file1 = new WaveFileReader(fileName) I'm getting half values for the same audio file (bitrate = 16, length = ~350000). Also the encoding for the first is "IEEEFloat" while the latter is "PCM". Any explanations...?
Thanks v much!
AudioFileReader is a wrapper around WaveFileReader (and supports several other file types), and auto-converts to IEEE float for you. If you want to read the audio directly into a byte array in whatever format it is in the WAV file, then you should just use WaveFileReader.
Hi I use NAudio and this piece of code to concatenate multiple mp3 files together.
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);
}
The problem is that when I read the output file in Google Chrome (no problem with IE or Firefox),
Chrome seems to determine the total duration of the file with the first mp3 file that has been concatenated. Like if I have 3 files
1.mp3 (6 seconds long)
2.mp3 (8 seconds long)
3.mp3 (4 seconds long)
output.mp3 (18 seconds long)
Chrome will pretend that the duration of the new file is only 6 seconds whilst it should be 18 seconds.
There might be a frame that indicates the end of file ? Is it possible? If yes which frame should I avoid writing to the output file ?
Is there a common frame header to specify the real file duration ?
Apparently the files have different bitrate so in effect you're creating a variable bitrate file and it looks like Google Chrome doesn't handle them correctly. This is common a common issue with MP3 players that do not handle variable bitrates correctly.
Also this is only safe if you're concatenating whole files. If for example you want to concatenate the 2nd half of a file to another then you need to parse the frame sideinfo and look for the field main_data_begin, if it is zero then it's ok to append. If it is non-zero then the frame's audio data starts one or more frames behind so you need to look for the next frame with main_data_begin == 0.
Edit:
After thinking about it, you don't want to do that at all because:
MP3 files attenuate the 1st frame so encoders pad the input with zeroes at the beginning (that's why an MP3 file is slightly larger than the original file after decoding), so there will be a short silence at the concatenation point.
Every MP3 frame's first half is overlapped with the 2nd half of the last frame during decoding, so concating will also introduce glitches.
I am an audio noob
I am looking to embed audio in an html page by passing the data as a string such as
< Audio src="data:audio/wav;base64,AA....." />
doing that works, but I need to raise the volume. I tried working with NAudio but it seems like it does some conversion and it will no longer play. This is the code I use to raise the volume:
public string ConvertToString(Stream audioStream)
{
audioStream.Seek(0,SeekOrigin.Begin);
byte[] bytes = new byte[audioStream.Length];
audioStream.Read(bytes,0,(int)audioStream.Length);
audioStream.Seek(0,SeekOrigin.Begin);
return Convert.ToBase64String(bytes);
}
var fReader = new WaveFileReader(strm);
var chan32 = new WaveChannel32(fReader,50.0F,0F);
var ouputString = "data:audio/wav;base64," + ConvertToString(chan32);
but when I put outputString into an audio tag it fails to play. What type of transformation does NAudio do, and how can I get it ton give me the audio stream in such a way that I can serialize it and the browser will be able to play it?
Or for another suggestion: if NAudio to heavyweight for something as simple as raising the volume what's a better option for me?
I'm no expert in embedding WAV files in web pages (and to be honest it doesn't seem like a good idea - WAV is one of the most inefficient ways of delivering sound to a web page), but I'd expect that the entier WAV file, including headers needs to be encoded. You are just writing out the sample data. So with NAudio you'd need to use a WaveFileWriter writing into a MemoryStream or a temporary file to create a volume adjusted WAV file that can be written to your page.
There are two additional problems with your code. One is that you have gone to 32 bit floating point, making the WAV file format even more inefficent (doubling the size of the original file). You need to use the Wave32To16Stream to go back to 16 bit before creating the WAV file. The second is that you are multiplying each sample by 50. This will almost certainly horribly distort the signal. Clipping can very easily occur when amplifying a WAV file, and it depends on how much headroom there is in the original recording. Often dynamic range compression is a better option than simply increasing the volume.
EDIT 1:
I build a torrent application; Downloading from diffrent clients simultaneously. Each download represent a portion for my file and diffrent clients have diffrent portions.
After a download is complete, I need to know which portion I need to achieve now by Finding "empty" portions in my file.
One way to creat a file with fixed size:
File.WriteAllBytes(#"C:\upload\BigFile.rar", new byte[Big Size]);
My portion Arr that represent my file as portions:
BitArray TorrentPartsState = new BitArray(10);
For example:
File size is 100.
TorrentPartsState[0] = true; // thats mean that in my file, from position 0 until 9 I **dont** need to fill in some information.
TorrentPartsState[1] = true; // thats mean that in my file, from position 10 until 19 I **need** to fill in some information.
I seatch an effective way to save what the BitArray is containing even if the computer/application is shut down. One way I tought of, is by xml file and to update it each time a portion is complete.
I don't think its smart and effective solution. Any idea for other one?
It sounds like you know the following when you start a transfer:
The size of the final file.
The (maximum) number of streams you intend to use for the file.
Create the output file and allocate the required space.
Create a second "control" file with a related filename, e.g. add you own extension. In that file maintain an array of stream status structures corresponding to the network streams. Each status consists of the starting offset and number of bytes transferred. Periodically flush the stream buffers and then update the control file to reflect the progress made and committed.
Variations on the theme:
The control file can define segments to be transferred, e.g. 16MB chunks, and treated as a work queue by threads that look for an incomplete segment and a suitable server from which to retrieve it.
The control file could be a separate fork within the result file. (Who am I kidding?)
You could use a BitArray (in System.Collections).
Then, when you visit on offset in the file, you can set the BitArray at that offset to true.
So for your 10,000 byte file:
BitArray ba = new BitArray(10000);
// Visited offset, mark in the BitArray
ba[4] = true;
Implement a file system (like on a disk) in your file - just use something simple, should be something available in the FOS arena
I have a byte array containing an MP3 stream.
Is it correct to assume that this stream would have to be further decoded if I want to be able convert to a WAV?
In its current byte state, is it possible to do basic functionality such as get/set position (time-wise)?
Yeah, MP3 files are very different from WAV files. WAV files contain raw audio data in the form of samples from beginning to end to paint the waveform of the output, the same way a bitmap file contains raw data about pixels from left to right, top to bottom. You can think of a WAV file as a bitmap picture of sound waves -- but rather than pixel colors, it stores audio intensities, typically 44,100 of them per second, for two channels if it's stereo, and 2 bytes per channel.
(Knowing this you can actually calculate the file size of a WAV file -- to store 1 minute of audio, you'd need 60 seconds * 44100 samples * 2 channels * 2 bytes = 10.09MB.)
MP3 files contain a mathematically modified version of this image and discards audio that humans can't hear. It works similarly to how jpeg images work to compress images.
Just as video cards ultimately need bitmaps to work with, sound cards ultimately need WAV data to work with -- so yes, you need a decoder.
At the beginning of Mp3 files is a block of data called an ID3 tag, which contains a bunch of basic information about the file -- artist names, track length, album names, stuff like that. You can use something like C# ID3 to read/write ID3 tags in C#.
As for audio itself, I'm not sure there are Mp3 decoders written entirely in C#. Technically there's no reason that it can't be done (it should be fine performance wise too), but the standard is pretty loose and the math is intense so people tend to just use things like FFMpeg to decode. Some ideas in this Google search.
If you don't need to do any special processing and you just want to play the audio, you can use the WPF/Silverlight Media element.
You can probably get some hints out of Josh Smith's Podder app.
NAudio is an open source .NET library that can read MP3 files.
To convert MP3 to WAV, use code similar to the following:
Stream inputStream = ...;
Stream outputStream = ...;
using (WaveStream waveStream = WaveFormatConversionStream.CreatePcmStream(new Mp3FileReader(inputStream)))
using (WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, waveStream.WaveFormat))
{
byte[] bytes = new byte[waveStream.Length];
waveStream.Read(bytes, 0, waveStream.Length);
waveFileWriter.WriteData(bytes, 0, bytes.Length);
waveFileWriter.Flush();
}
As per #Rei Miyasaka's answer, there is an MP3 decoder written in C#. Open source, too. Check out Mp3Sharp.
You can use http://sourceforge.net/projects/mpg123net/ to decode your mp3 in byte[] and further use decoded PCM for your liking.