Page 1 of 1

MP3 Player / Hands Free DJing

Posted: Wed Jul 02, 2003 5:01 pm
by naw
Hi, My little attempt at an MP3 Hands Free DJ tool...

I DJ at dance events sometimes but hate DJing, much rather have a boogie, so this lets me have the best of both worlds ;-)

Basically, tracks can be loaded/appended from individual MP3 files or collectively via M3U files through the "PlayList Manager"

Tracks are played from the "Track Manager", you can skip forward, back, next / previous track, pause or stop etc - The tracks' progress is displayed via a Slider Gadget and you can set the Volume / Fade In / FadeOut for individual tracks and *record* those settings using the "O" Button, the entry is recorded into a PlayerTracks.db file.

"Volume" and "Balance" are set using two miniature Sliders.

The "TrackList Manager" lets you do some rudimentary / simple reordering of the "PlayList" using the "A" and "V" Buttons.

You can insert a "STOP" using the "!" button and delete individual tracks (including any "STOPs" you insert with "X".

The PlayerTracks.db file is seperate from any *.M3U files so individual Volume / FadeIn / FadeOut settings may apply to *.MP3 files that are common accross many *.M3U files.

If you create an icons directory, the "Text" buttons will be replaced by graphical buttons. The files are:
back.ico, delete.ico, fwd.ico, next.ico, pause.ico, play.ico, prev.ico, record.ico, stop.ico.

email me and I'll send the icons I created ;-)

- Post any problems on the Forums - there shouldn't be anything major, though. If anyone makes any improvements, I'd be glad to see them...


Things to do:
I'd like to add some ID3 Tag Reading functionality to get Artist, Tempo etc but have struggled to find a library or function that reliably extracts that info.
I'd really like to add some facility to alter the Pitch / Tempo of a track - but suspect that is way beyond my ability (can anyone out there help?)







; PureBasic Visual Designer v3.62


;- MenuBar Constants
;
#MenuBar_9 = 0
#MENU_1 = 1
#MENU_2 = 2
#MENU_3 = 3
#MENU_6 = 4
#MENU_4 = 5

;- Gadget Constants
;
#STATUS=0
#B_PLAYLIST = 1
#LOAD = 2
#SAVE = 3
#DELETE = 4
#PROGRESS = 5
#FADEIN = 6
#FADEOUT = 7
#VOLUME = 8
#T_PROGRESS = 9
#T_START = 10
#T_STOP = 11
#BALANCE = 12
#PLAYLIST_FILE = 13
#B_TRACKLIST = 14
#TRACKINFO = 15
#REW = 16
#FF = 17
#PAUSE = 18
#PLAY = 19
#STOP = 20
#PREV = 23
#NEXT = 24
#TRACKLIST = 25
#PLAYLIST = 26
#RECORD = 29

;-PlayList AutoNav*
#PL_MOVEDN = 21
#PL_MOVEUP = 22
#PL_DELTRK =27
#PL_STOP=28

#IMG_STOP=9

#IMG_PLAY=1
#IMG_PAUSE=2
#IMG_FWD=3
#IMG_REW=4
#IMG_PREV=5
#IMG_NEXT=6
#IMG_DEL=7
#IMG_REC=8

;- StatusBar Constants
;
#StatusBar_11 = 0

;- Other Stuff

DefType.l
#FRAMEDIV.f=1000000000
#DEBUG=1
#DELAY=10
TRACKCTR=0
Global TRACKCTR



Procedure.s ReadINI(section.s,key.s,empty.s,inifile.s)
result.s=Space(255)
GetPrivateProfileString_(section,key,empty,@result,255,inifile)
ProcedureReturn result.s
EndProcedure




Procedure.l WriteINI(section.s,key.s,value.s,inifile.s)
ProcedureReturn WritePrivateProfileString_(section,key,value,inifile)
EndProcedure






Procedure Open_Window_0()
If OpenWindow(0, 343, 80, 614, 349, #PB_Window_SystemMenu |#PB_Window_TitleBar | #PB_Window_BorderLess | #PB_Window_ScreenCentered , "New window ( 0 )")
SetWindowPos_(WindowID(),#HWND_TOPMOST,200,200,0,0,#SWP_NOMOVE|#SWP_NOSIZE)
; If CreateMenu(#MenuBar_9, WindowID())
; MenuTitle("File")
; MenuItem(#MENU_1, "Open")
; MenuItem(#MENU_2, "Save")
; MenuItem(#MENU_3, "Save As")
; MenuItem(#MENU_6, "New")
; MenuBar()
; MenuItem(#MENU_4, "Quit")
; MenuTitle("Help")
; EndIf


; If CreateStatusBar(#StatusBar_11, WindowID()): EndIf

If CreateGadgetList(WindowID())
ComboBoxGadget(#PLAYLIST, 20, 30, 220, 240, #PB_ComboBox_Editable): AddGadgetItem(#PLAYLIST,0,"Recent Playlists:")
Frame3DGadget(#B_PLAYLIST, 10, 10, 600, 51, "Playlist Manager")
ButtonGadget(#LOAD, 250, 30, 40, 20, "Load")
; ButtonGadget(#SAVE, 290, 30, 40, 20, "Save")
; ButtonGadget(#DELETE, 560, 30, 40, 20, "Delete")
TrackBarGadget(#PROGRESS, 190, 70, 370, 20, 0, 10000)
TrackBarGadget(#FADEIN, 190, 90, 370, 20, 0, 10000): SetGadgetState(#FADEIN,0)
TrackBarGadget(#FADEOUT, 190, 110, 370, 20, 0, 10000): SetGadgetState(#FADEOUT,10000)
TrackBarGadget(#VOLUME, 70, 75, 100, 15, 0, 100): SetGadgetState(#VOLUME,100)
TextGadget(#T_PROGRESS, 560, 70, 50, 20, "Progress")
TextGadget(#T_START, 560, 90, 50, 20, "FadeIn")
TextGadget(#T_STOP, 560, 110, 50, 20, "FadeOut")
TrackBarGadget(#BALANCE, 70, 115, 100, 15, 0, 200): SetGadgetState(#BALANCE,100)
StringGadget(#PLAYLIST_FILE, 300, 30, 300, 20, "")
Frame3DGadget(#B_TRACKLIST, 10, 53, 600, 95, "Track Manager")
Frame3DGadget(#B_TRACKLIST, 10, 140, 600, 190, "TrackList Manager")
ListViewGadget(#TRACKINFO, 420, 160, 180, 150): AddGadgetItem(#TRACKINFO,0,"");: AddGadgetColumn(#TRACKINFO,1,"Value",86)
ListViewGadget(#TRACKLIST, 40, 160,380,150)
TextGadget(#STATUS,550,312,55,12,"STATUS")
If (LoadImage(#IMG_REW, "./icons/back.ico")): ButtonImageGadget(#REW, 30, 90, 20, 20, UseImage(#IMG_REW)): Else: ButtonGadget(#REW,30,90,20,20,"<<"): EndIf
If (LoadImage(#IMG_FWD, "./icons/fwd.ico")): ButtonImageGadget(#FF, 70, 90, 20, 20, UseImage(#IMG_FWD)): Else: ButtonGadget(#FF,70,90,20,20,">>"): EndIf
If (LoadImage(#IMG_PAUSE, "./icons/pause.ico")): ButtonImageGadget(#PAUSE, 140, 90, 20, 20, UseImage(#IMG_PAUSE)): Else: ButtonGadget(#PAUSE,140,90,20,20,"||"): EndIf
If (LoadImage(#IMG_PLAY, "./icons/play.ico")): ButtonImageGadget(#PLAY, 50, 90, 20, 20, UseImage(#IMG_PLAY)): Else: ButtonGadget(#PLAY,50,90,20,20,">"): EndIf
If (LoadImage(#IMG_STOP, "./icons/stop.ico")): ButtonImageGadget(#STOP, 120, 90, 20, 20, UseImage(#IMG_STOP)): Else: ButtonGadget(#STOP,120,90,20,20,"!"): EndIf
If (LoadImage(#IMG_REC, "./icons/record.ico")): ButtonImageGadget(#RECORD, 95, 90, 20, 20, UseImage(#IMG_REC)): Else: ButtonGadget(#RECORD,95,90,20,20,"O"): EndIf
If (LoadImage(#IMG_PREV, "./icons/prev.ico")): ButtonImageGadget(#PREV, 50, 70, 20, 20, UseImage(#IMG_PREV)): Else: ButtonGadget(#PREV,50,70,20,20,"A"): EndIf
If (LoadImage(#IMG_NEXT, "./icons/next.ico")): ButtonImageGadget(#NEXT, 50, 110, 20, 20, UseImage(#IMG_NEXT)): Else: ButtonGadget(#NEXT,50,110,20,20,"V"): EndIf
If (LoadImage(#IMG_DEL, "./icons/delete.ico")): ButtonImageGadget(#PL_DELTRK,16,160,20,20,UseImage(#IMG_DEL)): Else: ButtonGadget(#PL_DELTRK,16,160,20,20,"X"): EndIf
If (LoadImage(#IMG_PREV, "./icons/prev.ico")): ButtonImageGadget(#PL_MOVEUP,16, 180, 20, 20, UseImage(#IMG_PREV)): Else: ButtonGadget(#PL_MOVEUP,16,180,20,20,"A"): EndIf
If (LoadImage(#IMG_NEXT, "./icons/next.ico")): ButtonImageGadget(#PL_MOVEDN,16, 200, 20, 20, UseImage(#IMG_NEXT)): Else: ButtonGadget(#PL_MOVEDN,16,200,20,20,"V"): EndIf
If (LoadImage(#IMG_STOP, "./icons/stop.ico")): ButtonImageGadget(#PL_STOP,16, 220, 20, 20, UseImage(#IMG_STOP)): Else:ButtonGadget(#PL_STOP,16,220,20,20,"!"): EndIf

EndIf
EndIf
EndProcedure



Procedure.s LoadPlayList()
_index=0
_pl$=OpenFileRequester("Load Playlist","C:\My Music\*.m3u","PlayList|*.m3u|Track|*.mp3",1, #PB_Requester_MultiSelection)
_seek=0

;- Load Tracks from M3U File(s)

If (GetExtensionPart(_pl$)="m3u")
If (ReadFile(_file, _pl$))
SetGadgetText(#PLAYLIST_FILE,_pl$)
AddGadgetItem(#PLAYLIST,-1,_pl$)
Repeat:
_track$=ReadString():
If (FileSize(_track$)>1000): LoadMovie(1,_track$):
If (MovieLength()>0): _index=_index+1: AddGadgetItem(#TRACKLIST,-1,_track$): TRACKCTR=TRACKCTR+1: EndIf:
EndIf

Until Eof(_file)
EndIf
EndIf

;- Load Tracks from MP3 File(s)

If ( GetExtensionPart(_pl$)="mp3")
SetGadgetText(#PLAYLIST_FILE,"Multiple MP3 Selection")
_track$=_pl$
Repeat:
If (FileSize(_track$)>1000): LoadMovie(1,_track$): If (MovieLength()>0):
_index=_index+1: AddGadgetItem(#TRACKLIST, -1, _track$): TRACKCTR=TRACKCTR+1: EndIf: EndIf
_track$=NextSelectedFileName()
Until _track$=""
EndIf
AddGadgetItem(#TRACKLIST,-1," - END OF PLAYLIST -")
ProcedureReturn _pl$
EndProcedure




Procedure$ PlayTrack(_track$,_index)

_vol$=ReadINI(_track$,"VOL","100","./PlayerTracks.db")
_fadein$=ReadINI(_track$,"FADEIN","0","./PlayerTracks.db")
_fadeout$=ReadINI(_track$,"FADEOUT","10000","./PlayerTracks.db")

SetGadgetState(#VOLUME,Val(_vol$))

If (_track$=" - STOP -"): StopMovie(): ProcedureReturn("READY"): EndIf

If (IsFilename(_track$) Or FileSize(_track$)<1000 ): ProcedureReturn("BAD FILE"): EndIf

LoadMovie(1,_track$)

If (MovieLength()<0):
ProcedureReturn("BAD FILE")
Else:
SetGadgetState(#TRACKLIST,GetGadgetState(#TRACKLIST)):
LoadMovie(1,_track$): PlayMovie(1,0)
; FreeGadget(#PROGRESS): TrackBarGadget(#PROGRESS, 190, 70, 370, 20, 0, 10000)
; FreeGadget(#FADEIN): TrackBarGadget(#FADEIN, 190, 90, 370, 20, 0, 10000)
; FreeGadget(#FADEOUT): TrackBarGadget(#FADEOUT, 190, 110, 370, 20, 0, 10000):
; SetGadgetState(#FADEOUT,MovieLength()/#FRAMEDIV)

SetGadgetState(#FADEIN,Val(_fadein$))
SetGadgetState(#FADEOUT,Val(_fadeout$))


MovieSeek(GetGadgetState(#FADEIN) * (MovieLength()/10000))

RemoveGadgetItem(#TRACKINFO,1): AddGadgetItem(#TRACKINFO,1,"FileName"+Space(10)+GetFilePart(_track$))
RemoveGadgetItem(#TRACKINFO,2): AddGadgetItem(#TRACKINFO,2,"FileSize "+Space(10)+Str(FileSize(_track$))+" Bytes")
RemoveGadgetItem(#TRACKINFO,3): AddGadgetItem(#TRACKINFO,3,"# Frames"+Space(10)+Str(MovieLength()/10000)+" Frames")
ProcedureReturn("PLAYING")

Debug "MovieLength: "+Str(MovieLength()),#DEBUG
Debug "FRAMEDIV: "+Str(#FRAMEDIV),#DEBUG
Debug "xxx: "+Str(MovieLength()/#FRAMEDIV),#DEBUG

EndIf

EndProcedure











Procedure RecordTrackSettings(_track$,_vol,_fadein,_fadeout)
;
; writeINI(section.s,key.s,value.s,inifile.s)
;
WriteINI(_track$,"VOL",Str(_vol),"./PlayerTracks.db")
WriteINI(_track$,"FADEIN",Str(_fadein),"./PlayerTracks.db")
ProcedureReturn WriteINI(_track$,"FADEOUT",Str(_fadeout),"./PlayerTracks.db")


EndProcedure






;-MAIN#######################################



If (InitMovie()): Else: MessageRequester("Fatal Error","Can't Initialise Movie Player",1): EndIf

LOOPCTR=0

Open_Window_0()
AdvancedGadgetEvents(#TRUE)
STATUS$="READY": reps=0
_vol=100: bal=0

Repeat: EventID = WindowEvent(): Delay(#DELAY)
reps=reps+1
SetGadgetText(#STATUS,STATUS$)

If (STATUS$="PLAYING"); And reps=1)
RemoveGadgetItem(#TRACKINFO,4): AddGadgetItem(#TRACKINFO,4,"Position"+Space(10)+Str(MovieStatus()/10000))
RemoveGadgetItem(#TRACKINFO,5): AddGadgetItem(#TRACKINFO,5,"Fadein "+Space(10)+Str(GetGadgetState(#FADEIN)*(MovieLength()/10000)/10000))
RemoveGadgetItem(#TRACKINFO,6): AddGadgetItem(#TRACKINFO,6,"Fadeout"+Space(10)+Str(GetGadgetState(#FADEOUT) * (MovieLength()/10000)/10000))
RemoveGadgetItem(#TRACKINFO,7): AddGadgetItem(#TRACKINFO,7,"# Tracks"+Space(10)+Str(TRACKCTR))
SetGadgetState(#PROGRESS,MovieStatus()/(MovieLength()/10000)):
EndIf

If (reps=1): SetGadgetText(#STATUS,STATUS$) : EndIf
If (STATUS$="SEEK")
_divfactor.f=MovieLength()/10000
_seek.f=GetGadgetState(#PROGRESS)*_divfactor.f
RemoveGadgetItem(#TRACKINFO,4): AddGadgetItem(#TRACKINFO,4,"Position"+Space(10)+Str(MovieStatus()/10000)):
MovieSeek(_seek.f)
EndIf

If (GetGadgetState(#PROGRESS)>GetGadgetState(#FADEOUT)+1 And STATUS$<>"STOPPED" ); And reps=1):
_vol=_vol-1: MovieAudio(_vol,_bal): SetGadgetState(#VOLUME,_vol)
If (_vol=0):
_vol=100: SetGadgetState(#TRACKLIST,GetGadgetState(#TRACKLIST)+1): STATUS$=PlayTrack(GetGadgetText(#TRACKLIST),GetGadgetState(#TRACKLIST)):
EndIf
EndIf

If (GetGadgetState(#PROGRESS)>=9997)
SetGadgetState(#TRACKLIST,GetGadgetState(#TRACKLIST)+1): STATUS$=PlayTrack(GetGadgetText(#TRACKLIST),GetGadgetState(#TRACKLIST))
EndIf


If (GetGadgetText(#TRACKLIST)=" - END OF PLAYLIST -"): STATUS$="READY": StopMovie(): EndIf

If (reps>=300): reps=0: EndIf

If (GetGadgetState(#FADEIN)<0 Or GetGadgetState(#FADEOUT)<0): STATUS$="BAD FILE": EndIf

Select EventID:
Case #PB_EventGadget:
Select EventGadgetID():
Case #PLAYLIST: GID=0
Case #TRACKLIST: Select EventType():
Case #PB_EventType_LeftDoubleClick: STATUS$=PlayTrack(GetGadgetText(#TRACKLIST),GetGadgetState(#TRACKLIST))
EndSelect
Case #LOAD: PLAYLIST$=LoadPlayList()
Case #SAVE: GID=0
Case #DELETE: GID=0
Case #REW: MovieSeek(MovieStatus()-9999999)
Case #FF: MovieSeek(MovieStatus()+9999999)
Case #PAUSE: PauseMovie(): STATUS$="PAUSED"
Case #PLAY: Select STATUS$
Case "SEEK": STATUS$="RESUME"
Case "PAUSED" : ResumeMovie(): STATUS$="PLAYING"
Case "PLAYING": STATUS$=PlayTrack(GetGadgetText(#TRACKLIST),GetGadgetState(#TRACKLIST))
Case "STOPPED": STATUS$=PlayTrack(GetGadgetText(#TRACKLIST),GetGadgetState(#TRACKLIST))
Case "READY": STATUS$=PlayTrack(GetGadgetText(#TRACKLIST),GetGadgetState(#TRACKLIST))
EndSelect
Case #STOP: StopMovie(): STATUS$="STOPPED"
Case #PREV: SetGadgetState(#TRACKLIST,GetGadgetState(#TRACKLIST)-1): STATUS$=PlayTrack(GetGadgetText(#TRACKLIST),GetGadgetState(#TRACKLIST))
Case #NEXT: SetGadgetState(#TRACKLIST,GetGadgetState(#TRACKLIST)+1): STATUS$=PlayTrack(GetGadgetText(#TRACKLIST),GetGadgetState(#TRACKLIST))
Case #PROGRESS: STATUS$="SEEK":
Case #VOLUME: MovieAudio(GetGadgetState(#VOLUME), GetGadgetState(#BALANCE)-100): _vol=GetGadgetState(#VOLUME)
Case #BALANCE: MovieAudio(GetGadgetState(#VOLUME), GetGadgetState(#BALANCE)-100): _bal=GetGadgetState(#BALANCE)-100
Case #PL_DELTRK: RemoveGadgetItem(#TRACKLIST,GetGadgetState(#TRACKLIST)): SetGadgetState(#TRACKLIST,GetGadgetState(#TRACKLIST))
Case #PL_MOVEUP: _tmppos=GetGadgetState(#TRACKLIST): _tmpitem$=GetGadgetText(#TRACKLIST):
If (_tmppos>0):
RemoveGadgetItem(#TRACKLIST,GetGadgetState(#TRACKLIST)):
AddGadgetItem(#TRACKLIST,_tmppos-1,_tmpitem$):
SetGadgetState(#TRACKLIST,_tmppos-1)
EndIf

Case #PL_MOVEDN: _tmppos=GetGadgetState(#TRACKLIST): _tmpitem$=GetGadgetText(#TRACKLIST):
If (_tmppos<TRACKCTR-1)
RemoveGadgetItem(#TRACKLIST,GetGadgetState(#TRACKLIST)):
AddGadgetItem(#TRACKLIST,_tmppos+1,_tmpitem$):
SetGadgetState(#TRACKLIST,_tmppos+1)
EndIf
Case #PL_STOP: _tmppos=GetGadgetState(#TRACKLIST):
AddGadgetItem(#TRACKLIST,_tmppos," - STOP -")
SetGadgetState(#TRACKLIST,_tmppos):
Case #RECORD: OSTATUS$=STATUS$: STATUS$="RECORD": SetGadgetText(#STATUS,STATUS$)
_result=RecordTrackSettings(GetGadgetText(#TRACKLIST),GetGadgetState(#VOLUME),GetGadgetState(#FADEIN),GetGadgetState(#FADEOUT))
EndSelect
Case #PB_Event_Menu:
Case #PB_Event_CloseWindow: Exit=1
Case #PB_Event_Repaint:
Case #PB_Event_MoveWindow
EndSelect
Delay(#DELAY)
Select STATUS$:
Case "RESUME": STATUS$="PLAYING"
Case "BAD FILE": SetGadgetText(#STATUS,STATUS$):
Delay(#DELAY*1): SetGadgetState(#TRACKLIST,GetGadgetState(#TRACKLIST)+1):
STATUS$=PlayTrack(GetGadgetText(#TRACKLIST),GetGadgetState(#TRACKLIST)):
Case "RECORD": Delay(#DELAY*30): STATUS$=OSTATUS$: SetGadgetText(#STATUS,STATUS$)
EndSelect

Until Exit=1

Posted: Sun Jul 06, 2003 4:41 pm
by merendo
First: Nice work, buddy but the proggy looks a little bit too grey. More colors and colorfull images would be nice...

Second: I recommend you to use a professional Soundengine like FMod (http://www.fmod.org) because that raises your possibilities greatly. Echo, fade in and even an equalizer would be no problem anymore...

There is an example how to use FMod with PB, wait a second, I got the URL somewhere... Ok here it is: [url]ttp://www.purebasic.de/files/fmod.exe[/url].

Good luck and keep us posted ;)

FMOD

Posted: Mon Jul 07, 2003 1:00 pm
by naw
Thanks Merendo,

I downloaded the ZIP file from fmod.org - Blimey, looks a bit complicated...

The features I need are pitch/tempo control and some means of extracting ID3 v1/v2 tag info which I cant see in the FMOD docs...

FMOD might be a bit beyond me at this point, but I'll have a play around.

Ta - Nigel

Posted: Sun Aug 10, 2003 2:09 pm
by merendo
Look at www.purebasic.com at the downloads section. You will find an MP3-Player there. Perhaps this will also help you. Using the windows API and the MCI Interface could be very useful for you. Check the microsoft homepage for a documentation.

Bye!

Posted: Fri Aug 15, 2003 10:18 pm
by Johan_Haegg
Ok, this is how ID3v1 works:
Look in the 128 last bytes of the file for TAG, the following 125 bytes contain:
30bytes Song Title
30bytes Artist
30bytes Album
4bytes Year
30bytes Comment
1byte Genre

I have not tried this myself, but ill probably do tomorrow.