Kurs: Dem Klang auf der Spur
C 64
Musik-Kurs

Dem Klang auf der Spur (Teil 10)

Als krönender Abschluß dieses Kurses wird das Programm Sound-Editor zu einem kompletten Synthesizer-Programm ergänzt.

In der heutigen und letzten Folge des Synthesizer-Projekts soll der in Teil 9 beschriebene Sequenzer in den Sound-Editor integriert werden. Zum Sequenzer gibt es im Gesamtprogramm ein eigenes Untermenü, von dem aus er gestartet und gestoppt werden kann. In diesem Untermenü kann man auch das Spieltempo und einige weitere Parameter interaktiv einstellen. Damit liegt jetzt ein komplettes Synthesizer-Programm vor, das von den vielen klanglichen Möglichkeiten her die kommerziell angebotenen Synthesizer-Programme für den C 64 übertreffen dürfte. Für die grafische Gestaltung gibt es natürlich schönere und aufwendigere Konzepte, diese waren aber auch nicht das Thema dieses Kurses.

Um zu dem erwähnten Komplettprogramm zu gelangen, benötigt man diesmal mehrere Teile aus verschiedenen Abschnitten des Kurses:

MODULATOR(Teil 4)
SOUND EDITOR(Teil 6)
SEQUENCER.OBJ(Teil 8)
REM TEXT KILLER(Teil 10/Listing 1)
SOUND.ED.ZUSATZ(Teil 10/Listing 2)
SEQ.ERG.OBJ(Teil 10/Listing 3)

Zunächst muß das Programm »Sound-Editor« erweitert werden. Da es den zur Verfügung stehenden Speicher ($0801 — $8FFF) fast vollständig belegt, muß es erst einmal verkürzt werden. Dies ist durch Entfernen der vielen Kommentartexte auch leicht möglich. Wer schon beim Eintippen des Programms die Kommentartexte weggelassen hat, spart sich natürlich jetzt diese Arbeit.

Zum Entfernen von REM-Zeilen gibt es zwar gute und schnelle Tools, diese sind aber für den Sound-Editor leider nicht geeignet, da die REM-Zeilen auch als Sprungziele auftreten. Dabei werden die Zeilennummern der Sprungziele meistens aus einer Tabelle entnommen.

Der »REM-Text-Killer« aus Listing 1 entfernt lediglich Kommentartexte und läßt dabei die Zeilennummern mit leeren REM-Anweisungen stehen. Das kurze Programm muß zum Sound-Editor eingetippt werden. Zeile 0 des Sound-Editors muß gelöscht werden. Anschließend gibt man POKE 253,1: POKE 254,8 (RETURN) im Direktmodus ein und startet den REM-Text-Killer mit RUN. Dann wird der REM-Text-Killer wieder gelöscht und Zeile 0 wieder eingegeben.

Nun kann Listing 2 (Sound, ed. Erg.) eingegeben werden. Listing 2 enthält sowohl Zeilen, die im alten Sound Editor geändert werden müssen, als auch neu hinzukommende Programmteile, »Sound. Ed. Erg.« ist für sich allein aber kein lauffähiges Programm. Beim Eintippen kann man natürlich die Kommentartexte gleich weglassen. Das entstehende Komplettprogramm sollte man dann sofort auf Disk speichern. Es kann getestet werden, wenn alle Maschinenprogramme und ein Musikdatensatz zur Verfügung stehen.

An Maschinenprogrammen werden nachgeladen:

Bei dem letzten Programm handelt es sich um eine Ergänzung zum Sequenzer aus Teil 9. Diese Ergänzung, die mit dem MSE eingegeben werden muß (Listing 3), ist für den Betrieb zusammen mit dem Sound-Editor und mit »Modulator« erforderlich. Die technischen Einzelheiten wurden bereits in Teil 9 behandelt und sollen hier nicht mehr besprochen werden.

Um das bis jetzt aufgebaute System von Programmen zu testen, kann man den kleinen Musikdatensatz »Test.Song« (Tonleiter und Kadenz) aus MSE-Listing 4 verwenden.

Bedienung des Sequenzers

Der erweiterte Sound-Editor wird geladen und gestartet. Nach einer Initialisierungszeit von zirka 30 Sekunden meldet er sich mit dem Hauptmenü, von dem aus man mit »A« den Sequenzer erreichen kann. Parameter werden mit den Cursortasten angewählt und können mit den F-Tasten verändert werden. Solange allerdings kein Song (= Musikdatensatz) geladen worden ist, was in der Titelzeile angezeigt wird, kann der Sequenzer nicht gestartet werden.

