Dr.Godfried-Willem RAES

Kursus Experimentele Muziek: Boekdeel 1: Algoritmische Kompositie

Hogeschool Gent : Departement Muziek & Drama


<Terug naar inhoudstafel kursus>

   

1605:

 

Checking SYS-EX dump files

 

In hoofdstuk 5 behandelen we heel wat kommercieel verkrijgbare software waarmee midi-sturing, notatie en tot op zekere hoogte ook wel kompositie kan gebeuren. Een nauw met het gebruik van programmeerbare midi apparatuur verbonden probleem is gelegen in de noodzaak een back-up te maken van alle instellingen van de voor een bepaald stuk of projekt nodige apparatuur.

Uiteraard kunnen we hetzij via de bedieningsknoppen, hetzij via een externe sequencer, hetzij via een eigen programma, via system-exclusives dumps maken van zowat de gehele geheugeninhoud van de synthesizer of de module. Maar, zekerheid omtrent de geldigheid van een dergelijke back-up hebben we eigenlijk nooit...

Een back-up waarop we niet kunnen vertrouwen is nu slechts evenveel waard als helemaal geen enkele backup. Uiteraard kunnen we de geldigheid nagaan, door de hele dump naar de module terug te sturen. Indien dit suksesrijk verloopt dan leven we natuurlijk in de beste van alle denkbare werelden. Helaas... vaak lukt dit niet, en blijkt dat er in de praktijk enkele bytes in de transmissie verloren zijn gegaan, waardoor onze dump de hele zorgvuldig ingestelde programmering volkomen in de mist doet gaan, en we bovendien over geen enkele backup meer beschikken.

De nood aan een kontrolemiddel op de validiteit van sys-ex files zal dan ook wel duidelijk zijn.

Terloops weze hier ten overvloede toch nog opgemerkt dat de beste metode om met een redelijk gerust gemoed alle eventualiteiten tegemoet te treden bestaat in het zorgvuldig bijhouden van een logboek voor elk afzonderlijk projekt. Hierin nemen we alle programmawijzigingen, hardware specs, bedradingen, beschrijvingen van de gebruikte apparatuur enzomeer op. In het meest ellendige geval van een totale systeem crash (bvb. het fyzisch stukgaan van de apparatuur zelf -een geval waartegen geen enkele backup opgewassen is-) beschik je dankzij een goed bijgehouden logboek, nog steeds over de mogelijkheid het ontwikkelingsproces van het projekt opnieuw na te gaan. Ook audioopnames van de 'laatst werkende' versies kunnen heel wat verduidelijken en maken het vaak mogelijk een gegeven kompositorisch idee voor een helemaal verschillend hardware platform uit te werken. Wanneer je geen logboek hebt, vervalt ook deze mogelijkheid en kan je alleen nog op je eigen geheugen terugvallen. Overschat je mogelijkheden echter niet wat dit betreft...

Een (nog slechts schetsmatig) programma waarmee we erin slaagden zoiets op te zetten kan verlopen alsvolgt:

 

' *************************************************

' * SYSEXCHK.BAS *

' * utility by Dr.Godfried-Wilem RAES *

' *************************************************

' 22.05.1995: utility for checking sysex-files as received from MBATCH...

' This program demonstrates a good solution for the problem

' Basic has when dealing with two's complement numbers.

' If a binary file contains a number (%,&...) with the msb set

' it will be considered negative and all math dealing with splitting

' the data in single byte components goes crazy...

' (cfr. RDFIL-routines as used for reading P%(i,j) files)

' The crucial insight used here is based on the possibility

' of using the statement byte=VAL("&HFF") after conversion of

' the numbers to hexadecimal strings...

 

REM $DYNAMIC

COMMON SHARED P%()

COMMON SHARED C$

DECLARE SUB RDFIL ()

DIM SHARED P%(0 TO 1000)

 

We gaan ervan uit dat de sys-ex dumps te vinden zijn op een floppy die in de A-drive steekt:

 

InPath$ = "A:\TSR\"

 

De goed bevonden sys-ex dumps worden naar de harddisk weggeschreven:

 

UitPath$ = "C:\bc7\bom\tsr24\"

 

De te checken file-namen worden hier in een stringarray opgenomen:

Het programma werd gemaakt voor een (onbetrouwbare) digitech machine die niet minder dan 35 dumps nodig maakte. (bij een volledige programmatie van de machine kunnen het er zelfs meer dan 500 zijn...)

 

DIM FilAr$(0 TO 255)

nrfils = 35

FOR i% = 0 TO nrfils

READ FilAr$(i%)

NEXT i%

 

Eleganter zou hier het gebruik van een *.CFG file zijn , die als Ascii bestand door het programma kan ingelezen worden. De gegevens (de file-list) hoef je niet eens met de hand in te geven want DOS zelf biedt ons de mogelijkheid voor elk kommando de output om te leiden naar een file of een device: bvb. door de instruktie DIR > DUMPDOC.CFG ontstaat een file waarin de inhoud van het hele directory is opgenomen.

 

