'===========================================================================
' Subject: MP3 LIST                           Date: 09-19-00 (12:02)       
'  Author: Andreas van Cranenburgh            Code: QB, PDS                
'  Origin: andreaswolf@phreaker.net         Packet: MISC.ABC
'===========================================================================
'MP3List - By Andreas van Cranenburgh (C) 2000 - andreaswolf@mail.com
'Makes list of all MP3 files in one directory and writes it to 'MP3LIST.TXT'
'You can select what is to be listed, start with /? for help on this. The
'MP3 routine CheckMP3 was written by Frank Rorma, I modified it a little.
'The SUBs and FUNCTIONs starting with 'DRE.' are taken from 'The DRE Library',
'also written by me. You can visit my website with some of my programs at:
'
'                <<< http://thedre.freeshell.org >>>
'$INCLUDE: 'qb.bi'
DEFINT A-Z
DECLARE SUB DRE.Showbar (Ypos%, Xpos%, BarWidth%, Value%, MaxValue%)
DECLARE FUNCTION DRE.Dir% (Mask$, Attribute%, FileNames$(), FileSizes&())
DECLARE FUNCTION DRE.RegLow% (Number%)
DECLARE FUNCTION DRE.CurrentDir$ ()
DECLARE FUNCTION DRE.CurrentDrive$ ()
DECLARE FUNCTION DRE.Sfn2Lfn$ (File$)
DECLARE SUB CheckMP3 (File$, LFile$, OK)
CONST DIMFACTOR = 500
DIM ShortNames$(DIMFACTOR), LongNames$(DIMFACTOR), FileSizes&(DIMFACTOR)
DIM SHARED BYTE AS STRING
DIM SHARED TAG AS STRING, CurrentDir$
CurrentDir$ = DRE.CurrentDir$
PRINT "MP3List (/? for help) (C)2000 by Andreas van Cranenburgh andreaswolf@mail.com"
PRINT
IF INSTR(COMMAND$, "/?") THEN
	PRINT "Usage: MP3LIST [options]"
	PRINT "   &F - WIN95 Long filename without extension (.mp3)"
	PRINT "   &A - Artist"
	PRINT "   &S - Song"
	PRINT "   &T - Time"
	PRINT "   &C - Chanels (mono, stereo, joint-stereo)"
	PRINT "   &K - Kbps"
	PRINT "   &O - Original (yes/no)"
	PRINT "   &O - Original (yes/no)"
	PRINT "   &R - copyRight (yes/no)"
	PRINT "   /P - Create 'ALL.M3U' playlist in Winamp's .M3U format "
	PRINT "Example: MP3LIST &A - &S (&T min)"
	PRINT "Outputfile is MP3LIST.TXT"
	END
END IF

NumFiles = DRE.Dir("*.mp3", &H1, ShortNames$(), FileSizes&())
FOR a = 1 TO NumFiles
	LongNames$(a) = DRE.Sfn2Lfn(ShortNames$(a))
NEXT a

OPEN "c:\mp3list.txt" FOR OUTPUT AS #2    ' -!@!-
IF INSTR(COMMAND$, "/P") THEN
	OPEN "all.m3u" FOR OUTPUT AS #3
	PRINT #3, "#EXTM3U"
END IF