Im Untermenü Disk (mit »D« zu erreichen) kann man mit »F2« den Musikdatensatz »Test.Song« laden und gelangt dann automatisch wieder in das Sequenzer-Untermenü. Der Sequenzer kann jetzt mit »F5« gestartet und mit »F3« wieder angehalten werden. »F1« setzt ihn an den Anfang des geladenen Songs zurück.

TEMPO

Über das Tempo-Feld kann man die Abspielgeschwindigkeit im Bereich von 40 bis 480 bpm (beats per minute) einstellen. Geschwindigkeiten über 300 bpm sind allerdings musikalisch kaum noch sinnvoll, sondern eher für Klangexperimente gedacht.

MODUS

Im Song-Modus wird das ganze Stück gemäß Sequenzfolgeliste gespielt. Der Sequenzmodus ermöglicht es dagegen, einzelne Sequenzen beliebig oft zu hören.

SEQNR

Im Sequenz-Modus erscheint hier die Nummer der gespielten Sequenz. Damit ist die aktuelle Position in der Sequenzfolgeliste gemeint und nicht die Nummer der Sequenz bei ihrer Definition. Es kann also unter verschiedenen Nummern die gleiche Sequenz mehrmals zu hören sein. So besteht zum Beispiel »Test.Song« aus zwei verschiedenen Sequenzen, einer Tonleiter und einer Kadenz. Die Tonleiter wird wiederholt und ist unter den Sequenznummern 1 und 2 zu hören. Die Kadenz ist unter Nummer 3 zu finden. Im Song-Modus hat das SEQNR-Feld keine Bedeutung.

SOFT-EG

Die Funktion entspricht der schon bekannten, mit Shift-Space erreichbaren Kopplung des Soft-EG an das Tastenfeld-Spiel.

SUSTAIN

Die Sustain-Funktion ist auch beim Sequenzer wirksam. Sie verhindert das Rücksetzen der GATE-Bits der drei Stimmen. Dadurch klingen die Töne ohne Lautstärke-Dynamik durchgehend auf dem Sustain-Pegel. Während der Sequenzer läuft, bleiben alle anderen Funktionen des Sound-Editors voll erhalten. Man kann also an einem laufenden Musikstück Änderungen an der Klangeinstellung testen. Lediglich bei Diskettenoperationen wird der Sequenzer unterbrochen.

Mit dem Sequenzgenerator (Listing 5) kann man relativ einfach Song-Dateien erzeugen, die die für den Sequenzer erforderliche Struktur haben. Das Programm erzeugt aus einer in DATA-Zeilen abgelegten Folge von Noten einen Datensatz mit der in Folge 9 beschriebenen Zeigerstruktur. Die Daten werden direkt hinter die Soundparameter ($9000 bis $9A07) also ab $9A08 gespeichert. Das geschieht in der Reihenfolge:

Es steht der Speicherbereich bis $BFFF, also auch der RAM-Bereich $A0000 bis $BFFF unter dem Basic-ROM zur Verfügung. Da sich POKE-Befehle immer auf das RAM beziehen, sind dazu keine weiteren Maßnahmen notwendig. Programmteile, die auf diesen Bereich lesend zugreifen, sorgen selbständig für das erforderliche Umschalten zwischen RAM und ROM. Auf Editierfunktionen wurde bei diesem Programm verzichtet. Da die Noten in DATA-Zeilen geschrieben werden, kann man diese wie Basic-Programme mit dem Bildschirm-Editor behandeln.

Syntax der Notendaten

Ein Song ist in einzelne Sequenzen gegliedert, welche wiederum in bis zu drei Tracks (= Tonspuren) zerfallen. Den Aufbau macht man sich am besten anhand von Listing 5, Zeilen 8000-8820, klar. Dort steht das schon in Teil 9 als Hex-Dump abgedruckte Musikstück. Jenes ist allerdings für den Sequenzer in der jetzigen Form nicht weiter verwendbar, da es nicht im Speicherbereich ab $9A08 liegt. Die Zeilen 8100 bis 8130 beschreiben eine Sequenz, in der nur Stimme 3 programmiert wird. Der Track besteht dabei aus sieben Viertelnoten.

Sequenzen müssen mit SEQUENZ, (laufende Nummer) eingeleitet werden. Die laufende Nummer muß im Bereich 1 bis 200 liegen.

Innerhalb einer Sequenz wird mit TRACK, (1, 2 oder 3) angegeben, welcher Stimme die nachfolgenden Noten zuzuordnen sind. Man kann in einer Sequenz auch weniger als drei Tracks programmieren. Allen nicht programmierten Tracks ordnet das Generatorprogramm einen 4 Byte langen Dummy-Track zu, der nur aus einer Pause besteht und der nur einmal im Speicher stehen muß.

