Concatenating Mp3 files into one : Chrome issue - c#

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.

Related

Replace the text in a file, but faster

So I made a math problem program that basically reads one number from a text file (only number in that text file) and replaces it with a number+1 if number is not a solution.
Now the issue is, if I only add a text in the next row using
sw.WriteLine(text);
that makes the calculations really fast, doing 100k+ numbers in a few seconds, but it's just adding the number to the text file without deleting previous.
Alternatively I used
string[] lines = File.ReadAllLines("numbers.txt");
foreach (string line in lines)
{
lines[0] = Convert.ToString(biginta);
}
File.WriteAllLines("numbers.txt", lines);
but that made my program run considerably slower.
Is there a way I can replace text in a .txt file by using already open filestream?
I'm new to c# so my whole program is basically a Frankenstein of a code.
I'm using a file to store the next number needed to run because I turn off my pc overnight.
Honestly the quickest solutiion to this is the following: Read the file once, do several (like 100) calculations without saving and then store the current number back into the file.
Tune the interval so that you store the current state once every 5 seconds or so.
That gives you still a good starting point (at most 5 seconds lost work) but also reduces disk IO to the point where it won't slow down the calculation any more.

How often do WaveInEvent handlers fire?

I'm currently working on a program that analyses your voice.
I have a thread that runs WaveInEvent that records audio from mic.
When data is available (WaveInEventArgs event fires), it encodes it and serialises it and sends it to the analyser.
I'd like to be able to use an audio file, say a .mp3.
I'm reading it like this :
byte[] audioFileBytes = File.ReadAllBytes(audioFilePath);
And then sending it to the analyser the same way.
I'm encountering a couple of problems : the audio file is not processed on the other end - while it works if I use the "dynamic" audio input. I'm guessing it has to do with buffer length, but I can't find how long the WaveInEvent buffer is nor how often the WaveInEventArgs event fires.
Second, the data is treated in ~2 seconds, and I used to add timestamps to the data I received on the analyser side when I get it in realtime, so right now it adds one timestamp for the whole file. If I send it byte per byte, I'll get 1.2 million timestamps in about 2 seconds, which is still not printable on a graph - plus the graph should start at 0 and end at the length of the audio file (70 seconds here for the test one I have), not at 2 seconds.
So as a first step I thought about reading the audio file "in real time", and sending the audio from the file as if it came from the microphone, but I have no idea how to do that.
My question comes down to : how often do the WaveInEvent handlers fire ?
It's to do with the length of buffers. Every time a buffer is filled with audio the event will fire. Look at the BufferMilliseconds and NumberOfBuffers properties. You can set these to desired values before you start recording.

Finding "empty" portions in a file

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

Merging Mp3 files together from specific points in time in C#

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.

C# code to perform Binary search in a very big text file

Is there a library that I can use to perform binary search in a very big text file (can be 10GB).
The file is a sort of a log file - every row starts with a date and time. Therefore rows are ordered.
I started to write the pseudo-code on how to do it, but I gave up since it may seem condescending. You probably know how to write a binary search, it's really not complicated.
You won't find it in a library, for two reasons:
It's not really "binary search" - the line sizes are different, so you need to adapt the algorithm (e.g. look for the middle of the file, then look for the next "newline" and consider that to be the "middle").
Your datetime log format is most likely non-standard (ok, it may look "standard", but think a bit.... you probably use '[]' or something to separate the date from the log message, something like [10/02/2001 10:35:02] My message ).
On summary - I think your need is too specific and too simple to implement in custom code for someone to bother writing a library :)
As the line lengths are not guaranteed to be the same length, you're going to need some form of recognisable line delimiter e.g. carriage return or line feed.
The binary search pattern can then be pretty much your traditional algorithm. Seek to the 'middle' of the file (by length), seek backwards (byte by byte) to the start of the line you happen to land in, as identified by the line delimiter sequence, read that record and make your comparison. Depending on the comparison, seek halfway up or down (in bytes) and repeat.
When you identify the start index of a record, check whether it was the same as the last seek. You may find that, as you dial in on your target record, moving halfway won't get you to a different record. e.g. you have adjacent records of 100 bytes and 50 bytes respectively, so jumping in at 75 bytes always takes you back to the start of the first record. If that happens, read on to the next record before making your comparison.
You should find that you will reach your target pretty quickly.
You would need to be able to stream the file, but you would also need random access. I'm not sure how you accomplish this short of a guarantee that each line of the file contains the same number of bytes. If you had that, you could get a Stream of the object and use the Seek method to move around in the file, and from there you could conduct your binary search by reading in the number of bytes that constitute a line. But again, this is only valid if the lines are the same number of bytes. Otherwise, you would jump in and out of the middle of lines.
Something like
byte[] buffer = new byte[lineLength];
stream.Seek(lineLength * searchPosition, SeekOrigin.Begin);
stream.Read(buffer, 0, lineLength);
string line = Encoding.Default.GetString(buffer);
This shouldn't be too bad under the constraint that you hold an Int64 in memory for every line-feed in the file. That really depends upon how long the line of text is on average, given 1000 bytes per line you be looking at around (10,000,000,000 / 1000 * 4) = 40mb. Very big, but possible.
So try this:
Scan the file and store the ordinal offset of each line-feed in a List
Binary search the List with a custom comparer that scans to the file offset and reads the data.
If your file is static (or changes rarely) and you have to run "enough" queries against it, I believe the best approach will be creating "index" file:
Scan the initial file and take the datetime parts of the file plus their positions in the original (this is why has to be pretty static) encode them some how (for example: unix time (full 10 digits) + nanoseconds (zero-filled 4 digits) and line position (zero filed 10 digits). this way you will have file with consistent "lines"
preform binary search on that file (you may need to be a bit creative in order to achieve range search) and get the relevant location(s) in the original file
read directly from the original file starting from the given location / read the given range
You've got range search with O(log(n)) run-time :) (and you've created primitive DB functionality)
Needless to say that if the file data file is updated "too" frequently or you don't run "enough" queries against the index file you mat end up with spending more time on creating the index file than you are saving from the query file.
Btw, working with this index file doesn't require the data file to be sorted. As log files tend to be append only, and sorted, you may speed up the whole thing by simply creating index file that only holds the locations of the EOL marks (zero-filled 10 digits) in the data file - this way you can preform the binary search directly on the data-file (using the index file in order to determinate the seek positions in the original file) and if lines are appended to the log file you can simply add (append) their EOL positions to the index file.
The List object has a Binary Search method.
http://msdn.microsoft.com/en-us/library/w4e7fxsh%28VS.80%29.aspx

Categories