Contents
Articles
Behaviors
Books
Director News
Director Web Sites
FAQ
Games
Mailing Lists
News Groups
Project Examples
Reviews
Software
Tools
Useful Web Sites
Utilities
Xtras

Don't miss these
cXtraSendMail
SM scroll slowdown
Least Common Denominator
Full control of sprite
Write Text to File Example
Simatrix Lingo Font
Dir Player
auto scrolling entryfield
ScreenFade
QTMovieXtra
 

 

 

Behavior General Purpose MP3 Parent

Added on 9/24/2000

 

Compatibilities:
D7 D8 Mac PC Script

Required Xtras:
Binary IO

Rating:

Author: KendallAnderson (website)

This parent script will easily allow the reading and writing of ID3 Tags (which contain artist info, song title etc) to MP3 audio files. It will also read the MP3 header information, which includes items such as the bitrate, sampling frequency, copyright flag, etc. Requires Director 7.0+ (uses dot.syntax everywhere). Requires the BinaryIO Xtra.

-- MP3 Parent
-------------

-- General Purpose MP3 Info Parent Script

-- copyright (c) 2000 kendall anderson. all rights reserved.
-- contact: kpander@home.com, http://members.home.com/kpander/


-- History:
----------
-- jun 26, 1999: k. anderson // initial development
-- sep 09, 2000: k. anderson, modified, converted to parent script for mp3 database utility
-- sep 19, 2000: k. anderson, added _WriteMP3Tag function
-- sep 20, 2000: k. anderson, added _ReadMP3Header function
-- sep 21, 2000: k. anderson, additional code documentation for public consumption



-- Requirements:
---------------
-- *REQUIRES* the BinaryIO Xtra by Glenn Picher (go to www.updatestage.com for information)


-- Current Limitations:
----------------------
-- Only reads ID3 v1 tags, does NOT support v2, v3, etc.


-- Major Methods:
----------------
-- _ReadMP3Tag me, dPath, dFilename                -- returns the ID3 information as a property list
-- _WriteMP3Tag me, dPath, dFilename, dID3Tag      -- writes the ID3 property list 'dID3Tag' to the file
-- _ReadMP3Header me, dPath, dFilename             -- returns the MP3 header information as a list containing 2 property lists [ raw info, descriptive info ]


-- Data Formats:
---------------

-- dID3Tag (returned by _ReadMP3Tag and required by _WriteMP3Tag)
----------
-- dID3Tag.TAG                  always = "TAG"
-- dID3Tag.TITLE                Song Title
-- dID3Tag.ARTIST               Artist
-- dID3Tag.ALBUM                Album
-- dID3Tag.YEAR                 Year as string
-- dID3Tag.COMMENTS             Comments
-- dID3Tag.GENRE                Genre number (as character)

-- dID3Tag.GENREDESC            Genre Description name, ie: "Jazz", unused by _WriteMP3Tag
-- dID3Tag.FILESIZE             Returned by _ReadMP3Tag, unused by _WriteMP3Tag


-- dHeader (returned by _ReadMP3Header)
----------
-- dDescHeader = dHeader[2]     The header information, translated into descriptive values
--------------
-- dDescHeader.MPEGVersion      ie: "MPEG Version 2.5"
-- dDescHeader.Layer            ie: "Layer III"
-- dDescHeader.Protection       ie: "Protected by 16bit CRC"
-- dDescHeader.BitRate          ie: "128"
-- dDescHeader.SamplingRate     ie: "44000"
-- dDescHeader.Padding          ie: "frame is padded with one extra bit"
-- dDescHeader.Private          unknown
-- dDescHeader.ChannelMode      ie: "joint stereo (stereo)"
-- dDescHeader.ModeExtension    ie: "off, on"
-- dDescHeader.Copyright        ie: "Audio is not copyrighted"
-- dDescHeader.Original         ie: "Original media"
-- dDescHeader.Emphasis         ie: "none"