Innerhalb eines Tracks sind dann folgende Daten zulässig: a — b stellt das Verhältnis zwischen GATE-ON- und GATE-0FF-Zeit ein. Voreinstellung ist 1-1, das heißt, beide Zeiten sind gleich lang. Bei 1-0 hat die GATE-ON-Zeit die maximale Länge, bei 0-1 werden die Noten nur sehr kurz angeschlagen. Die Einstellung hat keinen Einfluß auf die Gesamtlänge der Noten. Diese wird mit a / b eingestellt. Beispiele sind:1/1 ganze Note

Die Längenangabe bezieht sich auf alle Noten bis zur nächsten Längenangabe.

Als Notennamen werden die üblichen Bezeichnungen C,D,E,F,G,A,H verwendet. Die Notennamen können mit»#« (zum Beispiel F# = Fis) zur Erhöhung um einen Halbton oder mit »B« (zum Beispiel EB = Es) zur Erniedrigung um einen Halbton ergänzt werden. Die Notennamen müssen mit einer Oktavnummer zwischen 0 und 6 versehen sein. Der Kammerton a mit 440 Hz hat in dieser Schreibweise den Namen A3.

P kennzeichnet eine Pause, für die ebenfalls die Längeneinstellung a/b gilt.

SEQUENZFOLGE, n1, n2, n3…0. Diese Anweisung darf an beliebiger Stelle stehen und muß einmal vorhanden sein. Sie stellt die schon erwähnte Sequenzfolgeliste dar, von der die Abspielreihenfolge der Sequenzen gesteuert wird. Die Sequenzen n1, n2 und so weiter müssen natürlich definiert werden. Die Liste wird mit einer 0 abgeschlossen.

ENDE schließt den Datensatz ab.

Das Generatorprogramm weist fehlerhafte Daten mit Fehlermeldungen zurück. Am Ende eines Generatorlaufs kann man den erzeugten Datensatz speichern. Dieser kann dann direkt vom erweiterten Sound-Editor geladen werden.

Mit der Integration des Sequenzers in den Sound-Editor findet dieser Kurs seinen Abschluß. Dem an Computermusik interessierten Anwender stehen nun leistungsfähige Programme zum Experimentieren und zur Realisierung seiner Ideen zur Verfügung. Der erfahrene Programmierer wird vielleicht das eine oder andere hier veröffentlichte Programm seinen Bedürfnissen anpassen können. Über eine Resonanz von seiten der Leser zum Beispiel in Form von Sound- oder Song-Dateien oder Ideen zur Erweiterung oder Verbesserung der Programme würde sich der Autor freuen.

