'***************************************************
'* 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