Click here to Skip to main content
11,641,708 members (54,336 online)
Click here to Skip to main content
Add your own
alternative version

Audio Book Player

, 11 Jun 2009 CPOL 122.3K 2.3K 82
Audio player designed specifically for listening to audio books
abPlayer.zip
Skins
Color
battery.jpg
cancel.jpg
clock.jpg
dark.jpg
exit.jpg
library.jpg
light.jpg
media.jpg
menu.jpg
next.jpg
ok.jpg
play.jpg
prev.jpg
props.jpg
remove.jpg
sleep.jpg
stop.jpg
switch.jpg
vol.jpg
Grayscale
battery.jpg
cancel.jpg
clock.bmp
dark.jpg
exit.jpg
library.jpg
light.jpg
media.jpg
menu.jpg
next.jpg
ok.jpg
play.jpg
prev.jpg
Props.jpg
remove.bmp
sleep.jpg
stop.jpg
switch.jpg
vol.jpg
abPlayer.suo
abPlayer
abPlayer.csproj.user
abPlayer.csproj.vspscc
bin
Release
abPlayer.pdb
abPlayer_exe
OcxControls.dll
OpenNETCF.Windows.Forms.AxHost.dll
Resources
System.Data.SqlServerCe.dll
WMPLib.dll
Properties
DLLs
ComLib.dll
ComLib.PocketPC.asmmeta.dll
OcxControls.dll
OcxControls.PocketPC.asmmeta.dll
OpenNETCF.Windows.Forms.AxHost.dll
OpenNETCF.Windows.Forms.AxHost.PocketPC.asmmeta.dll
WMPLib.dll
Graphics
book.bmp
bookshelf.jpg
check.png
dirclosed.bmp
diropen.bmp
uncheck.png
up.jpg
Submission_Form.zip
abPlayer_files
image001.jpg
image002.jpg
image003.jpg
image004.jpg
themedata.thmx
/* ----------------------------------------------------------

original C++ code by:
                    Gustav "Grim Reaper" Munkby
                    http://floach.pimpin.net/grd/
                    grimreaperdesigns@gmx.net

modified and converted to C# by:
                    Robert A. Wlodarczyk
                    http://rob.wincereview.com:8080
                    rwlodarc@hotmail.com
---------------------------------------------------------- */
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Collections;

class cMP3Info
{
    public struct sMp3HeaderBitsString
    {
        public String MPEGTypeBitsString;
        public String LayerBitsString;
        public String BitrateBitsString;
        public String FreqBitsString;
        public String ChannelModeBitsString;
    }
    public struct sXingHeader
    {
        public int NumberOfFrames;
        public int FileLenght;
        public int[] TOC;
        public int VBRScale;
    }
    public struct sID3v1TAG
    {
        public String SongTitle;
        public String Artist;
        public String Album;
        public String Year;
        public String Comment;
        public String GenreID;
    }
    public enum eChannelMode { Stereo, Joint_Stereo, Mono_2_Channels, Mono, Channel_Undefined };
    public enum eMPEGType { MPEG1, MPEG2, MPEG2_5, MPEG_UNDEFINED };
    public enum eLayerType { LayerI, LayerII, LayerIII, Leyer_Undefined };
    public enum eProtectionType { CRC_Protection, Not_Protected };
    public enum eCopyRight { CopyRighted, Not_CopyRighted };

    private FileInfo Mp3FInfo;
    private sMp3HeaderBitsString Mp3HeaderBitsStr;
    private BitArray MP3HeaderBits;
    private byte[] XingHeaderBytes = new byte[116];
    private int Mp3HeaderPosition, Mp3ClearSize;

    public cMP3Info(String MP3FilePath)
    {
        if (File.Exists(MP3FilePath))
        {
            Mp3FInfo = new FileInfo(MP3FilePath);
            if(!GetMP3HeaderBytes(Mp3FInfo.FullName))
                throw new Exception("Given file '" + MP3FilePath + "' isn't a valid Mp3 file.");
        }
        else
        {
            throw new Exception("Given file '" + MP3FilePath + "' doesn't exist.");
        }
    }

