using System;
namespace MP3Format
{
using System.IO;
class MP3Properties
{
private MP3.Version l_version;
private MP3.Layer l_layer;
private bool l_protected;
private int l_bitrate;
private int l_samplefreq;
private bool l_padding;
private bool l_private;
private MP3.ChannelMode l_channelmode;
private int l_modeextension;
private bool l_copyright;
private bool l_original;
private MP3.Emphasis l_emphasis;
private bool l_valid;
private string l_path;
public MP3Properties(uint header, string path)
{
l_path=path;
parseheader(header);
}
public MP3Properties(string path)
{
uint header=0;
FileStream stream = null;
stream = MP3.GetMP3Stream(path);
if (stream!=null)
{
header = MP3.GetMP3Header(stream);
stream.Close();
stream=null;
}
if (header!=0)
{
l_path=path;
parseheader(header);
}
}
private void parseheader(uint header)
{
uint l_hdr = header;
l_valid=false;
if (!((l_hdr&MP3.Sync)==MP3.Sync))
{
l_hdr=SwapBytes(l_hdr);
}
l_emphasis = (MP3.Emphasis)(l_hdr&0x3);
l_hdr>>=2;
l_original=(l_hdr&0x1)>0;
l_hdr>>=1;
l_copyright=(l_hdr&0x1)>0;
l_hdr>>=1;
l_modeextension=(int)l_hdr&0x3;
l_hdr>>=2;
l_channelmode = (MP3.ChannelMode)(l_hdr&0x3);
l_hdr>>=2;
l_private=(l_hdr&0x1)>0;
l_hdr>>=1;
l_padding=(l_hdr&0x1)>0;
l_hdr>>=1;
l_samplefreq=(int)l_hdr&0x3;
l_hdr>>=2;
l_bitrate=(int)l_hdr&0xF;
l_hdr>>=4;
l_protected=(l_hdr&0x1)>0;
l_hdr>>=1;
l_layer = (MP3.Layer)(l_hdr&0x3);
l_hdr>>=2;
l_version = (MP3.Version)(l_hdr&0x3);
l_hdr>>=2;
l_valid= (
(l_layer!=MP3.Layer.reserved) && // reerved field
(l_version!=MP3.Version.reserved) && // reserved field
(l_emphasis!=MP3.Emphasis.reserved) && // reserved field
(MP3.Bitrate(l_version,l_layer,l_bitrate)!=-1) && // bad bitrate
(MP3.SampleFrequency(l_version,l_samplefreq)!=-1) // reserved sample rate
);
}
private uint SwapBytes(uint toswap)
{
uint retval = toswap;
retval = (uint) ( ((toswap&0x000000ff)<<24) + ((toswap&0x0000ff00)<<8) + ((toswap&0x00ff0000)>>8) + ((toswap&0xff000000)>>24));
return retval;
}
public MP3.Version Version
{
get
{
if (l_valid)
return l_version;
else
return MP3.Version.reserved;
}
}
public MP3.Layer Layer
{
get
{
if (l_valid)
return l_layer;
else
return MP3.Layer.reserved;
}
}
public bool Protected
{
get
{
if (l_valid)
return l_protected;
else
return false;
}
}
public int Bitrate
{
get
{
if (l_valid)
return MP3.Bitrate(l_version,l_layer,l_bitrate);
else
return 0;
}
}
public int SampleFrequency
{
get
{
if (l_valid)
return MP3.SampleFrequency(l_version,l_samplefreq);
else
return 0;
}
}
public bool Padding
{
get
{
if (l_valid)
return l_padding;
else
return false;
}
}
public bool Private
{
get
{
if (l_valid)
return l_private;
else
return false;
}
}
public string ChannelMode
{
get
{
if (l_valid)
return MP3.ChannelModeStrings[(int)l_channelmode];
else
return "";
}
}
public string ModeExtension
{
get
{
if (l_valid)
return MP3.ModeExtension(l_layer,l_channelmode,l_modeextension);
else
return "";
}
}
public bool Copyright
{
get
{
if (l_valid)
return l_copyright;
else
return false;
}
}
public bool Original
{
get
{
if (l_valid)
return l_original;
else
return false;
}
}
public MP3.Emphasis Emphasis
{
get
{
if (l_valid)
return l_emphasis;
else
return MP3.Emphasis.reserved;
}
}
public bool Valid
{
get
{
return l_valid;
}
}
public string Filename
{
get
{
return l_path;
}
}
}
class MP3
{
static MP3()
{
}
public const uint Sync = 0xFFe0;
public const byte SyncHigh = 0xFF;
public const byte SyncLow = 0xE0;
public enum Version : int
{
V25= 0x0,
reserved = 0x1,
V2 = 0x2,
V1 = 0x3
}
public enum Layer : int
{
reserved = 0x0,
Layer_III = 0x1,
Layer_II = 0x2,
Layer_I = 0x3,
}
public enum ChannelMode : int
{
Stereo = 0x0,
Joint = 0x1,
Dual = 0x2,
Single = 0x3
}
public enum Emphasis
{
none = 0x0,
ms50_15 = 0x1,
reserved = 0x2,
CCIT = 0x3
}
public static string[] ChannelModeStrings =
{
"Stereo",
"Joint stereo (Stereo)",
"Dual channel (Stereo)",
"Single channel (Mono)"
};
public static string[] EmphasisStrings =
{
"none",
"50/15 ms",
"reserved",
"CCIT J.17"
};
private static int[] SampleFrequency_Version1 = { 44100, 48000, 32000, -1 };
private static int[] SampleFrequency_Version2 = { 22050, 24000, 16000, -1 };
private static int[] SampleFrequency_Version25 = { 11025, 12000, 8000, -1 };
private static int[] Bitrate_Version1Level1 = { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 488, -1 };
private static int[] Bitrate_Version1Level2 = { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 };
private static int[] Bitrate_Version1Level3 = { 0, 32, 40 ,48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 };
private static int[] Bitrate_Version2Level1 = { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 };
private static int[] Bitrate_Version2Level2 = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 };
public static int Bitrate(Version version, Layer layer, int value)
{
int retval = -1;
switch (version)
{
case Version.V1:
switch (layer)
{
case Layer.Layer_I:
retval = Bitrate_Version1Level1[value];
break;
case Layer.Layer_II:
retval = Bitrate_Version1Level2[value];
break;
case Layer.Layer_III:
retval = Bitrate_Version1Level3[value];
break;
}
break;
case Version.V2:
switch (layer)
{
case Layer.Layer_I:
retval = Bitrate_Version2Level1[value];
break;
case Layer.Layer_II:
case Layer.Layer_III:
retval = Bitrate_Version2Level2[value];
break;
}
break;
}
return retval;
}
public static string ModeExtension(Layer layer, ChannelMode mode, int value)
{
string retval = "";
if (mode == ChannelMode.Joint)
{
switch (layer)
{
case Layer.Layer_I:
case Layer.Layer_II:
switch (value)
{
case 0:
retval = "bands 4 to 31";
break;
case 1:
retval = "bands 8 to 31 ";
break;
case 2:
retval = "bands 12 to 31 ";
break;
case 3:
retval = "bands 16 to 31";
break;
}
break;
case Layer.Layer_III:
retval+="MS Stereo: ";
if ( (value & 0x2) > 0x0 )
{
retval +="on";
}
else
{
retval +="off";
}
retval +=", Intensity stereo: ";
if ( (value & 0x1) > 0x0 )
{
retval +="on";
}
else
{
retval +="off";
}
break;
}
}
return retval;
}
public static int SampleFrequency(Version version, int value)
{
int retval = 0;
switch(version)
{
case Version.V1:
retval = SampleFrequency_Version1[value];
break;
case Version.V2:
retval = SampleFrequency_Version2[value];
break;
case Version.V25:
retval = SampleFrequency_Version25[value];
break;
}
return retval;
}
public static MP3Properties GetFileProperties(string path)
{
MP3Properties retval=null;
FileStream stream=null;
uint header=0;
stream = MP3.GetMP3Stream(path);
if (stream!=null)
{
header = MP3.GetMP3Header(stream);
stream.Close();
stream=null;
}
if (header!=0) retval = new MP3Properties(header,path);
return retval;
}
public static FileStream GetMP3Stream(string path)
{
FileStream fs=null;
if (File.Exists(path))
{
try
{
fs=new FileStream(path,FileMode.Open,FileAccess.Read,FileShare.Read);
}
catch (FileNotFoundException)
{
// file doesnt exist
}
catch (DirectoryNotFoundException)
{
// the path is invalid
}
catch (IOException)
{
// cant open the file
}
}
return fs;
}
public static uint GetMP3Header(FileStream fs)
{
uint retval=0;
uint first=0;
uint second=0;
bool prevsync=false;
bool found=false;
byte cur=0;
BinaryReader bin = new BinaryReader(fs);
while (bin.BaseStream.Position<bin.BaseStream.Length)
{
cur = bin.ReadByte();
if (prevsync)
{
if ( (cur&MP3.SyncLow)==MP3.SyncLow)
{
bin.BaseStream.Seek(-2,SeekOrigin.Current );
if (first==0)
{
first = bin.ReadUInt32();
}
else
{
second = bin.ReadUInt32();
if (first!=second)
{
first=second;
second=0;
}
else
{
found=true;
break;
}
}
prevsync=false;
}
}
else
{
prevsync = (cur==MP3.SyncHigh);
}
}
bin.Close();
bin=null;
if (found) retval = second;
return retval;
}
}
}