-- dRawHeader = dHeader[1]      The first 32 bits of the file, parsed into specific properties
-------------
-- dRawHeader.MPEGVersion       2 bits
-- dRawHeader.Layer             2 bits
-- dRawHeader.Protection        1 bit
-- dRawHeader.BitRate           4 bits
-- dRawHeader.SamplingRate      2 bits
-- dRawHeader.Padding           1 bit
-- dRawHeader.Private           1 bit
-- dRawHeader.ChannelMode       2 bits
-- dRawHeader.ModeExtension     2 bits
-- dRawHeader.Copyright         1 bit
-- dRawHeader.Original          1 bit
-- dRawHeader.Emphasis          2 bits



-- Additional Credits:
---------------------
-- The two functions which convert an integer to a bit string,
-- and vice-versa, (_convBase and _ConvToInt) were found at
-- http://www.mediamacros.com, and are credited to:
-- Kevan Dettelbach, Chuck Neal and Joerg Seibert.








-- Local Properties:
-------------------
property pGenreList


-- Methods:
----------

on new me
  
  put "[ ID3 Tag Parent: birthed ]"
  register(xtra "binaryio","your-serial-number-here")
  
  _MakeGenreList(me)
  
  return me
  
end



-- read the specified MP3 file and return the ID3 Tag info as a property list
-- If the file doesn't exist, returns VOID
-- If the file does not have an ID3 Tag, returns a blank ID3 Tag with the filename as the SongTitle

-- returns the ID3 Tag data as a property list

on _ReadMP3Tag me, dPath, dFilename
  
  dFP = new(xtra "binaryio")                               -- instance the BinaryIO Xtra
  dErr = openfile(dFP, 1, dPath & dFilename)               -- check for errors opening the file
  
  if (dErr <> "OK") then                                   -- if the file didn't open, halt
    put "Error opening file! (" & dPath & dFilename & ")"
    dID3Tag = void
    
  else
    dTagSize = 128                                         -- MP3 tag is 128 bytes long
    dFileSize = GetFileSize(dFP)                           -- get the MP3 filesize
    SetfilePosition(dFP, dFileSize - 128)                  -- position ourselves at the end - 128 bytes
    
    dTagData = readBytes(dFp, dTagSize)                    -- read the tag data
    
    -- sort out the tag data into different fields
    dID3Tag = _ParseTagData(me, dTagData, dFileSize, dFilename)  
    
  end if
  
  
  dErr = closefile(dFP)
  dFP = void
  
  return dID3Tag
  
end


-- write the ID3 Tag (dID3Tag) to the specified file
-- if an ID3 Tag already exists, it will be replaced
-- if an ID3 Tag does NOT exist, it will be appended to the end of the file
-- NOTE: NO ERROR CHECKING is applied to the dID3Tag variable as of yet

-- returns string with result of the operation, first word will be either ERROR or OK

on _WriteMP3Tag me, dPath, dFilename, dID3Tag
  
  -- determine whether tag exists in the filename or not before writing
  -- pad the dID3Tag so that all fields are the correct length? YES YES
  
  dFP = new(xtra "binaryio")                               -- instance the BinaryIO Xtra
  dErr = openfile(dFP, 2, dPath & dFilename)               -- check for errors opening the file
  
  if (dErr <> "OK") then                                   -- if the file didn't open, halt
    dResult = "ERROR opening file! (" & dPath & dFilename & ")"
    
  else
    dTagSize = 128                                         -- MP3 tag is 128 bytes long
    dFileSize = GetFileSize(dFP)                           -- get the MP3 filesize
    SetfilePosition(dFP, dFileSize - 128)                  -- position ourselves at the end - 128 bytes
    
    dExistingTagData = readBytes(dFp, dTagSize)            -- read the tag data
    
    dID3Tag = _PadID3Tag(me, dID3Tag)                      -- make sure all fields are correct length
    
    if (dExistingTagData.char[1..3] = "TAG") then
      -- data already exists
      dResult = "OK Replacing existing ID3 for: [" & dFilename & "]"
      SetfilePosition(dFP, dFileSize - 128)
    else
      -- no data exists, write from the end of the file
      dResult = "OK Writing new ID3 for: [" & dFilename & "]"
      SetfilePosition(dFP, dFileSize)
    end if
    
    WriteBytes(dFP, dID3Tag.tag)
    WriteBytes(dFP, dID3Tag.title)
    WriteBytes(dFP, dID3Tag.artist)
    WriteBytes(dFP, dID3Tag.album)
    WriteBytes(dFP, dID3Tag.year)
    WriteBytes(dFP, dID3Tag.comments)
    WriteBytes(dFP, dID3Tag.genre)
    
  end if
  
  
  dErr = closefile(dFP)
  dFP = void
  
  
  put dResult
  return dResult
  
