-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathsndh.s
More file actions
401 lines (349 loc) · 12.6 KB
/
Copy pathsndh.s
File metadata and controls
401 lines (349 loc) · 12.6 KB
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
;
; SNDH header
; based on the official source from http://sndh.atari.org
;
.org 0
PC_REL_CODE=1 ; DO NOT CHANGE if 1, make code PC relative (helps if you move the routine around, like for example SNDH)
AVOID_SMC=1 ; DO NOT CHANGE if 1, assemble the player without SMC stuff, so it should be fine for CPUs with cache
;SID_VOICES=0 ; if 1, enable SID voices (takes more CPU time!)
UNROLLED_CODE=1 ; if 1, enable unrolled slightly faster YM register reading code
;USE_EVENTS=1 ; if 1, include events, and parse them
;USE_SID_EVENTS=0 ; if 1, use events to control SID.
; $Fn=sid setting, where n bits are xABC for which voice to use SID
;SAMPLES=1 ; if 1, enable sample player (events and samples need to be exported)
DUMP_SONG=0 ; if 1, produce a YM dump of the tune. DOES NOT WORK WITH SID OR EVENTS YET!
EVENT_CHANNEL_A_MASK equ 8+4
EVENT_CHANNEL_B_MASK equ 8+2
EVENT_CHANNEL_C_MASK equ 8+1
;
; Macros that ensure PC relative code
;
.macro clrx dst
.if PC_REL_CODE
clr\! \dst - PLY_AKYst_Init(a4)
.else
clr\! \dst
.endif
.endm
.macro tstx dst
.if PC_REL_CODE
tst\! \dst - PLY_AKYst_Init(a4)
.else
tst\! \dst
.endif
.endm
.macro movex src,dst
.if PC_REL_CODE
move\! \src,\dst - PLY_AKYst_Init(a4)
.else
move\! \src,\dst
.endif
.endm
.macro andx src,dst
if PC_REL_CODE
and\! \src,\dst - PLY_AKYst_Init(a4)
else
and\! \src,\dst
endif
endm
.macro orx src,dst
if PC_REL_CODE
or\! \src,\dst - PLY_AKYst_Init(a4)
else
or\! \src,\dst
endif
endm
;
; Event parser, in macro form (let's not waste a bsr and rts!)
;
.macro parse_events
;########################################################
;## Parse tune events
.if USE_EVENTS
.if PC_REL_CODE
movem.l d0/a0/a1/a4,-(sp)
lea PLY_AKYst_Init(pc),a4 ;base pointer for PC relative stores
.else
movem.l d0/a0/a1,-(sp)
.endif
clrx.b event_flag
.event_do_count:
move.w event_counter(pc),d0
subq #1,d0
bne.s .nohit
.event_read_val:
; time to read value
move.l events_pos(pc),a0
addq #2,a0
move.w (a0)+,d0
movex.b d0,event_byte
movex.b #1,event_flag ; there's a new event value to fetch
move.w (a0),d0
bne.s .noloopback
; loopback
addq #2,a0
move.l (a0),a0
lea Events_Loop,a1
sub.l a0,a1
lea tune_events(pc),a0
add.l a1,a0
movex.l a0,events_pos
movex.w (a0),event_counter
bra.s .event_do_count
.noloopback:
movex.l a0,events_pos
.nohit:
movex.w d0,event_counter
;done
.if PC_REL_CODE
movem.l (sp)+,d0/a0/a1/a4
.else
movem.l (sp)+,d0/a0/a1
.endif
.endif ; .if USE_EVENTS
if USE_SID_EVENTS
if PC_REL_CODE
movem.l d0/d1/a4,-(sp)
lea PLY_AKYst_Init(pc),a4 ; base pointer for PC relative stores
else
movem.l d0-d1,-(sp)
endif
tstx.b event_flag
beq.s .no_event
move.b event_byte(pc),d0
move.b d0,d1
and.b #$f0,d1
cmp.b #$f0,d1
bne.s .no_sid_event
btst #3,d0
bne .check_sid_on
.check_sid_off:
btst #2,d0
seq d1
btst #1,d0
seq d2
btst #0,d0
seq d3
andx.b d1,chan_a_sid_on
andx.b d2,chan_b_sid_on
andx.b d3,chan_c_sid_on
bra .no_sid_event
.check_sid_on:
btst #2,d0
sne d1
btst #1,d0
sne d2
btst #0,d0
sne d3
orx.b d1,chan_a_sid_on
orx.b d2,chan_b_sid_on
orx.b d3,chan_c_sid_on
.skip_chan_c:
.no_sid_event:
.no_event:
if PC_REL_CODE
movem.l (sp)+,d0/d1/a4
else
movem.l (sp)+,d0-d1
endif
endif ; .if USE_SID_EVENTS
;## Parse tune events
;########################################################
.endm
bra.w sndh_init
bra.w sndh_exit
bra.w sndh_vbl
dc.b 'SNDH'
; dc.b 'TITL','Love Potion Level 4 (Hello)',0
; dc.b 'COMM','XiA',0
; dc.b 'RIPP','Nobody',0
; dc.b 'CONV','Arkos2-2-SNDH',0
; dc.b 'VBL',0
include "sndh_header.s"
even
dc.b 'YEAR','2018',0
dc.b 'HDNS',0
even
.if USE_EVENTS
events_pos: ds.l 1
event_counter: ds.w 1
event_byte: dc.b 0
event_flag: dc.b 0
.even
.endif
sndh_init:
movem.l d0-a6,-(sp)
.if SID_VOICES & USE_SID_EVENTS
lea PLY_AKYst_Init(pc),a4 ;base pointer for PC relative stores
movex.b #-1,chan_a_sid_on
movex.b #-1,chan_b_sid_on
movex.b #-1,chan_c_sid_on
.endif ; .if SID_VOICES
.if PC_REL_CODE
lea PLY_AKYst_Init(pc),a4 ;base pointer for PC relative stores
.endif
.if USE_EVENTS
; reset event pos to start of event list
lea tune_events(pc),a0
movex.l a0,events_pos
movex.w (a0),event_counter
.endif ; .if USE_EVENTS
move.b #7,$ffff8800.w ;let's behave and save I/O port settings
movex.b $ffff8800.w,old_io_port_value
lea tune(pc),a0
bsr.w PLY_AKYst_Init
.if SID_VOICES
bsr sid_ini
.endif
movem.l (sp)+,d0-a6
rts
old_io_port_value: ds.b 1
even
sndh_exit:
movem.l d0-a6,-(sp)
.if SID_VOICES
bsr sid_exit
.endif
moveq #14-1,d0
moveq #0,d1
reset_psg: move.l d1,$ffff8800.w
add.l #$01000000,d1
dbra d0,reset_psg
move.b #7,$ffff8800.w ;let's behave and restore I/O port settings
move.b old_io_port_value(pc),$ffff8802.w
movem.l (sp)+,d0-a6
rts
sndh_vbl:
movem.l d0-a6,-(sp)
lea tune(pc),a0
parse_events
bsr.w PLY_AKYst_Play
.if SID_VOICES
lea values_store(pc),a0
bsr sid_play
.endif
movem.l (sp)+,d0-a6
rts
player:
even
include 'PlayerAky.s'
even
include "sndh_filenames.s"
.if SID_VOICES
include "sid.s"
.endif
.dc.b "ARKOS3-2-SNDH - The tune data ended at the start of this message"
;http://phf.atari.org
;(EOF)
; SNDH file structure, Revision 2.10
; Original SNDH Format devised by Jochen Knaus
; SNDH V1.1 Updated/Created by Anders Eriksson and Odd Skancke
; SNDH V2.0 by Phil Graham
; SNDH V2.1 by Phil Graham
; This document was originally created by Anders Eriksson, updated and
; adapted with SNDH v2 structures by Phil Graham.
; October, 2012
;
;
; All values are in MOTOROLA BIG ENDIAN format
;---------------------------------------------------------------------------
;Offset Size Function Example
;---------------------------------------------------------------------------
;0 4 INIT music driver bra.w init_music_driver
; (subtune number in d0.w)
;4 4 EXIT music driver bra.w exit_music_driver
;8 4 music driver PLAY bra.w vbl_play
;12 4 SNDH head dc.b 'SNDH'
;---------------------------------------------------------------------------
;Beneath follows the different TAGS that can (should) be used.
;The order of the TAGS is not important.
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
; TAG Description Example Termination
;---------------------------------------------------------------------------
; TITL Title of Song dc.b 'TITL','Led Storm',0 0 (Null)
; COMM Composer Name dc.b 'COMM','Tim Follin',0 0 (Null)
; RIPP Ripper Name dc.b 'RIPP','Me the hacker',0 0 (Null)
; CONV Converter Name dc.b 'CONV','Me the converter',0 0 (Null)
; ##?? Sub Tunes dc.b '##04',0 0 (Null)
; TA??? Timer A dc.b 'TA50',0 0 (Null)
; TB??? Timer B dc.b 'TB60',0 0 (Null)
; TC??? Timer C dc.b 'TC50',0 0 (Null)
; TD??? Timer D dc.b 'TD100',0 0 (Null)
; !V?? VBL dc.b '!V50',0 0 (Null)
; YEAR Year of release dc.b '1996',0 0 (Null) SNHDv2
; #!?? Default Sub tune dc.b '#!02',0 0 (Null) SNDHv21
; #!SN Sub tune names dc.w x1,x2,x3,x4 None
; dc.b "Subtune Name 1",0 0 (Null) SNDHv21
; dc.b "Subtune Name 2",0 0 (Null) SNDHv21
; dc.b "Subtune Name 3",0 0 (Null) SNDHv21
; dc.b "Subtune Name 4",0 0 (Null) SNDHv21
; TIME (sub) tune time dc.b 'TIME' None SNDHv2
; (in seconds) dc.w x1,x2,x3,x4
; HDNS End of Header dc.b 'HDNS' None SNDHv2
;---------------------------------------------------------------------------
;Calling method and speed
;---------------------------------------------------------------------------
;This a very important part to do correctly.
;Here you specify what hardware interrupt to use for calling the music
;driver.
;
;These options are available;
;dc.b '!Vnn' VBL (nn=frequency)
;dc.b 'TAnnn',0 Timer A (nnn=frequency)
;dc.b 'TBnnn',0 Timer B (nnn=frequency)
;dc.b 'TCnnn',0 Timer C (nnn=frequency)
;dc.b 'TDnnn',0 Timer D (nnn=frequency)
;
;VBL - Is NOT recommended for use. There is no change made to the
; VBL frequency so it will play at the current VBL speed.
;
;Timer A - Is only recommended if Timer C is not accurate enough. Use
; with caution, many songs are using Timer A for special
; effects.
;
;Timer B - Is only recommended if Timer C is not accurate enough. Use
; with caution, many songs are using Timer B for special
; effects.
;
;Timer C - The default timer if nothing is specified. Default speed
; is 50Hz. Use Timer C playback wherever possible. It hooks
; up to the OS 200Hz Timer C interrupt and leaves all other
; interrupts free for special effects.
;
; For songs with a replay speed uneven of 200Hz, SND Player
; uses a smart routine to correct for the wrong speed. The
; result is usually very good. If the result isn't good
; enough,then consider another Timer, but be careful with
; Timer collisions!
;
;Timer D - Is only recommended if Timer C is not accurate enough.
; Use with caution, many songs are using Timer D for
; special effects.
;---------------------------------------------------------------------------
; Default Tune Tag (!#??)
;---------------------------------------------------------------------------
; The !# Tag is followed by a two character ascii value signifying the
; default sub-tune to be played. If this tag is null then a sub-tune of
; 1 is assumed.
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
; Sub Tune Names (!#SN)
;---------------------------------------------------------------------------
; The !#SN Tag is followed by a table of word offsets pointing to the ascii
; text of sub tune names. The base offset is the actaul !#SN tag. See
; example header below.
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
; TIME Tag
;---------------------------------------------------------------------------
; The TIME tag is followed by 'x' short words ('x' being the number of
; tunes). Each word contains the length of each sub tune in seconds. If the
; word is null then it is assumed that the tune endlessly loops.
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
; HDNS Tag
;---------------------------------------------------------------------------
; The HDNS signifies the end of the SNDH header and the start of the actual
; music data. This tag must be on an even boundary.
;---------------------------------------------------------------------------