Concatenate MP3 Files

50 views
Skip to first unread message

markar...@gmail.com

unread,
Jan 26, 2006, 10:16:43 PM1/26/06
to
How would I concatenate two MP3 files, such that I can stream them out
as a single file?

Chris P. [MVP]

unread,
Jan 27, 2006, 11:55:08 AM1/27/06
to
On 26 Jan 2006 19:16:43 -0800, markar...@gmail.com wrote:

> How would I concatenate two MP3 files, such that I can stream them out
> as a single file?

On the most part you can just directly concatenate them. If there is any
tag blocks at the end they need to be removed first.

Mark A. Richman

unread,
Jan 28, 2006, 6:55:15 AM1/28/06
to
That seems deceptively simple. What if the two files have differing
bitrates? Maybe you can direct me to a code sample.

Thanks,
Mark

Alessandro Angeli [MVP::DigitalMedia]

unread,
Jan 28, 2006, 7:12:28 AM1/28/06
to
Mark A. Richman wrote:

An MP3 is an elementary stream, that is an unstructured
sequence of independent audio frames. As long as the last
frame of the first clip is a valid frame, you can just
append the second clip to it. Examples of invalid last
frames are a truncated frame or the ID3v1 tag.

Frames are independent from each other and they can have
different audio settings. However, while most MP3 decoders
will not mind a change in bitrate (since that's just what a
VBR stream is), they will most likely fail if the sampling
rate or channel count changes.

So, if you know that sampling rate and channel count are the
same and the files are not corrupted, just look for the
ID3v1 tag and remove it (that is, the last 128 bytes of the
file if they start with 'TAG') then append the files to each
other without worry.

If you want to be safe, you can use my sample MP3 parser to
make sure the files are neither corrupted nor incompatible:

http://groups.google.com/group/microsoft.public.win32.programmer.mmedia/msg/a2952ae237dc099d

http://groups.google.com/group/microsoft.public.win32.programmer.directx.audio/msg/d51709c699fa3b72


--
// Alessandro Angeli
// MVP :: Digital Media
// a dot angeli at psynet dot net


Mark A. Richman

unread,
Jan 28, 2006, 8:10:18 AM1/28/06
to
Thanks for the info...too bad I'm doing this in C# or I'd be able to
use that code. It doesn't look too easy to port over.

Alessandro Angeli [MVP::DigitalMedia]

unread,
Jan 28, 2006, 9:21:07 AM1/28/06
to
Mark A. Richman wrote:

Actually, it's very easy to port to C# and you can almost
use that code as it is by replacing the file I/O function
calls with a CLR I/O stream method calls.

Mark A. Richman

unread,
Jan 28, 2006, 1:52:29 PM1/28/06
to
I'm actuallly having more trouble with the array definitions. For
example, I have tried declaring the bitrates array two ways:

int[,,] bitrates = new int[4,4,16] and
int[][][] bitrates = new int[4][4][16]

neither of which are working too well. I can paste the whole block of
code if you like.

Aside from the TAG block at the end of the MP3 file, I also see lots of
header data. Do I need to alter/cut that out too when concatenating two
streams?

Thanks,
Mark

Alessandro Angeli [MVP::DigitalMedia]

unread,
Jan 28, 2006, 3:53:17 PM1/28/06
to
Mark A. Richman wrote:

> I'm actuallly having more trouble with the array
> definitions. For example, I have tried declaring the
> bitrates array two ways:
>
> int[,,] bitrates = new int[4,4,16] and
> int[][][] bitrates = new int[4][4][16]
>
> neither of which are working too well. I can paste the
> whole block of code if you like.
This is a jagged array:
 
 /// [4 /* version */][4 /* layer */][16 /* bitrate */]
 private static readonly int[][][] bitrates = {
  new int[][] { /* V2.5 */
   /* L0 */ new int[] { 0, },
   /* L3 */ new int[] { 0, },
   /* L2 */ new int[] { 0, },
   /* L1 */ new int[] { 0, },
  },
  new int[][] { /* V0.0 */
   /* L0 */ new int[] { 0, },
   /* L3 */ new int[] { 0, },
   /* L2 */ new int[] { 0, },
   /* L1 */ new int[] { 0, },
  },
  new int[][] { /* V2.0 */
   /* L0 */ new int[] { 0, },
   /* L3 */ new int[] { 0, },
   /* L2 */ new int[] { 0, },
   /* L1 */ new int[] { 0, },
  },
  new int[][] { /* V1.0 */
   /* L0 */ new int[] { 0, },
   /* L3 */ new int[] { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1,  },
   /* L2 */ new int[] { 0, },
   /* L1 */ new int[] { 0, },
  },
 };
However, this is necessary only because the table is incomplete and I used an abbreviated syntax. If you fill in the whole table (look at the articles I gave you the links to in the second reference), the array won't be jagged anymore and you can more easily initialize it:
 
 /// [4 /* version */][4 /* layer */][16 /* bitrate */]
 private static readonly int[,,] bitrates = {
  { /* V2.5 */
   /* L0 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
   /* L3 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
   /* L2 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
   /* L1 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
  },
  { /* V0.0 */
   /* L0 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
   /* L3 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
   /* L2 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
   /* L1 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
  },
  { /* V2.0 */
   /* L0 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
   /* L3 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
   /* L2 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
   /* L1 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
  },
  { /* V1.0 */
   /* L0 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
   /* L3 */ { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1, },
   /* L2 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
   /* L1 */ { 0,  1,  2,  3,  4,  5,  6,  7,   8,   9,  10,  11,  12,  13,  14, -1, },
  },
 };
 
> Aside from the TAG block at the end of the MP3 file, I
> also see lots of header data. Do I need to alter/cut that
> out too when concatenating two streams?
What do you mean?
Reply all
Reply to author
Forward
0 new messages