end




-- read the header information from the specified MP3 file
-- ie: version, bitrate, error protection, sampling freq, copyright, etc.

-- If the file could not be opened, returns VOID
-- If the read is successful, returns a list containing 2 property lists: [ RawHeader, DescriptiveHeader ]

on _ReadMP3Header me, dPath, dFilename
  
  dHeader = [:]
  
  dFP = new(xtra "binaryio")                               -- instance the BinaryIO Xtra
  dErr = openfile(dFP, 1, dPath & dFilename)               -- check for errors opening the file
  
  if (dErr <> "OK") then                                   -- if the file didn't open, halt
    put "ERROR opening file! (" & dPath & dFilename & ")"
    dHeader = void
    
  else
    
    -- to read the header info, read the first 4 bytes
    dHeaderRaw = ReadBytes(dFP, 4)
    
    -- construct a 32 bit long string
    dHeaderBitString = ""
    repeat with i = 1 to dHeaderRaw.length
      
      dBitString = ""
      dBitString = _ConvBase(me, chartonum(dHeaderRaw.char[i]), 2)  -- convert number to binary in string format
      repeat while(dBitString.length < 8)                           -- make sure each byte converts to 8 digit bitstring
        dBitString = "0" & dBitString
      end repeat
      
      dHeaderBitString = dHeaderBitString & dBitString
      
    end repeat
    
    dHeader = _ParseHeader(me, dHeaderBitString)      -- figure out what info was in the header
    
  end if
  
  
  dErr = closefile(dFP)
  dFP = void
  
  return dHeader
  
end










-- given dHeaderBitString = string like "1111110011111010011"... etc representing first 4 bytes of file
-- parse to properties

