First post, by Peter Swinkels
I found this GWBasic code at https://bisqwit.iki.fi/jutut/kuvat/programmin … s/midiplay.html :
0 REM MIDI PLAYER EXAMPLE PROGRAM COPYRIGHT (C) 2010 JOEL YLILUOMA1 DEFINT A-Z: OPTION BASE 0: KEY OFF: REM http://iki.fi/bisqwit/2 DIM adl(180, 11), chins(17), chpan(17), chpit(17)3 FOR i = 0 TO 180: FOR x = 0 TO 11: READ adl(i, x): NEXT x, i4 GOTO 100 ' Begin program5 'Set up OPL parameters (In: c = channel (0..17))6 'Out: p=I/O port, q = per-OPL channel (0..8), o=operator offset7 p = &H388 + 2 * (c\9): q = c MOD 9: o = (q MOD 3) + 8 * (q\3): RETURN8 'OPL_NoteOff(c): c=channel. CHANGES: q,p,o9 GOSUB 5: OUT p, &HB0 + q: OUT p+1, chpit(c) AND &HDF: RETURN10 'OPL_NoteOn(c,h#): c=channel,h#=hertz (0..131071). CHANGES: q,p,o,x11 GOSUB 512 x = &H2000: WHILE h# >= 1023.5: h# = h#/2: x=x+&H400: WEND 'Calculate octave13 x = x + CINT(h#)14 OUT p, &HA0 + q: OUT p+1, x AND 255: x = x \ 25615 OUT p, &HB0 + q: OUT p+1, x: chpit(c) = x: RETURN16 'Technically, AdLib requires some delay between consecutive OUT commands.17 'However, BASIC is slow enough, that this is not an issue really.18 'The paradigm "OUT p,index: OUT p+1,value" works perfectly.20 'OPL_Touch(c,v): c=channel, v=volume. CHANGES: q,p,o,i,v21 'The formula below: SOLVE(V=127*127 * 2^( (A-63) / 8), A)22 IF v < 72 THEN v = 0 ELSE v = LOG(v) * 11.541561# - 48.818955#25 'OPL_Touch_Real(c,v): Same as OPL_Touch, except takes logarithmic volume.26 GOSUB 5: i = chins(c)27 OUT p, &H40+o: q = adl(i, 2): GOSUB 2928 OUT p, &H43+o: q = adl(i, 3)29 OUT p+1, (q OR 63) - v + ((q AND 63) * v) \ 63: RETURN30 'OPL_Patch(c): c=channel. CHANGES: q,p,o,x,i31 GOSUB 5: i = chins(c): q = p+132 FOR x = 0 TO 133 OUT p, &H20+o+x*3: OUT q, adl(i, 0+x)34 OUT p, &H60+o+x*3: OUT q, adl(i, 4+x)35 OUT p, &H80+o+x*3: OUT q, adl(i, 6+x)36 OUT p, &HE0+o+x*3: OUT q, adl(i, 8+x)37 NEXT: RETURN38 'OPL_Pan(c): c=channel. CHANGES: q,p,o39 GOSUB 5: OUT p, &HC0+q: OUT p+1, adl(chins(c),10)-chpan(c): RETURN40 'OPL_Reset(). CHANGES: c,q,p,o,x,y,v,i41 'Detect OPL3 (send pulses to timer, opl3 enable register)42 c=0: GOSUB 5: FOR y = 3 TO 4: OUT p, 4: OUT p+1, y*32: NEXT: ?INP(p)43 c=9: GOSUB 5: FOR y = 0 TO 2: OUT p, 5: OUT p+1, y AND 1: NEXT44 'Reset OPL3 (turn off all notes, set vital settings)45 c=0: GOSUB 5: OUT p, 1: OUT p+1, 32 'Enable wave46 c=0: GOSUB 5: OUT p,&HBD:OUT p+1, 0 'Set melodic mode47 c=9: GOSUB 5: OUT p, 5: OUT p+1, 1 'Enable OPL348 c=9: GOSUB 5: OUT p, 4: OUT p+1, 0 'Select mode 0 (also try 63 for fun!)50 'OPL_Silence(): Silence all OPL channels. CHANGES q,p,o,v,c,i51 v = 0: FOR c = 0 TO 17: GOSUB 8: GOSUB 25: NEXT: RETURN70 'ReadString(): Read N bytes from file. Input: x. Output: s$. CHANGES x71 s$ = "": WHILE x > 0: x = x - 1: GET #1: s$ = s$ + b$: WEND: RETURN
75 'ReadVarLen(): Read variable length int from file. Output: x#. CHANGES x76 x# = 077 GET #1: x = ASC(b$): x# = x# * 128 + (x AND 127): IF x >= 128 THEN 7778 RETURN80 'ConvertInteger(): Parses s$ as big-endian integer, stores to x#. CHANGES x81 x# = 0: FOR x=1 TO LEN(s$): x# = x# * 256 + ASC(MID$(s$, x, 1)): NEXT: RETURN82 'The reason why # (DOUBLE) is used to store integer values83 'is that GW-BASIC has only one integer type: INTEGER.84 'It supports values in the range -32768..+32737. Making it unsuitable85 'for storing values such as delta-times and track lengths, both of which86 'are often greater than +32767 in common MIDI files. QuickBASIC supports87 'the LONG datatype instead, but I was aiming for GW-BASIC compatibility88 'in order to utilize my cool syntax highlighter for the majority89 'of the duration of demonstrating this program on Youtube. :)94 'Ethical subroutine95 GOTO 9796 KILL filename$97 RETURN100 '*** MAIN MIDI PLAYER PROGRAM ***101 'Information about each track:102 DIM tkPtr%(100), tkDelay#(100), tkStatus(100), playwait#103 'The same, but for loop-beginning:104 DIM loPtr%(100), loDelay#(100), loStatus(100), loopwait#105 'The same, but cached just in case loop-beginning must be written:106 DIM rbPtr%(100), rbDelay#(100), rbStatus(100)109 'Persistent settings for each MIDI channel.110 DIM ChPatch(15), ChBend#(15), ChVolume(15), ChPanning(15), ChVibrato(15)120 'For each active note, we need the following:121 ' Original note number (ORIGINAL, not simulated)122 ' Keyoff (Search Key)123 ' Aftertouch (Search Key)124 ' Simulated note number125 ' Keyon -> OPL_NoteOn126 ' Bend -> OPL_NoteOn127 ' Keyon/touch pressure128 ' Ctrl:Volume129 ' Adlib channel number130 ' All of above131 ' MIDI channel (multi search key)132 ' Bend133 ' Ctrl:Volume134 ' Ctrl:Pan140 DIM ActCount(15) 'number of active notes on each midi channel141 DIM ActTone(15,127) 'orignotenumber -> simulated notenumber142 DIM ActAdlChn(15,127) 'orignotenumber -> adlib channel143 DIM ActVol(15,127) 'orignotenumber -> pressure144 DIM ActRev(15,127) 'orignotenumber -> activeindex (index to ActList)145 DIM ActList(15,99) 'activeindex -> orignotenumber (index to ActVol etc)146 DIM chon(17),chage#(17)'adlchannel -> is_on,age (for channel allocation)148 DIM chm(17),cha(17) 'adlchannel -> midichn,activeindex (for collisions)149 DIM chx(17),chc(17) 'adlchannel -> x coordinate, color (for graphics)160 filename$ = "chmmr.mid" '<- FILENAME OF THE MIDI TO BE PLAYED161 GOSUB 40 ' Reset AdLib162 GOSUB 40 ' ...twice (just in case someone misprogrammed OPL3 previously)163 PLAYmode$ = "T255P64"164 PLAYmode% = 255 * 64 'Event tick frequency165 PLAYbuflen = 2 'Number of events to keep buffered166 COLOR 8: CLS : txtline = 2: PRINT "Press Q to quit; Space to pause"169 GOSUB 200 ' Load and play MIDI file170 'Begin main program (this simply monitors the playing status)171 'Beware that the timer routine accesses a lot of global variables.172 paused = 0173 hlt(0) = &HCBF4' HLT; RETF.174 hlt = VARPTR(hlt(0))175 CALL hlt176 ' ^This subroutine saves power. It also makes DOSBox faster.177 ' However, QuickBASIC has a different syntax for calling ASM178 ' subroutines, so the line 175 will have to be changed when179 ' porting to QuickBASIC. Disable it, or try this (qb /Lqb.qlb):180 'DEF SEG = VARSEG(hlt(0)): CALL ABSOLUTE(hlt)182 y$ = INKEY$183 IF y$ <> " " THEN 186184 paused = 1 - paused185 IF paused THEN ? "Pause": PLAY STOP ELSE ? "Ok": PLAY ON186 IF y$ <> "q" AND y$ <> CHR$(27) AND y$ <> CHR$(3) THEN 174190 PLAY OFF: PRINT "End!": GOSUB 50: KEY ON: END200 'Subroutine: Load MIDI file210 OPEN filename$ FOR RANDOM AS #1 LEN = 1: FIELD #1, 1 AS b$ 'Open file211 'QuickBASIC has BINARY access mode, which allows to use INPUT$() rather212 'than the silly fixed-size GET command, but GW-BASIC does not support213 'BINARY, so we use RANDOM here. The difference between BINARY and INPUT214 'is that INPUT chokes on EOF characters and translates CRLFs, making it215 'unsuitable for working with MIDI files.220 x = 4: GOSUB 70: IF s$ <> "MThd" THEN ERROR 13'Invalid type file230 x = 4: GOSUB 70: GOSUB 80: IF x# <> 6 THEN ERROR 13231 x = 2: GOSUB 70: GOSUB 80: Fmt = x#232 x = 2: GOSUB 70: GOSUB 80: TrackCount = x#: IF TrackCount>100 THEN ERROR 6233 x = 2: GOSUB 70: GOSUB 80: DeltaTicks = x#234 InvDeltaTicks# = PLAYmode% / (240000000# * DeltaTicks)240 Tempo# = 1000000# * InvDeltaTicks#241 bendsense# = 2 / 8192#250 FOR tk = 1 TO TrackCount251 x = 4: GOSUB 70: IF s$ <> "MTrk" THEN ERROR 13'Invalid type file252 x = 4: GOSUB 70: GOSUB 80: TrackLength% = x#: y% = LOC(1)253 GOSUB 75: tkDelay#(tk) = x# 'Read next event time254 tkPtr%(tk) = LOC(1) 'Save first event file position255 GET #1, y% + TrackLength% 'Skip to beginning of next track header270 NEXT275 FOR a = 0 TO 15: ChVolume(a) = 127: NEXT281 PLAY ON: ON PLAY(PLAYbuflen) GOSUB 300 'Set up periodic event handler282 began = 0: loopStart = 1: playwait# = 0: PLAY "MLMB"300 'Subroutine: Timer callback. Called when the PLAY buffer is exhausted.301 IF began THEN playwait# = playwait# - 1#302 'For each track where delay=0, parse events and read new delay.303 WHILE playwait# < .5#: GOSUB 310: WEND304 'Repopulate the PLAY buffer305 WHILE PLAY(0) < PLAYbuflen: PLAY PLAYmode$: WEND: RETURN310 'Subroutine: Process events on any track that is due311 FOR tk = 1 TO TrackCount312 rbPtr%(tk) = tkPtr%(tk)313 rbDelay#(tk) = tkDelay#(tk)314 rbStatus(tk) = tkStatus(tk)315 IF tkStatus(tk) < 0 OR tkDelay#(tk) > 0 THEN 319316 GOSUB 350 'Handle event317 GOSUB 75: tkDelay#(tk) = tkDelay#(tk) + x# 'Read next event time318 tkPtr%(tk) = LOC(1) 'Save modified file position319 NEXT320 IF loopStart = 0 THEN 338321 'Save loop begin322 FOR tk = 1 TO TrackCount323 loPtr%(tk) = rbPtr%(tk)324 loDelay#(tk) = rbDelay#(tk)325 loStatus(tk) = rbStatus(tk)326 NEXT327 loopwait# = playwait#328 loopStart = 0329 GOTO 338330 'Return to loop beginning331 FOR tk = 1 TO TrackCount332 tkPtr%(tk) = loPtr%(tk)333 tkDelay#(tk) = loDelay#(tk)334 tkStatus(tk) = loStatus(tk)335 NEXT336 loopEnd = 0337 playwait# = loopwait#338 'Find shortest delay from all tracks339 nd# = -1340 FOR tk = 1 TO TrackCount341 IF tkStatus(tk) < 0 THEN 343342 IF nd# = -1 OR tkDelay#(tk) < nd# THEN nd# = tkDelay#(tk)343 NEXT344 'Schedule the next playevent to be processed after that delay345 FOR tk = 1 TO TrackCount: tkDelay#(tk) = tkDelay#(tk) - nd#: NEXT346 t# = nd# * Tempo#: IF began THEN playwait# = playwait# + t#347 FOR a = 0 TO 17: chage#(a) = chage#(a) + t#: NEXT348 IF t# < 0 OR loopEnd THEN 330 ELSE RETURN 'Loop or done350 'Subroutine: Read an event from track, and read next delay. Input: tk351 'Note that we continuously access the disk file during playback.352 'This is perfectly fine when we are running on a modern OS, possibly353 'under the encapsulation of DOSBox, but if you're running this on354 'vanilla MS-DOS without e.g. SMARTDRV, you are going to find this355 'program very unsuitable for your MIDI playing needs, for the disk356 'drive would probably make more noise than the soundcard does.357 'We cannot cache tracks because of memory constraints in GW-BASIC.358 'In QBASIC, we could do better, but it would be cumbersome to implement.359 GET #1, tkPtr%(tk) + 1: b = ASC(b$)360 IF b < &HF0 THEN 380361 'Subroutine for Fx special events362 '? tk;":";HEX$(b);" at $";hex$(LOC(1))363 IF b = &HF7 OR b = &HF0 THEN 76'SysEx. Ignore Varlen.364 IF b = &HF3 THEN GET #1: RETURN365 IF b = &HF2 THEN GET #1: GET #1: RETURN370 'Subroutine for special event FF371 GET #1: evtype = ASC(b$): GOSUB 75: x = x#: GOSUB 70372 IF evtype = &H2F THEN tkStatus(tk) = -1373 IF evtype = &H51 THEN GOSUB 80: Tempo# = x# * InvDeltaTicks#374 IF evtype = 6 AND s$ = "loopStart" THEN loopStart = 1375 IF evtype = 6 AND s$ = "loopEnd" THEN loopEnd = 1376 IF evtype < 1 OR evtype > 6 THEN RETURN377 txtline = 3 + (txtline - 2) MOD 20378 LOCATE txtline, 1: COLOR 8: PRINT "Meta"; evtype; ": "; s$: RETURN380 'Subroutine for any normal event (80..EF)381 IF b < 128 THEN b = tkStatus(tk) OR &H80: GET #1, tkPtr%(tk)382 MidCh = b AND 15: tkStatus(tk) = b383 '? tk;":";HEX$(b);" at $";hex$(LOC(1))384 ON b\16 - 7 GOTO 400,420,460,470,490,492,495 'Choose event handler400 'Event: 8x Note Off401 GET #1: note = ASC(b$): GET #1': vol=ASC(b$)402 ChBend#(MidCh) = 0403 n = ActRev(MidCh,note): IF n = 0 THEN RETURN404 m = MidCh: GOTO 600 'deallocate active note, and return420 'Event: 9x Note On421 GET #1: note = ASC(b$): GET #1: vol = ASC(b$)422 IF vol = 0 THEN 402' Sometimes noteoffs are optimized as 0-vol noteons423 IF ActRev(MidCh,note) THEN RETURN 'Ignore repeat notes w/o keyoffs424 'Determine the instrument and the note value (tone)425 tone = note: i = ChPatch(MidCh)426 IF MidCh = 9 THEN i = 128+note-35: tone = adl(i,11) 'Translate percussion427 '(MIDI channel 9 always plays percussion and ignores the patch number)429 'Allocate AdLib channel (the physical sound channel for the note)430 bs# = -9: c = -1431 FOR a = 0 TO 17432 s# = chage#(a)433 IF chon(a) = 0 THEN s# = s# + 3d3 ' Empty channel = privileged434 IF chins(a) = i THEN s# = s# + .2# ' Same instrument = good435 IF i<128 AND chins(a)>127 THEN s# = s#*2+9'Percussion is inferior to melody436 IF s# > bs# THEN bs# = s#: c = a ' Best candidate wins437 NEXT438 IF chon(c) THEN m=chm(c): n=cha(c): GOSUB 600 'Collision: Kill old note439 chon(c) = 1: chins(c) = i: chage#(c) = 0: began = 1440 'Allocate active note for MIDI channel441 '"Active note" helps dealing with further events affecting this note.442 n = ActCount(MidCh) + 1443 ActList(MidCh, n) = note444 ActRev(MidCh,note) = n445 ActCount(MidCh) = n449 'Record info about this note450 ActTone(MidCh,note) = tone451 ActAdlChn(MidCh,note) = c452 ActVol(MidCh,note) = vol453 chm(c) = MidCh: cha(c) = n ' Save this note's origin so collision works.454 GOSUB 30 ' OPL_Patch455 GOSUB 530' OPL_Pan with ChPanning456 GOSUB 540' OPL_Touch with ChVolume457 chx(c) = 1 + (tone+63)MOD 80: chc(c) = 9+(chins(c)MOD 6)458 LOCATE 20-c, chx(c): COLOR chc(c): PRINT "#";459 GOTO 520 ' OPL_NoteOn with ChBend, and return460 'Event: Ax Note touch461 GET #1: note = ASC(b$): GET #1: vol = ASC(b$)462 IF ActRev(MidCh,note) = 0 THEN RETURN'Ignore touch if note is not active463 c = ActAdlChn(MidCh,note)464 LOCATE 20-c, chx(c): COLOR chc(c): PRINT "&";465 ActVol(MidCh,note) = vol466 GOTO 540 'update note volume, and return470 'Event: Bx Controller change471 GET #1: ctrlno = ASC(b$): GET #1: value = ASC(b$)472 IF ctrlno = 1 THEN ChVibrato(MidCh) = value 'TODO: handle473 IF ctrlno = 6 THEN bendsense# = value / 8192#474 IF ctrlno = 7 THEN ChVolume(MidCh) = value: mop = 2: GOTO 500475 IF ctrlno = 10 THEN 482 'Pan476 IF ctrlno = 121 THEN 486 'Reset controllers477 IF ctrlno = 123 THEN mop=5: GOTO 500 'All notes off on channel478 'Other ctrls worth considering:479 ' 0 = choose bank (bank+patch identifies the instrument)480 ' 64 = sustain pedal (when used, noteoff does not produce an adlib keyoff)481 RETURN482 'Ctrl 10: Alter the panning of the channel:483 p = 0: IF value < 48 THEN p = 32 ELSE IF value > 79 THEN p = 16484 ChPanning(MidCh) = p485 mop=4: GOTO 500486 'Ctrl 121: Reset all controllers to their default values.487 ChBend#(MidCh)=0: ChVibrato(MidCh)=0: ChPan(MidCh)=0488 mop=1: GOSUB 500: mop=2: GOSUB 500: mop=4: GOTO 500490 'Event: Cx Patch change491 GET #1: ChPatch(MidCh) = ASC(b$): RETURN492 'Event: Dx Channel after-touch493 GET #1: vol = ASC(b$): mop=3:GOTO 500 'TODO: Verify, is this correct action?495 'Event: Ex Wheel/bend496 GET #1: a = ASC(b$): GET #1497 ChBend#(MidCh) = (a + ASC(b$) * 128 - 8192) * bendsense#498 mop = 1: GOTO 500 'Update pitches, and return500 'Subroutine: Update all live notes. Input: MidCh,mop501 'Update when mop: 1=pitches; 2=volumes; 3=pressures; 4=pans, 5=off502 x1 = ActCount(MidCh)503 FOR a = 1 TO x1504 note = ActList(MidCh, a)505 c = ActAdlChn(MidCh,note): ON mop GOSUB 508,509,510,530,511506 NEXT507 RETURN508 tone = ActTone(MidCh,note): GOTO 520509 vol = ActVol(MidCh, note): GOTO 540510 ActVol(MidCh,note) = vol: GOTO 540511 m = MidCh: n = a: GOTO 600520 'Subroutine: Update note pitch. Input: c,MidCh,tone. CHANGES q,p,o,x,h#521 ' 907*2^(n/12) * (8363) / 44100522 h# = 172.00093# * EXP(.057762265#*(tone+ChBend#(MidCh))): GOTO 10'OPL_NoteOn530 'Subroutine: Update note pan. Input: c,MidCh531 chpan(c) = ChPanning(MidCh): GOTO 38 'OPL_Pan540 'Subroutine: Update note volume. Input: c,MidCh,vol. CHANGES q,p,o,v541 v = vol * ChVolume(MidCh): GOTO 20 'OPL_Touch600 'Subroutine: Deallocate active note (m = MidCh, n = index). CHANGES c,x,q601 'Uses m instead of MidCh because called also from alloc-collision code.602 x = ActCount(m) ' Find how many active notes603 q = ActList(m,n) ' q=note to be deactivated604 ActRev(m,q) = 0 ' that note is no more605 ActCount(m) = x-1 ' The list is now shorter606 c = ActAdlChn(m,q) ' But wait, which adlib channel was it on, again?607 chon(c)=0: chage#(c)=0: GOSUB 8'OPL_NoteOff608 LOCATE 20-c, chx(c): COLOR 1: PRINT ".";610 IF n = x THEN RETURN' Did we delete the last note?611 q = ActList(m,x) ' q = last note in list612 ActList(m,n) = q ' move into the deleted slot613 ActRev(m,q) = n614 cha(ActAdlChn(m,q)) = n615 RETURN760 'This FM Instrument Data comes from Miles Sound System, as used761 'in the following PC games: Star Control III and Asterix, under762 'the name AIL (Audio Interface Library). Today, AIL has been763 'released as "open-source freeware" under the name Miles Sound System.764 'AIL was used in more than fifty PC games, but so far, I have found765 'this particular set of General MIDI FM patches only in SC3 and Asterix.766 'Other games using AIL used different sets of FM patches. There is no767 'particular reason for preferring this patch set, and in fact, the768 'descendant of this program, ADLMIDI, http://iki.fi/source/adlmidi.html ,769 'features a large set of different FM patch sets to choose from.773 'In the Youtube video, I enter this huge blob of DATA lines very quickly774 'by using a preprogrammed input TSR, "inputter", which I made just for775 'this purpose.776 'It inputs the inline command "COLOR 0,4", turning text into black on red,777 'and then starts entering DATA lines in an arbitrary geometrical fashion.778 'After inputting, the text color is reset to normal with "COLOR 7,0".779 'Of course, the whole time, the poor syntax highlighter TSR (synhili)780 'does its best to make sense of whatever is being displayed on the screen,781 'causing the text to stay red only for a short while, whereever the cursor782 'was last. The resulting effect looks very cool, and most importantly,783 'the long sequence of DATA gets input in a non-boring manner.790 'The data bytes are:791 ' [0,1] AM/VIB/EG/KSR/Multiple bits for carrier and modulator respectively792 ' [2,3] KSL/Attenuation settings for carrier and modulator respectively793 ' [4,5] Attack and decay rates for carrier and modulator respectively794 ' [6,7] Sustain and release rates for carrier and modulator respectively795 ' [8,9] Wave select settings for carrier and modulator respectively796 ' [10] Feedback/connection bits for the channel (also stereo/pan bits)797 ' [11] For percussive instruments (GP35..GP87), the tone to play800 DATA 1, 1,143, 6,242,242,244,247,0,0, 56, 0: REM GM1:AcouGrandPiano801 DATA 1, 1, 75, 0,242,242,244,247,0,0, 56, 0: REM GM2:BrightAcouGrand802 DATA 1, 1, 73, 0,242,242,244,246,0,0, 56, 0: REM GM3:ElecGrandPiano803 DATA 129, 65, 18, 0,242,242,247,247,0,0, 54, 0: REM GM4:Honky-tonkPiano804 DATA 1, 1, 87, 0,241,242,247,247,0,0, 48, 0: REM GM5:Rhodes Piano805 DATA 1, 1,147, 0,241,242,247,247,0,0, 48, 0: REM GM6:Chorused Piano806 DATA 1, 22,128, 14,161,242,242,245,0,0, 56, 0: REM GM7:Harpsichord807 DATA 1, 1,146, 0,194,194,248,248,0,0, 58, 0: REM GM8:Clavinet808 DATA 12,129, 92, 0,246,243,244,245,0,0, 48, 0: REM GM9:Celesta809 DATA 7, 17,151,128,243,242,242,241,0,0, 50, 0: REM GM10:Glockenspiel810 DATA 23, 1, 33, 0, 84,244,244,244,0,0, 50, 0: REM GM11:Music box811 DATA 152,129, 98, 0,243,242,246,246,0,0, 48, 0: REM GM12:Vibraphone812 DATA 24, 1, 35, 0,246,231,246,247,0,0, 48, 0: REM GM13:Marimba813 DATA 21, 1,145, 0,246,246,246,246,0,0, 52, 0: REM GM14:Xylophone814 DATA 69,129, 89,128,211,163,243,243,0,0, 60, 0: REM GM15:Tubular Bells815 DATA 3,129, 73,128,117,181,245,245,1,0, 52, 0: REM GM16:Dulcimer816 DATA 113, 49,146, 0,246,241, 20, 7,0,0, 50, 0: REM GM17:Hammond Organ817 DATA 114, 48, 20, 0,199,199, 88, 8,0,0, 50, 0: REM GM18:Percussive Organ818 DATA 112,177, 68, 0,170,138, 24, 8,0,0, 52, 0: REM GM19:Rock Organ819 DATA 35,177,147, 0,151, 85, 35, 20,1,0, 52, 0: REM GM20:Church Organ820 DATA 97,177, 19,128,151, 85, 4, 4,1,0, 48, 0: REM GM21:Reed Organ821 DATA 36,177, 72, 0,152, 70, 42, 26,1,0, 60, 0: REM GM22:Accordion822 DATA 97, 33, 19, 0,145, 97, 6, 7,1,0, 58, 0: REM GM23:Harmonica823 DATA 33,161, 19,137,113, 97, 6, 7,0,0, 54, 0: REM GM24:Tango Accordion824 DATA 2, 65,156,128,243,243,148,200,1,0, 60, 0: REM GM25:Acoustic Guitar1825 DATA 3, 17, 84, 0,243,241,154,231,1,0, 60, 0: REM GM26:Acoustic Guitar2826 DATA 35, 33, 95, 0,241,242, 58,248,0,0, 48, 0: REM GM27:Electric Guitar1827 DATA 3, 33,135,128,246,243, 34,248,1,0, 54, 0: REM GM28:Electric Guitar2828 DATA 3, 33, 71, 0,249,246, 84, 58,0,0, 48, 0: REM GM29:Electric Guitar3829 DATA 35, 33, 74, 5,145,132, 65, 25,1,0, 56, 0: REM GM30:Overdrive Guitar830 DATA 35, 33, 74, 0,149,148, 25, 25,1,0, 56, 0: REM GM31:Distorton Guitar831 DATA 9,132,161,128, 32,209, 79,248,0,0, 56, 0: REM GM32:Guitar Harmonics832 DATA 33,162, 30, 0,148,195, 6,166,0,0, 50, 0: REM GM33:Acoustic Bass833 DATA 49, 49, 18, 0,241,241, 40, 24,0,0, 58, 0: REM GM34:Electric Bass 1834 DATA 49, 49,141, 0,241,241,232,120,0,0, 58, 0: REM GM35:Electric Bass 2835 DATA 49, 50, 91, 0, 81,113, 40, 72,0,0, 60, 0: REM GM36:Fretless Bass836 DATA 1, 33,139, 64,161,242,154,223,0,0, 56, 0: REM GM37:Slap Bass 1837 DATA 33, 33,139, 8,162,161, 22,223,0,0, 56, 0: REM GM38:Slap Bass 2838 DATA 49, 49,139, 0,244,241,232,120,0,0, 58, 0: REM GM39:Synth Bass 1839 DATA 49, 49, 18, 0,241,241, 40, 24,0,0, 58, 0: REM GM40:Synth Bass 2840 DATA 49, 33, 21, 0,221, 86, 19, 38,1,0, 56, 0: REM GM41:Violin841 DATA 49, 33, 22, 0,221,102, 19, 6,1,0, 56, 0: REM GM42:Viola842 DATA 113, 49, 73, 0,209, 97, 28, 12,1,0, 56, 0: REM GM43:Cello843 DATA 33, 35, 77,128,113,114, 18, 6,1,0, 50, 0: REM GM44:Contrabass844 DATA 241,225, 64, 0,241,111, 33, 22,1,0, 50, 0: REM GM45:Tremulo Strings845 DATA 2, 1, 26,128,245,133,117, 53,1,0, 48, 0: REM GM46:Pizzicato String846 DATA 2, 1, 29,128,245,243,117,244,1,0, 48, 0: REM GM47:Orchestral Harp847 DATA 16, 17, 65, 0,245,242, 5,195,1,0, 50, 0: REM GM48:Timpany848 DATA 33,162,155, 1,177,114, 37, 8,1,0, 62, 0: REM GM49:String Ensemble1849 DATA 161, 33,152, 0,127, 63, 3, 7,1,1, 48, 0: REM GM50:String Ensemble2850 DATA 161, 97,147, 0,193, 79, 18, 5,0,0, 58, 0: REM GM51:Synth Strings 1851 DATA 33, 97, 24, 0,193, 79, 34, 5,0,0, 60, 0: REM GM52:SynthStrings 2852 DATA 49,114, 91,131,244,138, 21, 5,0,0, 48, 0: REM GM53:Choir Aahs853 DATA 161, 97,144, 0,116,113, 57,103,0,0, 48, 0: REM GM54:Voice Oohs854 DATA 113,114, 87, 0, 84,122, 5, 5,0,0, 60, 0: REM GM55:Synth Voice855 DATA 144, 65, 0, 0, 84,165, 99, 69,0,0, 56, 0: REM GM56:Orchestra Hit856 DATA 33, 33,146, 1,133,143, 23, 9,0,0, 60, 0: REM GM57:Trumpet857 DATA 33, 33,148, 5,117,143, 23, 9,0,0, 60, 0: REM GM58:Trombone858 DATA 33, 97,148, 0,118,130, 21, 55,0,0, 60, 0: REM GM59:Tuba859 DATA 49, 33, 67, 0,158, 98, 23, 44,1,1, 50, 0: REM GM60:Muted Trumpet860 DATA 33, 33,155, 0, 97,127,106, 10,0,0, 50, 0: REM GM61:French Horn861 DATA 97, 34,138, 6,117,116, 31, 15,0,0, 56, 0: REM GM62:Brass Section862 DATA 161, 33,134,131,114,113, 85, 24,1,0, 48, 0: REM GM63:Synth Brass 1863 DATA 33, 33, 77, 0, 84,166, 60, 28,0,0, 56, 0: REM GM64:Synth Brass 2864 DATA 49, 97,143, 0,147,114, 2, 11,1,0, 56, 0: REM GM65:Soprano Sax865 DATA 49, 97,142, 0,147,114, 3, 9,1,0, 56, 0: REM GM66:Alto Sax866 DATA 49, 97,145, 0,147,130, 3, 9,1,0, 58, 0: REM GM67:Tenor Sax867 DATA 49, 97,142, 0,147,114, 15, 15,1,0, 58, 0: REM GM68:Baritone Sax868 DATA 33, 33, 75, 0,170,143, 22, 10,1,0, 56, 0: REM GM69:Oboe869 DATA 49, 33,144, 0,126,139, 23, 12,1,1, 54, 0: REM GM70:English Horn870 DATA 49, 50,129, 0,117, 97, 25, 25,1,0, 48, 0: REM GM71:Bassoon871 DATA 50, 33,144, 0,155,114, 33, 23,0,0, 52, 0: REM GM72:Clarinet872 DATA 225,225, 31, 0,133,101, 95, 26,0,0, 48, 0: REM GM73:Piccolo873 DATA 225,225, 70, 0,136,101, 95, 26,0,0, 48, 0: REM GM74:Flute874 DATA 161, 33,156, 0,117,117, 31, 10,0,0, 50, 0: REM GM75:Recorder875 DATA 49, 33,139, 0,132,101, 88, 26,0,0, 48, 0: REM GM76:Pan Flute876 DATA 225,161, 76, 0,102,101, 86, 38,0,0, 48, 0: REM GM77:Bottle Blow877 DATA 98,161,203, 0,118, 85, 70, 54,0,0, 48, 0: REM GM78:Shakuhachi878 DATA 98,161,153, 0, 87, 86, 7, 7,0,0, 59, 0: REM GM79:Whistle879 DATA 98,161,147, 0,119,118, 7, 7,0,0, 59, 0: REM GM80:Ocarina880 DATA 34, 33, 89, 0,255,255, 3, 15,2,0, 48, 0: REM GM81:Lead 1 squareea881 DATA 33, 33, 14, 0,255,255, 15, 15,1,1, 48, 0: REM GM82:Lead 2 sawtooth882 DATA 34, 33, 70,128,134,100, 85, 24,0,0, 48, 0: REM GM83:Lead 3 calliope883 DATA 33,161, 69, 0,102,150, 18, 10,0,0, 48, 0: REM GM84:Lead 4 chiff884 DATA 33, 34,139, 0,146,145, 42, 42,1,0, 48, 0: REM GM85:Lead 5 charang885 DATA 162, 97,158, 64,223,111, 5, 7,0,0, 50, 0: REM GM86:Lead 6 voice886 DATA 32, 96, 26, 0,239,143, 1, 6,0,2, 48, 0: REM GM87:Lead 7 fifths887 DATA 33, 33,143,128,241,244, 41, 9,0,0, 58, 0: REM GM88:Lead 8 brass888 DATA 119,161,165, 0, 83,160,148, 5,0,0, 50, 0: REM GM89:Pad 1 new age889 DATA 97,177, 31,128,168, 37, 17, 3,0,0, 58, 0: REM GM90:Pad 2 warm890 DATA 97, 97, 23, 0,145, 85, 52, 22,0,0, 60, 0: REM GM91:Pad 3 polysynth891 DATA 113,114, 93, 0, 84,106, 1, 3,0,0, 48, 0: REM GM92:Pad 4 choir892 DATA 33,162,151, 0, 33, 66, 67, 53,0,0, 56, 0: REM GM93:Pad 5 bowedpad893 DATA 161, 33, 28, 0,161, 49,119, 71,1,1, 48, 0: REM GM94:Pad 6 metallic894 DATA 33, 97,137, 3, 17, 66, 51, 37,0,0, 58, 0: REM GM95:Pad 7 halo895 DATA 161, 33, 21, 0, 17,207, 71, 7,1,0, 48, 0: REM GM96:Pad 8 sweep896 DATA 58, 81,206, 0,248,134,246, 2,0,0, 50, 0: REM GM97:FX 1 rain897 DATA 33, 33, 21, 0, 33, 65, 35, 19,1,0, 48, 0: REM GM98:FX 2 soundtrack898 DATA 6, 1, 91, 0,116,165,149,114,0,0, 48, 0: REM GM99:FX 3 crystal899 DATA 34, 97,146,131,177,242,129, 38,0,0, 60, 0: REM GM100:FX 4 atmosphere900 DATA 65, 66, 77, 0,241,242, 81,245,1,0, 48, 0: REM GM101:FX 5 brightness901 DATA 97,163,148,128, 17, 17, 81, 19,1,0, 54, 0: REM GM102:FX 6 goblins902 DATA 97,161,140,128, 17, 29, 49, 3,0,0, 54, 0: REM GM103:FX 7 echoes903 DATA 164, 97, 76, 0,243,129,115, 35,1,0, 52, 0: REM GM104:FX 8 sci-fi904 DATA 2, 7,133, 3,210,242, 83,246,0,1, 48, 0: REM GM105:Sitar905 DATA 17, 19, 12,128,163,162, 17,229,1,0, 48, 0: REM GM106:Banjo906 DATA 17, 17, 6, 0,246,242, 65,230,1,2, 52, 0: REM GM107:Shamisen907 DATA 147,145,145, 0,212,235, 50, 17,0,1, 56, 0: REM GM108:Koto908 DATA 4, 1, 79, 0,250,194, 86, 5,0,0, 60, 0: REM GM109:Kalimba909 DATA 33, 34, 73, 0,124,111, 32, 12,0,1, 54, 0: REM GM110:Bagpipe910 DATA 49, 33,133, 0,221, 86, 51, 22,1,0, 58, 0: REM GM111:Fiddle911 DATA 32, 33, 4,129,218,143, 5, 11,2,0, 54, 0: REM GM112:Shanai912 DATA 5, 3,106,128,241,195,229,229,0,0, 54, 0: REM GM113:Tinkle Bell913 DATA 7, 2, 21, 0,236,248, 38, 22,0,0, 58, 0: REM GM114:Agogo Bells914 DATA 5, 1,157, 0,103,223, 53, 5,0,0, 56, 0: REM GM115:Steel Drums915 DATA 24, 18,150, 0,250,248, 40,229,0,0, 58, 0: REM GM116:Woodblock916 DATA 16, 0,134, 3,168,250, 7, 3,0,0, 54, 0: REM GM117:Taiko Drum917 DATA 17, 16, 65, 3,248,243, 71, 3,2,0, 52, 0: REM GM118:Melodic Tom918 DATA 1, 16,142, 0,241,243, 6, 2,2,0, 62, 0: REM GM119:Synth Drum919 DATA 14,192, 0, 0, 31, 31, 0,255,0,3, 62, 0: REM GM120:Reverse Cymbal920 DATA 6, 3,128,136,248, 86, 36,132,0,2, 62, 0: REM GM121:Guitar FretNoise921 DATA 14,208, 0, 5,248, 52, 0, 4,0,3, 62, 0: REM GM122:Breath Noise922 DATA 14,192, 0, 0,246, 31, 0, 2,0,3, 62, 0: REM GM123:Seashore923 DATA 213,218,149, 64, 55, 86,163, 55,0,0, 48, 0: REM GM124:Bird Tweet924 DATA 53, 20, 92, 8,178,244, 97, 21,2,0, 58, 0: REM GM125:Telephone925 DATA 14,208, 0, 0,246, 79, 0,245,0,3, 62, 0: REM GM126:Helicopter926 DATA 38,228, 0, 0,255, 18, 1, 22,0,1, 62, 0: REM GM127:Applause/Noise927 DATA 0, 0, 0, 0,243,246,240,201,0,2, 62, 0: REM GM128:Gunshot928 DATA 16, 17, 68, 0,248,243,119, 6,2,0, 56, 35: REM GP35:Ac Bass Drum929 DATA 16, 17, 68, 0,248,243,119, 6,2,0, 56, 35: REM GP36:Bass Drum 1930 DATA 2, 17, 7, 0,249,248,255,255,0,0, 56, 52: REM GP37:Side Stick931 DATA 0, 0, 0, 0,252,250, 5, 23,2,0, 62, 48: REM GP38:Acoustic Snare932 DATA 0, 1, 2, 0,255,255, 7, 8,0,0, 48, 58: REM GP39:Hand Clap933 DATA 0, 0, 0, 0,252,250, 5, 23,2,0, 62, 60: REM GP40:Electric Snare934 DATA 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 47: REM GP41:Low Floor Tom935 DATA 12, 18, 0, 0,246,251, 8, 71,0,2, 58, 43: REM GP42:Closed High Hat936 DATA 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 49: REM GP43:High Floor Tom937 DATA 12, 18, 0, 5,246,123, 8, 71,0,2, 58, 43: REM GP44:Pedal High Hat938 DATA 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 51: REM GP45:Low Tom939 DATA 12, 18, 0, 0,246,203, 2, 67,0,2, 58, 43: REM GP46:Open High Hat940 DATA 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 54: REM GP47:Low-Mid Tom941 DATA 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 57: REM GP48:High-Mid Tom942 DATA 14,208, 0, 0,246,159, 0, 2,0,3, 62, 72: REM GP49:Crash Cymbal 1943 DATA 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 60: REM GP50:High Tom944 DATA 14, 7, 8, 74,248,244, 66,228,0,3, 62, 76: REM GP51:Ride Cymbal 1945 DATA 14,208, 0, 10,245,159, 48, 2,0,0, 62, 84: REM GP52:Chinese Cymbal946 DATA 14, 7, 10, 93,228,245,228,229,3,1, 54, 36: REM GP53:Ride Bell947 DATA 2, 5, 3, 10,180,151, 4,247,0,0, 62, 65: REM GP54:Tambourine948 DATA 78,158, 0, 0,246,159, 0, 2,0,3, 62, 84: REM GP55:Splash Cymbal949 DATA 17, 16, 69, 8,248,243, 55, 5,2,0, 56, 83: REM GP56:Cow Bell950 DATA 14,208, 0, 0,246,159, 0, 2,0,3, 62, 84: REM GP57:Crash Cymbal 2951 DATA 128, 16, 0, 13,255,255, 3, 20,3,0, 60, 24: REM GP58:Vibraslap952 DATA 14, 7, 8, 74,248,244, 66,228,0,3, 62, 77: REM GP59:Ride Cymbal 2953 DATA 6, 2, 11, 0,245,245, 12, 8,0,0, 54, 60: REM GP60:High Bongo954 DATA 1, 2, 0, 0,250,200,191,151,0,0, 55, 65: REM GP61:Low Bongo955 DATA 1, 1, 81, 0,250,250,135,183,0,0, 54, 59: REM GP62:Mute High Conga956 DATA 1, 2, 84, 0,250,248,141,184,0,0, 54, 51: REM GP63:Open High Conga957 DATA 1, 2, 89, 0,250,248,136,182,0,0, 54, 45: REM GP64:Low Conga958 DATA 1, 0, 0, 0,249,250, 10, 6,3,0, 62, 71: REM GP65:High Timbale959 DATA 0, 0,128, 0,249,246,137,108,3,0, 62, 60: REM GP66:Low Timbale960 DATA 3, 12,128, 8,248,246,136,182,3,0, 63, 58: REM GP67:High Agogo961 DATA 3, 12,133, 0,248,246,136,182,3,0, 63, 53: REM GP68:Low Agogo962 DATA 14, 0, 64, 8,118,119, 79, 24,0,2, 62, 64: REM GP69:Cabasa963 DATA 14, 3, 64, 0,200,155, 73,105,0,2, 62, 71: REM GP70:Maracas964 DATA 215,199,220, 0,173,141, 5, 5,3,0, 62, 61: REM GP71:Short Whistle965 DATA 215,199,220, 0,168,136, 4, 4,3,0, 62, 61: REM GP72:Long Whistle966 DATA 128, 17, 0, 0,246,103, 6, 23,3,3, 62, 44: REM GP73:Short Guiro967 DATA 128, 17, 0, 9,245, 70, 5, 22,2,3, 62, 40: REM GP74:Long Guiro968 DATA 6, 21, 63, 0, 0,247,244,245,0,0, 49, 69: REM GP75:Claves969 DATA 6, 18, 63, 0, 0,247,244,245,3,0, 48, 68: REM GP76:High Wood Block970 DATA 6, 18, 63, 0, 0,247,244,245,0,0, 49, 63: REM GP77:Low Wood Block971 DATA 1, 2, 88, 0,103,117,231, 7,0,0, 48, 74: REM GP78:Mute Cuica972 DATA 65, 66, 69, 8,248,117, 72, 5,0,0, 48, 60: REM GP79:Open Cuica973 DATA 10, 30, 64, 78,224,255,240, 5,3,0, 56, 80: REM GP80:Mute Triangle974 DATA 10, 30,124, 82,224,255,240, 2,3,0, 56, 64: REM GP81:Open Triangle975 DATA 14, 0, 64, 8,122,123, 74, 27,0,2, 62, 72: REM GP82976 DATA 14, 7, 10, 64,228, 85,228, 57,3,1, 54, 73: REM GP83977 DATA 5, 4, 5, 64,249,214, 50,165,3,0, 62, 70: REM GP84978 DATA 2, 21, 63, 0, 0,247,243,245,3,0, 56, 68: REM GP85979 DATA 1, 2, 79, 0,250,248,141,181,0,0, 55, 48: REM GP86980 DATA 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 53: REM GP87
There are a lot of OUT statements for OPL-3 related stuff accessing some Yamaha chip. I can't find much documentation about the subject online. Does anyone know a few good sources documenting this chip?
My GitHub:
https://github.com/peterswinkels