(Thomas Krätzig/tr)
15 ad=peek(253)+256*peek(254)
16 ll=peek(ad):lh=peek(ad+1)
17 poke 253,ll:poke 254,lh
18 ad=ll+256*lh
19 ll=peek(ad):lh=peek(ad+1)
20 if ll=0 and lh=0 then end
21 if peek(ad+4)<>143 then 17
22 zn=peek(ad+2)+256*peek(ad+3)
23 print chr$(145);zn;chr$(157);" rem"
24 print " run    "
25 poke 631,145:poke 632,145
26 poke 633,145:poke 634,145
27 poke 635,13 :poke 636,13
28 poke 198,6
29 end
Listing 1. »REM-TEXT-KILLER«. Bitte mit dem Checksummer (Seite 54) eingeben. Beachten Sie auch die Bedienungshinweise im Text.
1068 if m=7.5 then 7960
1080 if a=0 then a=.1:load"modulator",8,1
1082 if a=.1 then a=.2:load"sequencer.obj",8,1
1084 if a=.2 then a= 1:load"seq.erg.obj",8,1
1160 dim v%(8,255),tn%(255),th(24)
3358 poke 50334+sn,c(sn)
3400 rem-------------------------------
3405 rem tempo
3410 if pw<40  then pw=40
3415 if pw>480 then pw=480
3420 te=pw:sys do,pa,int(6e7/(24*te))
3425 sys pr,6,11,f2$;right$(str$(pw),3)
3430 return
3840 poke 50344,-su:if su then print chr$(18);
4132 sys pr,13,1,f2$;"   a";f1$;" sequencer"
7429 : poke 50334+i,c(i)
7532 sys pr,6,4,f2$;"f2"
7534 sys pr,6,7,f1$;"song   laden"
7632 sys 50198:gosub 2140:rem mod/seq aus
7670 ns=-1:a=211
7675 sys do,56326,int(6e7/(24*te))
7680 if sr then sys 51093:goto 1550
7685 sys mo+1033:goto 1550
7735 sys 50198:gosub 2140:remk mod/seq aus
7805 sys do,56326,int(6e7/(24*te))
7810 if sr then sys 51093:return
7815 sys 50185:return:rem nur mod. an
7900 rem-------------------------------
7905 rem song laden
7910 sys pr,6,7,f2$;"song   laden"
7915 sys pr,10,4,f1$;"dateiname ";
7920 sys pr,10,14,;:input dn$
7925 sys 50966:gosub 2140
7930 open 8,8,8,dn$+",p,r":close 8
7935 open 1,8,15:input#1,a,a$,x,y:close 1
7940 sys pr,12,4,"                             "
7945 if a=0 then 7955
7950 sys pr,12,3,a;a$;x;y:goto 7920
7955 a=0:m=7.5:load dn$,8,1
7960 sys pr,6,7,f1$;"song   laden"
7965 m=7:sq=-1
7970 sys do,56326,int(6e7/(24*te))
7975 sys do,50310,usr(39432)
7980 sys 51001 :rem seq/mod start/init
7985 if not sr then sys 50966
7990 a=65:goto 1550
8130 on l goto 8150,8220,8280,8310,8310
8180 for i=0 to 8:v%(i,a)=zn:next
8400 : for j=0 to 8:v%(j,a)=2000:next
8482 so=36864:ci=56320
8578 : poke 50334+sn,c(sn)
8627 poke 50303,0 :rem eg abkoppeln(seq)
8632 te=120       :rem tempo
8920 sq=0:sm=0:sr=0:a=2:return
9530 data ma,3700,160,3800,s,9990,a
9750 data m7,7600,133,7700,134,7900,137
9800 data m8,10420,029,10450,157
10000 rem==============================
10010 rem untermenue sequencer
10020 rem==============================
10030 m=8:pv=0:sys cl:print"{home}{down}";f1$;
10040 print" sequencer";
10045 if not sq then print"  (kein song vorhanden)"
10050 sys pr,4,10,"tempo modus seqnr  soft-eg"
10060 sys pr,5,4,"{CBM-A}CCCC{CBM-R}CCCCC{CBM-R}CCCCC{CBM-R}CCCCC{CBM-R}CCCCCCCCC{CBM-S}"
10070 sys pr,6,4,"B    B     B     B     B 1  2  3 B"
10080 sys pr,7,4,"{CBM-Z}CCCC{CBM-E}CCCCC{CBM-E}CCCCC{CBM-E}CCCCC{CBM-E}CCCCCCCCC{CBM-X}"
10090 sys pr,9,1,f2$;"f1";f1$;"  reset  ++                  1"
10100 sys pr,10,1,f2$;"f3";f1$;"  stop    +  song    +       2"
10110 sys pr,11,1,f2$;"f5";f1$;"  run     -  seq     -       3"
10120 sys pr,12,1,f2$;"f7";f1$;"         --"
10130 if sr then 10150
10140 sys pr,6,5,"stop":goto 10160
10150 sys pr,6,5,"run "
10160 sys pr,6,11,right$(str$(te),3)
10170 if sm then 10190
10180 sys pr,6,16,"song":goto 10210
10190 sys pr,6,16,"seq "
10200 sys pr,6,22,right$(" "+str$(se),3)
10210 rem
10220 x=peek(50303)
10230 if x and 1 then sys pr,6,28,"{rvon} 1 "
10240 if x and 2 then sys pr,6,31,"{rvon} 2 "
10250 if x and 4 then sys pr,6,34,"{rvon} 3 "
10300 av=10500:sys gs,av:return
10400 rem------------------------------
10410 rem parameterwahl durch cursor
10420 rem rechts
10430 av=av+100:if av>10900 then av=10500
10440 goto 10470
10450 rem links
10460 av=av-100:if av<10500 then av=10900
10470 for i=pb to pb+8:poke i,f1:next
10480 sys gt,av
10500 rem------------------------------
10510 rem run/stop waehlen
10520 pb=fa+245
10530 for i=pb to pb+3:poke i,f2:next
10540 pa=ci+12:pv=11000:return
10600 rem------------------------------
10610 rem tempo waehlen
10620 pb=fa+250
10630 for i=pb to pb+3:poke i,f2:next
10640 pa=ci+6:pw=te
10650 pm=500:p1=1:p2=10:pv=3400:return
10700 rem------------------------------
10710 rem modus waehlen
10720 pb=fa+256
10730 for i=pb to pb+3:poke i,f2:next
10740 pa=50345:pw=peek(pa)
10750 pv=11100:return
10800 rem------------------------------
10810 rem seqnr waehlen
10820 pb=fa+262
10830 for i=pb to pb+2:poke i,f2:next
10840 pw=se:p1=1:p2=1:pm=1000
10850 pv=11200:return
10900 rem------------------------------
10910 rem soft-eg waehlen
10920 pb=fa+268
10930 for i=pb to pb+8:poke i,f2:next
10940 pa=50303:pv=11300:return
11000 rem------------------------------
11010 rem sequencer reset/stop/run
11015 if not sq then return
11020 if a<133 or a>135 then return
11030 on a-132 goto 11040,11060,11080
11040 rem reset
11042 if sm then sys 51116:return
11045 sys 51001
11050 if not sr then sys 50966
11055 return
11060 rem stop
11065 sys 50966:sys pr,6,5,f2$;"stop"
11070 sr=0:if not su then 2140
11075 return
11080 rem run
11085 sys 51093:sys pr,6,5,f2$;"run "
11090 sr=-1:return
11100 rem------------------------------
11110 rem sequencer-modus (song/seq)
11112 if not sq then return
11115 if a=134 then 11130
11120 if a=135 then 11150
11125 return
11130 rem song-modus
11135 sm=0 :poke pa,0
11140 sys pr,6,16,f2$;"song"
11145 sys pr,6,22,"     ":return
11150 rem sequenz-modus
11155 sm=-1:poke pa,1:sys pr,6,16,"seq "
11160 sys pr,6,16,f2$;"seq "
11165 se=(usr(50312)-usr(50310))/3+1
11170 sys pr,6,22,f1$;right$(" "+str$(se),3)
11175 return
11200 rem------------------------------
11210 rem sequenz-nummer
11220 if not sm then return
11230 if pw=0 then pw=1:return
11240 ad=usr(50310)+(pw-1)*3
11250 if usr(ad)=0 then pw=pw-1:return
11260 sys do,50312,ad:se=pw
11270 sys do,50314,usr(ad)
11280 sys 51116 :rem nextseq
11285 sys pr,6,22,f2$;right$(" "+str$(se),3)
11290 return
11300 rem------------------------------
11310 rem sequencer soft-eg-steuerung
11320 x=peek(pa)
11330 for i=0 to 2
11340 : if a<>133+i then 11420
11350 : y=2^i
11360 : if (x and y) then 11400
11370 : x=x or y:poke pa,x
11380 : sys pr,6,28+3*i,f2$;"{rvon}";i+1;"{left} "
11390 : goto 11420
11400 : x=x and (255-y):poke pa,x
11410 : sys pr,6,28+3*i,f2$;i+1;"{left} "
11420 next i:return
Listing 2. »SOUND.ED.ZUSATZ«. Bitte mit dem Checksummer eingeben. Beachten Sie auch die Bedienungshinweise im Text.
PROGRAMM : SEQ.ERG.OBJ    C739 C855
-----------------------------------
C739 : 78 A5 FE 48 A5 FF 48 A9   1B
C741 : EA A2 02 9D 35 C5 9D A2   EE
C749 : C5 BD 92 C7 9D 5B C6 CA   F0
C751 : 10 F1 AD 86 C4 8D 88 C4   FA
C759 : AD 87 C4 8D 89 C4 20 ED   C8
C761 : C5 A9 E2 8D D7 C4 A9 C3   37
C769 : 8D D8 C4 A9 1E 8D 14 03   6D
C771 : A9 C5 8D 15 03 A9 D7 8D   FB
C779 : D3 C4 A9 C7 8D D4 C4 A9   F7
C781 : 82 8D 0D DC A9 11 8D 0F   20
C789 : DC 68 85 FF 68 85 FE 58   5A
C791 : 60 4C BE C7 78 A9 1E 8D   28
C799 : 14 03 A9 C5 8D 15 03 A9   33
C7A1 : 82 8D 0D DC A9 11 8D 0F   40
C7A9 : DC 58 60 78 A5 FE 48 A5   97
C7B1 : FF 48 20 ED C5 68 85 FF   50
C7B9 : 68 85 FE 58 60 AE 83 C4   C2
C7C1 : BD A1 C4 2C 7F C4 F0 08   F7
C7C9 : AD 48 C0 29 FE 8D 48 C0   EF
C7D1 : AD A8 C4 4C 5E C6 AE 85   6F
C7D9 : C4 9D 00 C0 A5 FE 9D 01   4F
C7E1 : C0 A5 FB 48 A5 FC 48 A5   2A
C7E9 : FD 48 86 FE 20 6A C2 AE   49
C7F1 : 83 C4 BD 18 C0 D0 12 AE   81
C7F9 : 85 C4 BD 05 C0 9D 00 D4   93
C801 : BD 06 C0 9D 01 D4 4C 2C   E5
C809 : C8 20 43 C2 AE 85 C4 BD   B0
C811 : 06 C0 85 FD 20 A6 C0 AE   30
C819 : 85 C4 18 BD 05 C0 65 FB   A2
C821 : 9D 00 D4 BD 06 C0 65 FC   A1
C829 : 9D 01 D4 AE 83 C4 BD A1   EA
C831 : C4 2C 7F C4 F0 08 AD 48   1A
C839 : C0 09 01 8D 48 C0 BD 9E   2F
C841 : C4 09 01 AE 85 C4 9D 04   9D
C849 : D4 68 85 FD 68 85 FC 68   EA
C851 : 85 FB 60 00               CF
Listing 3. »SEQ.ERG.OBJ«. Bitte mit dem MSE (Seite 54) eingeben.
PROGRAMM : TEST.SONG      9A08 9A5D
-----------------------------------
9A08 : 4E 9A 01 61 EF 00 00 15   39
9A10 : 9A 0A 9A 0A 9A 06 67 B0   70
9A18 : B2 B4 B5 B7 B9 BB C0 C0   87
9A20 : BA B8 B7 B5 B3 B2 B0 00   6E
9A28 : 2E 9A 38 9A 43 9A 12 67   25
9A30 : C0 C0 C0 BB 48 79 C0 00   4B
9A38 : 12 67 B7 B9 24 6D B7 48   40
9A40 : 79 B7 00 12 67 B4 B5 24   12
9A48 : 6D B2 48 79 B4 00 0F 9A   0C
9A50 : 00 0F 9A 00 28 9A 00 00   D6
9A58 : 00 00 00 01 08            20
Listing 4. »TEST.SONG«. Bitte mit dem MSE (Seite 54) eingeben.
1000 rem ******************************
1010 rem *                            *
1020 rem *       leseprogramm         *
1030 rem *   fuer sequencer-daten     *
1040 rem *                            *
1050 rem * erzeugt aus data-zeilen    *
1060 rem * einen absolut ladbaren     *
1070 rem * datensatz fuer sequencer   *
1080 rem *                            *
1090 rem * thomas kraetzig   sep 85   *
1100 rem *                            *
1110 rem ******************************
1120 rem
1130 rem konstanten und
1140 rem variablen mit vorbesetzungen
1150 rem
1160 dim sf(200) :rem sequenzfolgeliste
1170 dim sa(200) :rem sequenzadressenl.
1180 dim ta(3)   :rem trackadressen
1190 rem notennamen
1200 nn$="ccddeffggaah"
1210 dn$=""      :rem dateiname
1220 s=1         :rem aktuelle sequenz
1230 t=1         :rem aktueller track
1240 ad=0        :rem allg. adresse
1250 sa=39432    :rem $9a08
1260 q=96        :rem quantisierung
1270 r=0.5       :rem gate on/laenge
1280 nl=1/4      :rem notenlaenge
1290 l=0         :rem stringlaenge
1300 sv=12*4096  :rem save-routine
1500 rem-------------------------------
1510 rem programmstart
1520 rem-------------------------------
1530 rem save-maschinenprogramm
1540 for i=0 to 17
1550 read x:poke sv+i,x:next i
2020 rem
2030 rem dummy-track erzeugen
2040 ad=sa+2
2050 poke ad  ,1  :poke ad+1,97
2060 poke ad+2,239:poke ad+3,0
2070 h0=int(ad/256):l0=ad-256*h0
2080 ad=ad+4:a$=""
2100 rem naechstes datum lesen
2110 print" ";a$;:read a$
2120 l=len(a$):l$=left$(a$,1)
2150 if a$="p"            then 3100
2160 if a$="pause"        then 3100
2165 if a$="track"        then 3800
2170 if a$="sequenz"      then 4000
2175 if a$="sequenzfolge" then 3600
2190 if a$="ende"         then 4300
2200 rem
2210 rem nach notennamen suchen
2220 rem
2230 if l=1 then 5000
2240 if l>3 then 2500
2250 n=1
2260 if l$=mid$(nn$,n,1) then 2300
2270 n=n+1:if n<13 then 2260
2280 goto 2500 :rem keine note
2300 r$=right$(a$,1):o=val(r$)
2310 if o=0 and r$<>"0" then 2420
2320 if o>6 then 2420
2330 if l=2 then 3000
2340 m$=mid$(a$,2,1)
2350 if m$="#" then n=n+1:goto 3000
2360 if m$="b" then n=n-1:goto 3000
2380 f$="nur "+l$+"#"+r$+" oder "+l$+"b"+r$
2390 f$=f$+" oder "+l$+r$+" moeglich"
2400 goto 5000
2420 f$="oktavbereich 0-6"
2430 goto 5000
2500 rem
2510 rem nach / oder - suchen
2520 rem
2530 m$=mid$(a$,2,1)
2540 if m$<>"/" and m$<>"-" then 2560
2550 r$=right$(a$,l-2):goto 2600
2560 m$=mid$(a$,3,1)
2570 if m$<>"/" and m$<>"-" then 5000
2580 l$=left$(a$,2):r$=right$(a$,l-3)
2600 rem
2610 rem zaehler und nenner untersuchen
2620 rem
2630 z=val(l$)
2640 if z>0 and z<99 then 2670
2650 f$="zaehler-bereich 1 bis 99"
2660 goto 5000
2670 n=val(r$)
2680 if n>0 or m$="-" then 2710
2690 f$="nenner muss groesser 0 sein"
2700 goto 5000
2710 if m$="/" then 3200 :rem zeit
2720 if m$="-" then 3400 :rem on/off
2730 goto 5000
3000 rem-------------------------------
3010 rem note (tonnummer n  oktave o)
3020 rem-------------------------------
3030 if n=0  then n=12:o=o-1
3040 if n=13 then n=1 :o=o+1
3050 poke ad,128+16*o+n-1:ad=ad+1
3060 goto 2110
3100 rem-------------------------------
3110 rem pause
3120 rem-------------------------------
3130 poke ad,239:ad=ad+1:goto 2110
3200 rem-------------------------------
3210 rem zeit (notendauer)
3220 rem-------------------------------
3230 t=int(q*z/n)   :rem gesamtzeit
3240 an=int(r*q*z/n):rem gate-on-zeit
3250 of=t-an        :rem gate-off-zeit
3260 if an<=96 then 3290
3270 f$="gate-on-zeit zu gross"
3280 goto 5000
3290 if of<=30 then 3320
3300 f$="gate-off-zeit zu gross"
3310 goto 5000
3320 poke ad,an:ad=ad+1
3330 poke ad,of+97:ad=ad+1
3340 goto 2110
3400 rem-------------------------------
3410 rem verhaeltnis gate-on/gesamtzeit
3420 rem (z/n = gate on/gate-off)
3430 rem-------------------------------
3440 r=z/(z+n):goto 2110
3600 rem-------------------------------
3610 rem sequenzfolge
3620 rem-------------------------------
3630 print:print:as=0
3640 print" ";a$;:reada$:a=int(val(a$))
3650 if a=0 then 3670
3660 sf(as)=a:as=as+1:goto 3640
3670 if a$<>"0" then 3690
3680 print" 0":read a$:goto 2120
3690 f$="liste muss mit 0 abgeschlossen sein"
3700 goto 5000
3800 rem-------------------------------
3810 rem track
3820 rem-------------------------------
3830 print:print:print a$;
3840 read a$:a=int(val(a$))
3850 if a>=1 and a<=3 then 3880
3860 f$="nur 1,2,3 zulaessig"
3870 goto 5000
3880 print a:t=a
3890 if ns then ns=0:goto 3910
3900 poke ad,0:ad=ad+1
3910 hi=int(ad/256):lo=ad-256*hi
3920 poke sa(s)+(t-1)*2,lo
3930 poke sa(s)+(t-1)*2+1,hi
3940 read a$:goto 2120
4000 rem-------------------------------
4010 rem sequenz
4020 rem-------------------------------
4030 print:print:print:print a$;
4040 read a$:a=int(val(a$))
4050 if a>=1 and a<=200 then 4080
4060 f$="nur 1-200 zulaessig"
4070 goto 5000
4080 print a:s=a
4090 poke ad,0:ad=ad+1:ns=-1:sa(s)=ad
4100 rem track-zeiger auf dummy-track
4110 rem initialisieren
4120 poke ad  ,l0:poke ad+1,h0
4130 poke ad+2,l0:poke ad+3,h0
4140 poke ad+4,l0:poke ad+5,h0
4150 ad=ad+6
4160 read a$:goto 2120
4300 rem-------------------------------
4310 rem ende
4320 rem sequenzfolgeliste aufbauen
4330 rem-------------------------------
4340 print:print a$
4350 poke ad,0:ad=ad+1
4360 hi=int(ad/256):lo=ad-256*hi
4370 poke sa,lo:poke sa+1,hi
4380 for i=0 to as-1
4390 : x=sa(sf(i)):if x>0 then 4410
4400 : print"sequenz";i;"nicht definiert":goto 4420
4410 : hi=int(x/256):lo=x-256*hi
4420 : poke ad+3*i,lo
4430 : poke ad+3*i+1,hi
4440 : poke ad+3*i+2,0
4450 next i
4460 for i=0 to 2:poke ad+3*as+i,0:next
4470 ad=ad+3*as+3
4500 rem
4510 rem bereich sa-ad auf disk
4520 rem
4530 input"abspeichern (j/n) ";a$
4540 if a$<>"j" then end
4550 input"dateiname         ";dn$
4560 ah=int(sa/256):al=sa-256*ah
4570 eh=int(ad/256):el=ad-256*eh
4580 open 1,8,1,dn$
4590 poke 252,al:poke 253,ah
4600 poke 780,252
4610 poke 781,el:poke 782,eh
4620 sys sv:close 1
4630 end
5000 rem-------------------------------
5010 rem fehler
5020 rem-------------------------------
5030 print:print
5040 print"fehlerhaftes datum: ";a$
5050 if f$<>"" then print f$
5060 print:a$="":f$="":goto 2110
7000 rem-------------------------------
7010 rem save-routine
7020 rem-------------------------------
7030 data 072,165,001,041,254,133,001
7040 data 104,032,216,255,165,001,009
7050 data 001,133,001,096
8000 rem-------------------------------
8010 rem musikstueck
8020 rem (edvard grieg   kobold)
8030 rem-------------------------------
8100 data sequenz,1
8110 data track,3
8120 data 1-1,1/4,eb1,hb1,eb1,hb0
8130 data eb1,hb1,eb1
8140 rem
8200 data sequenz,2
8210 data track,1
8220 data 1-0,1/4,p,1/8,hb3,3/8,p
8230 data 1/8,hb3,3/8,p,1-1,1/4
8240 data hb3,gb3,gb3,hb3,a3,f3,f3,a3
8250 data 1/2,a3,p,1-0
8260 data 1/8,eb4,3/8,p,1/8,eb4,3/8,p
8270 data 1-1,1/4,eb4,cb4,cb4,eb4
8280 data d4,hb3,hb3,d4,1-0,1/4,d4
8290 data 1/2,p
8300 data track,2
8310 data 1-0,1/8,eb3,f3
8320 data gb3,f3,eb3,f3,gb3,f3,eb3,f3
8330 data 1-1,1/4,gb3,eb3,eb3,gb3
8340 data f3,c3,c3,f3,1/2,f3,1/4,p
8350 data 1-0,1/8,ab3,hb3
8360 data cb4,hb3,ab3,hb3
8370 data cb4,hb3,ab3,hb3,1-1,1/4
8380 data cb4,ab3,ab3,cb4,hb3,f3,f3,hb3
8390 data 1/2,hb3,1/4,p
8400 data track,3
8410 data 1-1,1/4,hb0,eb1,hb1,eb1
8420 rem
8430 data sequenz,3
8440 data track,1
8450 data 1-1,1/4,p
8460 data db5,p,db5,p,ab4,p,ab4,p
8470 data gb4,p,gb4,p,db4,p,db4
8480 data track,2
8490 data 1-0,1/8
8500 data gb4,ab4,hb4,ab4,gb4,ab4,hb4,p
8510 data db4,eb4,f4,eb4,db4,eb4,f4,p
8520 data cb4,db4,eb4,db4,cb4,db4,eb4,p
8530 data gb3,ab3,hb3,ab3,gb3,ab3,hb3,p
8540 data track,3
8550 data 1-0,1/4,p,1/2
8560 data gb3,p,db3,p,cb3,p,gb2,1/4,p
8570 rem
8600 data sequenz,4
8610 data track,1
8620 data 1-0,1/4,p,1/1,p,p,p,p,1/8
8630 data hb1,f2,hb2,hb2,f3,hb3,hb3,f4
8640 data 1/4,hb4,3/4,p
8650 data track,2
8660 data 1-0,1/8,f2,gb2,ab2,gb2,f2,p
8670 data gb2,f2,eb2,p,f2,eb2,db2,p
8680 data eb2,db2,c2,p,1/1,p,1/8
8690 data eb2,db2,cb2,p,1/2,p
8700 data 1/1,f1,1/4,f4,3/4,p
8710 data track,3
8720 data 1-0,1/8,f1,gb1,ab1,gb1,f1,p
8730 data gb1,f1,eb1,p,f1,eb1,db1,p
8740 data eb1,db1,c1,p,1/1,p,1/8
8750 data eb1,db1,cb1,p,1/2,p
8760 data 1/1,f0,1/4,f2,3/4,p
8800 rem
8810 data sequenzfolge,1,2,2,3,3,4,0
8820 data ende
Listing 5. »SEQUENZGENERATOR«. Bitte mit dem Checksummer (Seite 54) eingeben.
Kurs: Dem Klang auf der Spur
PDF Diesen Artikel als PDF herunterladen
Mastodon Diesen Artikel auf Mastodon teilen
← Vorheriger ArtikelNächster Artikel →