on _ParseHeader me, dBitString
  
  -- read each block of data into a variable, raw
  
  dFrameSync = dBitString.char[1..11]
  dMPEGVersion = dBitString.char[12..13]
  dLayer = dBitString.char[14..15]
  dProtectionBit = dBitString.char[16]
  dBitRate = dBitString.char[17..20]
  dSamplingRate = dBitString.char[21.22]
  dPadding = dBitString.char[23]
  dPrivate = dBitString.char[24]
  dChannelMode = dBitString.char[25..26]
  dModeExtension = dBitString.char[27..28]
  dCopyright = dBitString.char[29]
  dOriginal = dBitString.char[30]
  dEmphasis = dBitString.char[31..32]
  
  dRawHeader = [:]
  dDescHeader = [:]
  
  -- mpeg version #
  case (dMPEGVersion) of
    "00":
      dDescMPEGVersion = "MPEG Version 2.5"
      dSamplingRateList = [ "11025", "12000", "8000", "reserved" ]
    "01":
      dDescMPEGVersion = "reserved"
      dSamplingRateList = [ "reserved", "reserved", "reserved", "reserved" ]
    "10":
      dDescMPEGVersion = "MPEG Version 2"
      dSamplingRateList = [ "22050", "24000", "16000", "reserved" ]
    "11":
      dDescMPEGVersion = "MPEG Version 1"
      dSamplingRateList = [ "44100", "48000", "32000", "reserved" ]
  end case
  addProp dRawHeader, #MPEGVersion, dMPEGVersion
  addProp dDescHeader, #MPEGVersion, dDescMPEGVersion
  
  -- layer description
  case (dLayer) of
    "00": dDescLayer = "reserved"
    "01": dDescLayer = "Layer III"
    "10": dDescLayer = "Layer II"
    "11": dDescLayer = "Layer I"
  end case
  addProp dRawHeader, #Layer, dLayer
  addProp dDescHeader, #Layer, dDescLayer
  
  -- protection bit
  case (dProtectionBit) of
    "0": dDescProtection = "Protected by 16bit CRC"
    "1": dDescProtection = "Not Protected"
  end case
  addProp dRawHeader, #Protection, dProtectionBit
  addProp dDescHeader, #Protection, dDescProtection
  
  -- bitrate index
  dL1 = [ "free", "32", "64", "96", "128", "160", "192", "224", "256", "288", "320", "352", "384", "416", "448", "bad" ]
  dL2 = [ "free", "32", "40", "48", "56", "64", "80", "96", "112", "128", "160", "192", "224", "256", "320", "bad" ]
  dV1L3 = [ "free", "32", "40", "48", "56", "64", "80", "96", "112", "128", "160", "192", "224", "256", "320", "bad" ]
  dV2L3 = [ "free", "8", "16", "24", "32", "64", "80", "54", "64", "128", "160", "112", "128", "256", "320" ]
  
  case (dLayer) of
    "11": dBitRateList = dL1         -- layer I
    "10": dBitRateList = dL2         -- layer II
    "01":
      if (dMPEGVersion = "11") then  -- version 1
        dBitRateList = dV1L3
      else                           -- version 2 or version 2.5
        dBitRateList = dV2L3
      end if
  end case
  
  
  -- now, get element from the list
  dIndexPos = _ConvToInt(me, dBitRate, 2)  -- convert "1010" etc to integer
  dIndexPos = dIndexPos + 1
  
  dDescBitRate = dBitRateList[dIndexPos]
  
  addProp dRawHeader, #BitRate, dBitRate
  addProp dDescHeader, #BitRate, dDescBitRate
  
  
  -- sampling rate
  dIndexPos = _ConvToInt(me, dSamplingRate, 2)
  dIndexPos = dIndexPos + 1
  
  dDescSamplingRate = dSamplingRateList[dIndexPos]
  
  addProp dRawHeader, #SamplingRate, dSamplingRate
  addProp dDescHeader, #SamplingRate, dDescSamplingRate
  
  
  -- padding
  case (dPadding) of
    "0": dDescPadding = "frame is not padded"
    "1": dDescPadding = "frame is padded with one extra bit"
  end case
  addProp dRawHeader, #Padding, dPadding
  addProp dDescHeader, #Padding, dDescPadding
  
  
  -- private bit
  addProp dRawHeader, #Private, dPrivate
  addProp dDescHeader, #Private, dPrivate
  
  
  -- channel mode
  case (dChannelMode) of
    "00": dDescChannelMode = "stereo"
    "01": dDescChannelMode = "joint stereo (stereo)"
    "10": dDescChannelMode = "dual channel (stereo)"
    "11": dDescChannelMode = "single channel (mono)"
  end case
  addProp dRawHeader, #ChannelMode, dChannelMode
  addProp dDescHeader, #ChannelMode, dDescChannelMode
  
  
  -- mode extension -- *** NO IDEA HOW TO INTERPRET THIS ONE CORRECTLY...
  case (dModeExtension) of
    "00": dDescModeExtension = "off, off"
    "01": dDescModeExtension = "on, off"
    "10": dDescModeExtension = "off, on"
    "11": dDescModeExtension = "on, on"
  end case
  addProp dRawHeader, #ModeExtension, dModeExtension
  addProp dDescHeader, #ModeExtension, dDescModeExtension
  
  
  -- copyright
  case (dCopyright) of
    "0": dDescCopyright = "Audio is not copyrighted"
    "1": dDescCopyright = "Audio is copyrighted"
  end case
  addProp dRawHeader, #Copyright, dCopyright
  addProp dDescHeader, #Copyright, dDescCopyright
  
  
  -- original
  case (dOriginal) of
    "0": dDescOriginal = "Copy of original media"
    "1": dDescOriginal = "Original media"
  end case
  addProp dRawHeader, #Original, dOriginal
  addProp dDescHeader, #Original, dDescOriginal
  
  
  -- emphasis
  case (dEmphasis) of
    "00": dDescEmphasis = "none"
    "01": dDescEmphasis = "50/15 ms"
    "10": dDescEmphasis = "reserved"
    "11": dDescEmphasis = "CCIT J.17"
  end case
  addProp dRawHeader, #Emphasis, dEmphasis
  addProp dDescHeader, #Emphasis, dDescEmphasis
  
  
  
  return [ dRawHeader, dDescHeader ]
  