    private FileStream GetMp3FileStream(String MP3FilePath)
    {
        FileStream MP3FileStream;
        try
        {
            MP3FileStream = new FileStream(MP3FilePath, FileMode.Open);
        }
        catch (Exception Exc)
        {
            MP3FileStream = null;
            throw new Exception("An error occurred while trying to open file '" + MP3FilePath + "'.  " + Exc.Message);
        }
        if (MP3FileStream.CanRead)
            MP3FileStream.Position = 0;
        else
        {
            MP3FileStream = null;
            throw new Exception("Can't read file '" + MP3FilePath + "'.");
        }
        return MP3FileStream;
    }

    private String GetBitsString(int StartIndex, int EndIndex)
    {
        String BitsString = "";
        for (int i = StartIndex; i <= EndIndex; i++)
            BitsString += (MP3HeaderBits.Get(i)) ? "1" : "0";
        return BitsString;
    }

    private bool GetMP3HeaderBytes(String MP3FilePath)
    {
        FileStream MP3FileStream = GetMp3FileStream(MP3FilePath);
        BitArray TempMP3HeaderBits;
        byte[] MP3HeaderBytes = new byte[3];
        bool IsSyncByte = false;
        int i, j, Index, BitOffSet;
        MP3HeaderBits = new BitArray(24);

        try
        {
            while((MP3FileStream.Position + 4) <= MP3FileStream.Length)
            {
                if (MP3FileStream.ReadByte() == 0xFF)
                {
                    Mp3HeaderPosition = (int)MP3FileStream.Position;
                    IsSyncByte = true;
                }
                while(IsSyncByte)
                {
                    MP3FileStream.Read(MP3HeaderBytes, 0, 3);
                    TempMP3HeaderBits = new BitArray(MP3HeaderBytes);
                    bool cont = false;
                    for (i= 7; i >= 5; i--)
                    {
                        if (!TempMP3HeaderBits.Get(i))
                        {
                            IsSyncByte = false;
                            MP3FileStream.Position -= 3;
                            cont = true;
                            break;
                        }
                    }
                    if (cont) continue;
                    Index = 0;
                    BitOffSet = 0;
                    for(j=0;j<=2;j++)
                    {
                        for (i = 7; i >= 0; i--)
                        {
                            MP3HeaderBits.Set(Index, TempMP3HeaderBits.Get(BitOffSet + i));
                            Index += 1;
                        }
                        BitOffSet += 8;
                    }
                    Mp3HeaderBitsStr.MPEGTypeBitsString = GetBitsString(3, 4);
                    Mp3HeaderBitsStr.LayerBitsString = GetBitsString(5, 6);
                    Mp3HeaderBitsStr.BitrateBitsString = GetBitsString(8, 11);
                    Mp3HeaderBitsStr.FreqBitsString = GetBitsString(12, 13);
                    Mp3HeaderBitsStr.ChannelModeBitsString = GetBitsString(16, 17);
                    if (Mp3HeaderBitsStr.MPEGTypeBitsString == "01")
                    {
                        IsSyncByte = false;
                        MP3FileStream.Position -= 3;
                        continue;
                    }
                    if (Mp3HeaderBitsStr.LayerBitsString == "00")
                    {
                        IsSyncByte = false;
                        MP3FileStream.Position -= 3;
                        continue;
                    }
                    if (Mp3HeaderBitsStr.BitrateBitsString == "1111")
                    {
                        IsSyncByte = false;
                        MP3FileStream.Position -= 3;
                        continue;
                    }
                    if (Mp3HeaderBitsStr.FreqBitsString == "11")
                    {
                        IsSyncByte = false;
                        MP3FileStream.Position -= 3;
                        continue;
                    }
                    else
                    {
                        Mp3ClearSize = (int)(MP3FileStream.Length - Mp3HeaderPosition - 128);
                        return true;
                    }
                }
            }
        }
        catch (Exception Exc)
        { throw new Exception(Exc.Message); }
        finally
        { MP3FileStream.Close(); }
        return false;
    }

    public int Duration
    {
        get
        {
            return (int)Math.Round((double)((float)(Mp3ClearSize * (float)8) / (float)Bitrate));
        }
    }