PRINT STRING$(LEN(STR$(NumFiles - 2)) - 1, "0"); " /"; NumFiles - 2;
BarRow = CSRLIN
BarPos = POS(0)
FOR a = 3 TO NumFiles
	TempY = CSRLIN
	TempX = POS(0)
	'LOCATE BarRow, 1
	PRINT a - 2; "/"; NumFiles - 2;
	DRE.Showbar CSRLIN, BarPos, 40, a - 2, NumFiles - 2
	PRINT ((a - 2) \ (NumFiles - 2)) * 100; "%";
	LOCATE , 1
	'LOCATE TempY, TempX
	OPEN ShortNames$(a) FOR BINARY AS #1
	
	Header$ = SPACE$(2)
	GET #1, , Header$
	CLOSE #1
	
	SELECT CASE Header$
	CASE CHR$(255) + CHR$(251)
		CheckMP3 ShortNames$(a), LongNames$(a), -1
	CASE CHR$(255) + CHR$(250)
		CheckMP3 ShortNames$(a), LongNames$(a), -1
	CASE CHR$(255) + CHR$(227)
		COLOR 4
		PRINT "Can't read from MPEG 2.5 layer 3 files";
		COLOR 7
		PRINT " (" + LongNames$(a) + ")";
		PRINT SPACE$(79 - POS(0))
		CheckMP3 ShortNames$(a), LongNames$(a), 0
	CASE CHR$(255) + CHR$(243)
		COLOR 4
		PRINT "Can't read from MPEG 2.0 layer 3 files";
		COLOR 7
		PRINT " (" + LongNames$(a) + ")";
		PRINT SPACE$(79 - POS(0))
		CheckMP3 ShortNames$(a), LongNames$(a), 0
	CASE CHR$(82) + CHR$(73)
		COLOR 4
		PRINT "Can't read from files with RIFF header";
		COLOR 7
		PRINT " (" + LongNames$(a) + ")";
		PRINT SPACE$(79 - POS(0))
		CheckMP3 ShortNames$(a), LongNames$(a), 0
	CASE ELSE
		COLOR 4
		PRINT "Invalid MP3 file";
		COLOR 7
		PRINT " (" + LongNames$(a) + ")";
		PRINT SPACE$(79 - POS(0))
		CheckMP3 ShortNames$(a), LongNames$(a), 0
	END SELECT
NEXT a
PRINT
CLOSE
END
 
fout:
COLOR 4
PRINT "Unexpected error "; ERR
COLOR 7
END

WrongFileName:
PRINT "Wrong file name!"
END

DEFSNG A-Z
SUB CheckMP3 (File$, LFile$, OK%)
IF NOT OK% THEN GOTO Interpreter
BYTE = SPACE$(1)
TAG = SPACE$(3)
Artist$ = SPACE$(30)
Song$ = SPACE$(30)
OPEN File$ FOR BINARY AS #1
GET #1, 3, BYTE

IF ASC(BYTE) > 223 THEN kbps = 320
IF ASC(BYTE) < 224 AND ASC(BYTE) > 207 THEN kbps = 256
IF ASC(BYTE) < 208 AND ASC(BYTE) > 191 THEN kbps = 224
IF ASC(BYTE) < 192 AND ASC(BYTE) > 175 THEN kbps = 192
IF ASC(BYTE) < 176 AND ASC(BYTE) > 159 THEN kbps = 160
IF ASC(BYTE) < 160 AND ASC(BYTE) > 143 THEN kbps = 128
IF ASC(BYTE) < 144 AND ASC(BYTE) > 127 THEN kbps = 112
IF ASC(BYTE) < 128 AND ASC(BYTE) > 111 THEN kbps = 96
IF ASC(BYTE) < 112 AND ASC(BYTE) > 95 THEN kbps = 80
IF ASC(BYTE) < 96 AND ASC(BYTE) > 79 THEN kbps = 64
IF ASC(BYTE) < 80 AND ASC(BYTE) > 63 THEN kbps = 56
IF ASC(BYTE) < 64 AND ASC(BYTE) > 47 THEN kbps = 48
IF ASC(BYTE) < 48 AND ASC(BYTE) > 31 THEN kbps = 40
IF ASC(BYTE) < 32 AND ASC(BYTE) > 15 THEN kbps = 32
IF ASC(BYTE) < 16 THEN PRINT "Aborting, file has got an invalid header!": END

mins = (LOF(1) \ (kbps * (501 / 4))) \ 60
mins = mins + ((LOF(1) \ (kbps * (501 / 4))) - (60 * mins)) / 100
seconds = INT(mins) * 60 + (mins - INT(mins)) * 100
Minutes$ = LTRIM$(RTRIM$(STR$(mins)))
IF INSTR(Minutes$, ".") = 0 THEN
	Minutes$ = Minutes$ + ":00"
ELSE
	MID$(Minutes$, INSTR(Minutes$, "."), 1) = ":"
