'*************************************************** '* John Cage * '* "aslsp" * '*************************************************** '* software by * '* Godfried-Willem Raes * '* and * '* Kristof Lauwers * '*************************************************** ' 10.10.2007: First design of program. ' The piece can go on for days. ' If interrupted, by stopping the program, ' the performance will take up again where is left of. #COMPILE EXE #DIM ALL #INCLUDE "C:\B\pb\Winapi\win32api.inc" ' meta-compiler statement - include Windows functions #INCLUDE "C:\B\pb\gmt\g_kons.bi" ' include constants for GMT #INCLUDE "C:\B\pb\gmt\g_type.bi" ' include structures #INCLUDE "C:\B\pb\gmt\g_lib.bi" ' include DLL library via the declarations #INCLUDE "c:\b\pb\gmt\g_indep.bi" TYPE Score_Type BYTE timval AS DWORD statusbyte AS BYTE noot AS BYTE velo AS BYTE END TYPE GLOBAL Score() AS Score_Type DECLARE SUB Start () DECLARE FUNCTION Bigtime() AS QUAD ' returns the time in seconds since beginning of the year DECLARE FUNCTION Slowplay (timval AS QUAD) AS LONG ' very slow timing function DECLARE SUB Einde (hmo AS DWORD) FUNCTION PBMAIN () AS LONG STATIC t AS DWORD STATIC f AS LONG STATIC s AS LONG STATIC marker AS DWORD LOCAL dummy AS STRING STATIC value AS DWORD LOCAL longtime AS QUAD STATIC hmo AS LONG STATIC mididevice AS LONG LOCAL maand AS LONG LOCAL dag AS LONG LOCAL jaar AS LONG LOCAL cnt AS LONG STATIC scalefactor AS DOUBLE STATIC retval AS LONG STATIC duur AS DWORD STATIC eindduur AS QUAD logfile "start aslsp log","aslsp-debug.log" DIM Score(0) AS GLOBAL Score_Type start ' we start by opening the midi-out device for the internal synth. mididevice = 0 '1 ' 0= mpu, 1= internal synth ' the number here depends on your configuration. hmo = OpenMidiOutputDevice (mididevice) IF ISFALSE hmo THEN LOCATE 10,10 PRINT "Cannot open midi output device nr "; STR$(mididevice) WAITKEY$ EXIT FUNCTION ELSE LOCATE 10,10: PRINT "Midi output device opened succesfully" END IF ' this being done, we should read where we left of last time. LOCATE 12,10: PRINT "To interrupt the performance, the * key should be pressed!" longtime = Bigtime () LOCATE 13,10: PRINT "Bigtime now=" , longtime; "seconds since the start of the millenium" ' test for function ' eerst lezen we de gehele partituur in een array - inlezen uit file. ' we bepalen de originele duur ervan: s = FREEFILE ERRCLEAR OPEN "aslsp-raw.csv" FOR INPUT AS #s IF ERR THEN LOCATE 16,10: PRINT "Score not found! Press any key to exit" WAITKEY$ EXIT FUNCTION END IF cnt = 0 LINE INPUT #s, dummy ' eerste regel is tekst WHILE NOT EOF(s) INPUT #s,Score(cnt).timval, Score(cnt).statusbyte, Score(cnt).noot, Score(cnt).velo INCR cnt REDIM PRESERVE Score(cnt) AS GLOBAL Score_Type LOCATE 15,10: PRINT "Reading score line " ; STR$(cnt) WEND CLOSE #s LOCATE 16,10 : PRINT "Eindtijd= "; Score(cnt-1).timval ' nu hebben we de gehele partituur ingelezen en kennen we de totale duur in millisekonden ' de gewenste nieuwe duur is 160uur (4 maand a 5d/w a 8u/d ) ' dat is in sekonden 160 x 3600 = 576000 sekonden ' wanneer we de millisekonden als sekonden interpreteren hebben we alvast een 1000x rescaling ' daarbovenop moeten we dan nog vermenigvuldigen met 567. ' Na het inlezen van het txt bestandje algoritmizeren we dit vanuit de gewenste duur in uren ' noot, duur ' open het bestandje waaruit we de tellerstand inlezen. f = FREEFILE ERRCLEAR OPEN "aslsp.txt" FOR INPUT AS #f IF ERR THEN LOCATE 16,10: PRINT "aslsp.txt not found! Press a key to exit" WAITKEY$ EXIT FUNCTION END IF WHILE NOT EOF(f) INPUT #f, dummy logfile "input:" + dummy dummy = TRIM$(UCASE$(dummy)) SELECT CASE dummy CASE "DUUR" ' INPUT #f, duur 'for some reason this failed - duur was allways 0 INPUT #f, dummy 'this works.. duur = VAL(dummy) logfile "duur:" + STR$(duur) CASE "SCALE" INPUT #f, scalefactor ' multiplier for the timevalues in the file logfile "scale:" + STR$(scalefactor) ' with scalefactor = 1, the file lasts 12 minutes (720" and 25ms) CASE "MARKER" INPUT #f, marker ' plaats waar we gekomen waren bij de vorige onderbreking logfile "marker:" + STR$(marker) END SELECT WEND CLOSE #f IF ISFALSE(duur) THEN LOCATE 20,10: PRINT "Error: Duration not given ins aslsp.txt. Press a key to exit." WAITKEY$ EXIT FUNCTION END IF ' algoritme voor de berekening van de scalefactor: eindduur = duur * 3600 ' omzetting van uren naar sekonden logfile "eindduur:" + STR$(eindduur) logfile "last timvalfor" + STR$(cnt-1) + ":" + STR$(Score(cnt-1).timval) scalefactor = eindduur / Score(cnt-1).timval ' de 1000 multiplier in reeds verrekend in ms/s verhouding. ' ' ' scalefactor = scalefactor/100000 ' ' logfile "scalefactor:" + STR$(scalefactor) ' marker is de pointer in het array waar we gekomen waren 's = freefile 'open "aslsp-raw.csv" for input as #f 'DO ' INPUT #s, timval, statusbyte, note, velo ' if timval >= marker then ' ' now we are at the place where we left off ' end if 'LOOP UNTIL EOF(#s) LOCATE 20,10: PRINT "Starting/continuing the performance..." ' vooraleer we beginnen, moeten we nog de juiste klankjes en andere parameters instellen op de soundcard... controller 0,7,127 ' volume Progchange 0, 18 DO ' programma begint op marker ' we spelen gelijktijdige noten ook gelijktijdig: DO retval = Score(marker).timval logfile "play event" + STR$(marker) + " - timval:" + STR$(score(marker).timval) Play Score(marker).statusbyte, Score(marker).noot, Score(marker).velo INCR marker IF marker > UBOUND(score) THEN Einde(hmo) LOOP UNTIL retval <> Score(marker).timval ' call function to wait for next step IF marker + 1 <= UBOUND(score) THEN OPEN "aslsp.txt" FOR APPEND AS #f PRINT #f, "MARKER " PRINT #f, STR$(Marker) CLOSE #f logfile "----ready for slowplay" logfile "marker timval:" + STR$(Score(marker).timval) logfile "marker-1 timval:" + STR$(Score(marker-1).timval) logfile "Scalefact:" + STR$(scalefactor) 'the below was before SlowPlay ((Score(marker+1).timval - Score(marker).timval) * scalefactor), which was a bug, as marker here allready points to the next event to play! retval = SlowPlay (((Score(marker).timval - Score(marker-1).timval) * scalefactor)) ' this function returns 1 if it is time for a next note ' it returns the time it was running bbefore interruption if it was interrupted by the user ELSE Einde hmo END IF IF retval = -1 THEN EXIT LOOP ' this handles user interruption LOOP UNTIL marker > UBOUND(Score) controller 0,123, 1 'allnotesoff ' close midi port: midiInClose hmo ' write the place where we left of to the file: OPEN "aslsp.txt" FOR APPEND AS #f PRINT #f, 'otherwise it puts the next input on the end of the last line in the file PRINT #f, DATE$, TIME$ PRINT #f, "INTERRUPTED " PRINT #f, STR$(Bigtime) PRINT #f, "MARKER " PRINT #f, STR$(Marker) PRINT #f, "SCALEFACTOR" PRINT #f, STR$(Scalefactor) CLOSE #f 'moved this to the very end, so we are sure that the file gets written also if people end the program by clicking in the top right corner LOCATE 20,10: PRINT "Playing interupted. Press any key to quit this program" WAITKEY$ END FUNCTION SUB Einde (hmo AS DWORD) LOCAL f AS LONG LOCAL i AS INTEGER FOR i = 0 TO 15 AllNotesOff i ' all channels NEXT i midiInClose hmo LOCATE 20,10: PRINT "This is the very end of the piece..." OPEN "aslsp.txt" FOR APPEND AS #f PRINT #f, DATE$, TIME$ PRINT #f, "INTERRUPTED " , STR$(Bigtime) 'PRINT #f, "MARKER ", STR$(Marker) PRINT #f, "PIECE PERFORMED COMPLETELY" CLOSE #f WAITKEY$ END END SUB FUNCTION Slowplay (timval AS QUAD) AS LONG LOCAL timestart AS QUAD LOCAL timenow AS QUAD LOCAL dt AS QUAD LOCAL k$ IF ISFALSE timestart THEN timestart = Bigtime ' reinitialized on every call END IF DO SLEEP 0 ' we check every second, so thats our smallest resolution now ' if we leave the sleep out, we cannot use the computer for anything else... ' kl: if we use sleep 0, we give all the time we don't need to other processes.. timenow = Bigtime IF (timenow - timestart) <> dt THEN dt = timenow - timestart LOCATE 22, 10: PRINT "Next chord on/of within" + STR$(timval - dt) + " seconds." END IF ' IF timenow - bigtime >= timval THEN 'this can't be correct!? IF timenow - timestart >= timval THEN FUNCTION = 1 EXIT FUNCTION END IF ' if the user presses the stop key, we exit the function k$ = INKEY$ ' this may not be responsive enough... IF k$ = "*" THEN FUNCTION = -1 EXIT FUNCTION END IF LOOP END FUNCTION FUNCTION BigTime () AS QUAD LOCAL longtime AS QUAD LOCAL maand AS LONG LOCAL dag AS LONG LOCAL jaar AS LONG LOCAL cnt AS LONG ' bereken eerst de tijd in sekonden sedert begin van het millenium: maand = VAL(LEFT$(DATE$,2)) dag = VAL(MID$(DATE$,4,2)) jaar = VAL(RIGHT$(DATE$,4)) jaar = jaar - 2000 'PRINT jaar, maand, dag dag = dag - 1 ' de dag waarop we zijn is nog niet verstreken, daarvan moeten we slechts de uren tellen dag = dag + (jaar * 365) ' aantal verstreken dagen sedert begin millenium maand = maand -1 ' de maand waarin we zijn is nog niet verstreken en daarvan moeten dus alleen de dagen geteld. SELECT CASE maand CASE 0 ' maanden niet bij te tellen, januari loopt nog CASE 1 ' februari dag = dag + 31 ' januari bijtellen CASE 2 ' maart dag = dag + 31 + 28 CASE 3 dag = dag + 31 + 28 + 31 CASE 4 dag = dag + 31 + 28 + 31 + 30 CASE 5 dag = dag + 31 + 28 + 31 + 30 + 31 CASE 6 dag = dag + 31 + 28 + 31 + 30 + 31 + 30 CASE 7 dag = dag + 31 + 28 + 31 + 30 + 31 + 30 + 31 CASE 8 dag = dag + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 CASE 9 dag = dag + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 CASE 10 dag = dag + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 CASE 11 dag = dag + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 END SELECT ' tijd in sekonden sedert middernacht: longtime = (VAL(LEFT$(TIME$,2)) * 3600) + (VAL(MID$(TIME$,4,2)) * 60) + VAL(RIGHT$(TIME$,2)) logfile "compute longtime" logfile TIME$ logfile LEFT$(TIME$,2) logfile MID$(TIME$,3,2) logfile RIGHT$(TIME$,2) FUNCTION = (dag * 24 * 3600) + longtime END FUNCTION SUB Start () CLS LOCATE 1,1: PRINT " L O G O S O F T" LOCATE 2,1: PRINT " ***************" LOCATE 3,1: PRINT " a program for the performance of John Cage's " LOCATE 4,1: PRINT " written by" LOCATE 5,1: PRINT " dr.Godfried-Willen Raes" LOCATE 6,1: PRINT " and" LOCATE 7,1: PRINT " Kristof Lauwers" LOCATE 8,1: PRINT " commisioned by Stedelijke Muziekakademie Sint Niklaas" LOCATE 9,1: PRINT " october 2007" END SUB