Heb je slechts enkele file te testen, dan kan dit uiteraard ook zo:

INPUT "Input filename? (no path) "; C$

C$ = Path$ + C$

 

SCREEN 0

WIDTH 80, 43

FOR i% = 0 TO nrfils

CLS

C$ = InPath$ + FilAr$(i%)

RDFIL

 

Sxstart = -1

SXstop = -1

FOR i& = 0 TO UBOUND(P%)

IF P%(i&) = &HF0 THEN

PRINT

PRINT "Sysex start op"; i&: Sxstart = i&

END IF IF P%(i&) > 31 AND P%(i&) < 127 THEN PRINT CHR$(P%(i&));

IF P%(i&) = &HF7 THEN

PRINT

PRINT "E.O.X. op"; i&: SXstop = i&

END IF

NEXT i&

SLEEP 1

IF Sxstart = -1 THEN

PRINT

PRINT "INCOMPLETE SYSEX-DUMP: No &HF0 Header found! "

END IF

 

IF SXstop = -1 THEN

PRINT

PRINT "INCOMPLETE SYSEX-DUMP: No &HF7 terminator found! "

END IF

 

PRINT "Number of data-bytes ="; (SXstop - Sxstart) + 1

IF (SXstop - Sxstart) + 1 <> UBOUND(P%, 1) THEN

PRINT "Lenght of file different than lenght of sys-ex..."

INPUT " Delete invalid file? (Y/N) "; K1$

IF K1$ = "Y" OR K1$ = "y" THEN KILL C$

IF K1$ = "y" THEN K1$ = "Y"

END IF

 

IF (Sxstart = -1 OR SXstop = -1) AND K1$ <> "Y" THEN

INPUT " Delete invalid file? (Y/N) "; K1$

IF K1$ = "Y" OR K1$ = "y" THEN KILL C$

END IF

IF K1$ <> "Y" OR K1$ <> "y" THEN

D$ = UitPath$ + FilAr$(i%)

instruction$ = "Copy " + C$ + " " + D$

SHELL instruction$

END IF

NEXT i%

 

END

 

De data statements waarin de hele lijst te checken files is opgenomen staat hier aan het eind van de hoofdmodule van het programma:

 

DATA TSR24_00.BOM

DATA TSR24P0.BOM

DATA TSR24P1.BOM

DATA TSR24P2.BOM

DATA TSR24P3.BOM

DATA TSR24P4.BOM

DATA TSR24P5.BOM

DATA TSR24P6.BOM

DATA TSR24P7.BOM

DATA TSR24P8.BOM

DATA TSR24P9.BOM

DATA TSR24P10.BOM

DATA TSR24P11.BOM

DATA TSR24P12.BOM

DATA TSR24P13.BOM

DATA TSR24P14.BOM

DATA TSR24P15.BOM

DATA TSR24A0.BOM

DATA TSR24A1.BOM

DATA TSR24A2.BOM

DATA TSR24A3.BOM

DATA TSR24A4.BOM

DATA TSR24A5.BOM

DATA TSR24A6.BOM

DATA TSR24A7.BOM

DATA TSR24A8.BOM

DATA TSR24A9.BOM

DATA TSR24A10.BOM

DATA TSR24A11.BOM

DATA TSR24A12.BOM

DATA TSR24A13.BOM

DATA TSR24A14.BOM

DATA TSR24A15.BOM

DATA TSR24ALL.BOM

DATA TSR24LST.BOM

DATA TSR24MOD.BOM

 

De procedure waarmee de file zuiver binair wordt in gelezen en waarbij gebruik wordt gemaakt van de 'VAL("&Hxx")- truuk' volgt hier:

 

SUB RDFIL STATIC

' dit subprogramma leest een op disk opgeslagen binaire-file (midi dump) in een array

' de stringvariabele C$ bevat de naam van de binaire file evenals

' het eventuele pad om de file te vinden

' y& is gedefinieerd als een Long-Integer en daarvoor worden

' door Quick-basic 8 bytes in het geheugen gereserveerd.

' Verder in het programma gaan we de file inlezen via deze

' variabele in groepjes van 4 words.

i& = 0

OPEN C$ FOR BINARY AS #1: ' opent de binaire file

' bepaalt de grootte van het array op grond

' van de lengte van de file

REDIM P%(0 TO LOF(1))

' dimensioneer het nodige array in het geheugen

CLS ' wis het scherm

LOCATE 10, 10

PRINT " Reading "; C$; " ... w a i t !!! "; LOF(1); "bytes"

 

k& = 1 ' stel de teller op 1 (k&=i&+1)

WHILE NOT EOF(1)

' zolang de file niet teneinde is ...

GET #1, k&, y&

' lees op pointer-plaats k& een long integer

' (8-bytes)

tmp$ = HEX$(y&)

' zet deze integer om in zijn hexadecimaal equivalent als string

DO UNTIL LEN(tmp$) = 8: tmp$ = "0" + tmp$: LOOP

' als deze string geen volle 8 tekens lang is

