home *** CD-ROM | disk | FTP | other *** search
File List | 1989-04-05 | 9.4 KB | 204 lines |
- '
- ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
- ' Sequenzerprogramm mit Abspeichermöglichkeit als MIDI Standard File
- ' Unter-Routinen zum Einbinden in zukünftige KEYS-Listings zum Thema
- ' MIDI Standard Files
- ' geschrieben in GFA-BASIC 3.5E D, (C)1993 Stephan M. Sprenger
- ' PROSONIQ PRODUCTS SOFTWARE, Badenwerkstraße 9, 76137 Karlsruhe
- ' .............................................................................
- '
- '
- PROCEDURE convert_mid(abs_rel|,save_load|)
- '
- ' speichert/lädt Daten als MIDI Standard File:
- ' MIDI-Events in dat$(), Zeit als Clicks in time%()
- '
- ' Wenn Sie abs_rel| auf 1 setzen, erwartet die Routine in time%() die
- ' Zeitangabe als Absolutzeit (also als Zeit seit Spuranfang); ist
- ' abs_rel| Null, dann erwartet die Routine in time%() die seit dem
- ' vorhergehenden Event verstrichene Zeit.
- '
- ' In dat$() befinden sich die zu speichernden MIDI-Events; diese müssen
- ' pro Eintrag vollständig sein (ein Note-On liegt hier z.B. als
- ' dat$(2)=CHR$(144)+CHR$(60)+CHR$(64) vor).
- '
- ' Wenn save_load|=1 ist wird gespeichert, bei save_load|=0 wird geladen
- '
- @convert_init ! Konvertierungsroutine einrichten
- dummy$=INKEY$
- FILESELECT "A:\*.MID","MIDIFILE.MID",fn$
- DEFMOUSE 2
- IF fn$="" OR fn$="\"
- GOTO cancel
- ENDIF
- IF save_load|=1
- OPEN "O",#1,fn$
- PRINT #1,"MThd"; ! **** Header-Block-Kennung ****
- PRINT #1,MKL$(6); ! Länge des Headers
- PRINT #1,MKI$(0); ! File Format (0)
- PRINT #1,MKI$(1); ! Anzahl der Spuren
- PRINT #1,MKI$(&H18); ! 24 Clicks pro Viertelnote (MIDI Clock)
- PRINT #1,"MTrk"; ! ***** Spur-Block-Kennung *****
- PRINT #1,MKL$(0); ! Platzhalter für Blocklänge
- PRINT #1,CHR$(0); ! Delta-Time des ersten Events
- PRINT #1,CHR$(&HFF); ! Meta-Event: Spurname
- PRINT #1,MKI$(&H108); ! (01=Text, 08=Textlänge)
- PRINT #1,"MIDIFILE"; ! Spurname
- c%=0
- DO
- INC c%
- VOID FRE(0)
- r%=V:r$
- IF abs_rel|=1 ! time%() enthält Absolutzeit
- LPOKE r%+6,(time%(c%)-time%(c%-1)) ! Zeit zwischen zwei Events
- ELSE
- LPOKE r%+6,time%(c%) ! time%() enthält Delta-Time
- ENDIF
- POKE r%+2,1 ! Opcode: 1=DEZ-->VLN, 0=VLN-->DEZ
- d0=C:r%() ! VLN-Routine aufrufen
- FOR b|=0 TO 3 ! Bytes in Datei schreiben...
- IF PEEK(r%+6+b|)<>0
- PRINT #1,CHR$(PEEK(r%+6+b|));
- ENDIF
- NEXT b|
- PRINT #1,dat$(c%); ! MIDI-Daten in Datei ausgeben
- EXIT IF c%=last% ! Abbrechen wenn Spurende
- LOOP
- PRINT #1,CHR$(0); ! Delta-time% zum Spurende
- PRINT #1,CHR$(&HFF);MKI$(&H2F00); ! Meta-Event: Spurende
- CLOSE #1
- OPEN "U",#1,fn$ ! Datei nochmals öffnen
- l%=LOF(#1) ! Länge ermitteln
- SEEK #1,18 ! Byte #18 anfahren
- PRINT #1,MKL$(l%-18); ! Spurlänge eintragen
- ELSE
- c%=0 ! Zähler für Feldindex
- z%=0 ! Zähler für Absolutzeit
- b%=0 ! Zähler für gelesene Bytes
- evt$=""
- OPEN "I",#1,fn$ ! Datei zum Lesen öffnen
- id$=INPUT$(4,#1) ! Header-ID lesen
- h_l%=CVL(INPUT$(4,#1)) ! Header-Länge lesen
- ff&=CVI(INPUT$(2,#1)) ! File-Typ lesen
- anz&=CVI(INPUT$(2,#1)) ! Spuranzahl
- res&=CVI(INPUT$(2,#1)) ! Auflösung
- IF id$<>"MThd" OR ff%<>0 ! MIDI-File vom Typ 0?
- ALERT 3,"Ungültiges Fileformat - |Fileheader",1," OK ",r
- GOTO cancel ! Nein, dann Abbruch
- ENDIF
- id$=INPUT$(4,#1) ! Track-ID lesen
- b_l%=CVL(INPUT$(4,#1)) ! Länge der Spur
- IF id$<>"MTrk" ! Track-ID prüfen
- ALERT 3,"Ungültiges Fileformat - |Trackstruktur",1," OK ",r
- GOTO cancel ! Ungültig? dann raus
- ENDIF
- DO ! Leseschleife
- INC c% ! Zähler für Feld erhöhen
- t$=""
- DO ! Leseschleife für Zeit
- tim$=INPUT$(1,#1) ! Erstes Byte lesen
- INC b% ! Bytezähler +1
- t$=t$+tim$ ! ersten Zeitwert bilden
- EXIT IF ASC(tim$)<128 ! raus, wenn LSB gelesen
- LOOP
- VOID FRE(0)
- t$=MID$(t$,1,4)
- t$=STRING$(4-LEN(t$),0)+t$ ! Langwort bilden
- r%=V:r$ ! Adresse der Maschinenroutine
- POKE r%+2,0 ! Opcode: 0=VLN-->DEZ
- LPOKE r%+6,CVL(t$) ! Wert übergeben
- d0=C:r%() ! Maschinenprogramm aufrufen
- IF abs_rel|=0 ! Relative Zeit benötigt?
- time%(c%)=LPEEK(r%+6)/(res&/24) ! dann Delta-Time ablegen
- ELSE ! Absolutzeit?
- z%=z%+LPEEK(r%+6) ! dann Zeit bilden...
- time%(c%)=z%/(res&/24) ! ...und in interne Auflösung umrechnen
- ENDIF
- evt$=INPUT$(1,#1) ! Event, erstes Byte lesen
- INC b% ! wieder ein Byte mehr...
- rb|=(ASC(evt$)) AND &HF0 ! nur Hi-Nibble wird benötigt
- IF d_len&(rb|)=0 ! Event-Typ ist nicht bekannt?
- ALERT 3,"ERROR:|Unbekanntes MIDI-Event",1,"CANCEL",r
- EXIT IF r=1 ! dann nix wie raus...
- ENDIF
- IF evt$=CHR$(&HFF) ! Event ist Meta-Event...
- m_type&=ASC(INPUT$(1,#1)) ! ...dann Event-Typ feststellen
- m_l&=ASC(INPUT$(1,#1)) ! Länge feststellen
- RELSEEK #1,m_l& ! Meta-Event ignorieren...
- b%=b%+m_l&+2 ! ...und überspringen
- EXIT IF m_type&=&H2F ! raus wenn Meta-Event = Spurende
- ELSE
- dat$(c%)=evt$+INPUT$(d_len&(rb|)-1,#1) ! wenn normales MIDI-Event...
- b%=b%+d_len&(rb|) ! ... dann lesen und speichern
- ENDIF
- LOOP
- last%=c% ! Spurende
- ENDIF
- cancel:
- CLOSE #1 ! Datei schließen
- DEFMOUSE 0 ! Biene wegzaubern
- RETURN
- '
- PROCEDURE convert_init
- '
- ' Initialisierung der VLN/Dezimal-Routine.
- ' Die in r$ abgelegte Maschinenroutine erwartet in V:r$+2 als Byte den
- ' Opcode der auszuführenden Berechnung (0=VLN in Dezimalwert umrechnen,
- ' 1=Dezimalwert in VLN umrechnen) und in V:r$+6 den umzurechnenden Wert.
- ' Nach Aufruf der Routine kann von dort auch der berechnete Wert gelesen
- ' werden (Langwort). Die Wertübergabe über die Speicherstelle habe ich
- ' gewählt, weil die Übergabe über den Stack bei meiner GFA-Version nicht
- ' korrekt funktioniert.
- '
- r$=MKL$(&H60080000)+MKL$(0)+MKL$(&H41FA)+MKL$(&HFFF62228)
- r$=r$+MKL$(&H44A10)+MKL$(&H6754B2BC)+MKL$(&HFFFFFFF)+MKL$(&H62407003)
- r$=r$+MKL$(&HE389E209)+MKL$(&H8810007)+MKL$(&HB07C0003)+MKL$(&H67084A01)
- r$=r$+MKL$(&H670408C1)+MKL$(&H71401)+MKL$(&HE09AE089)+MKL$(&H51C8FFE2)
- r$=r$+MKL$(&H8020017)+MKL$(&H670408C2)+MKL$(&HF0802)+MKL$(&H1F6706)
- r$=r$+MKL$(&H820080)+MKL$(&H80002142)+MKL$(&H47000)+MKL$(&H4E75217C)
- r$=r$+MKL$(&HFFFFFFF7)+MKL$(&H470FF)+MKL$(&H4E75B2BC)+MKL$(&HFFFFFFF7)
- r$=r$+MKL$(&H62167003)+MKL$(&H1401EE9A)+MKL$(&HE08951C8)+MKL$(&HFFF8E89A)
- r$=r$+MKL$(&H2820FFF)+MKL$(&HFFFF60CE)+MKL$(&H217C0FFF)+MKL$(&HFFFF0004)
- r$=r$+MKL$(&H70FF4E75)
- '
- '
- d_len&(128)=3 ! Note-Off,Befehlslänge 3 Bytes
- d_len&(144)=3 ! Note-On, Befehlslänge 3 Bytes
- d_len&(160)=3 ! Poly Pressure
- d_len&(176)=3 ! Control Change
- d_len&(192)=2 ! Program Change
- d_len&(208)=2 ! Channel Pressure
- d_len&(224)=3 ! Pitch Wheel Change
- d_len&(&HF0)=&HFF ! Meta-Event darf keinen Fehler erzeugen
- '
- ' Es können hier weitere Befehlslängen für MIDI-Nachrichten eingetragen werden
- '
- RETURN
- '
- PROCEDURE midi_buffer(neue_adresse%,laenge%)
- adresse%=XBIOS(14,2)
- alte_buffer_adresse%=LPEEK(adresse%)
- SLPOKE adresse%+6,0
- SLPOKE adresse%,neue_adresse%
- SDPOKE adresse%+4,laenge%
- RETURN
- '
- PROCEDURE alter_buffer
- adresse%=XBIOS(14,2)
- SLPOKE adresse%,alte_buffer_adresse%
- alte_buffer_adresse%=0
- alter_buffer%=0
- @ende ! Programm verlassen
- RETURN
- '
- PROCEDURE all_notes_off
- FOR chan|=0 TO 15 ! Alle Kanäle durchgehen...
- FOR note|=0 TO 127 ! Alle Noten durchgehen...
- IF note|=0 ! Erstes Note-Off normal..
- OUT 3,128+chan|
- ENDIF
- OUT 3,note|,0 ! ..den Rest im Running-Mode
- NEXT note| ! senden (geht schneller)
- NEXT chan|
- RETURN
-