end








-- Convert a positive integer in a String based on base
-- for int-to-hex call ConvBase(nConv, 16)
-- for int-to-bit call ConvBase(nConv, 2)

on _convBase me, nConvNum, nBase
  if (nBase > 1 and nBase < 17) and (nConvNum > -1) then
    baseNums = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"]
    szConverted = ""
    repeat while nConvNum
      nMod = nConvNum mod nBase
      szConverted = baseNums[nMod + 1] & szConverted
      nConvNum = nConvNum / nBase
    end repeat
    return szConverted
  else
    return VOID
  end if
end


-- Convert a String into an integer,
-- for hex-to-int call convToInt(szConv, 16)
-- for bit-to-int call convToInt(szConv, 2) .....
-- no complete errorchecking: convToInt("2EF", 2) works, but makes no sense ;-)
on _ConvToInt me, szConvNum, nBase
  if nBase > 1 and nBase < 17 then
    baseNums = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"]
    nConverted = 0
    nMax = szConvNum.length
    repeat with nIndex = 1 to nMax
      nConverted = nConverted * nBase
      nConverted = nConverted + baseNums.getOne(szConvNum.char[nIndex]) - 1
    end repeat
    return nConverted
  else
    return VOID
  end if
end






-- make sure each field which will be written is exactly the correct length