' bvb. omdat er inpliciete leading 0's zijn zoals in FF = 000000FF, maak hem dan precies

' 8 tekens lang door toevoeging van nullen.

byte0$ = "&H" + RIGHT$(tmp$, 2)

' een eerste woord is nu gevormd door de laatste twee hexadecimale digits

byte1$ = "&H" + MID$(tmp$, 5, 2)

' twee voorlaatste digits

byte2$ = "&H" + MID$(tmp$, 3, 2)

' het tweede koppel

byte3$ = "&H" + LEFT$(tmp$, 2)

' en tot slot het eerste koppel

' De hele 8-byte string is nu omgezet in 4 strings van elk 2 bytes. Deze kunnen nu

' elk weer omgezet worden in hun numerieke integer waarde middels de VAL funktie:

P%(i&) = VAL(byte0$)

IF i& + 1 <= LOF(1) THEN P%(i& + 1) = VAL(byte1$)

IF i& + 2 <= LOF(1) THEN P%(i& + 2) = VAL(byte2$)

IF i& + 3 <= LOF(1) THEN P%(i& + 3) = VAL(byte3$)

k& = k& + 4 ' de teller wordt 4 eenheden opgeschoven ( =8 bytes)

IF k& > LOF(1) THEN CLOSE #1: EXIT SUB

IF i& + 4 < LOF(1) THEN

i& = i& + 4

ELSE

i& = LOF(1)

END IF

WEND

CLOSE #1

 

END SUB

 

De hier gebruikte inleesmetode moge dan al omslachtig lijken op het eerste gezicht, maar de rekenkundig op het eerste gezicht eenvoudiger konstruktie waarmee een long integer zou kunnen worden omgezet in 4 words, heeft intrinsieke bugs:

Stel dat y& het ingelezen long integer is, dan zou een rekenkundig logisch algoritme verlopen alsvolgt:

byte0= y& MOD &H100

y& = y& \ &H100

byte1= y& MOD &H100

y& = Y& \ &H100

byte2= y& MOD &H100

byte3 = y& \ &H100

Dit algoritime sluit rekenkundig als een bus, tot op het moment dat we er ons rekenschap van geven hoe negatieve getallen in basic worden opgeslagen!

Geven we eerst een goed werkend werkend voorbeeld:

Stel y&= &H60000000 ( dec. 1610612736)

Dan krijgen we in stapjes:

byte0= &H60000000 MOD &H100 = 0

y& = &H60000000 / &H100 = &H600000 (dec. 6291456)

byte1= &H600000 MOD &H100 = 0

y&= &H600000 / &H100 = &H6000 (dec. 24576)

byte2= &H6000 MOD &H100 = 0

byte3= &H6000 / &H100 = &H60 (dec. 96)

Wat volkomen korrekt is.

Maar, stellen we nu dat y& = &HF0000000 dan wordt dit door basic geinterpreteerd als de decimale waarde -268435456. Het hierboven geschreven algoritme toegepast daarop levert dan volgend onwaarschijnlijk rezultaat:

byte0 = &HF0000000 MOD &H100 = 0

y& = &HF0000000 \ &H100 = &HFFF00000 (dec. - 1048576)

byte1 = &HFFF00000 MOD &H100 = 0

y& = &HFFF00000 \ &H100 = &HFFFFF000 (dec. -4096)

byte2 = &HFFFFF000 MOD &H100 = 0

byte3 = &HFFFFF000 \ &H100 = &HFFF0 (dec. -16)

Terwijl we voor het laatste byte &HF0, of, 240, zouden verwachten...

In plaats van de splitsing 240 00 00 00 krijgen we dus:

-16 00 00 00

Deze anomalie treedt op in alle gevallen waarin in het getal y& het hoogste bit 1 is. Dan immers treedt het two's complements algortime eigen aan Basic in werking.

We zouden uiteraard het algoritme zo kunnen ontwerpen dat we het verloop ervan afhankelijk maken van het al dan niet geset zijn van het hoogste bit. Maar zelfs dan, blijft de rekenkundige weg hier komputertechnisch gezien, veel trager dan de ogenschijnlijke omweg via stringmanipulatie. De oorzaak daarvan is te vinden in de 6 opeenvolgende delingen die binnen het rekenkundig algoritme moeten worden afgehandeld.

 

De TSR24 waarvoor dit programma oorspronkelijk werd geschreven, maakt geen gebruik van checksums. Voor andere machines ligt het voor de hand de checksum kontrole op de geldigheid van de file eveneens in de loop van hetzelfde programma door te voeren. Andere machines geven in hun handleiding expliciete gegevens omtrent de exakte lengte in bytes van de sysex dumps. Die lengte kunnen we dan uiteraard kontroleren.

Het programma zal voor elke machine weer, telkens een beetje verschillend zijn. Uiteraard dien je wel te beschikken over enige dokumentatie met betrekking de de sys-ex implementatie van de betreffende machine.

 


Filedate: 940306

Terug naar inhoudstafel kursus: <Index Kursus>

Naar homepage dr.Godfried-Willem RAES