END IF
IF LEFT$(RIGHT$(Minutes$, 2), 1) = ":" THEN Minutes$ = Minutes$ + "0"
IF LEFT$(Minutes$, 1) = ":" THEN Minutes$ = "0" + Minutes$

GET #1, 4, BYTE
IF ASC(BYTE) < 64 THEN OutType$ = "stereo"
IF ASC(BYTE) > 63 AND ASC(BYTE) < 128 THEN OutType$ = "j-stereo"
IF ASC(BYTE) > 127 AND ASC(BYTE) < 192 THEN OutType$ = "2 channels"
IF ASC(BYTE) > 191 THEN OutType$ = "mono"
OrigiCopy = (ASC(BYTE) \ 4) - ((ASC(BYTE) \ 4) \ 4) * 4
IF OrigiCopy = 0 THEN copy$ = "no": origi$ = "no"
IF OrigiCopy = 1 THEN copy$ = "no": origi$ = "yes"
IF OrigiCopy = 2 THEN copy$ = "yes": origi$ = "no"
IF OrigiCopy = 3 THEN copy$ = "yes": origi$ = "yes"

TAG = SPACE$(3)
GET #1, LOF(1) - 127, TAG
IF TAG = "TAG" THEN
	GET #1, LOF(1) - 94, Artist$
	GET #1, LOF(1) - 124, Song$
END IF
CLOSE #1

Interpreter:
IF TAG <> "TAG" THEN
	Artist$ = "N/A"
	Song$ = "N/A"
END IF
IF Minutes$ = "" THEN Minutes$ = "    "
IF OutType$ = "" THEN OutType$ = "Unknown"
Text$ = ""
FOR a = 1 TO LEN(COMMAND$)
	IF MID$(COMMAND$, a, 1) = "&" OR MID$(COMMAND$, a, 1) = "/" THEN
		a = a + 1
		SELECT CASE UCASE$(MID$(COMMAND$, a, 1))
		CASE "F"
			Text$ = Text$ + LEFT$(LFile$, LEN(LFile$) - 4)
		CASE "A"
			Text$ = Text$ + RTRIM$(Artist$)
		CASE "S"
			Text$ = Text$ + RTRIM$(Song$)
		CASE "T"
			Text$ = Text$ + Minutes$
		CASE "C"
			Text$ = Text$ + OutType$
		CASE "Y"
			Text$ = Text$ + Year$
		CASE "K"
			IF kbps <> 0 THEN
				Text$ = Text$ + LTRIM$(STR$(kbps))
			ELSE
				Text$ = Text$ + "?"
			END IF
		CASE "O"
			Text$ = Text$ + origi$
		CASE "R"
			Text$ = Text$ + copy$
		END SELECT
	ELSE
		Text$ = Text$ + MID$(COMMAND$, a, 1)
	END IF
NEXT a
IF COMMAND$ = "" THEN Text$ = LFile$
PRINT #2, Text$
IF INSTR(COMMAND$, "/P") THEN
	IF seconds <> 0 THEN PRINT #3, "#EXTINF:" + LTRIM$(STR$(seconds)) + "," + LEFT$(LFile$, LEN(LFile$) - 4)
	PRINT #3, CurrentDir$ + "\" + LFile$
END IF
'PRINT #2, LEFT$(LFile$, LEN(LFile$) - 4); ", " + Minutes$; " min,";
'PRINT #2, kbps; "kbps, "; OutType$
END SUB

DEFINT A-Z
FUNCTION DRE.CurrentDir$
'Returns current directory. Returning string includes drive and full path.
'A maximum of 128 characters are returned. (Like CURDIR$ in PDS and VB)
DIM InRegs AS RegTypeX, OutRegs AS RegTypeX
PathSize$ = SPACE$(64)
InRegs.ax = &H1900
CALL INTERRUPTX(&H21, InRegs, OutRegs)
CurrentDrive$ = CHR$(65 + OutRegs.ax MOD 256)
InRegs.ax = &H4700
InRegs.dx = ASC(LEFT$(CurrentDrive$, 1)) - 64
InRegs.ds = VARSEG(PathSize$)
InRegs.si = SADD(PathSize$)
CALL INTERRUPTX(&H21, InRegs, OutRegs)
DRE.CurrentDir$ = CurrentDrive$ + ":\" + LEFT$(PathSize$, INSTR(PathSize$, CHR$(0)) - -(INSTR(PathSize$, CHR$(0)) > 1))
END FUNCTION

