3 * This version is for testing m68k-assembler. It
's certainly not the
4 * most up to date one (look for the ymamoto or mumble packages for that).
7 * YMamoto - a playback routine for the Atari ST
8 * Julian Squires / 2004-2005
10 * See the README file for the broad strokes.
13 * * check alignment of everything, make sure it's correct.
14 * * make sure the way we
're unpacking relative >>2 pointers works
15 * properly for large pointers.
16 * * add hw-envelope envelopes/macros.
17 * * portamento/slur/glissando.
19 * * AM sample support.
21 * NOTES FOR CODE READERS:
23 * * The implementations of arpeggio effects and software volume
24 * envelopes are almost identical; so if you find a bug in one,
25 * please look for that bug in the other. ;-)
30 number_of_channels = 3
32 ;; song data structure
33 song_data_arpeggio_pointer = 0
34 song_data_venv_pointer = 2
35 song_data_vibrato_pointer = 4
37 song_data_number_of_tracks = 7
38 song_data_track_ptrs = 8
40 ;; track data structure; repeats for each channel.
41 track_data_channel_ptr = 0
43 ;; arpeggio table structure
48 ;; volume envelope table structure
53 ;; vibrato table structure
54 vibrato_length = 0 ; not really necessary, but...
60 ;; song status structure
61 song_current_track = 0
62 song_registers_to_write = 1
63 song_ym_shadow = 2 ; to 15.. we don't touch the IO registers.
66 ;; channel status structure
71 channel_arp_position
= 8
72 channel_current_note
= 9
73 channel_current_volume
= 10
74 channel_volume_envelope
= 11
75 channel_venv_position
= 12
76 channel_pitch_envelope
= 13
77 channel_pitchenv_position
= 14
78 channel_env_shift
= 15
79 channel_vibrato_position
= 16 ;
and 17
81 channel_status_size
= 20 ; I
'd prefer to keep this a multiple of 4,
82 ; for easy wiping of the structure.
85 channel_state_enabled = 0
86 channel_state_tone = 1 ; tentative;
87 channel_state_noise = 2 ; tentative;
88 channel_state_env_follow = 3 ; will change;
89 channel_state_first_frame = 4 ; tentative.
96 extern plot_debug_dword
98 ; ymamoto_init (a0 = song pointer, d0 = track to setup.)
101 MOVEM.L D0-D1/A0-A2, -(A7)
106 ;; FIXME verify that the supplied track is not out of bounds.
108 ;; setup pointers: channels for this track, tables.
110 MOVE.B D0, song_current_track(A1)
112 ;; setup YM shadow registers.
114 MOVE.L D1, song_ym_shadow(A1)
115 MOVE.L D1, song_ym_shadow+4(A1)
116 MOVE.L D1, song_ym_shadow+8(A1)
117 MOVE.W D1, song_ym_shadow+12(A1)
118 MOVE.B #$FF, song_ym_shadow+7(A1) ; mixer.
120 ;; setup each channel
121 MOVEQ #number_of_channels-1, D0
124 DBF D0, .reset_channels
126 MOVEM.L (A7)+, D0-D1/A0-A2
130 * Sets up the YM with some sane values so that when we leave,
131 * we don't have horrible screaming chip noise.
146 ;; ymamoto_update
: call once per frame.
147 GLOBAL ymamoto_update
149 MOVEM.
L D0-D6
/A0-A1
, -(A7
)
153 MOVE.
B #13-1, song_registers_to_write(A1)
162 MOVE.
B song_registers_to_write
(A1
), D0
165 LEA song_ym_shadow
(A1
), A1
172 DBF D0
, .write_ym_registers
174 MOVEM.
L (A7
)+, D0-D6
/A0-A1
178 * update_channel
: expects the song data pointer in A0
, and the channel
181 MOVEM.
L A1-A4
, -(A7
) ; save registers.
.. don't bother with Dx
182 ; because they're saved in ymamoto_update.
185 LEA song_ym_shadow
(A1
), A3
187 ;; load channel status ptr into A1
188 LEA channel_status
, A1
190 BEQ .channel_status_loaded
192 .next_channel_status:
193 ADD.L #channel_status_size, A1
194 DBEQ D1
, .next_channel_status
195 .channel_status_loaded:
197 BTST.
B #channel_state_enabled, channel_state(A1)
200 BCLR.
B #channel_state_first_frame, channel_state(A1)
202 ;; decrement
and check counter
203 SUBQ.W
#1, channel_counter(A1)
204 BPL
.update_playing_note
207 ; Command processing.
208 MOVEA.
L channel_data_ptr
(A1
), A2
211 BPL
.process_new_note
212 ;; otherwise
, this is
a command.
221 CMP.
B #command_jump_table_len, D2
222 BGE .unknown_channel_command ; valid entries from 0 to c_j_t_len-1.
223 LEA
.command_jump_table, A4
229 DC.
L .unknown_channel_command, .arpeggio_command
230 ;;
2 -> detune
(reserved
).
231 DC.
L .unknown_channel_command, .volume_command, .venv_command
232 ;;
6 -> AM sample playback
(reserved
);
7 -> hard env
(reserved
).
233 DC.
L .noise_command, .unknown_channel_command, .unknown_channel_command
234 DC.
L .env_follow_command, .pitch_env_command, .slur_command
235 DC.
L .vibrato_command
236 command_jump_table_len
= (. - .command_jump_table)/4
239 ;; if the arp value in D1 is
0, disable arpeggiation.
240 ;; otherwise
, set the arp bit in channel status.
241 MOVE.
B D1
, channel_arpeggio
(A1
)
242 MOVE.
B #0, channel_arp_position(A1)
243 BRA
.load_new_command
246 MOVE.
B D1
, channel_current_volume
(A1
)
247 BRA
.load_new_command
250 MOVE.
B D1
, channel_volume_envelope
(A1
)
251 MOVE.
B #0, channel_venv_position(A1)
252 BRA
.load_new_command
256 BRA
.load_new_command
260 BEQ .disable_env_follow
261 BSET.
B #channel_state_env_follow, channel_state(A1)
262 MOVE.
B #4, channel_env_shift(A1) ; should be /16 by default.
264 BEQ .load_new_command
265 SUB.B #1, channel_env_shift(A1) ; Follow one octave lower.
266 BRA
.load_new_command
268 BCLR.
B #channel_state_env_follow, channel_state(A1)
269 BRA
.load_new_command
273 BRA
.load_new_command
277 BRA
.load_new_command
280 MOVE.
B D1
, channel_vibrato
(A1
)
281 MOVE.W
#0, channel_vibrato_position(A1)
282 BRA
.load_new_command
284 .unknown_channel_command:
286 BRA
.load_new_command
292 BNE .track_loop_command
293 ;; This is
a track end command
($
8000). Mute this channel, set
294 ;; channel disable bit
, and then end immediately.
298 BCLR.
B #channel_state_enabled, channel_state(A1)
308 ;; XXX below unused
, potentially flaky
313 ADD.L D2
, channel_data_ptr
(A1
)
314 MOVEA.
L channel_data_ptr
(A1
), A2
315 BRA
.load_new_command
319 BNE .unknown_global_command
320 ;; XXX unimplemented; just have to setup
a vector to call on
321 ;; this command
, or similar.
322 BRA
.load_new_command
324 .unknown_global_command:
326 BRA
.load_new_command
334 ;; otherwise
, we need to start playing
a tone.
335 BSET.
B #channel_state_first_frame, channel_state(A1)
336 BSET.
B #channel_state_tone, channel_state(A1)
337 MOVE.
B D2
, channel_current_note
(A1
)
338 MOVE.
B #0, channel_arp_position(A1) ; reset arpeggio.
339 MOVE.
B #0, channel_venv_position(A1) ; reset volume envelope.
340 MOVE.W
#0, channel_vibrato_position(A1)
341 ;; unmute this channel
345 BRA
.calculate_duration
348 CMPI.
B #126, D2 ; Is it a wait (as opposed to a rest)?
349 BEQ .calculate_duration
351 BCLR.
B #channel_state_tone, channel_state(A1)
354 BSET D0
, D2 ; Mute channel.
359 MOVE.W D1
, channel_counter
(A1
)
361 .update_channel_data_ptr:
362 MOVE.
L A2
, channel_data_ptr
(A1
)
365 * Effects processing.
367 * The note value is loaded from channel status
, and effects
368 * which have an effect at
a chromatic tone level are
369 * processed
, first
(arpeggios
). Then the frequency is looked
370 * up
, and effects which change the raw frequency
(portamento
)
371 * are processed. Finally any other effects
(venv
, hard
372 * envelope
) are processed.
374 .update_playing_note:
375 BTST.
B #channel_state_tone, channel_state(A1)
377 MOVE.
B channel_current_note
(A1
), D3
380 ; Note value effects.
382 .update_arpeggio: ; Arpeggios.
383 MOVE.
B channel_arpeggio
(A1
), D1
384 BEQ .lookup_frequency ; ... or next effect, if there is one.
385 MOVE.W song_data_arpeggio_pointer
(A0
), D2
387 MOVE.
B channel_arp_position
(A1
), D2
389 MOVE.
B arpeggio_length
(A2
), D1
390 CMP.
B D2
, D1 ; if arp position greater than length
,
392 MOVE.
B arpeggio_loop
(A2
), D2 ;
... reset to loop point.
394 ;; load arp delta
, update playing note.
395 MOVE.
B arpeggio_data
(A2
,D2
), D1
397 MOVE.
B D3
, channel_current_note
(A1
)
398 ;; update arp position.
400 MOVE.
B D2
, channel_arp_position
(A1
)
403 ; Frequency value effects.
405 LEA note_to_ymval_xlate
, A2
411 MOVE.
B channel_vibrato
(A1
), D1
412 BEQ .update_hw_envelope
413 MOVE.W song_data_vibrato_pointer
(A0
), D2
415 ;; always update position
416 ADD.W
#1, channel_vibrato_position(A1)
417 MOVE.W channel_vibrato_position
(A1
), D2
420 MOVE.
B vibrato_delay
(A2
), D4
422 BMI
.update_hw_envelope ; Next effect.
424 ;; vibrato freq
= ((frequency
*2^
1/12 - frequency
)/2)/depth
425 ;; Note that
1/((2^
1/12)-1) is pretty close to
16, so this can
be
426 ;; approximated with
(frequency
>>4)/depth
or so. Because this
427 ;; value can get quite small
, we represent the vibrato frequency
428 ;; as
a 12.4 fixed point fraction.
431 CMP.
B vibrato_depth
(A2
), D4
432 BEQ .vibrato_oscillator
433 SUB.B vibrato_depth
(A2
), D4 ; Could replace this division with
434 LSL.
B #2, D4 ; something more clever -- note that the
435 DIVU.W D4
, D1 ; divisor is
(8-depth
)*4.
437 ;; low n bits of position are our oscillator.
(This classic trick
438 ;; stolen from Rob Hubbard.
.. except he used a fixed-frequency
441 MOVE.
B vibrato_osc_mask
(A2
), D4
443 AND.W D4
, D2 ;
AND (2^speed
)-1
446 CMP.
B D4
, D2 ;
CMP 2^
(speed-
1)
447 BCC .i_love_rob_hubbard
450 EOR.
B D4
, D2 ;
XOR (2^speed
)-1
452 .i_love_rob_hubbard: ; I'm glad I strip debugging symbols.
454 MULU.W D2, D4 ; Add vibrato frequency <oscillator> times.
455 LSR.L #4, D4 ; Fixup vibrato fraction.
458 MOVE.B vibrato_speed(A2), D4
459 LSL.L D4, D1 ; (frq << (speed-1)) >> 4... it's safe for
460 LSR.
L #5, D1 ; us to simplify this to (frq<<speed)>>5.
461 ADD.W D1
, D3 ; Center the vibrato.
464 BTST.
B #channel_state_env_follow, channel_state(A1)
465 BEQ .set_frequency ; ... or next effect.
466 MOVE.W D3
, D1 ; D1
<- current frequency.
467 MOVE.
B channel_env_shift
(A1
), D2
470 MOVE.
B D1
, $
B(A3
) ; Env fine adjustment.
472 MOVE.
B D1
, $C
(A3
) ; Env rough adjustment.
473 BTST.
B #channel_state_first_frame, channel_state(A1)
474 BEQ .set_frequency ; only update on first frame of note.
475 MOVE.
B #$E, $D(A3) ; Env shape: CONT;ATT
477 MOVE.
B #14-1, song_registers_to_write(A2)
493 MOVE.
B channel_current_volume
(A1
), D3
495 .update_venv: ; Soft volume envelope.
496 MOVE.
B channel_volume_envelope
(A1
), D1
497 BEQ .set_volume ; ... or next effect, if there is one.
498 MOVE.W song_data_venv_pointer
(A0
), D2
500 MOVE.
B channel_venv_position
(A1
), D2
501 MOVE.
B venv_length
(A2
), D1 ; Load length.
502 CMP.
B D2
, D1 ; If position greater than length
,
503 BGT .venv_update_note
504 MOVE.
B venv_loop
(A2
), D2 ;
... reset to loop point.
506 MOVE.
B venv_data
(A2
,D2
), D3 ; Note that this might become
507 ADDQ.
B #1, D2 ; relative someday soon.
508 MOVE.
B D2
, channel_venv_position
(A1
)
511 BTST.
B #channel_state_env_follow, channel_state(A1)
513 OR.B #$10, D3 ; Envelope on.
520 ;;; End of main playroutine.
523 ;; Takes D0
= channel number.
524 ;; Returns channel status pointer in A1.
526 MOVEM.
L D0-D1
/A0
/A2
, -(A7
) ; save registers
530 ;; load appropriate track address.
533 MOVE.
B song_current_track
(A1
), D1
536 MOVE.W song_data_track_ptrs
(A0
,D1
), D1
537 ASL.
L #2, D1 ; XXX: should be .L?
538 LEA.
L track_data_channel_ptr
(A0
,D1.
L), A2
540 ;; load appropriate channel status structure.
541 LEA channel_status
, A1
544 ADD.L #channel_status_size, A1 ; next channel status.
545 ADD.L #2, A2 ; next channel pointer.
549 ;; wipe channel status structure first.
557 ;; setup data pointer.
561 MOVE.
L D0
, channel_data_ptr
(A1
)
564 BSET.
B #channel_state_enabled, channel_state(A1)
566 MOVEM.
L (A7
)+, D0-D1
/A0
/A2 ; restore registers
570 * Generic routine for loading values from tables of form
572 * entry_length
:byte
, entry_data
:(length+
1 bytes
)
573 * Takes D1
-> record idx
, D2
-> packed pointer to table
,
575 * Returns pointer to record in A2. Modifies D1
,D2.
582 ADDQ.
L #1, A2 ; skip length of table.
583 ;; find our entry in the table.
600 DC.W $EEE
,$E18
,$D4D
,$C8E
,$BDA
,$B2F
,$A8F
,$
9F7,$
968,$
8E1
,$
861,$
7E9
601 DC.W $
777,$
70C
,$
6A7
,$
647,$
5ED
,$
598,$
547,$
4FC
,$
4B4
,$
470,$
431,$
3F4
602 DC.W $
3BC,$
386,$
353,$
324,$
2F6,$
2CC
,$
2A4
,$
27E
,$
25A,$
238,$
218,$
1FA
603 DC.W $
1DE
,$
1C3
,$
1AA
,$
192,$
17B,$
166,$
152,$
13F
,$
12D
,$
11C
,$
10C
,$
FD
604 DC.W $EF
,$E1
,$D5
,$C9
,$
BE,$B3
,$A9
,$
9F
,$
96,$
8E
,$
86,$
7F
605 DC.W $
77,$
71,$
6A,$
64,$
5F
,$
59,$
54,$
50,$
48,$
47,$
43,$
3F
606 DC.W $
3C
,$
38,$
35,$
32,$
2F
,$
2D
,$
2A,$
28,$
26,$
24,$
22,$
20
607 DC.W $
1E
,$
1C
,$
1B,$
19,$
18,$
16,$
15,$
14,$
13,$
11,$
10,$
0F
615 channel_status
: DS.
B channel_status_size
*number_of_channels
617 song_status
: DS.
B song_status_size