    public String DurationString
    {
        get
        {
            return new TimeSpan(0, 0, Duration).ToString();
        }
    }

    public sID3v1TAG ID3v1
    {
        get
        {
            return GetID3v1TAG(Mp3FInfo.FullName);
        }
    }

    public FileInfo Mp3FileInfo
    {
        get
        {
            return Mp3FInfo;
        }
    }

    public eMPEGType MPEGType
    {
        get
        {
            switch (Mp3HeaderBitsStr.MPEGTypeBitsString)
            {
                case "11": return eMPEGType.MPEG1;
                case "10": return eMPEGType.MPEG2;
                case "00": return eMPEGType.MPEG2_5;
            }
            return eMPEGType.MPEG_UNDEFINED;
        }
    }

    public bool IsVBR
    {
        get
        {
            FileStream MP3FileStream = GetMp3FileStream(Mp3FInfo.FullName);
            System.Text.UTF8Encoding ByteToStringConv = new System.Text.UTF8Encoding();
            byte[] XingBytes = new byte[4];
            try
            {
                if (MPEGType == eMPEGType.MPEG1)
                    if (ChannelMode == eChannelMode.Mono)
                        MP3FileStream.Position = Mp3HeaderPosition + 20;
                    else
                        MP3FileStream.Position = Mp3HeaderPosition + 35;
                else
                    if (ChannelMode == eChannelMode.Mono)
                        MP3FileStream.Position = Mp3HeaderPosition + 12;
                    else
                        MP3FileStream.Position = Mp3HeaderPosition + 20;
                MP3FileStream.Read(XingBytes, 0, 4);
                if ((ByteToStringConv.GetString(XingBytes, 0, 4) == "Xing") ||
                    (ByteToStringConv.GetString(XingBytes,0 , 4) == "Info"))
                {
                    MP3FileStream.Read(XingHeaderBytes, 0, 116);
                    return true;
                }
                return false;
            }
            catch (Exception Exc)
            { throw new Exception("Can't read file '" + Mp3FInfo.FullName + "'.  " + Exc.Message); }
            finally
            { MP3FileStream.Close(); }
        }
    }

    public eChannelMode ChannelMode
    {
        get
        {
            switch (Mp3HeaderBitsStr.ChannelModeBitsString)
            {
                case "00": return eChannelMode.Stereo;
                case "01": return eChannelMode.Joint_Stereo;
                case "10": return eChannelMode.Mono_2_Channels;
                case "11": return eChannelMode.Mono;
            }
            return eChannelMode.Channel_Undefined;
        }
    }

    public int SamplingRateFreq
    {
        get
        {
            switch (MPEGType)
            {
                case eMPEGType.MPEG1 :
                    switch (Mp3HeaderBitsStr.FreqBitsString)
                    {
                        case "00": return 44100;
                        case "01": return 48000;
                        case "10": return 32000;
                    }
                    break;
                case eMPEGType.MPEG2 :
                    switch (Mp3HeaderBitsStr.FreqBitsString)
                    {
                        case "00": return 22050;
                        case "01": return 24000;
                        case "10": return 16000;
                    }
                    break;
                case eMPEGType.MPEG2_5 :
                    switch (Mp3HeaderBitsStr.FreqBitsString)
                    {
                        case "00": return 11025;
                        case "01": return 12000;
                        case "10": return 08000;
                    }
                    break;
            }
            return 44100;
        }
    }

// Public Function GetLayer() As LayerType
    public eLayerType LayerType
    {
        get
        {
            switch(Mp3HeaderBitsStr.LayerBitsString)
            {
                case "01" : return eLayerType.LayerIII;
                case "10" : return eLayerType.LayerII;
                case "11" : return eLayerType.LayerI;
                default: return eLayerType.Leyer_Undefined;
            }
        }
    }

