'*************************************************** '* 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 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 ' LOCAL longtimecounter 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 DIM Score(0) AS GLOBAL Score_Type start ' we start by opening the midi-out device for the internal synth. mididevice = 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$(1) 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 OPEN "aslsp-raw.csv" FOR INPUT AS #s 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 OPEN "aslsp.txt" FOR INPUT AS #f WHILE NOT EOF(f) INPUT #f, dummy dummy = TRIM$(UCASE$(dummy)) SELECT CASE dummy CASE "DUUR" INPUT #f, duur CASE "SCALE" INPUT #f, scalefactor ' multiplier for the timevalues in the file ' 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 END SELECT WEND CLOSE #f ' algoritme voor de berekening van de scalefactor: eindduur = duur * 3600 ' omzetting van uren naar sekonden scalefactor = eindduur / Score(cnt-1).timval ' de 1000 multiplier in reeds verrekend in ms/s verhouding. ' 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 144,7,127 ' volume DO ' programma begint op marker ' we spelen gelijktijdige noten ook gelijktijdig: DO retval = 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 retval = SlowPlay ((Score(marker+1).timval - Score(marker).timval) * scalefactor) ' this function returns 1 if it is time for a next note ' it returns -1 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) WAITKEY$ ' close midi port: midiInClose hmo ' write the place where we left of to the file: OPEN "aslsp.txt" FOR APPEND AS #f PRINT #f, DATE$, TIME$ PRINT #f, "INTERRUPTED " , STR$(Bigtime) PRINT #f, "MARKER ", STR$(Marker) PRINT #f, "SCALEFACTOR", STR$(Scalefactor) CLOSE #f 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 21,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 k$ IF ISFALSE timestart THEN timestart = Bigtime ' reinitialized on every call END IF DO SLEEP 1 ' we check every second, so thats our smallest resolution now ' if we leave the sleep out, we cannot use the computer for anything else... timenow = Bigtime IF timenow - bigtime >= 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$,3,2)) * 60) + VAL(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