'--------------------------------------------------------------------------------- ' ' This program started as a demonstration program for the experimental GUI widgets ' and now has grown into a plain but usuable MIDI file player. ' ' To compile this program, make sure to obtain all the plugins from the BaCon ' website, then adjust the path to those files below accordingly. ' ' April 2016, Peter van Eerten - MIT License ' '--------------------------------------------------------------------------------- ' Adjust to the correct paths INCLUDE canvas.bac INCLUDE canvas-plugin-gui.bac INCLUDE ../openal.bac INCLUDE ../openal-plugin-syn.bac ' Create configuration directory IF NOT(FILEEXISTS(GETENVIRON$("HOME") & "/.canvas-midiplayer")) THEN MAKEDIR GETENVIRON$("HOME") & "/.canvas-midiplayer" ENDIF ' Memorize the choosen sound font CONST SF_Config$ = GETENVIRON$("HOME") & "/.canvas-midiplayer/soundfont.cfg" ' Memorize the last directory with MIDI files CONST DIR_Config$ = GETENVIRON$("HOME") & "/.canvas-midiplayer/lastdir.cfg" ' Initialize OpenAL sound renderer OPENAL_INIT DECLARE Sound_Font$, Last_Dir$ DECLARE Current_Song, Currently_Playing DECLARE cfg TYPE FILE* '--------------------------------------------------------------------------------- SUB Populate_Filelist(id) LOCAL file$ LOCAL dir TYPE DIR* LOCAL dc, fc, i ' Empty the file list GUI_Set_String(id, "label", "") ' Count all directories and files first OPEN CURDIR$ FOR DIRECTORY AS dir REPEAT GETFILE file$ FROM dir IF NOT(LEN(file$)) THEN CONTINUE IF FILETYPE("./" & file$) = 2 THEN INCR dc IF LCASE$(RIGHT$(file$, 4)) = ".mid" OR LCASE$(RIGHT$(file$, 4)) = ".sf2" THEN INCR fc UNTIL ISFALSE(LEN(file$)) CLOSE DIRECTORY dir ' Dynamic arrays to store all names LOCAL d$ TYPE STRING ARRAY dc LOCAL f$ TYPE STRING ARRAY fc dc = fc = 0 ' Now get all the dir and filenames OPEN CURDIR$ FOR DIRECTORY AS dir REPEAT GETFILE file$ FROM dir IF NOT(LEN(file$)) THEN CONTINUE IF FILETYPE("./" & file$) = 2 THEN d$[dc] = file$ INCR dc ENDIF IF LCASE$(RIGHT$(file$, 4)) = ".mid" OR LCASE$(RIGHT$(file$, 4)) = ".sf2" THEN f$[fc] = file$ INCR fc ENDIF UNTIL ISFALSE(LEN(file$)) CLOSE DIRECTORY dir ' Sort everything IF dc > 0 THEN SORT d$ SIZE dc-1 IF fc > 0 THEN SORT f$ SIZE fc-1 ' Write results to widget FOR i = 0 TO dc-1 GUI_Set_String(id, "label", d$[i]) NEXT FOR i = 0 TO fc-1 GUI_Set_String(id, "label", f$[i]) NEXT END SUB '--------------------------------------------------------------------------------- SUB List_CB(id) LOCAL select$ select$ = GUI_Get_String$(id, "label") IF NOT(LEN(select$)) THEN EXIT IF select$ = ".." OR FILETYPE("./" & select$) = 2 THEN CHANGEDIR select$ CALL Populate_Filelist(id) ELIF LCASE$(RIGHT$(select$, 4)) = ".sf2" THEN GUI_Set_String(font_label, "label", select$) Sound_Font$ = CURDIR$ & "/" & select$ OPEN SF_Config$ FOR WRITING AS cfg WRITELN Sound_Font$ TO cfg CLOSE FILE cfg ENDIF END SUB '--------------------------------------------------------------------------------- SUB Play_CB(id) IF SYN_BUSY(Current_Song) THEN SYN_STOP(Current_Song) IF FILEEXISTS(CURDIR$ & "/" & GUI_Get_String$(file_list, "label")) AND LEN(Sound_Font$) AND RIGHT$(CURDIR$ & "/" & GUI_Get_String$(file_list, "label"), 4) = ".mid" THEN Current_Song = SYN_OPEN(CURDIR$ & "/" & GUI_Get_String$(file_list, "label"), Sound_Font$) CALL Vol_CB(volume) SYN_PLAY(Current_Song) GUI_Set_String(file_label, "label", "Playing: " & GUI_Get_String$(file_list, "label")) Currently_Playing = TRUE OPEN DIR_Config$ FOR WRITING AS cfg WRITELN CURDIR$ TO cfg CLOSE FILE cfg ENDIF END SUB SUB Next_CB(id) LOCAL row IF SYN_BUSY(Current_Song) THEN SYN_STOP(Current_Song) SYN_CLOSE(Current_Song) ENDIF row = GUI_Get_Property(file_list, "value") INCR row GUI_Set_Property(file_list, "value", row) IF GUI_Get_Property(file_list, "value") = row THEN CALL Play_CB(0) ELSE Currently_Playing = FALSE ENDIF END SUB SUB Stop_CB(id) IF SYN_BUSY(Current_Song) THEN SYN_STOP(Current_Song) SYN_CLOSE(Current_Song) Currently_Playing = FALSE ENDIF END SUB SUB Exit_CB(id) IF SYN_BUSY(Current_Song) THEN SYN_CLOSE(Current_Song) SYN_FREE OPENAL_FREE QUIT END SUB SUB Vol_CB(id) SYN_VOLUME(Current_Song, GUI_Get_Property(id, "value")/100) ENDSUB SUB Player_Events LOCAL row INK(255,255,255,255) CLS ' Fill sound buffers IF SYN_BUSY(Current_Song) THEN SYN_UPDATE(Current_Song) ELIF Currently_Playing THEN CALL Next_CB(0) ENDIF ' Update GUI GUI_Events END SUB '--------------------------------------------------------------------------------- ' First goto last known directory IF FILEEXISTS(DIR_Config$) THEN OPEN DIR_Config$ FOR READING AS cfg READLN Last_Dir$ FROM cfg CLOSE FILE cfg IF FILEEXISTS(Last_Dir$) THEN CHANGEDIR Last_Dir$ ENDIF ENDIF ' Gui definition from here WINDOW("A midi player in an OpenGL canvas", 800, 500) GUI_Background_Color(255, 255, 255, 255) GUI_Foreground_Color(64, 64, 190, 255) GUI_Font_Color(16, 16, 128, 255) GUI_Font_Size(0.6) file_list = GUI_List(30, 30, 440, 400, List_CB) Populate_Filelist(file_list) GUI_Frame("Sound font", 500, 30, 270, 90) font_label = GUI_Label("", 520, 80) GUI_Frame("Controls", 500, 150, 270, 100) play_button = GUI_Button("PLAY", 520, 180, 70, 50, Play_CB) pause_button = GUI_Button("NEXT", 600, 180, 70, 50, Next_CB) stop_button = GUI_Button("STOP", 680, 180, 70, 50, Stop_CB) GUI_Frame("Volume", 500, 280, 270, 80) volume = GUI_HSlider(530, 320, 210, 10, 0, 100, Vol_CB) GUI_Set_Property(volume, "value", 80) GUI_Label("The MIDI player", 510, 400) exit_button = GUI_Button("EXIT", 670, 380, 100, 50, Exit_CB) file_label = GUI_Label("File:", 30, 460) ' Check sound font configuration file IF FILEEXISTS(SF_Config$) THEN OPEN SF_Config$ FOR READING AS cfg READLN Sound_Font$ FROM cfg CLOSE FILE cfg IF FILEEXISTS(Sound_Font$) THEN GUI_Set_String(font_label, "label", MID$(Sound_Font$, INSTRREV(Sound_Font$, "/")+1)) ENDIF ENDIF ' Some callback to handle our drawing CALLBACK(40, Player_Events) WAITKEY