FUNCTION DRE.CurrentDrive$
'Returns currentdrive letter (without the ':').
DIM InRegs AS RegTypeX, OutRegs AS RegTypeX
InRegs.ax = &H1900
CALL INTERRUPTX(&H21, InRegs, OutRegs)
DRE.CurrentDrive$ = CHR$(65 + DRE.RegLow(OutRegs.ax))
END FUNCTION

FUNCTION DRE.Dir (Mask$, Attribute, FileNames$(), FileSizes&())
'Like DIR in DOS. Returns the number of files found and places names, sizes,
'attributes, dates and times in arrays. Not sorted.
DIM InRegs  AS RegTypeX, OutRegs AS RegTypeX
DTA$ = SPACE$(80)

InRegs.ax = &H1A00
InRegs.ds = VARSEG(DTA$)
InRegs.dx = SADD(DTA$)
CALL INTERRUPTX(&H21, InRegs, OutRegs)       '***Set DTA***

FileName$ = Mask$
IF RIGHT$(FileName$, 1) <> CHR$(0) THEN FileName$ = FileName$ + CHR$(0)

InRegs.ax = &H4E00
InRegs.bx = 0
InRegs.cx = Attribute     '32
InRegs.dx = SADD(FileName$)
CALL INTERRUPTX(&H21, InRegs, OutRegs)       '***FindFirst***

IF OutRegs.flags AND 1 THEN
	EXIT FUNCTION
END IF
InRegs.ax = &H4F00
InRegs.bx = 0
InRegs.cx = 0
InRegs.dx = 0
DO WHILE Check < 18
	File$ = MID$(DTA$, 31, 12)
	IF INSTR(File$, CHR$(0)) THEN File$ = LEFT$(File$, INSTR(File$, CHR$(0)) - 1)
	NumberOfFiles = NumberOfFiles + 1
	FileNames$(NumberOfFiles) = File$
	FileSizes&(NumberOfFiles) = CVL(MID$(DTA$, 27, 4))
	CALL INTERRUPTX(&H21, InRegs, OutRegs)
	Check = OutRegs.ax
LOOP
DRE.Dir = NumberOfFiles
END FUNCTION

FUNCTION DRE.RegLow (Number)
'Returns lower byte of 'Number'
IF Number >= 0 THEN
	DRE.RegLow = Number MOD 256
ELSE
	DRE.RegLow = (65536 + Number) MOD 256
END IF
END FUNCTION

FUNCTION DRE.Sfn2Lfn$ (File$)
'Returns long name of a short filename.
DIM InRegs AS RegTypeX
FileN$ = File$ + CHR$(0)
OutN$ = SPACE$(261)
InRegs.ax = &H7160
InRegs.cx = &H2
InRegs.ds = VARSEG(FileN$)
InRegs.si = SADD(FileN$)
InRegs.es = VARSEG(OutN$)
InRegs.di = SADD(OutN$)
CALL INTERRUPTX(&H21, InRegs, InRegs)
IF INSTR(OutN$, CHR$(0)) > 1 THEN OutN$ = LEFT$(OutN$, INSTR(OutN$, CHR$(0)) - 1)
WHILE INSTR(OutN$, "\")
	OutN$ = MID$(OutN$, INSTR(OutN$, "\") + 1)
WEND
DRE.Sfn2Lfn$ = OutN$
END FUNCTION

SUB DRE.Showbar (Ypos, Xpos, BarWidth, Value, MaxValue)
'Draws a percentage bar.
OutCome = Value / (MaxValue / (BarWidth + 1))
LOCATE Ypos, Xpos
PRINT STRING$(OutCome, 219) + STRING$(BarWidth - OutCome + 1, 176);
END SUB