    public sXingHeader XingHeader
    {
        get
        {
            sXingHeader CXingHeader = new sXingHeader();
            byte[] FileLenghtBytes = new byte[4];
            byte[] FrameCountBytes = new byte[4];
            byte[] VBRScaleBytes = new byte[4];
            int Index = 0;
            int i;
            int[] TOC = new int[100];
            if (IsVBR)
            {
                for (i = 3; i >= 0; i--)
                {
                    VBRScaleBytes[Index] = XingHeaderBytes[112 + i];
                    FrameCountBytes[Index] = XingHeaderBytes[4 + i];
                    FileLenghtBytes[Index] = XingHeaderBytes[8 + i];
                    Index += 1;
                }
                for (i = 0; i <= 99; i++)
                    TOC[i] = Convert.ToInt32(XingHeaderBytes[12 + i]);
            }
            else
            {
                throw new Exception("'" + Mp3FInfo.FullName + "' is not VBR");
            }
            CXingHeader.FileLenght = BitConverter.ToInt32(FileLenghtBytes, 0);
            CXingHeader.NumberOfFrames = BitConverter.ToInt32(FrameCountBytes, 0);
            CXingHeader.VBRScale = BitConverter.ToInt32(VBRScaleBytes, 0);
            CXingHeader.TOC = TOC;
            return CXingHeader;
        }
    }

    public int Bitrate
    {
        get
        {
            int[] BitrateArray;
            if (MPEGType == eMPEGType.MPEG1)
            {
                if (LayerType == eLayerType.LayerI)
                {
                    BitrateArray = new int[] { 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 };
                }
                else
                    if (LayerType == eLayerType.LayerII)
                    {
                        BitrateArray = new int[] { 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 };
                    }
                    else
                    {
                        BitrateArray = new int[] { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 };
                    }
            }
            else
            {
                if (LayerType == eLayerType.LayerI)
                {
                    BitrateArray = new int[] { 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 172, 224, 256 };
                }
                else
                {
                    BitrateArray = new int[] { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 };
                }
            }
            if (!IsVBR)
            {
                switch (Mp3HeaderBitsStr.BitrateBitsString)
                {
                    case "0001": return BitrateArray[0] * 1000;
                    case "0010": return BitrateArray[1] * 1000;
                    case "0011": return BitrateArray[2] * 1000;
                    case "0100": return BitrateArray[3] * 1000;
                    case "0101": return BitrateArray[4] * 1000;
                    case "0110": return BitrateArray[5] * 1000;
                    case "0111": return BitrateArray[6] * 1000;
                    case "1000": return BitrateArray[7] * 1000;
                    case "1001": return BitrateArray[8] * 1000;
                    case "1010": return BitrateArray[9] * 1000;
                    case "1011": return BitrateArray[10] * 1000;
                    case "1100": return BitrateArray[11] * 1000;
                    case "1101": return BitrateArray[12] * 1000;
                    case "1110": return BitrateArray[13] * 1000;
                    default: return BitrateArray[3] * 1000; // actually invalid
                }
            }
            else
            {
                sXingHeader CXingHeader = XingHeader;
                int LastByte, AverageFrameLenght, AverageBitrate;
                LastByte = (int)Math.Round((double)((float)(CXingHeader.TOC[99] / (float)256) * (float)CXingHeader.FileLenght));
                AverageFrameLenght = (int)Math.Round((double)(float)(CXingHeader.FileLenght / (float)CXingHeader.NumberOfFrames));
                AverageBitrate = (int)Math.Round((double)(((float)(AverageFrameLenght * SamplingRateFreq / (float)144) / (float)1000)));
                return AverageBitrate * 1000;
            }
        }
    }

    private byte CheckForZeroBytes(byte ByteToCheck)
    {
        System.Text.UTF8Encoding ByteToStringConv = new System.Text.UTF8Encoding();
        byte[] EmptyCharByte = ByteToStringConv.GetBytes(" ");
        if (ByteToCheck == 0)
            return EmptyCharByte[0];
        else
            return ByteToCheck;
    }