on _PadID3Tag me, dID3Tag
  
  dTagLengths = []
  add dTagLengths, [ #title, 30 ]
  add dTagLengths, [ #artist, 30 ]
  add dTagLengths, [ #album, 30 ]
  add dTagLengths, [ #year, 4 ]
  add dTagLengths, [ #comments, 30 ]
  add dTagLengths, [ #genre, 1 ]
  
  
  repeat with dLimits in dTagLengths
    
    dProp = dLimits[1]
    dValue = dLimits[2]
    
    dItem = dID3Tag[dProp]
    dItem = _SetLength(me, dItem, dValue)
    
    dID3Tag[dProp] = dItem
    
  end repeat
  
  return dID3Tag
  
end


-- set the length of a text string - pad with spaces, or truncate

on _SetLength me, dItem, dValue
  
  if (dItem.length > dValue) then
    dItem = dItem.char[1..dValue]  
  else
    repeat while (dItem.length < dValue)
      --dItem = dItem & numTochar(0)
      dItem = dItem & " "  -- should this be a numtochar(0) instead of SPACE?
    end repeat
  end if
  
  return dItem
  
end


-- given the raw tag data, convert it into a property list

on _ParseTagData me, dTagData, dFileSize, dFilename
  
  dID3Tag = [:]
  
  if (dTagData.length = 0) then
    dIdentity = "ID3 TAG MISSING"
  else
    dIdentity = dTagData.char[1..3]
  end if
  
  addProp dID3Tag, #TAG, dIdentity
  
  
  if (dIdentity <> "TAG") then
    -- put "Invalid tag or this MP3 file does not have any ID data."
    -- create temporary tag with blank entries
    
    dID3Tag.TAG = "TAG"
    addProp dID3Tag, #TITLE, dFilename
    addProp dID3Tag, #ARTIST, ""
    addProp dID3Tag, #ALBUM, ""
    addProp dID3Tag, #YEAR, ""
    addProp dID3Tag, #COMMENTS, ""
    addProp dID3Tag, #GENRE, numtochar(126)
    addProp dID3Tag, #GENREDESC, "Unknown"
    addProp dID3Tag, #FILESIZE, dFileSize
    
    
  else
    dSongTitle = dTagData.char[4..33]  -- 30 chars
    dArtist = dTagData.char[34..63]    -- 30 chars
    dAlbum = dTagData.char[64..93]     -- 30 chars
    dYear = dTagData.char[94..97]      --  4 chars
    dComments = dTagData.char[98..127] -- 30 chars
    dGenre = dTagData.char[128..128]   --  1 char
    
    dGenreDescription = _GetGenre(me, chartonum(dGenre))
    
    addProp dID3Tag, #TITLE, dSongTitle
    addProp dID3Tag, #ARTIST, dArtist
    addProp dID3Tag, #ALBUM, dAlbum
    addProp dID3Tag, #YEAR, dYear
    addProp dID3Tag, #COMMENTS, dComments
    addProp dID3Tag, #GENRE, dGenre
    addProp dID3Tag, #GENREDESC, dGenreDescription
    addProp dID3Tag, #FILESIZE, dFileSize
    
  end if
  
  return dID3Tag
  
end


-- given genre #, return the text description of the genre

on _GetGenre me, dGenre
  
  dGenre = dGenre + 1   -- because the list starts with a value of 0 (Blues)
  
  if (dGenre > pGenreList.count) then
    dGenreText = "Unknown"
  else
    dGenreText = pGenreList[dGenre]
  end if
  
  return dGenreText
  
end


-- assemble the list of genre descriptions

on _MakeGenreList me
  
  dList = []
  
  add dList, "Blues"             -- 000
  add dList, "Classic Rock"      -- 001
  add dList, "Country"           -- 002
  add dList, "Dance"             -- 003
  add dList, "Disco"             -- 004
  add dList, "Funk"              -- 005
  add dList, "Grunge"            -- 006
  add dList, "Hip-Hop"           -- 007
  add dList, "Jazz"              -- 008
  add dList, "Metal"             -- 009
  add dList, "New Age"           -- 010
  add dList, "Oldies"            -- 011
  add dList, "Other"             -- 012
  add dList, "Pop"               -- 013
  add dList, "R&B"               -- 014
  add dList, "Rap"               -- 015
  add dList, "Reggae"            -- 016
  add dList, "Rock"              -- 017
  add dList, "Techno"            -- 018
  add dList, "Industrial"        -- 019
  add dList, "Alternative"       -- 020
  add dList, "Ska"               -- 021
  add dList, "Death Metal"       -- 022
  add dList, "Pranks"            -- 023
  add dList, "Soundtrack"        -- 024
  add dList, "Euro-Techno"       -- 025
  add dList, "Ambient"           -- 026
  add dList, "Trip-Hop"          -- 027
  add dList, "Vocal"             -- 028
  add dList, "Jazz+Funk"         -- 029
  add dList, "Fusion"            -- 030
  add dList, "Trance"            -- 031
  add dList, "Classical"         -- 032
  add dList, "Instrumental"      -- 033
  add dList, "Acid"              -- 034
  add dList, "House"             -- 035
  add dList, "Game"              -- 036
  add dList, "Sound Clip"        -- 037
  add dList, "Gospel"            -- 038
  add dList, "Noise"             -- 039
  add dList, "AlternRock"        -- 040
  add dList, "Bass"              -- 041
  add dList, "Soul"              -- 042
  add dList, "Punk"              -- 043
  add dList, "Space"             -- 044
  add dList, "Meditative"        -- 045
  add dList, "Instrumental Pop"  -- 046
  add dList, "Instrumental Rock" -- 047
  add dList, "Ethnic"            -- 048
  add dList, "Gothic"            -- 049
  add dList, "Darkwave"          -- 050
  add dList, "Techno-Industrial" -- 051
  add dList, "Electronic"        -- 052
  add dList, "Pop-Folk"          -- 053
  add dList, "Eurodance"         -- 054
  add dList, "Dream"             -- 055
  add dList, "Southern Rock"     -- 056
  add dList, "Comedy"            -- 057
  add dList, "Cult"              -- 058
  add dList, "Gangsta"           -- 059
  add dList, "Top 40"            -- 060
  add dList, "Christian Rap"     -- 061
  add dList, "Pop/Funk"          -- 062
  add dList, "Jungle"            -- 063
  add dList, "Native American"   -- 064
  add dList, "Cabaret"           -- 065
  add dList, "New Wave"          -- 066
  add dList, "Psychadelic"       -- 067
  add dList, "Rave"              -- 068
  add dList, "Showtunes"         -- 069
  add dList, "Trailer"           -- 070
  add dList, "Lo-Fi"             -- 071
  add dList, "Tribal"            -- 072
  add dList, "Acid Punk"         -- 073
  add dList, "Acid Jazz"         -- 074
  add dList, "Polka"             -- 075
  add dList, "Retro"             -- 076
  add dList, "Musical"           -- 077
  add dList, "Rock & Roll"       -- 078
  add dList, "Hard Rock"         -- 079
  add dList, "Folk"              -- 080
  add dList, "Folk-Rock"         -- 081
  add dList, "National Folk"     -- 082
  add dList, "Swing"             -- 083
  add dList, "Fast Fusion"       -- 084
  add dList, "Bebob"             -- 085
  add dList, "Latin"             -- 086
  add dList, "Revival"           -- 087
  add dList, "Celtic"            -- 088
  add dList, "Bluegrass"         -- 089
  add dList, "Avantgarde"        -- 090
  add dList, "Gothic Rock"       -- 091
  add dList, "Progressive Rock"  -- 092
  add dList, "Psychedelic Rock"  -- 093
  add dList, "Symphonic Rock"    -- 094
  add dList, "Slow Rock"         -- 095
  add dList, "Big Band"          -- 096
  add dList, "Chorus"            -- 097
  add dList, "Easy Listening"    -- 098
  add dList, "Acoustic"          -- 099
  add dList, "Humour"            -- 100
  add dList, "Speech"            -- 101
  add dList, "Chanson"           -- 102
  add dList, "Opera"             -- 103
  add dList, "Chamber Music"     -- 104
  add dList, "Sonata"            -- 105
  add dList, "Symphony"          -- 106
  add dList, "Booty Bass"        -- 107
  add dList, "Primus"            -- 108
  add dList, "Porn Groove"       -- 109
  add dList, "Satire"            -- 110
  add dList, "Slow Jam"          -- 111
  add dList, "Club"              -- 112
  add dList, "Tango"             -- 113
  add dList, "Samba"             -- 114
  add dList, "Folklore"          -- 115
  add dList, "Ballad"            -- 116
  add dList, "Power Ballad"      -- 117
  add dList, "Rhythmic Soul"     -- 118
  add dList, "Freestyle"         -- 119
  add dList, "Duet"              -- 120
  add dList, "Punk Rock"         -- 121
  add dList, "Drum Solo"         -- 122
  add dList, "Acapella"          -- 123
  add dList, "Euro-House"        -- 124
  add dList, "Dance Hall"        -- 125
  
  pGenreList = dList
  
end

 


Contact

MMI
36 South Court Sq
Suite 300
Newnan, GA 30263
USA

Send e-mail