Question

What is the simplest way to determine the length (in seconds) of a given mp3 file, without using outside libraries? (python source highly appreciated)

Was it helpful?

Solution

You can use pymad. It's an external library, but don't fall for the Not Invented Here trap. Any particular reason you don't want any external libraries?

import mad

mf = mad.MadFile("foo.mp3")
track_length_in_milliseconds = mf.total_time()    

Spotted here.

--

If you really don't want to use an external library, have a look here and check out how he's done it. Warning: it's complicated.

OTHER TIPS

For google followers' sake, here are a few more external libs:

mpg321 -t

ffmpeg -i

midentify (mplayer basically) see Using mplayer to determine length of audio/video file

mencoder (pass it invalid params, it will spit out an error message but also give you info on the file in question, ex $ mencoder inputfile.mp3 -o fake)

mediainfo program http://mediainfo.sourceforge.net/en

exiftool

the linux "file" command

mp3info

sox

refs: https://superuser.com/questions/36871/linux-command-line-utility-to-determine-mp3-bitrate

http://www.ruby-forum.com/topic/139468

mp3 length in milliseconds

(making this a wiki for others to add to).

and libs: .net: naudio, java: jlayer, c: libmad

Cheers!

Simple, parse MP3 binary blob to calculate something, in Python

That sounds like a pretty tall order. I don't know Python, but here's some code I've refactored from another program I once tried to write.

Note: It's in C++ (sorry, it's what I've got). Also, as-is, it'll only handle constant bit rate MPEG 1 Audio Layer 3 files. That should cover most, but I can't make any guarantee as to this working in all situations. Hopefully this does what you want, and hopefully refactoring it into Python is easier than doing it from scratch.

// determines the duration, in seconds, of an MP3;
// assumes MPEG 1 (not 2 or 2.5) Audio Layer 3 (not 1 or 2)
// constant bit rate (not variable)

#include <iostream>
#include <fstream>
#include <cstdlib>

using namespace std;

//Bitrates, assuming MPEG 1 Audio Layer 3
const int bitrates[16] = {
         0,  32000,  40000,  48000,  56000,  64000,  80000,   96000,
    112000, 128000, 160000, 192000, 224000, 256000, 320000,       0
  };


//Intel processors are little-endian;
//search Google or see: http://en.wikipedia.org/wiki/Endian
int reverse(int i)
{
    int toReturn = 0;
    toReturn |= ((i & 0x000000FF) << 24);
    toReturn |= ((i & 0x0000FF00) << 8);
    toReturn |= ((i & 0x00FF0000) >> 8);
    toReturn |= ((i & 0xFF000000) >> 24);
    return toReturn;
}

//In short, data in ID3v2 tags are stored as
//"syncsafe integers". This is so the tag info
//isn't mistaken for audio data, and attempted to
//be "played". For more info, have fun Googling it.
int syncsafe(int i)
{
 int toReturn = 0;
 toReturn |= ((i & 0x7F000000) >> 24);
 toReturn |= ((i & 0x007F0000) >>  9);
 toReturn |= ((i & 0x00007F00) <<  6);
 toReturn |= ((i & 0x0000007F) << 21);
 return toReturn;     
}

//How much room does ID3 version 1 tag info
//take up at the end of this file (if any)?
int id3v1size(ifstream& infile)
{
   streampos savePos = infile.tellg(); 

   //get to 128 bytes from file end
   infile.seekg(0, ios::end);
   streampos length = infile.tellg() - (streampos)128;
   infile.seekg(length);

   int size;
   char buffer[3] = {0};
   infile.read(buffer, 3);
   if( buffer[0] == 'T' && buffer[1] == 'A' && buffer[2] == 'G' )
     size = 128; //found tag data
   else
     size = 0; //nothing there

   infile.seekg(savePos);

   return size;

}

//how much room does ID3 version 2 tag info
//take up at the beginning of this file (if any)
int id3v2size(ifstream& infile)
{
   streampos savePos = infile.tellg(); 
   infile.seekg(0, ios::beg);

   char buffer[6] = {0};
   infile.read(buffer, 6);
   if( buffer[0] != 'I' || buffer[1] != 'D' || buffer[2] != '3' )
   {   
       //no tag data
       infile.seekg(savePos);
       return 0;
   }

   int size = 0;
   infile.read(reinterpret_cast<char*>(&size), sizeof(size));
   size = syncsafe(size);

   infile.seekg(savePos);
   //"size" doesn't include the 10 byte ID3v2 header
   return size + 10;
}

int main(int argCount, char* argValues[])
{
  //you'll have to change this
  ifstream infile("C:/Music/Bush - Comedown.mp3", ios::binary);

  if(!infile.is_open())
  {
   infile.close();
   cout << "Error opening file" << endl;
   system("PAUSE");
   return 0;
  }

  //determine beginning and end of primary frame data (not ID3 tags)
  infile.seekg(0, ios::end);
  streampos dataEnd = infile.tellg();

  infile.seekg(0, ios::beg);
  streampos dataBegin = 0;

  dataEnd -= id3v1size(infile);
  dataBegin += id3v2size(infile);

  infile.seekg(dataBegin,ios::beg);

  //determine bitrate based on header for first frame of audio data
  int headerBytes = 0;
  infile.read(reinterpret_cast<char*>(&headerBytes),sizeof(headerBytes));

  headerBytes = reverse(headerBytes);
  int bitrate = bitrates[(int)((headerBytes >> 12) & 0xF)];

  //calculate duration, in seconds
  int duration = (dataEnd - dataBegin)/(bitrate/8);

  infile.close();

  //print duration in minutes : seconds
  cout << duration/60 << ":" << duration%60 << endl;

  system("PAUSE");
  return 0;
}

simply use mutagen

$pip install mutagen

use it in python shell:

from mutagen.mp3 import MP3
audio = MP3(file_path)
print audio.info.length

Also take a look at audioread (some linux distros including ubuntu have packages), https://github.com/sampsyo/audioread

audio = audioread.audio_open('/path/to/mp3')
print audio.channels, audio.samplerate, audio.duration

You might count the number of frames in the file. Each frame has a start code, although I can't recollect the exact value of the start code and I don't have MPEG specs laying around. Each frame has a certain length, around 40ms for MPEG1 layer II.

This method works for CBR-files (Constant Bit Rate), how VBR-files work is a completely different story.

From the document below:

For Layer I files us this formula:

FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4

For Layer II & III files use this formula:

FrameLengthInBytes = 144 * BitRate / SampleRate + Padding

Information about MPEG Audio Frame Header

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top