; ************************************* ; * Jaguar Soundtracker Module Player * ; * (c) 1995 Sinister Developments * ; ************************************* ; ; * Last update : 08/12/95 ; ; * To initialise DSP etc. JSR PLAYER+$0 ; (Always do this before setting up new modules etc.) ; ; * To setup a new module load start address to A0 and JSR PLAYER+$4 ; (Sound channels 1-4 are automatically cleared when a new module is setup) ; ; * In the VBL routine JSR PLAYER+$8 ; (A 50/60 hz speed adjustment is already included) ; ; * To playback a sample JSR PLAYER+$c with the following parameters: ; D0=Sample length ; D1=Sample looping length (or 0 for normal sample) ; D2=Sample Priority (0=highest, $ffff=lowest) ; (An equal priority sample will replace an existing one) ; D3=Sample volume (or 0 for default, set by JSR PLAYER+$18) ; D4=Sample Frequency (or 0 for $1ac default) ; A0=Sample start address ; A1=Sample looping start address (or 0 for normal sample) ; Sample playback channel (5-8) is returned in D0, or 0 if sample was not played ; Sample format is 16Khz, 8 bit mono, signed (use goldwave and save as raw) ; Routine Returns d0=0 - No sample played (priority too low) ; Routine Returns d0=5,6,7,8 - sample played on this channel ; ; * To modify the volume and/or frequency of a sample currently being played ; JSR PLAYER+$24 with the following parameters: ; D0=Channel Number ; D1=New volume (or 0 to leave unchanged) ; D2=New Frequency (or 0 to leave unchanged) ; ; * To clear and release sound channels load first channel to clear in D0 and ; number of channels to clear in D1, then JSR PLAYER+$10 ; (eg. To clear all 8 channels set D0=1,D1=8, to clear only sample channels ; set D0=5,D1=4 etc.) ; (Note: If a module is still playing (ie. the vbl module player is enabled) ; there's no point in clearing channels 1-4 'cause another sample will be ; played on the next vbl anyway!) ; ; * To set the music volume load D0=0 to $ff, then JSR PLAYER+$14 ; ; * To set sample volume load D0=0 to $ff, then JSR PLAYER+$18 ; ; * To enable the vbl module player JSR PLAYER+$1c ; (This is enabled as default by the setup new mod call, JSR PLAYER+$4) ; ; * To disable the vbl module player JSR PLAYER+$20 ; (Samples can still be played on channels 5-8, but no music will play on ; channels 1-4) ; ; * All registers are saved/restored as required on entry/exit of each routine ; .text bra setup_dsp ; +$00 bra init_new_mod ; +$04 bra vbl_handler ; +$08 bra play_sample ; +$0c bra clear_channels ; +$10 bra set_mus_volume ; +$14 bra set_efx_volume ; +$18 bra enable_music ; +$1c bra disable_music ; +$20 bra modify_channel ; +$24 .dc.b "ATARI JAGUAR SOUNDTRACKER MODULE PLAYER " .dc.b "COPYRIGHT (C) 1995 SINISTER DEVELOPMENTS" .long setup_dsp: ;setup dsp, init some vars etc. movem.l d0-a6,-(sp) lea vars_space(pc),a6 move.w #-1,skip_mod-vars_space(a6) ;skip vbl player move.w #0,sound_frame-vars_space(a6) ;reset 50/60 hz counter move.l #0,D_CTRL ;stop dsp move.l #0,D_FLAGS ;set dsp flags lea dsp_code_start(pc),a0 lea dsp_code_end(pc),a1 lea D_RAM,a2 .loop1: move.l (a0)+,(a2)+ ;copy dsp code to dsp ram move.l (a0)+,(a2)+ move.l (a0)+,(a2)+ move.l (a0)+,(a2)+ cmp.l a0,a1 bgt.s .loop1 lea dsp_chan1,a0 ;clear dsp channels table moveq #31,d0 ;8 channels at 32 bytes each .loop2: move.l #0,(a0)+ move.l #0,(a0)+ dbf d0,.loop2 move.l #$1b,SCLK ;setup dsp timer move.l #$15,SMODE move.l #D_RAM,D_PC ;set dsp pc to start of code move.l #1,D_CTRL ;start dsp moveq #1,d0 ;start from chan 1 moveq #8,d1 ;for 8 channels bsr clear_channels ;clear all sound channels movem.l (sp)+,d0-a6 rts init_new_mod: ;initialise a new module movem.l d0-a6,-(sp) bsr disable_music bsr setup_new_mod bsr enable_music movem.l (sp)+,d0-a6 rts setup_new_mod: ;setup new mod, sample tables and vars etc. lea vars_space(pc),a6 moveq #26,d0 lea chan_temp(pc),a1 ;clear channel workspace .loop3: move.l #0,(a1)+ move.l #0,(a1)+ dbf d0,.loop3 moveq #3,d0 ;setup chan num pointer and porta masks moveq #1,d1 lea chan_temp(pc),a1 .loop6: move.w #$ff,low_mask-chan_temp(a1) ;default no mask for $ff move.w d1,chan_num-chan_temp(a1) addq.w #1,d1 lea 54(a1),a1 dbf d0,.loop6 moveq #3,d0 ;clear channel sample w/space lea chan_samps(pc),a1 .loop2: move.l #0,(a1)+ move.l #0,(a1)+ dbf d0,.loop2 lea $3b8(a0),a1 lea $43c(a0),a2 cmp.l #"M.K.",-4(a2) ;check for mod type beq.s .over5 lea -$1e0(a1),a1 ;adjust for mod type lea -$1e4(a2),a2 .over5: move.l a1,patt_pos_pntr-vars_space(a6) move.l a2,patt_data_pntr-vars_space(a6) moveq #0,d0 move.b (a1),d0 lsl.l #8,d0 lsl.l #2,d0 add.l a2,d0 move.l d0,song_data_pntr-vars_space(a6) move.b #6,speed-vars_space(a6) ;init a few pointers and counters move.b #0,counter-vars_space(a6) ;the var names should say it all! move.b #0,song_pos-vars_space(a6) move.l #0,pattern_pos-vars_space(a6) moveq #$7f,d0 moveq #0,d1 .loop1: cmp.b (a1)+,d1 bge.s .over1 move.b -1(a1),d1 .over1: dbf d0,.loop1 addq.w #1,d1 lsl.l #8,d1 lsl.l #2,d1 lea 0(a2,d1.l),a1 lea sample_starts(pc),a2 ;pre-calc sample table move.l patt_pos_pntr-vars_space(a6),d0 sub.l a0,d0 sub.l #$16,d0 divu #$1e,d0 ;max 31 samples per mod subq.w #1,d0 lea $2a(a0),a0 ;point to start .loop5: moveq #0,d1 ;first clear all regs moveq #0,d2 moveq #0,d3 moveq #0,d4 moveq #0,d5 movem.w (a0),d1-d4 ;get data tst.w d3 bne.s .over2 lsl.l #1,d1 lsl.l #1,d4 move.l d1,d5 bra.s .over4 .over2: move.l d3,d5 add.l d4,d5 cmp.l d1,d5 bgt.s .over3 lsl.l #1,d3 .over3: lsl.l #1,d1 lsl.l #1,d4 move.l d3,d5 add.l d4,d5 cmp.l d1,d5 ble.s .over4 move.l d1,d4 sub.l d3,d4 move.l d1,d5 .over4: move.l a1,(a2)+ ;store sample start address lsr.l #1,d4 lsr.l #1,d5 move.w d5,(a2)+ move.l a1,(a2) ;store for sample end address add.l d3,(a2)+ ;and modify move.w d4,(a2)+ move.w d2,d3 and.w #$ff00,d3 ;get high byte of word lsr.w #8,d3 ;and shift down move.w d3,(a2)+ ;store and.w #$ff,d2 ;get low byte of word move.w d2,(a2)+ ;and store add.l d1,a1 ;next sample lea 30(a0),a0 ;next table entry dbf d0,.loop5 ;and again rts enable_music: ;enable the vbl mod player movem.l d0/d1/a6,-(sp) lea vars_space(pc),a6 moveq #1,d0 moveq #4,d1 bsr clear_channels ;clear the mod channels 1-4 move.w #0,skip_mod-vars_space(a6) ;enable vbl mod player movem.l (sp)+,d0/d1/a6 rts disable_music: ;disable the vbl mod player movem.l d0/d1/a6,-(sp) lea vars_space(pc),a6 move.w #-1,skip_mod-vars_space(a6) ;disable vbl mod player moveq #1,d0 moveq #4,d1 bsr clear_channels ;clear the mod channels 1-4 movem.l (sp)+,d0/d1/a6 rts set_mus_volume: ;setup mod playback volume to D0=0 to $ff move.l a6,-(sp) lea vars_space(pc),a6 and.w #$ff,d0 move.w d0,period-vars_space(a6) move.l (sp)+,a6 rts set_efx_volume: ;setup the sample playback volume to D0=0 to $ff move.l a6,-(sp) lea vars_space(pc),a6 and.l #$ff,d0 move.w d0,efx_vol-vars_space(a6) move.l dsp_chan5+4,d1 ;get channel 5 volume and.l #$ffff0000,d1 ;leave loop flag or.l d0,d1 ;new volume move.l d1,dsp_chan5+4 ;and store move.l dsp_chan6+4,d1 ;get channel 6 volume and.l #$ffff0000,d1 ;leave loop flag or.l d0,d1 ;new volume move.l d1,dsp_chan6+4 ;and store move.l dsp_chan7+4,d1 ;get channel 7 volume and.l #$ffff0000,d1 ;leave loop flag or.l d0,d1 ;new volume move.l d1,dsp_chan7+4 ;and store move.l dsp_chan8+4,d1 ;get channel 8 volume and.l #$ffff0000,d1 ;leave loop flag or.l d0,d1 ;new volume move.l d1,dsp_chan8+4 ;and store move.l (sp)+,a6 rts clear_channels: ;clear and release sound channels: movem.l a4-a6,-(sp) ;D0=start chan, D1=number of chans lea vars_space(pc),a6 lea samp_flag(pc),a5 lea dsp_chan1,a4 ;start of dsp channels table and.l #$f,d0 ;mask start channel (1-8) subq.w #1,d0 ;modify for dbf lsl.w #5,d0 ;each channel table entry is 32 bytes long add.l d0,a4 ;start address in dsp table and.l #$f,d1 ;mask number of chanels to clear subq.w #1,d1 ;modify for dbf .loop1: move.l #0,(a4) ;disable channel cmp.l #dsp_chan5,a4 ;check for chan 5 bne.s .over1 move.w #-1,(a5) ;and release sample priority .over1: cmp.l #dsp_chan6,a4 ;check for chan 6 bne.s .over2 move.w #-1,2(a5) ;and release sample priority .over2: cmp.l #dsp_chan7,a4 ;check for chan 7 bne.s .over3 move.w #-1,4(a5) ;and release sample priority .over3: cmp.l #dsp_chan8,a4 ;check for chan 8 bne.s .over4 move.w #-1,6(a5) ;and release sample priority .over4: lea 32(a4),a4 ;next dsp table entry dbf d1,.loop1 ;do the rest... movem.l (sp)+,a4-a6 rts play_sample: ;Play a sample: D0=Sample length, D1=Sample looping length (or 0) ;D2=Sample priority ($ffff=lowest,0=highest) movem.l d1-a6,-(sp) ;D3=Sample volume (0 for default), D4=Sample Freq (0 for default) lea vars_space(pc),a6 ;A0=Sample start address, A1=Sample looping start address (or 0) lsl.l #8,d0 ;shift sample length 8 bits, mul 256 lsl.l #8,d1 ;shift sample looping length 8 bits, mul 256 and.l #$ffff,d2 ;mask sample priority and.l #$ff,d3 ;mask sample volume and.l #$ffff,d4 ;mask sample frequency move.l #0,a3 ;setup sample channel used to return to caller lea samp_flag(pc),a4 ;sample priorties table lea dsp_chan5,a5 ;start at chan 5 in dsp table moveq #3,d7 ;4 sample channels .loop1: tst.l (a5) ;is this channel free or now completed playing? bne.s .over1 ;no, so skip move.w #-1,(a4) ;yes, reset channel sample priority to minimum .over1: lea 2(a4),a4 ;next chan samp priority table entry lea 32(a5),a5 ;next dsp table entry dbf d7,.loop1 ;do rest of channels lea samp_flag(pc),a5 ;point to samp priority table moveq #0,d6 ;setup highest priority moveq #3,d7 ;check 4 channels .loop2: cmp.w (a5)+,d6 ;get sample priority from table bcc.s .over2 ;search for lower priority move.w -2(a5),d6 ;found, get lower value move.w d7,d5 ;save which channel it was found in .over2: dbf d7,.loop2 ;do rest of channels cmp.w d2,d6 ;check lowest priority in table with current priority bcs .exit ;did we find a low enough priority to replace? move.w d5,d6 ;save found pointer addq.w #1,d6 ;adjust 0-3 to 1-4 lsl.w #1,d6 ;and double for word table sub.l d6,a5 ;adjust sample priority table pointer to correct entry move.w d2,(a5) ;and store new priority lea dsp_chan5,a5 ;yes, point to chan 5 in dsp table moveq #3,d7 ;check for 4 channels sub.w d5,d7 ;adjust for channel found add.l #5,a3 ;adjust for start channel 5 add.l d7,a3 ;and add channel number to give 5-8 lsl.l #5,d7 ;mult by 32 for dsp table entry length add.l d7,a5 ;a5 now points to free channel in dsp table move.l #0,(a5) ;disable channel in dsp table move.l d0,8(a5) ;copy sample length to dsp table move.l a0,12(a5) ;copy sample start address to dsp table move.l a1,24(a5) ;copy start address of loop for looping sample to dsp table move.l #0,28(a5) ;setup current sample offset tst.l d3 ;has sample volume been passed to us? bne.s .over3 ;if not, then just use default move.w efx_vol-vars_space(a6),d3 ;get the sample volume .over3: move.l d1,20(a5) ;store sample looping length for looped sample in dsp table tst.l d1 ;check if sample is looped beq.s .over4 ;if not, then don't flag sample as looped or.l #$ffff0000,d3 ;flag sample as being looped by setting top word of volume .over4: move.l d3,4(a5) ;store sample volume in dsp table tst.l d4 ;has sample freq been passed? bne.s .over5 ;if not, then just use default move.w #$1ac,d4 ;set the default sample freq .over5: mulu #$1c,d4 ;adjust sample freq up divu #$2b,d4 ;and down and.l #$ffff,d4 ;mask sample freq move.l d4,16(a5) ;and store in dsp table move.l #1,(a5) ;mark channel as enabled in dsp table .exit: move.l a3,d0 ;return channel used to caller (0=none found, or 5-8 if sample played) movem.l (sp)+,d1-a6 rts modify_channel: ;modify a samples current parameters: D0=Channel to modify, movem.l d0-a6,-(sp) ;D1=New Volume (or 0), D2=New Frequency (or 0) lea dsp_chan1,a5 ;start at chan 1 in dsp table subq.l #1,d0 ;channel -1 and.l #$ff,d0 ;mask channel number and.l #$ff,d1 ;mask sample volume and.l #$ffff,d2 ;mask sample frequency lsl.l #5,d0 ;mult by 32 for dsp table entry length add.l d0,a5 ;point to channel to modify in dsp table tst.l d1 ;was new volume passed beq.s .over1 ;skip volume modify move.l 4(a5),d7 ;get channel volume from dsp table and.l #$ffff0000,d7 ;mask sample looping flag or.l d1,d7 ;new volume move.l d7,4(a5) ;modify dsp table for new volume .over1: tst.l d2 ;was new frequency passed beq.s .exit ;skip frequency modify mulu #$1c,d2 ;adjust sample freq up divu #$2b,d2 ;and down and.l #$ffff,d2 ;mask sample frequency move.l d2,16(a5) ;and store in dsp table .exit: movem.l (sp)+,d0-a6 rts .dc.b "ATARI JAGUAR SOUNDTRACKER MODULE PLAYER " .dc.b "COPYRIGHT (C) 1995 SINISTER DEVELOPMENTS" .long vbl_handler: ;this is where all the work is done movem.l d0-a6,-(sp) lea vars_space(pc),a6 tst.w skip_mod-vars_space(a6) ;mod playback disabled or not setup yet? bne .exit move.w CONFIG,d0 ;check for 50/60 hz and.w #VIDTYPE,d0 beq.s .pal_vid addq.w #1,sound_frame-vars_space(a6) ;update frame count cmp.w #6,sound_frame-vars_space(a6) ;skip every 6th frame for correct sound speed bne.s .pal_vid move.w #0,sound_frame-vars_space(a6) ;and reset frame count bra .exit .pal_vid: bsr play_mod ;play the module!! lea chan_samps(pc),a0 ;sample w/space for each channel 1-4 lea freq_table(pc),a1 ;freq convertor table lea chan_temp(pc),a2 ;vars w/space for each channel 1-4 lea dsp_chan1,a3 ;dsp channel table moveq #3,d7 ;do all 4 channels .chan_loop1: moveq #0,d0 move.w set_per-chan_temp(a2),d0 ;get the period of this channel tst.w d0 ;if zero, no need to update beq.s .over1 ;so skip? lsl.w #1,d0 ;table is stored in words move.w 0(a1,d0.w),d0 ;get the new freq value and.l #$0000ffff,d0 ;clear top word move.l d0,16(a3) ;and store in dsp table .over1: moveq #0,d0 move.w vol2-chan_temp(a2),d0 ;get the chan volume and.l #$ffff0000,chan_vol-chan_temp(a2) ;leave upper 16 bits for samp loop flag or.l d0,chan_vol-chan_temp(a2) ;store chan volume move.l chan_vol-chan_temp(a2),4(a3) ;copy to dsp table move.l (a0),d0 ;has this samp been done yet? tst.l d0 bmi.s .over2 ;if so, skip move.l #-1,(a0) ;ok, it's done now move.l #0,(a3) ;disable channel for the moment tst.l d0 ;has the sample finished beq.s .over2 ;if so, end move.l d0,12(a3) ;store start address of sample to dsp table move.l #0,28(a3) ;reset current sample offset in dsp table and.l #$0000ffff,chan_vol-chan_temp(a2) ;reset sample looping flag by clearing top 16 bits move.l chan_vol-chan_temp(a2),4(a3) ;and store to dsp table move.l 4(a0),d1 ;get sample length lsr.l #8,d1 ;in 256 byte offsets move.l d1,8(a3) ;and store to dsp table moveq #0,d1 move.w rep_length-chan_temp(a2),d1 ;get sample repeat value lsl.l #8,d1 ;in 512 byte offsets lsl.l #1,d1 move.l d1,20(a3) ;and store to dsp table move.l loop_start-chan_temp(a2),d2 ;address to re-start looped sample cmp.l d0,d2 ;is loop start = sample start? bne.s .over3 ;if not, do it cmp.l #$200,d1 ;does sample repeat within $200 (too quick!) ble.s .over4 ;if so, skip it, 512 byte increments allowed only! .over3: move.l d2,24(a3) ;store start of looping address or.l #$ffff0000,chan_vol-chan_temp(a2) ;flag this as a looping sample, set top 16 bits move.l chan_vol-chan_temp(a2),4(a3) ;store in dsp table .over4: move.l #1,(a3) ;enable this sample for dsp .over2: lea 8(a0),a0 ;next channel sample table entry lea 54(a2),a2 ;next channels vars table entry lea 32(a3),a3 ;next dsp channel table entry dbf d7,.chan_loop1 ;and do the other channels .exit: movem.l (sp)+,d0-a6 rts play_mod: ;from here it's all just pretty standard mod player stuff, you can lea vars_space(pc),a6 ;work it out from the amazingly informative labels and var names!! moveq #0,d0 move.b counter-vars_space(a6),d0 addq.w #1,d0 cmp.b speed-vars_space(a6),d0 blt.s .no_new_note move.b #0,counter-vars_space(a6) tst.b patt_del_time2-vars_space(a6) beq.s .get_new_note move.w #0,efx_type-vars_space(a6) bsr .do_efx bra.s .not_play .no_new_note: move.b d0,counter-vars_space(a6) move.w #0,efx_type-vars_space(a6) bsr .do_efx bra .no_new_pos1 .get_new_note: move.l song_data_pntr-vars_space(a6),a0 add.l pattern_pos-vars_space(a6),a0 bsr .do_voice move.w #1,efx_type-vars_space(a6) bsr .do_efx .not_play: add.l #$10,pattern_pos-vars_space(a6) tst.b patt_del_time1-vars_space(a6) beq.s .skip1 move.b patt_del_time1-vars_space(a6),patt_del_time2-vars_space(a6) move.b #0,patt_del_time1-vars_space(a6) .skip1: tst.b patt_del_time2-vars_space(a6) beq.s .skip2 subq.b #1,patt_del_time2-vars_space(a6) beq.s .skip2 sub.l #$10,pattern_pos-vars_space(a6) .skip2: tst.b break_flag-vars_space(a6) beq.s .skip3 move.b #0,break_flag-vars_space(a6) moveq #0,d0 move.b break_pos-vars_space(a6),d0 move.b #0,break_pos-vars_space(a6) lsl.w #4,d0 move.l d0,pattern_pos-vars_space(a6) .skip3: cmp.l #$400,pattern_pos-vars_space(a6) blt.s .no_new_pos1 .next_pos: moveq #0,d0 move.b break_pos-vars_space(a6),d0 lsl.w #4,d0 move.l d0,pattern_pos-vars_space(a6) move.b #0,break_pos-vars_space(a6) move.b #0,pos_jump_flag-vars_space(a6) moveq #0,d0 move.b song_pos-vars_space(a6),d0 addq.w #1,d0 move.l patt_pos_pntr-vars_space(a6),a0 cmp.b -2(a0),d0 blt.s .no_new_pos2 moveq #0,d0 .no_new_pos2: and.w #$7f,d0 move.b d0,song_pos-vars_space(a6) move.b 0(a0,d0.w),d0 lsl.l #8,d0 lsl.l #2,d0 add.l patt_data_pntr-vars_space(a6),d0 move.l d0,song_data_pntr-vars_space(a6) .no_new_pos1: tst.b pos_jump_flag-vars_space(a6) bne.s .next_pos rts .do_efx: moveq #3,d0 lea chan_temp(pc),a0 .loop1: movem.l d0/a0,-(sp) bsr check_efx movem.l (sp)+,d0/a0 lea 54(a0),a0 dbf d0,.loop1 rts .do_voice: moveq #3,d0 lea chan_temp(pc),a1 lea chan_samps(pc),a2 .chan_loop1: movem.l d0/a1-a2,-(sp) bsr play_voice movem.l (sp)+,d0/a1-a2 lea 54(a1),a1 lea 8(a2),a2 dbf d0,.chan_loop1 rts play_voice: move.l (a0)+,d0 move.l d0,(a1) move.w d0,d1 swap d0 and.w #$f000,d0 and.w #$f000,d1 lsr.w #4,d1 or.w d0,d1 tst.w d1 beq.s .set_regs lea sample_starts(pc),a4 subq.w #1,d1 lsr.w #4,d1 and.w #$1f0,d1 add.w d1,a4 move.l (a4),samp_start-chan_temp(a1) move.w 4(a4),samp_length-chan_temp(a1) move.l 6(a4),loop_start-chan_temp(a1) move.l 6(a4),wave_start-chan_temp(a1) move.w 10(a4),rep_length-chan_temp(a1) move.w 12(a4),fine_tune-chan_temp(a1) move.w 14(a4),vol1-chan_temp(a1) .set_regs: move.w (a1),d0 and.w #$fff,d0 beq .exit move.w 2(a1),d1 and.w #$ff0,d1 cmp.w #$e50,d1 bne.s .no_fine_tune moveq #0,d1 move.b 3(a1),d1 move.w d1,fine_tune-chan_temp(a1) bra.s .set_period .no_fine_tune: move.b 2(a1),d1 and.w #$f,d1 cmp.w #3,d1 beq set_tone_porta cmp.w #5,d1 beq set_tone_porta cmp.w #9,d1 bne.s .set_period moveq #0,d1 move.b 3(a1),d1 tst.w d1 beq.s .over1 move.b d1,samp_offset-chan_temp(a1) .over1: move.b samp_offset-chan_temp(a1),d1 lsl.w #7,d1 cmp.w samp_length-chan_temp(a1),d1 bge.s .skip1 sub.w d1,samp_length-chan_temp(a1) lsl.w #1,d1 add.l d1,samp_start-chan_temp(a1) bra.s .set_period .skip1: move.w #1,samp_length-chan_temp(a1) .set_period: move.w (a1),d0 and.w #$fff,d0 lea period_table(pc),a3 moveq #$24,d2 .ftu_loop: cmp.w (a3)+,d0 dbcc d2,.ftu_loop moveq #0,d1 move.w fine_tune-chan_temp(a1),d1 mulu #$48,d1 move.w -2(a3,d1.l),d0 move.w d0,per-chan_temp(a1) moveq #0,d1 move.w 2(a1),d1 and.w #$ff0,d1 cmp.w #$ed0,d1 beq.s .exit btst #2,wave_control-chan_temp(a1) bne.s .vib_no_chng move.b #0,vibrato_pos-chan_temp(a1) .vib_no_chng: btst #6,wave_control-chan_temp(a1) bne.s .trem_no_chng move.b #0,tremolo_pos-chan_temp(a1) .trem_no_chng: move.l samp_start-chan_temp(a1),(a2) move.w samp_length-chan_temp(a1),4(a2) asl 4(a2) .exit: rts set_tone_porta: move.w (a1),d0 and.w #$fff,d0 moveq #0,d1 move.w fine_tune-chan_temp(a1),d1 mulu #$48,d1 lea period_table(pc),a3 add.l d1,a3 moveq #0,d1 .s_t_p_loop: cmp.w 0(a3,d1.w),d0 bcc.s .s_t_p_found addq.w #2,d1 cmp.w #$48,d1 bcs.s .s_t_p_loop moveq #$46,d1 .s_t_p_found: move.w fine_tune-chan_temp(a1),d0 and.w #8,d0 beq.s .s_t_p_goss tst.w d1 beq.s .s_t_p_goss subq.w #2,d1 .s_t_p_goss: move.w 0(a3,d1.w),d0 move.w d0,wanted_per-chan_temp(a1) move.b #0,tone_port_dir-chan_temp(a1) cmp.w per-chan_temp(a1),d0 beq.s .clear_t_p bge.s .exit move.b #1,tone_port_dir-chan_temp(a1) bra.s .exit .clear_t_p: move.w #0,wanted_per-chan_temp(a1) .exit: rts check_efx: bsr update_funk move.w per-chan_temp(a0),set_per-chan_temp(a0) move.w vol1-chan_temp(a0),vol2-chan_temp(a0) moveq #0,d0 move.w 2(a0),d0 and.w #$fff,d0 beq.s .over1 move.l d0,d1 and.w #$ff,d1 lsr.w #8,d0 lea efx_set_1(pc),a1 tst.w efx_type-vars_space(a6) beq.s .over2 lea efx_set_2(pc),a1 .over2: tst.b 0(a1,d0.w) beq.s .over1 lsl.w #1,d0 lea e_command_table(pc),a1 add.w 0(a1,d0.w),a1 jsr (a1) .over1: move.w period-vars_space(a6),d0 mulu vol2-chan_temp(a0),d0 move.w d0,vol2-chan_temp(a0) rts arpeggio: moveq #0,d0 move.b counter-vars_space(a6),d0 divs #3,d0 swap d0 cmp.w #0,d0 beq.s .arpeggio2 cmp.w #2,d0 beq.s .arpeggio1 moveq #0,d0 move.w d1,d0 lsr.w #4,d0 bra.s .arpeggio3 .arpeggio1: moveq #0,d0 move.w d1,d0 and.w #$f,d0 bra.s .arpeggio3 .arpeggio2: move.w per-chan_temp(a0),d2 bra.s .arpeggio4 .arpeggio3: asl.w #1,d0 moveq #0,d1 move.w fine_tune-chan_temp(a0),d1 mulu #$48,d1 lea period_table(pc),a1 add.l d1,a1 moveq #0,d1 move.w per-chan_temp(a0),d1 moveq #$24,d3 .arp_loop: move.w 0(a1,d0.w),d2 cmp.w (a1)+,d1 bcc.s .arpeggio4 dbf d3,.arp_loop .exit: rts .arpeggio4: move.w d2,set_per-chan_temp(a0) bra.s .exit porta_up: and.w low_mask-chan_temp(a0),d1 move.w #$ff,low_mask-chan_temp(a0) sub.w d1,per-chan_temp(a0) move.w per-chan_temp(a0),d1 and.w #$fff,d1 cmp.w #$71,d1 bpl.s .skip1 and.w #$f000,per-chan_temp(a0) or.w #$71,per-chan_temp(a0) .skip1: move.w per-chan_temp(a0),d1 and.w #$fff,d1 move.w d1,set_per-chan_temp(a0) rts porta_down: and.w low_mask-chan_temp(a0),d1 move.w #$ff,low_mask-chan_temp(a0) add.w d1,per-chan_temp(a0) move.w per-chan_temp(a0),d1 and.w #$fff,d1 cmp.w #$358,d1 bmi.s .skip1 and.w #$f000,per-chan_temp(a0) or.w #$358,per-chan_temp(a0) .skip1: move.w per-chan_temp(a0),d1 and.w #$fff,d1 move.w d1,set_per-chan_temp(a0) rts tone_portamento: tst.w d1 beq.s tp_no_change move.b d1,tone_port_spd-chan_temp(a0) move.b #0,3(a0) tp_no_change: tst.w wanted_per-chan_temp(a0) beq.s .exit moveq #0,d0 move.b tone_port_spd-chan_temp(a0),d0 tst.b tone_port_dir-chan_temp(a0) bne.s .tone_up add.w d0,per-chan_temp(a0) move.w wanted_per-chan_temp(a0),d2 cmp.w per-chan_temp(a0),d2 bgt.s .set_period move.w d2,per-chan_temp(a0) move.w #0,wanted_per-chan_temp(a0) bra.s .set_period .tone_up: sub.w d0,per-chan_temp(a0) move.w wanted_per-chan_temp(a0),d2 cmp.w per-chan_temp(a0),d2 blt.s .set_period move.w d2,per-chan_temp(a0) move.w #0,wanted_per-chan_temp(a0) .set_period: move.w per-chan_temp(a0),d0 move.b gliss_funk-chan_temp(a0),d1 and.w #$f,d1 beq.s .gliss_skip moveq #0,d1 move.w fine_tune-chan_temp(a0),d1 mulu #$48,d1 lea period_table(pc),a1 add.l d1,a1 moveq #0,d1 .gliss_loop: cmp.w 0(a1,d1.w),d0 bcc.s .gliss_found addq.w #2,d1 cmp.w #$48,d1 bcs.s .gliss_loop moveq #$46,d1 .gliss_found: move.w 0(a1,d1.w),d0 .gliss_skip: move.w d0,set_per-chan_temp(a0) .exit: rts vibrato: tst.w d1 beq.s vibrato2 move.b vibrato_cmd-chan_temp(a0),d2 and.w #$f,d1 beq.s .vib_skip1 and.w #$f0,d2 or.w d1,d2 .vib_skip1: move.b 3(a0),d1 and.w #$f0,d1 beq.s vib_skip2 and.w #$f,d2 or.w d1,d2 vib_skip2: move.b d2,vibrato_cmd-chan_temp(a0) vibrato2: move.b vibrato_pos-chan_temp(a0),d0 lea vibrato_table(pc),a1 lsr.w #2,d0 and.w #$1f,d0 moveq #0,d1 move.b wave_control-chan_temp(a0),d1 and.w #3,d1 beq.s .vib_sine lsl.w #3,d0 cmp.w #1,d1 beq.s .vib_rampdown1 move.w #$ff,d1 bra.s .vib_set .vib_rampdown1: tst.b vibrato_pos-chan_temp(a0) bpl.s .vib_rampdown2 move.w #$ff,d1 sub.w d0,d1 bra.s .vib_set .vib_rampdown2: move.w d0,d1 bra.s .vib_set .vib_sine: move.b 0(a1,d0.w),d1 .vib_set: move.b vibrato_cmd-chan_temp(a0),d0 and.w #$f,d0 mulu d0,d1 lsr.w #7,d1 move.w per-chan_temp(a0),d0 tst.b vibrato_pos-chan_temp(a0) bmi.s .vib_neg add.w d1,d0 bra.s .vibrato3 .vib_neg: sub.w d1,d0 .vibrato3: move.w d0,set_per-chan_temp(a0) move.b vibrato_cmd-chan_temp(a0),d0 lsr.w #2,d0 and.w #$3c,d0 add.b d0,vibrato_pos-chan_temp(a0) rts tone_plus_vol_slide: move.w d1,-(sp) bsr volume_slide move.w (sp)+,d1 bsr tone_portamento rts vibrato_plus_vol_slide: move.w d1,-(sp) bsr volume_slide move.w (sp)+,d1 bsr vib_skip2 rts tremolo: tst.w d1 beq.s .tremolo2 move.b tremolo_cmd-chan_temp(a0),d2 and.w #$f,d1 beq.s .trem_skip1 and.w #$f0,d2 or.w d1,d2 .trem_skip1: move.b 3(a0),d1 and.w #$f0,d1 beq.s .trem_skip2 and.w #$f,d2 or.w d1,d2 .trem_skip2: move.b d2,tremolo_cmd-chan_temp(a0) .tremolo2: move.b tremolo_pos-chan_temp(a0),d0 lea vibrato_table(pc),a1 lsr.w #2,d0 and.w #$1f,d0 moveq #0,d1 move.b wave_control-chan_temp(a0),d1 lsr.w #4,d1 and.w #3,d1 beq.s .trem_sine lsl.w #3,d0 cmp.w #1,d1 beq.s .trem_ramp_dn1 move.w #$ff,d1 bra.s .trem_set .trem_ramp_dn1: tst.b vibrato_pos-chan_temp(a0) bpl.s .trem_ramp_dn2 move.w #$ff,d1 sub.w d0,d1 bra.s .trem_set .trem_ramp_dn2: move.w d0,d1 bra.s .trem_set .trem_sine: move.b 0(a1,d0.w),d1 .trem_set: move.b tremolo_cmd-chan_temp(a0),d0 and.w #$f,d0 mulu d0,d1 lsr.w #6,d1 move.w vol1-chan_temp(a0),d0 tst.b tremolo_pos-chan_temp(a0) bmi.s .trem_neg add.w d1,d0 bra.s .tremolo3 .trem_neg: sub.w d1,d0 .tremolo3: bpl.s .trem_skip moveq #0,d0 .trem_skip: cmp.w #$40,d0 ble.s .trem_ok moveq #$40,d0 .trem_ok: move.w d0,vol2-chan_temp(a0) move.b tremolo_cmd-chan_temp(a0),d0 lsr.w #2,d0 and.w #$3c,d0 add.b d0,tremolo_pos-chan_temp(a0) rts e_command_8: rts sample_offset: tst.w d1 beq.s .not_new move.b d1,samp_offset-chan_temp(a0) .not_new: move.b samp_offset-chan_temp(a0),d1 lsl.w #7,d1 cmp.w samp_length-chan_temp(a0),d1 bge.s .skip sub.w d1,samp_length-chan_temp(a0) lsl.w #1,d1 add.l d1,samp_start-chan_temp(a0) bra.s .exit .skip: move.w #1,samp_length-chan_temp(a0) .exit: rts volume_slide: move.w vol1-chan_temp(a0),d3 move.w d1,d2 lsr.w #4,d1 and.w #$f,d1 tst.w d1 beq.s .vol_slide_dn add.w d1,d3 cmp.w #$40,d3 bmi.s .skip moveq #$40,d3 bra.s .skip .vol_slide_dn: and.w #$f,d2 sub.w d2,d3 bpl.s .skip moveq #0,d3 .skip: move.w d3,vol1-chan_temp(a0) move.w d3,vol2-chan_temp(a0) rts position_jump: subq.w #1,d1 move.b d1,song_pos-vars_space(a6) pos_jump: move.b #0,break_pos-vars_space(a6) move.b #$ff,pos_jump_flag-vars_space(a6) rts volume_change: cmp.w #$40,d1 ble.s .volume_ok moveq #$40,d1 .volume_ok: move.w d1,vol1-chan_temp(a0) move.w d1,vol2-chan_temp(a0) rts pattern_break: move.l d1,d2 lsr.w #4,d1 mulu #$a,d1 and.w #$f,d2 add.w d2,d1 cmp.w #$3f,d1 bhi.s pos_jump move.b d1,break_pos-vars_space(a6) move.b #$ff,pos_jump_flag-vars_space(a6) .exit: rts e_commands: move.w d1,d2 and.w #$f,d1 and.w #$f0,d2 lsr.w #3,d2 lea command_lo_table(pc),a1 add.w 0(a1,d2.w),a1 jsr (a1) rts set_speed: tst.w d1 beq.s .exit move.b #0,counter-vars_space(a6) move.b d1,speed-vars_space(a6) .exit: rts command_lo_0: rts lo_fine_porta_up: tst.b counter-vars_space(a6) bne.s .exit move.w #$f,low_mask-chan_temp(a0) bsr porta_up .exit: rts lo_fine_porta_down: tst.b counter-vars_space(a6) bne.s .exit move.w #$f,low_mask-chan_temp(a0) bsr porta_down .exit: rts set_gliss_control: and.b #$f0,gliss_funk-chan_temp(a0) or.b d1,gliss_funk-chan_temp(a0) rts set_vibrato_control: and.b #$f0,wave_control-chan_temp(a0) or.b d1,wave_control-chan_temp(a0) rts set_fine_tune: move.w d1,fine_tune-chan_temp(a0) rts jump_loop: tst.b counter-vars_space(a6) bne.s .exit tst.w d1 beq.s .set_loop tst.b loop_count-chan_temp(a0) beq.s .over1 subq.b #1,loop_count-chan_temp(a0) beq.s .exit .over2: move.b patt_pos-chan_temp(a0),break_pos-vars_space(a6) move.b #$ff,break_flag-vars_space(a6) bra.s .exit .over1: move.b d1,loop_count-chan_temp(a0) bra.s .over2 .set_loop: move.l pattern_pos-vars_space(a6),d1 lsr.w #4,d1 move.b d1,patt_pos-chan_temp(a0) .exit: rts set_tremolo_control: lsl.w #4,d1 and.b #$f,wave_control-chan_temp(a0) or.b d1,wave_control-chan_temp(a0) rts command_lo_8: rts retrig_note: tst.w d1 beq.s exit_retrig moveq #0,d2 move.b counter-vars_space(a6),d2 bne.s .over1 move.w (a0),d2 and.w #$fff,d2 bne.s exit_retrig moveq #0,d2 move.b counter-vars_space(a6),d2 .over1: divu d1,d2 swap d2 tst.w d2 bne.s exit_retrig do_retrig: move.w chan_num-chan_temp(a0),d1 lsl.w #3,d1 lea chan_samps(pc),a1 move.l samp_start-chan_temp(a0),0(a1,d1.w) move.w samp_length-chan_temp(a0),4(a1,d1.w) asl 4(a1,d1.w) exit_retrig: rts volume_fine_up: tst.b counter-vars_space(a6) bne.s .exit lsl.w #4,d1 bsr volume_slide .exit: rts volume_fine_down: tst.b counter-vars_space(a6) bne.s .exit bsr volume_slide .exit: rts note_cut: cmp.b counter-vars_space(a6),d1 bne.s .exit move.w #0,vol1-chan_temp(a0) move.w #0,vol2-chan_temp(a0) .exit: rts note_delay: cmp.b counter-vars_space(a6),d1 bne.s .exit tst.w (a0) beq.s .exit bsr do_retrig .exit: rts pattern_delay: tst.b counter-vars_space(a6) bne.s .exit tst.b patt_del_time2-vars_space(a6) bne.s .exit addq.w #1,d1 move.b d1,patt_del_time1-vars_space(a6) .exit: rts funk_it: tst.b counter-vars_space(a6) bne.s exit_funk_it lsl.w #4,d1 and.b #$f,gliss_funk-chan_temp(a0) or.b d1,gliss_funk-chan_temp(a0) tst.w d1 beq.s exit_funk_it update_funk: move.l a0,-(sp) moveq #0,d1 move.b gliss_funk-chan_temp(a0),d1 lsr.w #4,d1 beq.s exit_funk_it lea funk_table(pc),a1 move.b 0(a1,d1.w),d1 add.b d1,funk_offset-chan_temp(a0) btst #7,funk_offset-chan_temp(a0) beq.s exit_funk_it move.b #0,funk_offset-chan_temp(a0) move.l loop_start-chan_temp(a0),d0 moveq #0,d1 move.w rep_length-chan_temp(a0),d1 add.l d1,d0 add.l d1,d0 move.l wave_start-chan_temp(a0),a1 addq.l #1,a1 cmp.l d0,a1 bcs.s funk_ok move.l loop_start-chan_temp(a0),a1 funk_ok: move.l a1,wave_start-chan_temp(a0) moveq #$ff,d0 sub.b (a0),d0 move.b d0,(a0) exit_funk_it: move.l (sp)+,a0 rts e_command_table: .dc.w arpeggio-e_command_table .dc.w porta_up-e_command_table .dc.w porta_down-e_command_table .dc.w tone_portamento-e_command_table .dc.w vibrato-e_command_table .dc.w tone_plus_vol_slide-e_command_table .dc.w vibrato_plus_vol_slide-e_command_table .dc.w tremolo-e_command_table .dc.w e_command_8-e_command_table .dc.w sample_offset-e_command_table .dc.w volume_slide-e_command_table .dc.w position_jump-e_command_table .dc.w volume_change-e_command_table .dc.w pattern_break-e_command_table .dc.w e_commands-e_command_table .dc.w set_speed-e_command_table command_lo_table: .dc.w command_lo_0-command_lo_table .dc.w lo_fine_porta_up-command_lo_table .dc.w lo_fine_porta_down-command_lo_table .dc.w set_gliss_control-command_lo_table .dc.w set_vibrato_control-command_lo_table .dc.w set_fine_tune-command_lo_table .dc.w jump_loop-command_lo_table .dc.w set_tremolo_control-command_lo_table .dc.w command_lo_8-command_lo_table .dc.w retrig_note-command_lo_table .dc.w volume_fine_up-command_lo_table .dc.w volume_fine_down-command_lo_table .dc.w note_cut-command_lo_table .dc.w note_delay-command_lo_table .dc.w pattern_delay-command_lo_table .dc.w funk_it-command_lo_table .dc.b "ATARI JAGUAR SOUNDTRACKER MODULE PLAYER " .dc.b "COPYRIGHT (C) 1995 SINISTER DEVELOPMENTS" .long efx_set_1: .dc.l $01010101,$01010101 .dc.l $00000100,$00000100 efx_set_2: .dc.l $00000000,$00000000 .dc.l $00010001,$01010101 vars_space: .dc.l "VARS" ;these are all general vars for the tracker etc. counter: .dc.b 0 speed: .dc.b 0 song_pos: .dc.b 0 break_pos: .dc.b 0 pos_jump_flag: .dc.b 0 break_flag: .dc.b 0 period: .dc.w 0 efx_vol: .dc.w 0 patt_del_time1: .dc.b 0 patt_del_time2: .dc.b 0 patt_pos_pntr: .dc.l 0 patt_data_pntr: .dc.l 0 pattern_pos: .dc.l 0 song_data_pntr: .dc.l 0 efx_type: .dc.w 0 skip_mod: .dc.w -1 sound_frame: .dc.w 0 samp_flag: .dc.w -1,-1,-1,-1 chan_temp: .dc.w 0,0,0 ;these are repeated after the main set a further 3 times, tone_port_dir: .dc.b 0 ;once for each channel... hence all the .dc.l 0 at the end of this lot! tone_port_spd: .dc.b 0 tremolo_cmd: .dc.b 0 tremolo_pos: .dc.b 0 vibrato_cmd: .dc.b 0 vibrato_pos: .dc.b 0 wave_control: .dc.b 0 funk_offset: .dc.b 0 gliss_funk: .dc.b 0 loop_count: .dc.b 0 patt_pos: .dc.b 0 samp_offset: .dc.b 0 samp_start: .dc.l 0 samp_length: .dc.w 0 wave_start: .dc.l 0 loop_start: .dc.l 0 rep_length: .dc.w 0 per: .dc.w 0 set_per: .dc.w 0 wanted_per: .dc.w 0 vol1: .dc.w 0 vol2: .dc.w 0 fine_tune: .dc.w 0 chan_vol: .dc.l 0 low_mask: .dc.w 0 chan_num: .dc.w 0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0 sample_starts: .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 chan_samps: .dc.l 0,0 ;start address and length of sample .dc.l 0,0 ;for each of 4 channels .dc.l 0,0 .dc.l 0,0 funk_table: .dc.b 0,5,6,7,8,10,11,13,16,19,22,26,32,43,64,128 vibrato_table: .dc.b 0,24,49,74,97,120,141,161 .dc.b 180,197,212,224,235,244,250,253 .dc.b 255,253,250,244,235,224,212,197 .dc.b 180,161,141,120,97,74,49,24 period_table: ; Tuning 0, Normal .dc.w 856,808,762,720,678,640,604,570,538,508,480,453 .dc.w 428,404,381,360,339,320,302,285,269,254,240,226 .dc.w 214,202,190,180,170,160,151,143,135,127,120,113 ; Tuning 1 .dc.w 850,802,757,715,674,637,601,567,535,505,477,450 .dc.w 425,401,379,357,337,318,300,284,268,253,239,225 .dc.w 213,201,189,179,169,159,150,142,134,126,119,113 ; Tuning 2 .dc.w 844,796,752,709,670,632,597,563,532,502,474,447 .dc.w 422,398,376,355,335,316,298,282,266,251,237,224 .dc.w 211,199,188,177,167,158,149,141,133,125,118,112 ; Tuning 3 .dc.w 838,791,746,704,665,628,592,559,528,498,470,444 .dc.w 419,395,373,352,332,314,296,280,264,249,235,222 .dc.w 209,198,187,176,166,157,148,140,132,125,118,111 ; Tuning 4 .dc.w 832,785,741,699,660,623,588,555,524,495,467,441 .dc.w 416,392,370,350,330,312,294,278,262,247,233,220 .dc.w 208,196,185,175,165,156,147,139,131,124,117,110 ; Tuning 5 .dc.w 826,779,736,694,655,619,584,551,520,491,463,437 .dc.w 413,390,368,347,328,309,292,276,260,245,232,219 .dc.w 206,195,184,174,164,155,146,138,130,123,116,109 ; Tuning 6 .dc.w 820,774,730,689,651,614,580,547,516,487,460,434 .dc.w 410,387,365,345,325,307,290,274,258,244,230,217 .dc.w 205,193,183,172,163,154,145,137,129,122,115,109 ; Tuning 7 .dc.w 814,768,725,684,646,610,575,543,513,484,457,431 .dc.w 407,384,363,342,323,305,288,272,256,242,228,216 .dc.w 204,192,181,171,161,152,144,136,128,121,114,108 ; Tuning -8 .dc.w 907,856,808,762,720,678,640,604,570,538,508,480 .dc.w 453,428,404,381,360,339,320,302,285,269,254,240 .dc.w 226,214,202,190,180,170,160,151,143,135,127,120 ; Tuning -7 .dc.w 900,850,802,757,715,675,636,601,567,535,505,477 .dc.w 450,425,401,379,357,337,318,300,284,268,253,238 .dc.w 225,212,200,189,179,169,159,150,142,134,126,119 ; Tuning -6 .dc.w 894,844,796,752,709,670,632,597,563,532,502,474 .dc.w 447,422,398,376,355,335,316,298,282,266,251,237 .dc.w 223,211,199,188,177,167,158,149,141,133,125,118 ; Tuning -5 .dc.w 887,838,791,746,704,665,628,592,559,528,498,470 .dc.w 444,419,395,373,352,332,314,296,280,264,249,235 .dc.w 222,209,198,187,176,166,157,148,140,132,125,118 ; Tuning -4 .dc.w 881,832,785,741,699,660,623,588,555,524,494,467 .dc.w 441,416,392,370,350,330,312,294,278,262,247,233 .dc.w 220,208,196,185,175,165,156,147,139,131,123,117 ; Tuning -3 .dc.w 875,826,779,736,694,655,619,584,551,520,491,463 .dc.w 437,413,390,368,347,328,309,292,276,260,245,232 .dc.w 219,206,195,184,174,164,155,146,138,130,123,116 ; Tuning -2 .dc.w 868,820,774,730,689,651,614,580,547,516,487,460 .dc.w 434,410,387,365,345,325,307,290,274,258,244,230 .dc.w 217,205,193,183,172,163,154,145,137,129,122,115 ; Tuning -1 .dc.w 862,814,768,725,684,646,610,575,543,513,484,457 .dc.w 431,407,384,363,342,323,305,288,272,256,242,228 .dc.w 216,203,192,181,171,161,152,144,136,128,121,114 freq_table: .dc.l $0000f000,$78005000,$3c003000,$28002249 .dc.l $1e001aaa,$180015d1,$14001276,$11241000 .dc.l $0f000e1e,$0d550ca1,$0c000b6d,$0ae80a6f .dc.l $0a000999,$093b08e3,$08920846,$080007bd .dc.l $07800745,$070f06db,$06aa067c,$06500627 .dc.l $060005da,$05b60594,$05740555,$0537051b .dc.l $050004e5,$04cc04b4,$049d0487,$0471045d .dc.l $04490435,$04230411,$040003ef,$03de03cf .dc.l $03c003b1,$03a20395,$0387037a,$036d0361 .dc.l $03550349,$033e0333,$0328031d,$03130309 .dc.l $030002f6,$02ed02e4,$02db02d2,$02ca02c2 .dc.l $02ba02b2,$02aa02a3,$029b0294,$028d0286 .dc.l $02800279,$0272026c,$02660260,$025a0254 .dc.l $024e0249,$0243023e,$02380233,$022e0229 .dc.l $0224021f,$021a0216,$0211020d,$02080204 .dc.l $020001fb,$01f701f3,$01ef01eb,$01e701e3 .dc.l $01e001dc,$01d801d5,$01d101cd,$01ca01c7 .dc.l $01c301c0,$01bd01ba,$01b601b3,$01b001ad .dc.l $01aa01a7,$01a401a1,$019f019c,$01990196 .dc.l $01940191,$018e018c,$01890187,$01840182 .dc.l $0180017d,$017b0178,$01760174,$0172016f .dc.l $016d016b,$01690167,$01650163,$0161015f .dc.l $015d015b,$01590157,$01550153,$0151014f .dc.l $014d014c,$014a0148,$01460145,$01430141 .dc.l $0140013e,$013c013b,$01390137,$01360134 .dc.l $01330131,$0130012e,$012d012b,$012a0128 .dc.l $01270125,$01240123,$01210120,$011f011d .dc.l $011c011b,$01190118,$01170116,$01140113 .dc.l $01120111,$010f010e,$010d010c,$010b0109 .dc.l $01080107,$01060105,$01040103,$01020101 .dc.l $010000fe,$00fd00fc,$00fb00fa,$00f900f8 .dc.l $00f700f6,$00f500f4,$00f300f2,$00f100f0 .dc.l $00f000ef,$00ee00ed,$00ec00eb,$00ea00e9 .dc.l $00e800e7,$00e600e6,$00e500e4,$00e300e2 .dc.l $00e100e1,$00e000df,$00de00dd,$00dd00dc .dc.l $00db00da,$00d900d9,$00d800d7,$00d600d6 .dc.l $00d500d4,$00d300d3,$00d200d1,$00d000d0 .dc.l $00cf00ce,$00ce00cd,$00cc00cc,$00cb00ca .dc.l $00ca00c9,$00c800c8,$00c700c6,$00c600c5 .dc.l $00c400c4,$00c300c3,$00c200c1,$00c100c0 .dc.l $00c000bf,$00be00be,$00bd00bd,$00bc00bb .dc.l $00bb00ba,$00ba00b9,$00b900b8,$00b700b7 .dc.l $00b600b6,$00b500b5,$00b400b4,$00b300b3 .dc.l $00b200b2,$00b100b1,$00b000b0,$00af00af .dc.l $00ae00ae,$00ad00ad,$00ac00ac,$00ab00ab .dc.l $00aa00aa,$00a900a9,$00a800a8,$00a700a7 .dc.l $00a600a6,$00a600a5,$00a500a4,$00a400a3 .dc.l $00a300a2,$00a200a2,$00a100a1,$00a000a0 .dc.l $00a0009f,$009f009e,$009e009d,$009d009d .dc.l $009c009c,$009b009b,$009b009a,$009a0099 .dc.l $00990099,$00980098,$00980097,$00970096 .dc.l $00960096,$00950095,$00950094,$00940094 .dc.l $00930093,$00920092,$00920091,$00910091 .dc.l $00900090,$0090008f,$008f008f,$008e008e .dc.l $008e008d,$008d008d,$008c008c,$008c008b .dc.l $008b008b,$008b008a,$008a008a,$00890089 .dc.l $00890088,$00880088,$00870087,$00870087 .dc.l $00860086,$00860085,$00850085,$00840084 .dc.l $00840084,$00830083,$00830083,$00820082 .dc.l $00820081,$00810081,$00810080,$00800080 .dc.l $0080007f,$007f007f,$007e007e,$007e007e .dc.l $007d007d,$007d007d,$007c007c,$007c007c .dc.l $007b007b,$007b007b,$007a007a,$007a007a .dc.l $00790079,$00790079,$00780078,$00780078 .dc.l $00780077,$00770077,$00770076,$00760076 .dc.l $00760075,$00750075,$00750075,$00740074 .dc.l $00740074,$00730073,$00730073,$00730072 .dc.l $00720072,$00720071,$00710071,$00710071 .dc.l $00700070,$00700070,$0070006f,$006f006f .dc.l $006f006f,$006e006e,$006e006e,$006e006d .dc.l $006d006d,$006d006d,$006c006c,$006c006c .dc.l $006c006b,$006b006b,$006b006b,$006b006a .dc.l $006a006a,$006a006a,$00690069,$00690069 .dc.l $00690069,$00680068,$00680068,$00680067 .dc.l $00670067,$00670067,$00670066,$00660066 .dc.l $00660066,$00660065,$00650065,$00650065 .dc.l $00650064,$00640064,$00640064,$00640063 .dc.l $00630063,$00630063,$00630062,$00620062 .dc.l $00620062,$00620061,$00610061,$00610061 .dc.l $00610061,$00600060,$00600060,$00600060 .dc.l $0060005f,$005f005f,$005f005f,$005f005e .dc.l $005e005e,$005e005e,$005e005e,$005d005d .dc.l $005d005d,$005d005d,$005d005c,$005c005c .dc.l $005c005c,$005c005c,$005b005b,$005b005b .dc.l $005b005b,$005b005b,$005a005a,$005a005a .dc.l $005a005a,$005a0059,$00590059,$00590059 .dc.l $00590059,$00590058,$00580058,$00580058 .dc.l $00580058,$00580057,$00570057,$00570057 .dc.l $00570057,$00570056,$00560056,$00560056 .dc.l $00560056,$00560055,$00550055,$00550055 .dc.l $00550055,$00550054,$00540054,$00540054 .dc.l $00540054,$00540054,$00530053,$00530053 .dc.l $00530053,$00530053,$00530052,$00520052 .dc.l $00520052,$00520052,$00520052,$00510051 .dc.l $00510051,$00510051,$00510051,$00510050 .dc.l $00500050,$00500050,$00500050,$00500050 .dc.l $0050004f,$004f004f,$004f004f,$004f004f .dc.l $004f004f,$004e004e,$004e004e,$004e004e .dc.l $004e004e,$004e004e,$004d004d,$004d004d .dc.l $004d004d,$004d004d,$004d004d,$004c004c .dc.l $004c004c,$004c004c,$004c004c,$004c004c .dc.l $004c004b,$004b004b,$004b004b,$004b004b .dc.l $004b004b,$004b004b,$004a004a,$004a004a .dc.l $004a004a,$004a004a,$004a004a,$004a0049 .dc.l $00490049,$00490049,$00490049,$00490049 .dc.l $00490049,$00480048,$00480048,$00480048 .dc.l $00480048,$00480048,$00480048,$00470047 .dc.l $00470047,$00470047,$00470047,$00470047 .dc.l $00470047,$00460046,$00460046,$00460046 .dc.l $00460046,$00460046,$00460046,$00450045 .dc.l $00450045,$00450045,$00450045,$00450045 .dc.l $00450045,$00450044,$00440044,$00440044 .dc.l $00440044,$00440044,$00440044,$00440044 .dc.l $00430043,$00430043,$00430043,$00430043 .dc.l $00430043,$00430043,$00430043,$00420042 .dc.l $00420042,$00420042,$00420042,$00420042 .dc.l $00420042,$00420041,$00410041,$00410041 .dc.l $00410041,$00410041,$00410041,$00410041 .dc.l $00410041,$00400040,$00400040,$00400040 .dc.l $00400040,$00400040,$00400040,$00400040 .dc.l $00400040,$00400040,$00400040,$00400040 .phrase dsp_code_start: .dsp .org D_RAM movei #dsp_main,r0 ;point to start jump (r0) ;go start nop nop nop nop dsp_int: load (r28),r29 ;get dsp flags bclr #3,r29 ;interrupt serviced load (r31),r30 ;get return from stack bset #10,r29 ;clear int source flag addq #4,r31 ;update stack addq #2,r30 ;update return address movei #1,r27 ;set int wait flag jump (r30) ;return from int store r29,(r28) ;set dsp flags dsp_main: movei #dsp_stack,r31 ;point to stack moveta r31,r31 ;in both reg sets movei #D_FLAGS,r28 ;point to DSP flags movei #dsp_dummy,r26 ;empty sample pointer load (r28),r0 ;get dsp flags bset #5,r0 ;enable timer int store r0,(r28) ;do it movei #$20,r25 ;channel offset skip movei #0,r24 ;channel disabled movei #$ff,r23 ;setup mask do_chan_1: movei #dsp_chan1,r14 ;Reset table pointer movei #do_chan_2,r0 ;Skip address load (r14),r1 ;On/Off? move r26,r15 ;Point to dummy samp cmp r24,r1 ;Is channel disabled? jump eq,(r0) ;Do next channel load (r14+16/4),r1 ;Samp freq load (r14+28/4),r15 ;Current samp offset load (r14+8/4),r2 ;Samp length add r1,r15 ;New offset load (r14+4/4),r1 ;Volume cmp r15,r2 ;At sample end? moveta r1,r20 ;Save chan 1 volume jr pl,.over1 ;Not at end yet? btst #16,r1 ;Sample looped? jr ne,.over2 ;Yes? nop move r26,r15 ;No, point to dummy jump (r0) ;Do next channel store r24,(r14) ;Flag channel as done .over2: sub r2,r15 ;For current offset load (r14+20/4),r0 ;Samp looping length load (r14+24/4),r1 ;Looping start address store r0,(r14+8/4) ;Reset samp length store r1,(r14+12/4) ;Reset start address .over1: move r15,r0 ;Save current offset store r15,(r14+28/4) ;Update current offset shrq #8,r15 ;Divide by 256 load (r14+12/4),r1 ;Samp start address and r23,r0 ;mask $ff add r1,r15 ;Samp Offset address moveta r0,r0 ;Save offset low-byte do_chan_2: add r25,r14 ;Skip address movei #do_chan_3,r0 ;Skip address load (r14),r1 ;On/Off? move r26,r16 ;Point to dummy samp cmp r24,r1 ;Is channel disabled? jump eq,(r0) ;Do next channel load (r14+16/4),r1 ;Samp freq load (r14+28/4),r16 ;Current samp offset load (r14+8/4),r2 ;Samp length add r1,r16 ;New offset load (r14+4/4),r1 ;Volume cmp r16,r2 ;At sample end? moveta r1,r21 ;Save chan 1 volume jr pl,.over1 ;Not at end yet? btst #16,r1 ;Sample looped? jr ne,.over2 ;Yes? nop move r26,r16 ;No, point to dummy jump (r0) ;Do next channel store r24,(r14) ;Flag channel as done .over2: sub r2,r16 ;For current offset load (r14+20/4),r0 ;Samp looping length load (r14+24/4),r1 ;Looping start address store r0,(r14+8/4) ;Reset samp length store r1,(r14+12/4) ;Reset start address .over1: move r16,r0 ;Save current offset store r16,(r14+28/4) ;Update current offset shrq #8,r16 ;Divide by 256 load (r14+12/4),r1 ;Samp start address and r23,r0 ;mask $ff add r1,r16 ;Samp Offset address moveta r0,r1 ;Save offset low-byte do_chan_3: add r25,r14 ;Skip address movei #do_chan_4,r0 ;Skip address load (r14),r1 ;On/Off? move r26,r17 ;Point to dummy samp cmp r24,r1 ;Is channel disabled? jump eq,(r0) ;Do next channel load (r14+16/4),r1 ;Samp freq load (r14+28/4),r17 ;Current samp offset load (r14+8/4),r2 ;Samp length add r1,r17 ;New offset load (r14+4/4),r1 ;Volume cmp r17,r2 ;At sample end? moveta r1,r22 ;Save chan 1 volume jr pl,.over1 ;Not at end yet? btst #16,r1 ;Sample looped? jr ne,.over2 ;Yes? nop move r26,r17 ;No, point to dummy jump (r0) ;Do next channel store r24,(r14) ;Flag channel as done .over2: sub r2,r17 ;For current offset load (r14+20/4),r0 ;Samp looping length load (r14+24/4),r1 ;Looping start address store r0,(r14+8/4) ;Reset samp length store r1,(r14+12/4) ;Reset start address .over1: move r17,r0 ;Save current offset store r17,(r14+28/4) ;Update current offset shrq #8,r17 ;Divide by 256 load (r14+12/4),r1 ;Samp start address and r23,r0 ;mask $ff add r1,r17 ;Samp Offset address moveta r0,r2 ;Save offset low-byte do_chan_4: add r25,r14 ;Skip address movei #do_chan_5,r0 ;Skip address load (r14),r1 ;On/Off? move r26,r18 ;Point to dummy samp cmp r24,r1 ;Is channel disabled? jump eq,(r0) ;Do next channel load (r14+16/4),r1 ;Samp freq load (r14+28/4),r18 ;Current samp offset load (r14+8/4),r2 ;Samp length add r1,r18 ;New offset load (r14+4/4),r1 ;Volume cmp r18,r2 ;At sample end? moveta r1,r23 ;Save chan 1 volume jr pl,.over1 ;Not at end yet? btst #16,r1 ;Sample looped? jr ne,.over2 ;Yes? nop move r26,r18 ;No, point to dummy jump (r0) ;Do next channel store r24,(r14) ;Flag channel as done .over2: sub r2,r18 ;For current offset load (r14+20/4),r0 ;Samp looping length load (r14+24/4),r1 ;Looping start address store r0,(r14+8/4) ;Reset samp length store r1,(r14+12/4) ;Reset start address .over1: move r18,r0 ;Save current offset store r18,(r14+28/4) ;Update current offset shrq #8,r18 ;Divide by 256 load (r14+12/4),r1 ;Samp start address and r23,r0 ;mask $ff add r1,r18 ;Samp Offset address moveta r0,r3 ;Save offset low-byte do_chan_5: add r25,r14 ;Skip address movei #do_chan_6,r0 ;Skip address load (r14),r1 ;On/Off? move r26,r19 ;Point to dummy samp cmp r24,r1 ;Is channel disabled? jump eq,(r0) ;Do next channel load (r14+16/4),r1 ;Samp freq load (r14+28/4),r19 ;Current samp offset load (r14+8/4),r2 ;Samp length add r1,r19 ;New offset load (r14+4/4),r1 ;Volume cmp r19,r2 ;At sample end? moveta r1,r24 ;Save chan 1 volume jr pl,.over1 ;Not at end yet? btst #16,r1 ;Sample looped? jr ne,.over2 ;Yes? nop move r26,r19 ;No, point to dummy jump (r0) ;Do next channel store r24,(r14) ;Flag channel as done .over2: sub r2,r19 ;For current offset load (r14+20/4),r0 ;Samp looping length load (r14+24/4),r1 ;Looping start address store r0,(r14+8/4) ;Reset samp length store r1,(r14+12/4) ;Reset start address .over1: move r19,r0 ;Save current offset store r19,(r14+28/4) ;Update current offset shrq #8,r19 ;Divide by 256 load (r14+12/4),r1 ;Samp start address and r23,r0 ;mask $ff add r1,r19 ;Samp Offset address moveta r0,r4 ;Save offset low-byte do_chan_6: add r25,r14 ;Skip address movei #do_chan_7,r0 ;Skip address load (r14),r1 ;On/Off? move r26,r20 ;Point to dummy samp cmp r24,r1 ;Is channel disabled? jump eq,(r0) ;Do next channel load (r14+16/4),r1 ;Samp freq load (r14+28/4),r20 ;Current samp offset load (r14+8/4),r2 ;Samp length add r1,r20 ;New offset load (r14+4/4),r1 ;Volume cmp r20,r2 ;At sample end? moveta r1,r25 ;Save chan 1 volume jr pl,.over1 ;Not at end yet? btst #16,r1 ;Sample looped? jr ne,.over2 ;Yes? nop move r26,r20 ;No, point to dummy jump (r0) ;Do next channel store r24,(r14) ;Flag channel as done .over2: sub r2,r20 ;For current offset load (r14+20/4),r0 ;Samp looping length load (r14+24/4),r1 ;Looping start address store r0,(r14+8/4) ;Reset samp length store r1,(r14+12/4) ;Reset start address .over1: move r20,r0 ;Save current offset store r20,(r14+28/4) ;Update current offset shrq #8,r20 ;Divide by 256 load (r14+12/4),r1 ;Samp start address and r23,r0 ;mask $ff add r1,r20 ;Samp Offset address moveta r0,r5 ;Save offset low-byte do_chan_7: add r25,r14 ;Skip address movei #do_chan_8,r0 ;Skip address load (r14),r1 ;On/Off? move r26,r21 ;Point to dummy samp cmp r24,r1 ;Is channel disabled? jump eq,(r0) ;Do next channel load (r14+16/4),r1 ;Samp freq load (r14+28/4),r21 ;Current samp offset load (r14+8/4),r2 ;Samp length add r1,r21 ;New offset load (r14+4/4),r1 ;Volume cmp r21,r2 ;At sample end? moveta r1,r26 ;Save chan 1 volume jr pl,.over1 ;Not at end yet? btst #16,r1 ;Sample looped? jr ne,.over2 ;Yes? nop move r26,r21 ;No, point to dummy jump (r0) ;Do next channel store r24,(r14) ;Flag channel as done .over2: sub r2,r21 ;For current offset load (r14+20/4),r0 ;Samp looping length load (r14+24/4),r1 ;Looping start address store r0,(r14+8/4) ;Reset samp length store r1,(r14+12/4) ;Reset start address .over1: move r21,r0 ;Save current offset store r21,(r14+28/4) ;Update current offset shrq #8,r21 ;Divide by 256 load (r14+12/4),r1 ;Samp start address and r23,r0 ;mask $ff add r1,r21 ;Samp Offset address moveta r0,r6 ;Save offset low-byte do_chan_8: add r25,r14 ;Skip address movei #done_chans,r0 ;Skip address load (r14),r1 ;On/Off? move r26,r22 ;Point to dummy samp cmp r24,r1 ;Is channel disabled? jump eq,(r0) ;Do next channel load (r14+16/4),r1 ;Samp freq load (r14+28/4),r22 ;Current samp offset load (r14+8/4),r2 ;Samp length add r1,r22 ;New offset load (r14+4/4),r1 ;Volume cmp r22,r2 ;At sample end? moveta r1,r27 ;Save chan 1 volume jr pl,.over1 ;Not at end yet? btst #16,r1 ;Sample looped? jr ne,.over2 ;Yes? nop move r26,r22 ;No, point to dummy jump (r0) ;Do next channel store r24,(r14) ;Flag channel as done .over2: sub r2,r22 ;For current offset load (r14+20/4),r0 ;Samp looping length load (r14+24/4),r1 ;Looping start address store r0,(r14+8/4) ;Reset samp length store r1,(r14+12/4) ;Reset start address .over1: move r22,r0 ;Save current offset store r22,(r14+28/4) ;Update current offset shrq #8,r22 ;Divide by 256 load (r14+12/4),r1 ;Samp start address and r23,r0 ;mask $ff add r1,r22 ;Samp Offset address moveta r0,r7 ;Save offset low-byte done_chans: loadb (r15),r0 ;get chan 1 byte 1 loadb (r16),r1 ;get chan 2 byte 1 shlq #8,r0 ;scale up shlq #8,r1 ;scale up moveta r0,r8 ;store chan 1 byte 1 moveta r1,r10 ;store chan 2 byte 1 addqt #1,r15 ;inc chan 1 pointer addqt #1,r16 ;inc chan 2 pointer loadb (r15),r0 ;get chan 1 byte 2 loadb (r16),r1 ;get chan 2 byte 2 shlq #8,r0 ;scale up shlq #8,r1 ;scale up moveta r0,r9 ;store chan 1 byte 2 moveta r1,r11 ;store chan 2 byte 2 loadb (r17),r0 ;get chan 3 byte 1 loadb (r18),r1 ;get chan 4 byte 1 shlq #8,r0 ;scale up shlq #8,r1 ;scale up moveta r0,r12 ;store chan 3 byte 1 moveta r1,r14 ;store chan 4 byte 1 addqt #1,r17 ;inc chan 3 pointer addqt #1,r18 ;inc chan 4 pointer loadb (r17),r0 ;get chan 3 byte 2 loadb (r18),r1 ;get chan 4 byte 2 shlq #8,r0 ;scale up shlq #8,r1 ;scale up moveta r0,r13 ;store chan 3 byte 2 moveta r1,r15 ;store chan 4 byte 2 loadb (r19),r0 ;get chan 5 byte loadb (r20),r1 ;get chan 6 byte moveta r0,r16 ;store chan 5 byte moveta r1,r17 ;store chan 6 byte loadb (r21),r0 ;get chan 7 byte loadb (r22),r1 ;get chan 8 byte moveta r0,r18 ;store chan 7 byte moveta r1,r19 ;store chan 8 byte load (r28),r0 ;get DSP FLAGS bset #14,r0 ;change to alt regs store r0,(r28) ;do it nop nop movefa r23,r28 ;get $ff sub r0,r28 ;calc chan 1 offset imult r0,r9 ;scale byte 2 imult r28,r8 ;scale byte 1 movefa r23,r28 ;get $ff add r8,r9 ;combine chan1 byte1+2 sub r1,r28 ;calc chan 2 offset imult r1,r11 ;scale byte 2 imult r28,r10 ;scale byte 1 movefa r23,r28 ;get $ff add r10,r11 ;combine chan2 byte1+2 sub r2,r28 ;calc chan 3 offset imult r2,r13 ;scale byte 2 imult r28,r12 ;scale byte 1 movefa r23,r28 ;get $ff add r12,r13 ;combine chan3 byte1+2 sub r3,r28 ;calc chan 4 offset imult r3,r15 ;scale byte 2 imult r28,r14 ;scale byte 1 add r14,r15 ;combine chan4 byte1+2 sharq #8,r9 ;lose 8 low bits ch 1 sharq #8,r11 ;lose 8 low bits ch 2 sharq #8,r13 ;lose 8 low bits ch 3 sharq #8,r15 ;lose 8 low bits ch 4 shlq #8,r16 ;scale up chan 5 byte shlq #8,r17 ;scale up chan 6 byte shlq #8,r18 ;scale up chan 7 byte shlq #8,r19 ;scale up chan 8 byte imult r20,r9 ;volume scale chan 1 imult r21,r11 ;volume scale chan 2 imult r22,r13 ;volume scale chan 3 imult r23,r15 ;volume scale chan 4 imult r24,r16 ;volume scale chan 5 imult r25,r17 ;volume scale chan 6 imult r26,r18 ;volume scale chan 7 imult r27,r19 ;volume scale chan 8 sharq #15,r9 ;scale down chan 1 sharq #15,r11 ;scale down chan 2 sharq #15,r13 ;scale down chan 3 sharq #15,r15 ;scale down chan 4 sharq #8,r16 ;scale down chan 5 sharq #8,r17 ;scale down chan 6 sharq #8,r18 ;scale down chan 7 sharq #8,r19 ;scale down chan 8 movei #$5800,r0 ;normal scale mixer movei #$6000,r1 ;higher scale mixer movei #$3000,r2 ;lower scale mixer imultn r9,r1 ;chan 1 loud left imacn r11,r2 ;chan 2 quiet left imacn r13,r2 ;chan 3 quiet left imacn r15,r1 ;chan 4 loud left imacn r16,r0 ;chan 5 normal left imacn r17,r0 ;chan 6 normal left imacn r18,r0 ;chan 7 normal left imacn r19,r0 ;chan 8 normal left resmac r3 ;final left chan mix imultn r9,r2 ;chan 1 quiet right imacn r11,r1 ;chan 2 loud right imacn r13,r1 ;chan 3 loud right imacn r15,r2 ;chan 4 quite right imacn r16,r0 ;chan 5 normal right imacn r17,r0 ;chan 6 normal right imacn r18,r0 ;chan 7 normal right imacn r19,r0 ;chan 8 normal right resmac r4 ;final right chan mix sharq #15,r3 ;get 16 most sig bits sharq #15,r4 ;get 16 most sig bits sat16s r3 ;saturate 16 bit left sat16s r4 ;saturate 16 bit right movefa r28,r0 ;get dsp flags pointer load (r0),r1 ;get dsp flags bclr #14,r1 ;change to normal regs store r1,(r0) ;do it nop nop moveq #0,r27 ;clear int wait flag movefa r3,r0 ;get left channel val movefa r4,r1 ;get right channel val movei #L_I2S,r14 ;point to sound h/ware movei #do_chan_1,r2 ;point to start s_wait_int: cmpq #1,r27 ;wait for timer int jr ne,s_wait_int ;not yet? nop store r0,(r14) ;output left channel store r1,(r14+4/4) ;output right channel jump (r2) ;and do it all again nop ;this is the weird one!!!! .phrase .dc.l 0,0,0,0,0,0,0,0 ;stack w/space dsp_stack: .dc.l 0,0 ;stack pointer dsp_dummy: .dc.l 0,0 ;empty dummy sample dsp_chan1: .dc.l 0 ;enable/disable channel, 0=disabled .dc.l 0 ;channel volume in low word, sample looping flag in high word .dc.l 0 ;sample length .dc.l 0 ;sample start address .dc.l 0 ;sample playback frequency .dc.l 0 ;sample looping length (or 0) .dc.l 0 ;sample looping start address (or 0) .dc.l 0 ;current offset into sample dsp_chan2: .dc.l 0,0,0,0,0,0,0,0 ;chans 2 to 8 are as above dsp_chan3: .dc.l 0,0,0,0,0,0,0,0 dsp_chan4: .dc.l 0,0,0,0,0,0,0,0 dsp_chan5: .dc.l 0,0,0,0,0,0,0,0 dsp_chan6: .dc.l 0,0,0,0,0,0,0,0 dsp_chan7: .dc.l 0,0,0,0,0,0,0,0 dsp_chan8: .dc.l 0,0,0,0,0,0,0,0 .68000 dsp_code_end: .dc.l 0