    private sID3v1TAG GetID3v1TAG(String MP3FilePath)
    {
        FileStream MP3FileStream = GetMp3FileStream(MP3FilePath);
        System.Text.UTF8Encoding ByteToStringConv = new System.Text.UTF8Encoding();
        sID3v1TAG CID3v1;
        byte[] ID3v1Bytes = new byte[128];
        byte[] SongTitleBytes = new byte[30];
        byte[] ArtistBytes = new byte[30];
        byte[] AlbumBytes = new byte[30];
        byte[] CommentBytes = new byte[30];
        byte[] YearBytes = new byte[4];
        int i;
        try
        {
            MP3FileStream.Position = MP3FileStream.Length - 128;
            MP3FileStream.Read(ID3v1Bytes, 0, 128);
        }
        catch
        {
            throw new Exception("Can't read file '" + MP3FilePath + "'.");
        }
        finally
        {
            MP3FileStream.Close();
        }
        for (i = 0; i <= 29; i++)
        {
            SongTitleBytes[i] = CheckForZeroBytes(ID3v1Bytes[3 + i]);
            ArtistBytes[i] = CheckForZeroBytes(ID3v1Bytes[33 + i]);
            AlbumBytes[i] = CheckForZeroBytes(ID3v1Bytes[63 + i]);
            CommentBytes[i] = CheckForZeroBytes(ID3v1Bytes[97 + i]);
        }
        for (i = 0; i <= 3; i++)
            YearBytes[i] = CheckForZeroBytes(ID3v1Bytes[93 + i]);
        CID3v1.SongTitle = ByteToStringConv.GetString(SongTitleBytes, 0, 30);
        CID3v1.Artist = ByteToStringConv.GetString(ArtistBytes, 0, 30);
        CID3v1.Album = ByteToStringConv.GetString(AlbumBytes, 0, 30);
        CID3v1.Comment = ByteToStringConv.GetString(CommentBytes, 0, 30);
        CID3v1.Year = ByteToStringConv.GetString(YearBytes, 0, 4);
        CID3v1.GenreID = ID3v1Bytes[127].ToString();
        return CID3v1;
    }

    public eProtectionType Protection
    {
        get
        {
            if (!MP3HeaderBits.Get(7))
                return eProtectionType.CRC_Protection;
            else
                return eProtectionType.Not_Protected;
        }
    }

    public eCopyRight CopyRight
    {
        get
        {
            return (MP3HeaderBits.Get(20))? eCopyRight.CopyRighted:
                eCopyRight.Not_CopyRighted;
        }
    }

    public String GetGenreString(int GenreID)
    {
        String[] AvailableGenres = {"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", 
                "Hip - Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", 
                "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro -Techno", "Ambient", 
                "Trip -Hop", "Vocal", "Jazz Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", 
                "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", 
                "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno -Industrial", "Electronic", 
                "Pop -Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap", 
                "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", 
                "Lo - Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", 
                "Folk", "Folk/Rock", "National Folk", "Swing", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", 
                "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", 
                "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", 
                "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", 
                "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A Cappella", "Euro - House", 
                 "Dance Hall", "Goa", "Drum & Bass", "Club - House", "Hardcore", "Terror", "Indie", "BritPop", "Negerpunk", 
                "Polsk Punk", "Beat", "Christian Gangsta Rap", "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian", 
                "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "Synthpop"};
        try { return AvailableGenres[GenreID]; }
        catch { return " "; }
    }

    public String[] MediaProperties
    {
        get
        {
            String[] props = new String[9];
            props[0] = "MPEG Type = " + MPEGType.ToString();
            props[1] = "Layer = " + LayerType.ToString();
            props[2] = "Protection = " + Protection.ToString();
            props[3] = "Bitrate Type = " + ((IsVBR) ? "VBR" : "CBR");
            props[4] = "Bitrate = " + Bitrate.ToString("#,###,### Bits/Sec");
            props[5] = "Duration = " + DurationString;
            props[6] = "Channel Mode = " + ChannelMode.ToString();
            props[7] = "Copyrighted = " + ((CopyRight == eCopyRight.CopyRighted) ? "Yes" : "No");
            props[8] = "Frequency = " + SamplingRateFreq.ToString("#,###,### Hz");
            return props;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

brochpirate
Israel Israel
No Biography provided

You may also be interested in...

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150731.1 | Last Updated 11 Jun 2009
Article Copyright 2008 by brochpirate
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid