-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathc64_play.a65
684 lines (644 loc) · 17.5 KB
/
c64_play.a65
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
; ---------------------------------------------------------------------
; DRO AdLib OPL2 player for Commodore 64 equipped with SFX
; Sound Expander cartridge with YM3812 chip (the "normal" chip
; this cartridge was shipped with may work, but since OPL2 features
; do not exist on those, music will be somewhat "odd" to listen to).
; --OR--
; It will be able to run on MEGA65 using its built in implementation
; of an OPL3 chip. Currently only tested with Xemu emulation of MEGA65,
; which has some issues though.
; ---------------------------------------------------------------------
; VERSION: 1.3a
; ---------------------------------------------------------------------
; (C)2011,2020-2021,2024 LGB (Gábor Lénárt) lgb@lgb.hu, this program can be used
; according to the GNU/GPL 2 or 3 (or later, if a new one is released) license.
; License: http://www.gnu.org/licenses/gpl-2.0.html
; License: http://www.gnu.org/licenses/gpl-3.0.html
; Personal note: PLEASE drop me a mail if you have ideas to modify
; this program (patches, bugs, features etc) or if you use it in your work,
; as the GPL defines, you should provide the source of your work then
; too as it must be GPL then. Thanks! Of course any feedback is welcome, anyway.
; ---------------------------------------------------------------------
; Needs Sound Expander cartridge equipped with YM3812 chip.
; It plays DOSBOX captured "DRO" files, version2 format is supported only
; (see later in the source at the .DEFINE DRO_FILE statement).
; ---------------------------------------------------------------------
; QUICK INSTALL/TEST HOWTO:
;
; Assembler:
; Get ca65 from the cc65 suite (www.cc65.org). Yes, it's a C
; compiler for 6502 in general, but we need only the
; assembler&linker only, not the compiler itself.
; GNU make
; Preparation:
; You must get a DRO (v2) file from somewhere (grab one with DOSBOX
; for example), you must place it into the directory where this
; asm source is, and you may want to modify the source at the
; .DEFINE DRO_FILE for incbin'ing the right file. I can't
; distribute music too much, since I haven't got an own one ...
; PLEASE CONTACT ME, if you have DRO file which can be distributed
; - as an example - with the source! IT WOULD BE REALLY NICE!
; Compilation:
; Simply say: make
; Test (with VICE emulator):
; use "make vice" to start VICE with the program
; You can configure the SFX Sound Expander cartridge "by hand"
; too in the menu of the VICE, of course. About VICE: it did not
; work for me (version 2.3) on Linux (no sound and/or even crash),
; also I've heard reports
; that it has problems with Windows too (I don't have Windows,
; so I can't tell) sometimes (?) at least. You may want to check
; VICE's SVN repository out for the development release; it works
; for me now (2.3.11, SVN revision I've tested with: 24920)!!
; The best thing is test on the real hardware though!
; UPDATE:
; * thanks to Raj for testing it on a real hardware :)
; * thanks to Soci for suggesting devel version of VICE to test with
; ---------------------------------------------------------------------
; What I could test with VICE (video):
; C64 (VICE emulation): http://www.youtube.com/watch?v=umiL62CPObg
; MEGA65 (Xemu emulation): https://www.youtube.com/watch?v=yEowEZfkLOY
; Project can be found here:
; https://github.com/lgblgblgb/c64-sfx-cartridge-player
; ---------------------------------------------------------------------
; TODO list:
; * rework the player to use IRQ for playing
; * get a "safe" (free to distribute) DRO music to include
; * SID mode: try to mimic the cartridge with SID: will sound
; awful (with rapidly changed channels) but it can be used to
; test the stuff without a cartridge too (on C65/MEGA65
; or C64 with dual-SID, it can be more interesting though)
; ---------------------------------------------------------------------
.IFDEF MEGA65
.SETCPU "4510"
.MACRO STAOPL_Z
NOP
STA (oplregs),Z
.ENDMACRO
D018_VALUE = 38 ; MEGA65
.ELSE
D018_VALUE = 23 ; C64
.ENDIF
.ZEROPAGE
ZP: .RES 2 ; general purpose zeropage locations we use (two bytes)
song_p: .RES 2 ; byte pointer inside the DRO stream (two bytes)
.IFDEF MEGA65
oplregs:.RES 4
.ENDIF
.BSS
screen_reg_addrs: .RES 512
.CODE
.IFDEF MEGA65
.ORG $1FFF
.ELSE
.ORG $7FF
.ENDIF
; BASIC stub: do NOT place anything into the STARTUP segment
; before the stub itself!
;.SEGMENT "STARTUP"
.WORD basic_loader
basic_loader:
.WORD @lastline,2024
.IFDEF MEGA65
.WORD $02FE ; "BANK" BASIC10/65 token (double byte token!)
.BYTE "0:"
.ENDIF
.BYTE $9E ; "SYS" basic token
.BYTE $30+.LOBYTE(main/10000)
.BYTE $30+.LOBYTE((main .MOD 10000)/1000)
.BYTE $30+.LOBYTE((main .MOD 1000)/100)
.BYTE $30+.LOBYTE((main .MOD 100)/10)
.BYTE $30+.LOBYTE( main .MOD 10)
.BYTE 0
@lastline:
.WORD 0,0
.BYTE 0
; end of BASIC stub
; Character remapping for screen codes:
; We manipulate screen directly, and I don't want to convert texts
; in the asm file, so let's just leave it for the assembler:
; CA65 can make custom charset conversion configred by .CHARMAP
; constructs: conversion from ASCII (the assembly file's charset)
; to C64 screen codes (can be poked directly into the video RAM).
; Not remapped characters left as-is (by c64 target) hopefully
; most of them at least are OK :)
.REPEAT 26,l
.CHARMAP l + 97, l + 1 ; lower case
.CHARMAP l + 65, l + 65 ; upper case
.ENDREP
.CHARMAP 64, 0 ; @
.CHARMAP 95, 100 ; _
;song_length = song + 12 ; we don't use length currently, but the label after the included DRO to match against the position counter
cmd_short_delay = song + 23
cmd_long_delay = song + 24
codemap_len = song + 25
codemap = song + 26
.IFNDEF MEGA65
SFX_YM_SELECT_REGISTER = $DF40
SFX_YM_DATA_REGISTER = $DF50
.ENDIF
.IFDEF MEGA65
SCREEN_ADDRESS = $0800
.ELSE
SCREEN_ADDRESS = $0400
.ENDIF
COLOR_ADDRESS = $D800
COLOR_RAM_OFFSET = COLOR_ADDRESS - SCREEN_ADDRESS
REGDUMP_START_POS = SCREEN_ADDRESS + 41
SONG_POSITION_POS = SCREEN_ADDRESS + 24*40
MSG_POS = SCREEN_ADDRESS + 22*40
SONG_NAME_POS = SONG_POSITION_POS + 15
DELAY_POS_COLRAM = MSG_POS + 37 + COLOR_RAM_OFFSET
MSG_COLOR = 7
HEADER_COLOR = 13
COMMON_COLOR = 1
NAME_COLOR = 14
DELAY_ACTIVE_COLOR = 1
DELAY_INACTIVE_COLOR = 11
LINE_COLOR = 3
; You need a version 2 DRO file here
; DOSBOX 0.74 (maybe 0.73 too, but note: older versions
; produces older formatted DRO files which are NOT supported
; at all!) can produce such a file in OPL2 capture mode
; No check about the file, it must be version 2 DRO, and
; the whole C64 program must fit into the memory of course
; with the DRO included.
; This name is also stored as the song name (and shown in the
; player) however, since we use screen codes, it won't be so
; correct. File name should not be too long because it should
; fit onto the screen. The name is also used to .INCBIN the
; actual file, see later at .INCBIN
;.DEFINE DRO_FILE "dune_title.dro"
.DEFINE DRO_FILE "test.dro"
header:
.BYTE " "
.IFNDEF MEGA65
.BYTE "C64"
.ELSE
.BYTE "M65"
.ENDIF
.BYTE " DRO player v1.3a by LGB lgb@lgb.hu "
header_size = * - header
song:
; Do not put anything extra here: label "song" must be
; just before the DRO stream, and "song_end" should be
; after it! Also read note at the .DEFINE line above.
.INCBIN DRO_FILE
song_end:
dro_file_name: .BYTE DRO_FILE
dro_file_name_size = * - dro_file_name
hextab: .BYTE "0123456789ABCDEF"
msg:
.IFNDEF MEGA65
.BYTE "Hold key 'x' to reset C64. Delay:"
.ELSE
.BYTE "Hold key 'x' to reset MEGA65. Delay:"
.ENDIF
.BYTE '-'+128
.BYTE 'S'+128
.BYTE 'L'+128
msg_size = * - msg
show_reg:
LDX ZP+1 ; X:=value (since we will reuse it)
LDY ZP
LDA screen_reg_addrs,Y
STA ZP
LDA screen_reg_addrs+256,Y
STA ZP+1
TXA
LDY #0
show_hex_byte: ; A=byte, ZP: screen address base, Y = offset (from ZP)
PHA
LSR A
LSR A
LSR A
LSR A
TAX
LDA hextab,X
STA (ZP),Y
PLA
AND #15
TAX
LDA hextab,X
INY
STA (ZP),Y
INY
RTS
reset_sfx:
.IFDEF MEGA65
; Setting up memory pointer
; 7FFDF00 -> 07 FF DF 00
LDA #$00
STA oplregs
LDA #$DF
STA oplregs+1
LDA #$FF
STA oplregs+2
LDA #$07
STA oplregs+3
; Write zeroes for all registers:
LDA #0
LDX #0
: LDZ #$40
TXA
STAOPL_Z
JSR waitopl
LDZ #$50
LDA #$00
STAOPL_Z
JSR waitopl
INX
BNE :-
; MEGA65 specific sequence which seems to be needed to produce any sound. Thanks, btoschi!
; ($C0...$C8, 9 registers)
LDX #$C0
: LDZ #$40
TXA
STAOPL_Z
JSR waitopl
LDZ #$50
LDA #$F0
STAOPL_Z
JSR waitopl
INX
CPX #$C9
BNE :-
RTS
.ELSE
LDA #0
TAY
: STY SFX_YM_SELECT_REGISTER ; select YM register
NOP ; some wait after writing
NOP
NOP
NOP
STA SFX_YM_DATA_REGISTER ; write to selected YM register now
LDX #4 ; some more delay we need here ...
: DEX
NOP
BNE :-
INY
STY $D020 ; it is really not needed :)
BNE :--
RTS
.ENDIF
main:
; Disable interrupts (timing can be "perfect")
; Note: later, the stuff should be rewritten to be
; IRQ based player ...
; The timing is a disaster in the current code:
; we only count instruction cycles more or less correctly
; assuming about 1MHz clock (the more accurate value
; depends on PAL/NTSC, etc). Also, because of other things
; (fetching byte, writing SFX regs, displaying) needs
; time and it is not counted, the exact timing is surely bad.
; This is only a quick TEST, do not except advanced
; features now.
SEI
.IFDEF MEGA65
LDA #0
TAZ
TAX
TAY
MAP
; Turn off "force fast" mode of MEGA65 just in case (player uses software timing ...)
LDA #64
STA 0
; Set MEGA65 I/O mode: not needed too much by this player yet, but maybe in the future
; CPU persona of MEGA65 [may?] defaults to 6510 (thus excluding the linear addressing we need!) in normal C64 VIC I/O mode ...
LDA #$47
STA $D02F
LDA #$53
STA $D02F
; ...
LDA #0
STA $D030
STA $D031
.ENDIF
; Select lower-case character set
LDA #D018_VALUE
STA $D018
; "Nice" black screen, also clear it, with filling the color RAM as well
LDX #0
STX $D020
STX $D021
:
LDA #' '
STA SCREEN_ADDRESS,X
STA SCREEN_ADDRESS+$100,X
STA SCREEN_ADDRESS+$200,X
STA SCREEN_ADDRESS+$300,X
LDA #COMMON_COLOR
STA COLOR_ADDRESS,X
STA COLOR_ADDRESS+$100,X
STA COLOR_ADDRESS+$200,X
STA COLOR_ADDRESS+$300,X
INX
BNE :-
; Display the top header
: LDA header,X
ORA #128 ; in inverse (bit 7 set)
STA SCREEN_ADDRESS,X
LDA #HEADER_COLOR ; with some different color ....
STA COLOR_ADDRESS,X
INX
CPX #header_size
BNE :-
; Display the msg
LDX #0
: LDA msg,X
STA MSG_POS,X
LDA #MSG_COLOR
STA MSG_POS+COLOR_RAM_OFFSET,X
INX
CPX #msg_size
BNE :-
; Display song name (note: there is no check about the length, do not use too long name to leave the area of the video RAM)
LDX #0
: LDA dro_file_name,X
ORA #128 ; in inverse (bit 7 set)
STA SONG_NAME_POS,X
LDA #NAME_COLOR
STA SONG_NAME_POS+COLOR_RAM_OFFSET,X
INX
CPX #dro_file_name_size
BNE :-
; Display lines
LDX #39
: LDA #100
STA MSG_POS-40,X
LDA #99
STA MSG_POS+40,X
LDA #LINE_COLOR
STA MSG_POS+COLOR_RAM_OFFSET-40,X
STA MSG_POS+COLOR_RAM_OFFSET+40,X
DEX
BPL :-
; Generate our table for displaying YM registers
; It's the direct C64 addresses in the video RAM for
; 0...255 values (AdLib registers).
LDA #.LOBYTE(screen_reg_addrs)
STA ZP
LDA #.HIBYTE(screen_reg_addrs)
STA ZP+1
LDY #0 ; AdLib register counter
LDX #13 ; number of bytes to display within a C64 text line
@scraddrtabfillloop: ; we all love self-modifying code, right?
; write out low byte of the screen address
@scraddrtablo = * + 1
LDA #.LOBYTE(REGDUMP_START_POS)
STA (ZP),Y
STA @dot
; write out high byte of the screen address
INC ZP+1
@scraddrtabhi = * + 1
LDA #.HIBYTE(REGDUMP_START_POS)
STA (ZP),Y
STA @dot+1
DEC ZP+1
; display a dot
LDA #46
@dot = * + 1
STA $FFFF
; see, if we have to move to next line instead
LDA #3 ; the increment needed
DEX
CLC
BNE :+
ADC #1
LDX #13
:
ADC @scraddrtablo
STA @scraddrtablo
BCC :+
INC @scraddrtabhi
:
INY
BNE @scraddrtabfillloop
; Program CIA-1 for our simple kbd "scan", we only check a single matrix row/col,
; so this is the only place where it's needed to setup
; they key is "x" what we're looking for
LDA #%11111011
STA $DC00
@main_player:
; We must find the (C64 memory) address of the first byte
; to be "played". DRO's header is not a fix sized in length,
; we must add the size of "codemap table" after it's starting
; address to get that.
; Initialize low byte
LDA #.LOBYTE(codemap)
CLC
ADC codemap_len
STA song_p
; Initialize high byte
LDA #.HIBYTE(codemap)
ADC #0 ; use carry too!
STA song_p+1
; show pos info ...
LDX #.LOBYTE(SONG_POSITION_POS)
STX ZP
LDX #.HIBYTE(SONG_POSITION_POS)
STX ZP+1
LDY #0
JSR show_hex_byte ; song_p high byte is already in A, print it
LDA song_p
JSR show_hex_byte ; also print the low byte then
LDA #'/'
STA (ZP),Y
INY
INY
INY
INY
INY
STA (ZP),Y
INY
LDA #.HIBYTE(song_end)
JSR show_hex_byte
LDA #.LOBYTE(song_end)
JSR show_hex_byte
; Clear SFX registers ...
JSR reset_sfx
.IFDEF MEGA65
JSR init_mixer
.ENDIF
; Start playing actually ...
@play_loop:
; show current position of playback (C64 memory address)
LDA #.LOBYTE(SONG_POSITION_POS+5)
STA ZP
LDA #.HIBYTE(SONG_POSITION_POS+5)
STA ZP+1
LDY #0
LDA song_p+1
JSR show_hex_byte
LDA song_p
JSR show_hex_byte
; check keyboard
JSR @chk_kbd
; fetch two bytes from the DRO stream, store those in zeropage vars ZP and ZP+1
; we can't increment pointer in "once" (with Y being 0 then 1, then
; the pointer increment) as we don't know the
; stream is algined two 2 bytes boundary (depends on the codemap table
; size, specific to a given DRO file - even if the start of the file is aligned!)
LDY #0
LDA (song_p),Y
STA ZP
INC song_p
BNE :+
INC song_p+1
: LDA (song_p),Y
STA ZP+1
INC song_p
BNE :+
INC song_p+1
:
; Ok, check the fetched byte now
LDA ZP ; now we must examine the 1st byte: can be command or codemap position
CMP cmd_short_delay ; is it a short delay command?
BEQ @short_delay
CMP cmd_long_delay ; is it a long delay command?
BEQ @long_delay
; no delay commands: the byte is a codemap position
TAX ; move to X
; clear delay info, no delay
LDA #DELAY_INACTIVE_COLOR
STA DELAY_POS_COLRAM+1
STA DELAY_POS_COLRAM+2
LDA #DELAY_ACTIVE_COLOR
STA DELAY_POS_COLRAM
; Convert into register number
LDA codemap,X
; Note: we should use delays after writing registers (see: reset_sfx)
; However, at this point we have enough instructions between writes,
; so I simply don't need any additional delay (I hope so, at least)
.IFDEF MEGA65
; Check if register is not forbidden to write
; THIS IS MY LAST ATTEMPT to try to make it work with MEGA65 with disallowing
; DRO to modify certain registers ...
TAX
LDY skip_mega_reg_tab,X
BNE @skipmegareg
LDZ #$40
STAOPL_Z
.ELSE
STA SFX_YM_SELECT_REGISTER
.ENDIF
STA ZP ; store YM register number in ZP
NOP ; anyway, it seems some delay needed at least HERE (before data write)
NOP
LDA ZP+1
.IFDEF MEGA65
LDZ #$50
STAOPL_Z
.ELSE
STA SFX_YM_DATA_REGISTER
.ENDIF
@skipmegareg:
; show it!
JSR show_reg
; check looping
LDA song_p+1
CMP #.HIBYTE(song_end)
BCC @play_loop
LDA song_p
CMP #.LOBYTE(song_end)
BCC @play_loop
JMP @main_player ; end of the song: start it again!
; In delay codes we check keyboard to see if we want to exit.
; That also used as a part of the delay.
@short_delay: ; "short delay" in DRO files means waiting X+1 miliseconds
LDA #DELAY_INACTIVE_COLOR
STA DELAY_POS_COLRAM
STA DELAY_POS_COLRAM+2
LDA #DELAY_ACTIVE_COLOR
STA DELAY_POS_COLRAM+1
LDX ZP+1 ; after this, we should wait X+1 msecs
INX
: LDY #40 ;25*40=1000 cycles [25=20 - see below - plus 5], about one msec.
: JSR @chk_kbd ; 6 cycles for JSR, 14 for the subrutine: 20 cycles
DEY ; 2 cycles
BNE :- ; 3 cycles
DEX
BNE :--
JMP @play_loop
@long_delay: ; "long delay" in DRO files means waiting (X+1)*256 miliseconds
LDA #DELAY_INACTIVE_COLOR
STA DELAY_POS_COLRAM
STA DELAY_POS_COLRAM+1
LDA #DELAY_ACTIVE_COLOR
STA DELAY_POS_COLRAM+2
LDX ZP+1 ; after this, we should wait (X+1)*256 msecs
INX
: TXA
PHA
LDX #0
: LDY #40
: JSR @chk_kbd
DEY
BNE :-
DEX
BNE :--
PLA
TAX
DEX
BNE :---
JMP @play_loop
@chk_kbd: ; if I am correct, it's about 14 cycles normally
LDA $DC01 ; 4 cycles
AND #%10000000 ; 2 cycles
BEQ @reset ; 2 cycles (branch is not taken)
RTS ; 6 cycles
@reset: ; It's now safe to turn off your computer. :)
LDA #%00001011
STA $D011
JSR reset_sfx
LDA $DC01
AND #%10000000
BEQ @reset
LDA #$FF
STA 1
JMP ($FFFC)
.IFDEF MEGA65
skip_mega_reg_tab:
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $0X
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $1X
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $2X
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $3X
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $4X
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $5X
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $6X
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $7X
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $8X
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $9X
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $AX
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $BX
.BYTE 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1 ; $CX
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $DX
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $EX
.BYTE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 ; $FX
waitopl:
PHX
LDX #$98
: DEX
BNE :-
PLX
RTS
; Again, btoschi's code :)
init_mixer:
ldx #00
loop:
lda mixervals,x
sta $d6f4
inx
lda mixervals,x
sta $d6f5
inx
cpx #2*8
bne loop
rts
mixervals: ; reg, value
.byte $1c, $a0, $1d, $a0 ; OPL_FM LFT
.byte $3c, $a0, $3d, $a0 ; OPL_FM RGT
.byte $dc, $a0, $dd, $a0 ; OPL_FM HDL
.byte $fc, $a0, $fd, $a0 ; OPL_FM HDR
.ENDIF