diff --git a/lib/libpt/ptplayer.asm b/lib/libpt/ptplayer.asm index 86d692d4..130cb4a8 100644 --- a/lib/libpt/ptplayer.asm +++ b/lib/libpt/ptplayer.asm @@ -1,3410 +1,3205 @@ -;************************************************** -;* ----- Protracker V2.3B Playroutine ----- * -;************************************************** -; -; Version 6.2 -; Written by Frank Wille in 2013, 2016, 2017, 2018, 2019, 2020, 2021, 2022. -; -; I, the copyright holder of this work, hereby release it into the -; public domain. This applies worldwide. -; -; The default version (single section, local base register) should -; work with most assemblers. Tested are: Devpac, vasm, PhxAss, -; Barfly-Asm, SNMA, AsmOne, AsmPro. -; -; The small data model can be enabled by defining the symbol SDATA. In -; this case all functions expect a4 to be initialised with the small -; data base register. Interrupt functions restore a4 from _LinkerDB. -; Small data may work with vasm and PhxAss only. -; -; Exported functions and variables: -; (CUSTOM is the custom-chip register set base address $dff000.) -; -; _mt_install_cia(a6=CUSTOM, a0=VectorBase, d0=PALflag.b) -; Install a CIA-B interrupt for calling mt_music or mt_sfxonly. -; The music module is replayed via mt_music when _mt_Enable is non-zero. -; Otherwise the interrupt handler calls mt_sfxonly to play sound -; effects only. VectorBase is 0 for 68000, otherwise set it to the CPU's -; VBR register. A non-zero PALflag selects PAL-clock for the CIA timers -; (NTSC otherwise). -; -; _mt_remove_cia(a6=CUSTOM) -; Remove the CIA-B music interrupt, restore the previous handler and -; reset the CIA timer registers to their original values. -; -; _mt_init(a6=CUSTOM, a0=TrackerModule, a1=Samples|NULL, d0=InitialSongPos.b) -; Initialize a new module. -; Reset speed to 6, tempo to 125 and start at the given song position. -; Master volume is at 64 (maximum). -; When a1 is NULL the samples are assumed to be stored after the patterns. -; -; _mt_end(a6=CUSTOM) -; Stop playing current module and sound effects. -; -; _mt_soundfx(a6=CUSTOM, a0=SamplePointer, -; d0=SampleLength.w, d1=SamplePeriod.w, d2=SampleVolume.w) -; Request playing of an external sound effect on the most unused channel. -; This function is for compatibility with the old API only. -; You should call _mt_playfx instead. MINIMAL=0 only. -; -; channelStatus(d0) = _mt_playfx(a6=CUSTOM, a0=SfxStructurePointer) -; Request playing of a prioritized external sound effect, either on a -; fixed channel or on the most unused one. -; Structure layout of SfxStructure: -; void *sfx_ptr (pointer to sample start in Chip RAM, even address) -; WORD sfx_len (sample length in words) -; WORD sfx_per (hardware replay period for sample) -; WORD sfx_vol (volume 0..64, is unaffected by the song's master volume) -; BYTE sfx_cha (0..3 selected replay channel, -1 selects best channel) -; BYTE sfx_pri (priority, must be in the range 1..127) -; When multiple samples are assigned to the same channel the lower -; priority sample will be replaced. When priorities are the same, then -; the older sample is replaced. -; The chosen channel is blocked for music until the effect has -; completely been replayed. -; Returns a pointer to a channel-status structure when the sample -; is scheduled for playing, and NULL when the request was ignored. -; MINIMAL=0 only. -; -; _mt_loopfx(a6=CUSTOM, a0=SfxStructurePointer) -; Request playing of a looped sound effect on a fixed channel, which -; will be blocked for music until the effect is stopped (_mt_stopfx). -; It uses the same sfx-structure as _mt_playfx, but the priority is -; ignored. A looped sound effect has always highest priority and will -; replace a previous effect on the same channel. No automatic channel -; selection possible! -; Also make sure the sample starts with a zero-word, which is used -; for idling when the effect is stopped. This word is included in the -; total length calculation, but excluded when actually playing the loop. -; MINIMAL=0 only. -; -; _mt_stopfx(a6=CUSTOM, d0=Channel.b) -; Immediately stop a currently playing sound effect on a channel (0..3) -; and make it available for music, or other effects, again. This is the -; only way to stop a looped sound effect (_mt_loopfx), besides stopping -; replay completely (_mt_end). MINIMAL=0 only. -; -; _mt_musicmask(a6=CUSTOM, d0=ChannelMask.b) -; Bits set in the mask define which specific channels are reserved -; for music only. Set bit 0 for channel 0, ..., bit 3 for channel 3. -; When calling _mt_soundfx or _mt_playfx with automatic channel selection -; (sfx_cha=-1) then these masked channels will never be picked. -; The mask defaults to 0. MINIMAL=0 only. -; -; _mt_mastervol(a6=CUSTOM, d0=MasterVolume.w) -; Set a master volume from 0 to 64 for all music channels. -; Note that the master volume does not affect the volume of external -; sound effects (which is desired). MINIMAL=0 only. -; -; _mt_samplevol(d0=SampleNumber.w, d1=Volume.b) -; Redefine a sample's volume. May also be done while the song is playing. -; Warning: Does not check arguments for valid range! You must have done -; _mt_init before calling this function! -; The new volume is persistent. Even when the song is restarted. -; MINIMAL=0 only. -; -; _mt_channelmask(a6=CUSTOM, d0=ChannelMask.b) -; Bits cleared in the mask define which specific channels are muted -; for music replay. Clear bit 0 for channel 0, ..., bit 3 for channel 3. -; The mask defaults to all channels unmuted (bits set) and is reset to -; this state on _mt_init and _mt_end. MINIMAL=0 only. -; -; _mt_music(a6=CUSTOM) -; The replayer routine. Can be called from your own VBlank interrupt -; handler when VBLANK_MUSIC is set. Is otherwise called automatically -; by Timer-A interrupts after _mt_install_cia. -; -; Byte Variables: -; -; _mt_Enable -; Set this byte to non-zero to play music, zero to pause playing. -; Note that you can still play sound effects, while music is stopped. -; It is set to 0 by _mt_install_cia. -; -; _mt_E8Trigger -; This byte reflects the value of the last E8 command. -; It is reset to 0 after _mt_init. -; -; _mt_MusicChannels -; This byte defines the number of channels which should be dedicated -; for playing music. So sound effects will never use more -; than 4 - _mt_MusicChannels channels at once. Defaults to 0. -; MINIMAL=0 only. -; - -; Optionally you can build a minimal version, which includes just -; the player. No sound effects insert, no master volume, no sample -; volume, etc. Define the symbol MINIMAL=1 for it. - ifnd MINIMAL -MINIMAL equ 0 - endc - -; You may disable sawtooth and rectangle vibratos/tremolos here, which -; will be replaced by sine-waves. They are rarely used and disabling -; them will free a lot of memory for the tables. - ifnd ENABLE_SAWRECT -ENABLE_SAWRECT equ 1 - endc - -; Set this if you can guarantee that the word at $0 is cleared and if -; you want to use if for idle-looping of samples. - ifnd NULL_IS_CLEARED -NULL_IS_CLEARED equ 0 - endc - -; This disables initialization of CIA Timer-A interrupts for music -; replay, which means you cannot set the tempo with the F-command -; anymore and you have to call _mt_music yourself out of your own -; VBlank interrupt handler. Also sound effects will no longer work, -; when no music is playing (_mt_Enable=0). - ifnd VBLANK_MUSIC -VBLANK_MUSIC equ 0 - endc - -; Delay in CIA-ticks, which guarantees that at least one Audio-DMA -; took place, even with the lowest periods. -; 496 should be the correct value. But there are some A1200 which -; need at least 550. -DMADELAY equ 576 ; was 496 - - -; Custom chip registers -CUSTOM equ $dff000 -INTREQR equ $01e -INTENAR equ $01c -DMACON equ $096 -INTENA equ $09a -INTREQ equ $09c -AUD0LC equ $0a0 -AUD0LEN equ $0a4 -AUD0VOL equ $0a8 -AUD1LC equ $0b0 -AUD1LEN equ $0b4 -AUD1VOL equ $0b8 -AUD2LC equ $0c0 -AUD2LEN equ $0c4 -AUD2VOL equ $0c8 -AUD3LC equ $0d0 -AUD3LEN equ $0d4 -AUD3VOL equ $0d8 - -; Audio channel registers -AUDLC equ 0 -AUDLEN equ 4 -AUDPER equ 6 -AUDVOL equ 8 - -; CIA registers -CIAA equ $bfe001 -CIAB equ $bfd000 -CIAPRA equ $000 -CIATALO equ $400 -CIATAHI equ $500 -CIATBLO equ $600 -CIATBHI equ $700 -CIAICR equ $d00 -CIACRA equ $e00 -CIACRB equ $f00 - - -; Sound effects structure, passed into _mt_playfx - rsreset -sfx_ptr rs.l 1 -sfx_len rs.w 1 -sfx_per rs.w 1 -sfx_vol rs.w 1 -sfx_cha rs.b 1 -sfx_pri rs.b 1 -sfx_sizeof rs.b 0 - - -; Channel Status - rsreset -n_note rs.w 1 -n_cmd rs.b 1 -n_cmdlo rs.b 1 -n_index rs.b 1 -n_sfxpri rs.b 1 -n_reserved1 rs.b 2 -n_start rs.l 1 -n_loopstart rs.l 1 -n_length rs.w 1 -n_replen rs.w 1 -n_period rs.w 1 -n_volume rs.w 1 -n_pertab rs.l 1 -n_dmabit rs.w 1 -n_noteoff rs.w 1 -n_toneportspeed rs.w 1 -n_wantedperiod rs.w 1 -n_pattpos rs.w 1 -n_funk rs.w 1 -n_wavestart rs.l 1 -n_reallength rs.w 1 -n_intbit rs.w 1 -n_sfxptr rs.l 1 -n_sfxlen rs.w 1 -n_sfxper rs.w 1 -n_sfxvol rs.w 1 -n_looped rs.b 1 -n_minusft rs.b 1 -n_vibratoamp rs.b 1 -n_vibratospd rs.b 1 -n_vibratopos rs.b 1 -n_vibratoctrl rs.b 1 -n_tremoloamp rs.b 1 -n_tremolospd rs.b 1 -n_tremolopos rs.b 1 -n_tremoloctrl rs.b 1 -n_gliss rs.b 1 -n_sampleoffset rs.b 1 -n_loopcount rs.b 1 -n_funkoffset rs.b 1 -n_retrigcount rs.b 1 - ifeq MINIMAL -n_freecnt rs.b 1 -n_musiconly rs.b 1 -n_enable rs.b 1 - else -n_reserved2 rs.b 3 - endc -n_sizeof rs.b 0 - - - ifd SDATA - xref _LinkerDB ; small data base from linker - near a4 - code - endc - - - -;--------------------------------------------------------------------------- - xdef _mt_install_cia -_mt_install_cia: -; Install a CIA-B interrupt for calling mt_music. -; a6 = CUSTOM -; a0 = VectorBase -; d0 = PALflag.b (0 is NTSC) - - ifnd SDATA - move.l a4,-(sp) - lea mt_data(pc),a4 - endc - - clr.b mt_Enable(a4) - - ; remember level 6 vector and interrupt enable - lea $78(a0),a0 - move.l a0,mt_Lev6Int(a4) - move.w #$2000,d1 - and.w INTENAR(a6),d1 - or.w #$8000,d1 - move.w d1,mt_Lev6Ena(a4) - - ; disable level 6 EXTER interrupts, set player interrupt vector - move.w #$2000,INTENA(a6) - move.l (a0),mt_oldLev6(a4) - lea mt_TimerAInt(pc),a1 - move.l a1,(a0) - - ; reset TimerB toggle - lea TB_toggle(pc),a0 - clr.b (a0) - - ; disable CIA-B interrupts, stop and save all timers - lea CIAB,a0 - moveq #0,d1 - move.b #$7f,CIAICR(a0) - move.b d1,CIACRA(a0) - move.b d1,CIACRB(a0) - lea mt_oldtimers(a4),a1 - move.b CIATALO(a0),(a1)+ - move.b CIATAHI(a0),(a1)+ - move.b CIATBLO(a0),(a1)+ - move.b CIATBHI(a0),(a1) - - ifeq VBLANK_MUSIC - ; determine if 02 clock for timers is based on PAL or NTSC - tst.b d0 - bne .1 - move.l #1789773,d0 ; NTSC - bra .2 -.1: move.l #1773447,d0 ; PAL -.2: move.l d0,mt_timerval(a4) - - ; load TimerA in continuous mode for the default tempo of 125 - divu #125,d0 - move.b d0,CIATALO(a0) - lsr.w #8,d0 - move.b d0,CIATAHI(a0) - move.b #$11,CIACRA(a0) ; load timer, start continuous - endc ; !VBLANK_MUSIC - - ; load TimerB with DMADELAY ticks for setting DMA and repeat - move.b #DMADELAY&255,CIATBLO(a0) - move.b #DMADELAY>>8,CIATBHI(a0) - - ; Ack. pending interrupts, TimerA and TimerB interrupt enable - tst.b CIAICR(a0) - move.w #$2000,INTREQ(a6) - ifne VBLANK_MUSIC - move.b #$82,CIAICR(a0) ; TimerB only for VBLANK_MUSIC - else - move.b #$83,CIAICR(a0) - endc - - ; enable level 6 interrupts - move.w #$a000,INTENA(a6) - - bra mt_reset - - -;--------------------------------------------------------------------------- - xdef _mt_remove_cia -_mt_remove_cia: -; Remove CIA-B music interrupt and restore the old vector. -; a6 = CUSTOM - - ifnd SDATA - move.l a4,-(sp) - lea mt_data(pc),a4 - endc - - ; disable level 6 and CIA-B interrupts - lea CIAB,a0 - move.w #$2000,d0 - move.b #$7f,CIAICR(a0) - move.w d0,INTENA(a6) - tst.b CIAICR(a0) - move.w d0,INTREQ(a6) - - ; restore old timer values - lea mt_oldtimers(a4),a1 - move.b (a1)+,CIATALO(a0) - move.b (a1)+,CIATAHI(a0) - move.b (a1)+,CIATBLO(a0) - move.b (a1),CIATBHI(a0) - move.b #$10,CIACRA(a0) - move.b #$10,CIACRB(a0) - - ; restore original level 6 interrupt vector - move.l mt_Lev6Int(a4),a1 - move.l mt_oldLev6(a4),(a1) - - ; reenable CIA-B ALRM interrupt, which was set by AmigaOS - move.b #$84,CIAICR(a0) - - ; reenable previous level 6 interrupt - move.w mt_Lev6Ena(a4),INTENA(a6) - - ifnd SDATA - move.l (sp)+,a4 - endc - rts - - -;--------------------------------------------------------------------------- -mt_TimerAInt: -; TimerA interrupt calls mt_music at a selectable tempo (Fxx command), -; which defaults to 50 times per second. - - ; check for TB interrupt and clear CIAB interrupt flags - btst #1,CIAB+CIAICR - bne mt_TimerBInt - - ifne VBLANK_MUSIC - move.w #$2000,CUSTOM+INTREQ ; ack interrupt and leave - nop - rte - - else - ; Now it should be a TA interrupt. - ; Other level 6 interrupt sources have to be handled elsewhere. - movem.l d0-d7/a0-a6,-(sp) - lea CUSTOM,a6 - ifd SDATA - lea _LinkerDB,a4 - else - lea mt_data(pc),a4 - endc - - ; clear EXTER interrupt flag - move.w #$2000,INTREQ(a6) - - ; do music when enabled - tst.b mt_Enable(a4) - ifeq MINIMAL - beq .2 - else - beq .1 - endc - - bsr mt_music ; music with sfx inserted -.1: movem.l (sp)+,d0-d7/a0-a6 - nop - rte - - ifeq MINIMAL -.2: bsr mt_sfxonly ; no music, only sfx - movem.l (sp)+,d0-d7/a0-a6 - nop - rte - endc - endc ; !VBLANK_MUSIC - - -;--------------------------------------------------------------------------- -mt_TimerBInt: -; Handle one-shot TimerB interrupt. -; TB_toggle-technique suggested by Ross/EAB. - - move.l a0,-(sp) - lea TB_toggle(pc),a0 - not.b (a0) - lea CUSTOM+INTREQ,a0 - beq mt_TimerBsetrep - - ; restart timer for repeat, enable audio DMA after DMADELAY ticks - move.w #$2000,(a0) ; clear EXTER interrupt flag - move.b #$19,CIAB+CIACRB - move.w mt_dmaon(pc),DMACON-INTREQ(a0) - - move.l (sp)+,a0 - nop - rte - -mt_dmaon: - dc.w $8000 -TB_toggle: - dc.b 0 - even - - -;--------------------------------------------------------------------------- -mt_TimerBsetrep: -; Oneshot TimerB interrupt to set repeat samples after another DMADELAY ticks. -; a0 = INTREQ - - ; clear EXTER and possible audio interrupt flags - move.l a4,-(sp) - move.l d0,a4 - moveq #$2000>>7,d0 ; EXTER-flag - or.b mt_dmaon+1(pc),d0 - lsl.w #7,d0 - move.w d0,(a0) - move.l a4,d0 - - ; set repeat sample pointers and lengths - ifd SDATA - lea _LinkerDB,a4 - else - lea mt_data(pc),a4 - endc - move.l mt_chan1+n_loopstart(a4),AUD0LC-INTREQ(a0) - move.w mt_chan1+n_replen(a4),AUD0LEN-INTREQ(a0) - move.l mt_chan2+n_loopstart(a4),AUD1LC-INTREQ(a0) - move.w mt_chan2+n_replen(a4),AUD1LEN-INTREQ(a0) - move.l mt_chan3+n_loopstart(a4),AUD2LC-INTREQ(a0) - move.w mt_chan3+n_replen(a4),AUD2LEN-INTREQ(a0) - move.l mt_chan4+n_loopstart(a4),AUD3LC-INTREQ(a0) - move.w mt_chan4+n_replen(a4),AUD3LEN-INTREQ(a0) - - move.l (sp)+,a4 - move.l (sp)+,a0 - nop - rte - - -;--------------------------------------------------------------------------- - xdef _mt_init -_mt_init: -; Initialize new module. -; Reset speed to 6, tempo to 125 and start at given song position. -; Master volume is at 64 (maximum). -; a6 = CUSTOM -; a0 = module pointer -; a1 = sample pointer (NULL means samples are stored within the module) -; d0 = initial song position - - ifnd SDATA - move.l a4,-(sp) - lea mt_data(pc),a4 - endc - - move.l a0,mt_mod(a4) - movem.l d2/a2,-(sp) - - ; set initial song position - cmp.b 950(a0),d0 - blo .1 - moveq #0,d0 -.1: move.b d0,mt_SongPos(a4) - - move.l a1,d0 ; sample data location is given? - bne .4 - - ; get number of highest pattern - lea 952(a0),a1 ; song arrangement list - moveq #127,d0 - moveq #0,d2 -.2: move.b (a1)+,d1 - cmp.b d2,d1 - bls .3 - move.b d1,d2 -.3: dbf d0,.2 - addq.b #1,d2 ; number of patterns - - ; now we can calculate the base address of the sample data - moveq #10,d0 - asl.l d0,d2 - lea (a0,d2.l),a1 - add.w #1084,a1 - - ; save start address of each sample and do some fixes for broken mods -.4: lea mt_SampleStarts(a4),a2 - moveq #1,d2 - moveq #31-1,d0 -.5: move.l a1,(a2)+ - moveq #0,d1 - move.w 42(a0),d1 - cmp.w d2,d1 ; length 0 and 1 define unused samples - bls .6 - add.l d1,d1 - add.l d1,a1 - bra .7 -.6: clr.w 42(a0) ; length 1 means zero -> no sample -.7: lea 30(a0),a0 - dbf d0,.5 - - movem.l (sp)+,d2/a2 - - ifeq VBLANK_MUSIC - ; reset CIA timer A to default (125) - move.l mt_timerval(a4),d0 - divu #125,d0 - move.b d0,CIAB+CIATALO - lsr.w #8,d0 - move.b d0,CIAB+CIATAHI - endc - -mt_reset: -; a4 must be initialised with base register - - ; reset speed and counters - move.b #6,mt_Speed(a4) - clr.b mt_Counter(a4) - clr.w mt_PatternPos(a4) - clr.b mt_PattDelTime(a4) - clr.b mt_PattDelTime2(a4) - clr.w mt_PBreakPos(a4) - clr.b mt_PBreakFlag(a4) - clr.b mt_PosJumpFlag(a4) - - ; disable the filter - or.b #2,CIAA+CIAPRA - - ifeq MINIMAL - ; set master volume to 64 - lea MasterVolTab64(pc),a0 - move.l a0,mt_MasterVolTab(a4) - endc - - ; set channel index - clr.b mt_chan1+n_index(a4) - move.b #1,mt_chan2+n_index(a4) - move.b #2,mt_chan3+n_index(a4) - move.b #3,mt_chan4+n_index(a4) - - ; initialise channel DMA and interrupt bits - move.w #$0001,mt_chan1+n_dmabit(a4) - move.w #$0002,mt_chan2+n_dmabit(a4) - move.w #$0004,mt_chan3+n_dmabit(a4) - move.w #$0008,mt_chan4+n_dmabit(a4) - move.w #$0080,mt_chan1+n_intbit(a4) - move.w #$0100,mt_chan2+n_intbit(a4) - move.w #$0200,mt_chan3+n_intbit(a4) - move.w #$0400,mt_chan4+n_intbit(a4) - - clr.b mt_E8Trigger(a4) - ifeq MINIMAL - clr.b mt_SongEnd(a4) - clr.b mt_SilCntValid(a4) - endc - - ifnd SDATA - move.l (sp)+,a4 - endc - - -;--------------------------------------------------------------------------- - xdef _mt_end -_mt_end: -; Stop playing current module. -; a6 = CUSTOM - - move.w #$4000,INTENA(a6) - ifd SDATA - clr.b mt_Enable(a4) - lea mt_chan1(a4),a0 - bsr resetch - lea mt_chan2(a4),a0 - bsr resetch - lea mt_chan3(a4),a0 - bsr resetch - lea mt_chan4(a4),a0 - bsr resetch - else - lea mt_data(pc),a1 - clr.b mt_Enable(a1) - lea mt_chan1(a1),a0 - bsr resetch - lea mt_chan2(a1),a0 - bsr resetch - lea mt_chan3(a1),a0 - bsr resetch - lea mt_chan4(a1),a0 - bsr resetch - endc - moveq #0,d0 - move.w d0,AUD0VOL(a6) - move.w d0,AUD1VOL(a6) - move.w d0,AUD2VOL(a6) - move.w d0,AUD3VOL(a6) - move.w #$000f,DMACON(a6) - move.w #$c000,INTENA(a6) - rts - - -resetch: -; a0 = channel status -; All registers are preserved! - - move.w #320,n_period(a0) ; make sure period is not illegal - clr.w n_volume(a0) - clr.w n_sfxlen(a0) - clr.w n_funk(a0) - clr.b n_sfxpri(a0) - clr.b n_looped(a0) - clr.b n_gliss(a0) - ifeq MINIMAL - clr.b n_musiconly(a0) - st n_enable(a0) - endc - rts - - - ifeq MINIMAL -;--------------------------------------------------------------------------- - xdef _mt_soundfx -_mt_soundfx: -; Request playing of an external sound effect on the most unused channel. -; This function is for compatibility with the old API only! -; You should call _mt_playfx instead! -; a6 = CUSTOM -; a0 = sample pointer -; d0.w = sample length in words -; d1.w = sample period -; d2.w = sample volume - - lea -sfx_sizeof(sp),sp - move.l a0,sfx_ptr(sp) - movem.w d0-d2,sfx_len(sp) - move.w #$ff01,sfx_cha(sp) ; any channel, priority=1 - move.l sp,a0 - bsr _mt_playfx - lea sfx_sizeof(sp),sp - rts - - -;--------------------------------------------------------------------------- - xdef _mt_playfx -_mt_playfx: -; Request playing of a prioritized external sound effect, either on a -; fixed channel or on the most unused one. -; A negative channel specification means to use the best one. -; The priority is unsigned and should be greater than zero. -; This channel will be blocked for music until the effect has finished. -; a6 = CUSTOM -; a0 = sfx-structure pointer with the following layout: -; 0: ptr, 4: len.w, 6: period.w, 8: vol.w, 10: channel.b, 11: priority.b -; -> d0 = pointer to channel status or NULL when sample was ignored - - ifd SDATA - movem.l d2-d7/a0-a3/a5,-(sp) - else - movem.l d2-d7/a0-a5,-(sp) - lea mt_data(pc),a4 - endc - - move.w #$4000,INTENA(a6) - moveq #0,d0 - move.b sfx_cha(a0),d0 - bpl channelsfx ; use fixed channel for effect - - ; Did we already calculate the n_freecnt values for all channels? - tst.b mt_SilCntValid(a4) - bne freecnt_valid - - ; Look at the next 8 pattern steps to find the longest sequence - ; of silence (no new note or instrument). - moveq #8,d2 - move.l #$fffff000,d3 ; mask to ignore effects - - ; reset freecnts for all channels - moveq #0,d0 - move.b d0,mt_chan1+n_freecnt(a4) - move.b d0,mt_chan2+n_freecnt(a4) - move.b d0,mt_chan3+n_freecnt(a4) - move.b d0,mt_chan4+n_freecnt(a4) - moveq #-1,d4 - moveq #-1,d5 - moveq #-1,d6 - moveq #-1,d7 - - ; get pattern pointer - move.l mt_mod(a4),a3 ; a3 mod pointer - lea 952(a3),a5 ; a5 song arrangement list - move.w mt_PatternPos(a4),d1 - move.b mt_SongPos(a4),d0 -.1: move.b (a5,d0.w),d0 - swap d0 - lea 1084(a3),a1 - lsr.l #6,d0 - add.l d0,a1 - lea 1024(a1),a2 ; a2 end of pattern - add.w d1,a1 ; a1 current pattern pos - -.2: moveq #0,d0 - - move.l (a1)+,d1 - and.l d3,d1 - sne d1 - and.b d1,d4 - sub.b d4,mt_chan1+n_freecnt(a4) - add.b d4,d0 - - move.l (a1)+,d1 - and.l d3,d1 - sne d1 - and.b d1,d5 - sub.b d5,mt_chan2+n_freecnt(a4) - add.b d5,d0 - - move.l (a1)+,d1 - and.l d3,d1 - sne d1 - and.b d1,d6 - sub.b d6,mt_chan3+n_freecnt(a4) - add.b d6,d0 - - move.l (a1)+,d1 - and.l d3,d1 - sne d1 - and.b d1,d7 - sub.b d7,mt_chan4+n_freecnt(a4) - add.b d7,d0 - - ; break the loop when no channel has any more free pattern steps - beq .7 - - ; otherwise break after 8 pattern steps - subq.w #1,d2 - beq .7 - - ; End of pattern reached? Then load next pattern pointer. - cmp.l a2,a1 - blo .2 - moveq #0,d1 - moveq #1,d0 - add.b mt_SongPos(a4),d0 - and.w #$007f,d0 - cmp.b 950(a3),d0 ; end of song reached? - blo .1 - moveq #0,d0 - bra .1 - -.7: st mt_SilCntValid(a4) - -freecnt_valid: - sub.l a2,a2 - move.b sfx_pri(a0),d2 - - ; Determine which channels are already allocated for sound - ; effects and check if the limit was reached. In this case only - ; replace sound effect channels by higher priority. - moveq #3,d0 - sub.b mt_MusicChannels(a4),d0 - move.b mt_chan1+n_sfxpri(a4),d4 - or.b mt_chan1+n_musiconly(a4),d4 - sne d1 - add.b d1,d0 - move.b mt_chan2+n_sfxpri(a4),d5 - or.b mt_chan2+n_musiconly(a4),d5 - sne d1 - add.b d1,d0 - move.b mt_chan3+n_sfxpri(a4),d6 - or.b mt_chan3+n_musiconly(a4),d6 - sne d1 - add.b d1,d0 - move.b mt_chan4+n_sfxpri(a4),d7 - or.b mt_chan4+n_musiconly(a4),d7 - sne d1 - add.b d1,d0 - bmi .overwrite ; all channels reserved/playing effects - - ; We will prefer a music channel which had an audio interrupt, - ; because that means the last instrument sample has been played - ; completely, and the channel is now in an idle loop. - ; Also exclude channels which have set a repeat loop. - ; Try not to break them! - moveq #0,d3 - tst.b mt_chan1+n_looped(a4) - bne .1 - or.w #$0080,d3 -.1: tst.b mt_chan2+n_looped(a4) - bne .2 - or.w #$0100,d3 -.2: tst.b mt_chan3+n_looped(a4) - bne .3 - or.w #$0200,d3 -.3: tst.b mt_chan4+n_looped(a4) - bne .4 - or.w #$0400,d3 -.4: move.w INTREQR(a6),d1 - and.w d3,d1 - bne .6 - - ; All channels are busy. Then break the non-looped ones first... - move.w d3,d1 - bne .6 - - ; ..except there are none. Then it doesn't matter. :| - move.w #$0780,d1 - - ; first look for the best unused channel -.6: moveq #0,d3 - btst #7,d1 - seq d0 - or.b d4,d0 - bne .7 - lea mt_chan1+n_freecnt(a4),a1 - cmp.b (a1),d3 - bhi .7 - move.l a1,a2 - move.b (a1),d3 -.7: btst #8,d1 - seq d0 - or.b d5,d0 - bne .8 - lea mt_chan2+n_freecnt(a4),a1 - cmp.b (a1),d3 - bhi .8 - move.l a1,a2 - move.b (a1),d3 -.8: btst #9,d1 - seq d0 - or.b d6,d0 - bne .9 - lea mt_chan3+n_freecnt(a4),a1 - cmp.b (a1),d3 - bhi .9 - move.l a1,a2 - move.b (a1),d3 -.9: btst #10,d1 - seq d0 - or.b d7,d0 - bne .10 - lea mt_chan4+n_freecnt(a4),a1 - cmp.b (a1),d3 - bhi .10 - move.l a1,a2 - bra found_sfx_ch - -.10: move.l a2,d3 - bne found_sfx_ch - -.overwrite: - ; finally try to overwrite a sound effect with lower/equal priority - moveq #0,d3 - tst.b d4 - beq .11 - cmp.b d4,d2 - blo .11 - lea mt_chan1+n_freecnt(a4),a1 - cmp.b (a1),d3 - bhi .11 - move.l a1,a2 - move.b (a1),d3 -.11: tst.b d5 - beq .12 - cmp.b d5,d2 - blo .12 - lea mt_chan2+n_freecnt(a4),a1 - cmp.b (a1),d3 - bhi .12 - move.l a1,a2 - move.b (a1),d3 -.12: tst.b d6 - beq .13 - cmp.b d6,d2 - blo .13 - lea mt_chan3+n_freecnt(a4),a1 - cmp.b (a1),d3 - bhi .13 - move.l a1,a2 - move.b (a1),d3 -.13: tst.b d7 - beq .14 - cmp.b d7,d2 - blo .14 - lea mt_chan4+n_freecnt(a4),a1 - cmp.b (a1),d3 - bhi .14 - move.l a1,a2 - -.14: move.l a2,d3 - beq exit_playfx ; ignore new sfx due to low priority - -found_sfx_ch: - lea -n_freecnt(a2),a2 - bra set_sfx - -channelsfx: -; a0 = sfx structure -; d0 = fixed channel for new sound effect - add.w d0,d0 - lea mt_chan1(a4),a2 - add.w channel_offsets(pc,d0.w),a2 - - ; priority high enough to replace a present effect on this channel? - move.b sfx_pri(a0),d2 - cmp.b n_sfxpri(a2),d2 - bhs set_sfx - sub.l a2,a2 - bra exit_playfx - -set_sfx: -; activate the sound effect on this channel -; a0 = sfx structure -; d2 = sfx priority -; a2 = channel status - move.l (a0)+,n_sfxptr(a2) ; sfx_ptr - move.w (a0)+,n_sfxlen(a2) ; sfx_len - move.w (a0)+,n_sfxper(a2) ; sfx_per - move.w (a0),n_sfxvol(a2) ; sfx_vol - move.b d2,n_sfxpri(a2) - -exit_playfx: - move.w #$c000,INTENA(a6) - move.l a2,d0 ; ptr to selected channel or NULL - - ifd SDATA - movem.l (sp)+,d2-d7/a0-a3/a5 - else - movem.l (sp)+,d2-d7/a0-a5 - endc - rts - -channel_offsets: - dc.w 0*n_sizeof,1*n_sizeof,2*n_sizeof,3*n_sizeof - - -;--------------------------------------------------------------------------- - xdef _mt_loopfx -_mt_loopfx: -; Request playing of a looped sound effect on a fixed channel, which -; will be blocked for music until the effect is stopped (_mt_stopfx). -; It uses the same sfx-structure as _mt_playfx, but the priority is -; ignored. A looped sound effect has always highest priority and will -; replace a previous effect on the same channel. No automatic channel -; selection possible! -; Also make sure the sample starts with a zero-word, which is used -; for idling when the effect is stopped. This word is included in the -; total length calculation, but excluded when actually playing the loop. -; a6 = CUSTOM -; a0 = sfx-structure pointer with the following layout: -; 0: ptr, 4: len.w, 6: period.w, 8: vol.w, 10: channel.b - - ifnd SDATA - lea mt_data+mt_chan1(pc),a1 - else - lea mt_chan1(a4),a1 - endc - - moveq #3,d0 - and.b sfx_cha(a0),d0 - add.w d0,d0 - add.w channel_offsets(pc,d0.w),a1 - - move.w #$4000,INTENA(a6) - move.l (a0)+,n_sfxptr(a1) ; sfx_ptr - move.w (a0)+,n_sfxlen(a1) ; sfx_len - move.w (a0)+,n_sfxper(a1) ; sfx_per - move.w (a0),n_sfxvol(a1) ; sfx_vol - st n_sfxpri(a1) ; sfx_pri -1 enables looped mode - move.w #$c000,INTENA(a6) - - rts - - -;--------------------------------------------------------------------------- - xdef _mt_stopfx -_mt_stopfx: -; Immediately stop a currently playing sound effect on a channel. -; a6 = CUSTOM -; d0.b = channel (0..3) - - ifnd SDATA - lea mt_data+mt_chan1(pc),a0 - else - lea mt_chan1(a4),a0 - endc - - and.w #3,d0 - add.w d0,d0 - add.w channel_offsets(pc,d0.w),a0 - - move.w #$4000,INTENA(a6) - tst.b n_sfxpri(a0) - beq .1 ; no sfx playing anyway - moveq #1,d0 - move.b d0,n_sfxpri(a0) - move.w d0,n_sfxlen(a0) ; idle loop - move.w #108,n_sfxper(a0) ; enter idle as quickly as possible - clr.w n_sfxvol(a0) ; and cut volume - ifne NULL_IS_CLEARED - clr.b n_looped(a0) - clr.l n_sfxptr(a0) ; use $0 for idle-looping - else - tst.b n_looped(a0) - beq .1 - clr.b n_looped(a0) - subq.l #2,n_sfxptr(a0) ; idle loop at sample-start - 2 - endc -.1: move.w #$c000,INTENA(a6) - - rts - - -;--------------------------------------------------------------------------- - xdef _mt_musicmask -_mt_musicmask: -; Set bits in the mask define which specific channels are reserved -; for music only. -; a6 = CUSTOM -; d0.b = channel-mask (bit 0 for channel 0, ..., bit 3 for channel 3) - - ifnd SDATA - move.l a4,-(sp) - lea mt_data(pc),a4 - endc - - move.w #$4000,INTENA(a6) - - lsl.b #5,d0 - scs mt_chan4+n_musiconly(a4) - add.b d0,d0 - scs mt_chan3+n_musiconly(a4) - add.b d0,d0 - scs mt_chan2+n_musiconly(a4) - add.b d0,d0 - scs mt_chan1+n_musiconly(a4) - - move.w #$c000,INTENA(a6) - - ifnd SDATA - move.l (sp)+,a4 - endc - rts - - -;--------------------------------------------------------------------------- - xdef _mt_mastervol -_mt_mastervol: -; Set a master volume from 0 to 64 for all music channels. -; Note that the master volume does not affect the volume of external -; sound effects (which is desired). -; a6 = CUSTOM -; d0.w = master volume - - ifnd SDATA - move.l a4,-(sp) - lea mt_data(pc),a4 - endc - - ; stingray, since each volume table has a size of 65 bytes - ; we simply multiply (optimised of course) by 65 to get the - ; offset to the correct table - lea MasterVolTab0(pc),a0 - add.w d0,a0 - lsl.w #6,d0 - add.w d0,a0 - - ; set new table and adapt all channel volumes immediately - move.w #$4000,INTENA(a6) - move.l a0,mt_MasterVolTab(a4) - bsr set_all_volumes - move.w #$c000,INTENA(a6) - - ifnd SDATA - move.l (sp)+,a4 - endc - rts - - -;--------------------------------------------------------------------------- - xdef _mt_channelmask -_mt_channelmask: -; Define which music channels are muted. Doesn't affect sound effects. -; a6 = CUSTOM -; d0.b = channel-mask (bit 0 for channel 0, ..., bit 3 for channel 3) - - ifnd SDATA - move.l a4,-(sp) - lea mt_data(pc),a4 - endc - - move.w #$4000,INTENA(a6) - - lsl.b #5,d0 - scs mt_chan4+n_enable(a4) - add.b d0,d0 - scs mt_chan3+n_enable(a4) - add.b d0,d0 - scs mt_chan2+n_enable(a4) - add.b d0,d0 - scs mt_chan1+n_enable(a4) - move.l mt_MasterVolTab(a4),a0 - bsr set_all_volumes - - move.w #$c000,INTENA(a6) - - ifnd SDATA - move.l (sp)+,a4 - endc - rts - - -;--------------------------------------------------------------------------- -set_all_volumes: -; a0 = Master volume table - - tst.b mt_chan1+n_sfxpri(a4) - bne .1 - move.w mt_chan1+n_volume(a4),d0 - move.b (a0,d0.w),d0 - and.b mt_chan1+n_enable(a4),d0 - move.w d0,AUD0VOL(a6) -.1: tst.b mt_chan2+n_sfxpri(a4) - bne .2 - move.w mt_chan2+n_volume(a4),d0 - move.b (a0,d0.w),d0 - and.b mt_chan2+n_enable(a4),d0 - move.w d0,AUD1VOL(a6) -.2: tst.b mt_chan3+n_sfxpri(a4) - bne .3 - move.w mt_chan3+n_volume(a4),d0 - move.b (a0,d0.w),d0 - and.b mt_chan3+n_enable(a4),d0 - move.w d0,AUD2VOL(a6) -.3: tst.b mt_chan4+n_sfxpri(a4) - bne .4 - move.w mt_chan4+n_volume(a4),d0 - move.b (a0,d0.w),d0 - and.b mt_chan4+n_enable(a4),d0 - move.w d0,AUD3VOL(a6) -.4: rts - - -;--------------------------------------------------------------------------- - xdef _mt_samplevol -_mt_samplevol: -; Redefine a sample's volume. May also be done while the song is playing. -; Warning: Does not check arguments for valid range! You must have done -; _mt_init before calling this function! -; The new volume is persistent. Even when the song is restarted. -; d0.w = sample number (0-31) -; d1.b = volume (0-64) - - ifd SDATA - move.l mt_mod(a4),a0 - else - move.l mt_data+mt_mod(pc),a0 - endc - - swap d1 - move.w d0,d1 - add.w d1,d1 - lsl.w #5,d0 - sub.w d1,d0 ; table index: sample number * 30 - swap d1 - move.b d1,12+3(a0,d0.w) ; set sample's volume - rts - endc ; !MINIMAL - - -;--------------------------------------------------------------------------- - xdef _mt_music -_mt_music: -; Used when called by external interrupt handler. -; Saves/restores all registers and sets up A4 when needed. -; a6 = CUSTOM - - ifd SDATA - movem.l d2-d7/a2-a3/a5,-(sp) - bsr mt_music - movem.l (sp)+,d2-d7/a2-a3/a5 - else ; !SDATA - movem.l d2-d7/a2-a5,-(sp) - lea mt_data(pc),a4 - bsr mt_music - movem.l (sp)+,d2-d7/a2-a5 - endc - rts - -mt_music: -; Called from interrupt. -; Play next position when Counter equals Speed. -; Effects are always handled. -; a6 = CUSTOM - - moveq #0,d7 ; d7 is always zero - - lea mt_dmaon+1(pc),a0 - move.b d7,(a0) - - addq.b #1,mt_Counter(a4) - - move.b mt_Counter(a4),d0 - cmp.b mt_Speed(a4),d0 - blo no_new_note - - ; handle a new note - move.b d7,mt_Counter(a4) - tst.b mt_PattDelTime2(a4) - beq get_new_note - - ; we have a pattern delay, check effects then step - lea AUD0LC(a6),a5 - lea mt_chan1(a4),a2 - bsr mt_checkfx - lea AUD1LC(a6),a5 - lea mt_chan2(a4),a2 - bsr mt_checkfx - lea AUD2LC(a6),a5 - lea mt_chan3(a4),a2 - bsr mt_checkfx - lea AUD3LC(a6),a5 - lea mt_chan4(a4),a2 - bsr mt_checkfx - bra settb_step - -no_new_note: - ; no new note, just check effects, don't step to next position - lea AUD0LC(a6),a5 - lea mt_chan1(a4),a2 - bsr mt_checkfx - lea AUD1LC(a6),a5 - lea mt_chan2(a4),a2 - bsr mt_checkfx - lea AUD2LC(a6),a5 - lea mt_chan3(a4),a2 - bsr mt_checkfx - lea AUD3LC(a6),a5 - lea mt_chan4(a4),a2 - bsr mt_checkfx - - ; set one-shot TimerB interrupt for enabling DMA, when needed - move.b mt_dmaon+1(pc),d0 - beq same_pattern - move.b #$19,CIAB+CIACRB ; load/start timer B, one-shot - bra same_pattern - -get_new_note: - ; determine pointer to current pattern line - move.l mt_mod(a4),a0 - lea 12(a0),a3 ; sample info table - lea 1084(a0),a1 ; pattern data - lea 952(a0),a0 - moveq #0,d0 - move.b mt_SongPos(a4),d0 - move.b (a0,d0.w),d0 ; current pattern number - swap d0 - lsr.l #6,d0 - add.l d0,a1 ; pattern base - add.w mt_PatternPos(a4),a1 ; a1 pattern line - - ; play new note for each channel, apply some effects - lea AUD0LC(a6),a5 - lea mt_chan1(a4),a2 - bsr mt_playvoice - lea AUD1LC(a6),a5 - lea mt_chan2(a4),a2 - bsr mt_playvoice - lea AUD2LC(a6),a5 - lea mt_chan3(a4),a2 - bsr mt_playvoice - lea AUD3LC(a6),a5 - lea mt_chan4(a4),a2 - bsr mt_playvoice - -settb_step: - ; set one-shot TimerB interrupt for enabling DMA, when needed - move.b mt_dmaon+1(pc),d0 - beq pattern_step - move.b #$19,CIAB+CIACRB ; load/start timer B, one-shot - -pattern_step: - ; next pattern line, handle delay and break - ifeq MINIMAL - clr.b mt_SilCntValid(a4) ; recalculate silence counters - endc - moveq #16,d2 ; offset to next pattern line - - move.b mt_PattDelTime2(a4),d1 - move.b mt_PattDelTime(a4),d0 - beq .1 - move.b d0,d1 - move.b d7,mt_PattDelTime(a4) -.1: tst.b d1 - beq .3 - subq.b #1,d1 - beq .2 - moveq #0,d2 ; do not advance to next line -.2: move.b d1,mt_PattDelTime2(a4) - -.3: add.w mt_PatternPos(a4),d2 ; d2 PatternPos - - ; check for break - bclr d7,mt_PBreakFlag(a4) - beq .4 - move.w mt_PBreakPos(a4),d2 - move.w d7,mt_PBreakPos(a4) - - ; check whether end of pattern is reached -.4: move.w d2,mt_PatternPos(a4) - cmp.w #1024,d2 - blo same_pattern - -song_step: - move.w mt_PBreakPos(a4),mt_PatternPos(a4) - move.w d7,mt_PBreakPos(a4) - move.b d7,mt_PosJumpFlag(a4) - - ; next position in song - moveq #1,d0 - add.b mt_SongPos(a4),d0 - and.w #$007f,d0 - move.l mt_mod(a4),a0 - cmp.b 950(a0),d0 ; end of song reached? - blo .1 - moveq #0,d0 ; restart the song from the beginning - ifeq MINIMAL - addq.b #1,mt_SongEnd(a4) - bne .2 - clr.b mt_Enable(a4) ; stop the song when mt_SongEnd was -1 -.2: and.b #$7f,mt_SongEnd(a4) - endc -.1: move.b d0,mt_SongPos(a4) - -same_pattern: - tst.b mt_PosJumpFlag(a4) - bne song_step - - rts - - - ifeq MINIMAL -;--------------------------------------------------------------------------- -mt_sfxonly: -; Called from interrupt. -; Plays sound effects on free channels. -; a6 = CUSTOM - - moveq #0,d7 ; d7 is always zero - - lea mt_dmaon+1(pc),a0 - move.b d7,(a0) - - lea AUD0LC(a6),a5 - lea mt_chan1(a4),a2 - bsr chan_sfx_only - lea AUD1LC(a6),a5 - lea mt_chan2(a4),a2 - bsr chan_sfx_only - lea AUD2LC(a6),a5 - lea mt_chan3(a4),a2 - bsr chan_sfx_only - lea AUD3LC(a6),a5 - lea mt_chan4(a4),a2 - bsr chan_sfx_only - - move.b mt_dmaon+1(pc),d0 - beq .1 - move.b #$19,CIAB+CIACRB ; load/start timer B, one-shot - -.1: rts - - -chan_sfx_only: -; Check for new sound samples. Check if previous ones are finished. -; a2 = channel data -; a5 = audio registers - - tst.b n_sfxpri(a2) - beq .1 - - move.w n_sfxlen(a2),d0 - bne start_sfx - tst.b n_looped(a2) - bne .1 - - move.w n_intbit(a2),d0 - and.w INTREQR(a6),d0 - beq .1 - move.w n_dmabit(a2),d0 - and.w mt_dmaon(pc),d0 - bne .1 - - ; last sound effect sample has played, so unblock this channel again - move.b d7,n_sfxpri(a2) - -.1: rts - - -;--------------------------------------------------------------------------- -start_sfx: -; d0 = sfx_len in words -; a2 = channel data -; a5 = audio registers - - ; play new sound effect on this channel - move.w n_dmabit(a2),d1 - move.w d1,DMACON(a6) - - move.l n_sfxptr(a2),a0 - tst.b n_sfxpri(a2) - bpl .1 - - ; looped sound effect - st n_looped(a2) - addq.l #2,a0 ; skip first word, used for idling - subq.w #1,d0 - move.l a0,AUDLC(a5) - move.w d0,AUDLEN(a5) - bra .2 - - ; normal sound effect -.1: move.b d7,n_looped(a2) - move.l a0,AUDLC(a5) - move.w d0,AUDLEN(a5) - moveq #1,d0 ; idles after playing once - ifne NULL_IS_CLEARED - sub.l a0,a0 - endc - - ; save repeat and period for TimerB interrupt -.2: move.l a0,n_loopstart(a2) - move.w d0,n_replen(a2) - move.w n_sfxper(a2),d0 - move.w d0,AUDPER(a5) - move.w d0,n_period(a2) - move.w n_sfxvol(a2),AUDVOL(a5) - - move.w d7,n_sfxlen(a2) ; don't call start_sfx again - - lea mt_dmaon(pc),a0 - or.w d1,(a0) ; DMA-channel to enable on TimerB - rts - endc ; !MINIMAL - - -;--------------------------------------------------------------------------- -mt_checkfx: -; a2 = channel data -; a5 = audio registers - - ifeq MINIMAL - tst.b n_sfxpri(a2) - beq .3 - - move.w n_sfxlen(a2),d0 - beq .2 - bsr start_sfx - - ; channel is blocked, only check some E-commands -.1: move.w #$0fff,d4 - and.w n_cmd(a2),d4 - move.w d4,d0 - clr.b d0 - cmp.w #$0e00,d0 - bne mt_nop - and.w #$00ff,d4 - bra blocked_e_cmds - -.2: tst.b n_looped(a2) - bne .1 - move.w n_intbit(a2),d0 - and.w INTREQR(a6),d0 - beq .1 - move.w n_dmabit(a2),d0 - and.w mt_dmaon(pc),d0 - bne .1 - - ; sound effect sample has played, so unblock this channel again - move.b d7,n_sfxpri(a2) - endc ; !MINIMAL - - ; do channel effects between notes -.3: move.w n_funk(a2),d0 - beq .4 - bsr mt_updatefunk - -.4: move.w #$0fff,d4 - and.w n_cmd(a2),d4 - beq mt_pernop - and.w #$00ff,d4 - - moveq #$0f,d0 - and.b n_cmd(a2),d0 - add.w d0,d0 - move.w fx_tab(pc,d0.w),d0 - jmp fx_tab(pc,d0.w) - -fx_tab: - dc.w mt_arpeggio-fx_tab ; $0 - dc.w mt_portaup-fx_tab - dc.w mt_portadown-fx_tab - dc.w mt_toneporta-fx_tab - dc.w mt_vibrato-fx_tab ; $4 - dc.w mt_tonevolslide-fx_tab - dc.w mt_vibrvolslide-fx_tab - dc.w mt_tremolo-fx_tab - dc.w mt_nop-fx_tab ; $8 - dc.w mt_nop-fx_tab - dc.w mt_volumeslide-fx_tab - dc.w mt_nop-fx_tab - dc.w mt_nop-fx_tab ; $C - dc.w mt_nop-fx_tab - dc.w mt_e_cmds-fx_tab - dc.w mt_nop-fx_tab - - -mt_pernop: -; just set the current period - - move.w n_period(a2),AUDPER(a5) -mt_nop: - rts - - -;--------------------------------------------------------------------------- -mt_playvoice: -; a1 = pattern ptr -; a2 = channel data -; a3 = sample info table -; a5 = audio registers - - move.l (a1)+,d6 ; d6 current note/cmd words - - ifeq MINIMAL - ; channel blocked by external sound effect? - tst.b n_sfxpri(a2) - beq .2 - - move.w n_sfxlen(a2),d0 - beq .1 - bsr start_sfx - bra moreblockedfx - - ; do only some limited commands, while sound effect is in progress -.1: tst.b n_looped(a2) - bne moreblockedfx - move.w n_intbit(a2),d0 - and.w INTREQR(a6),d0 - beq moreblockedfx - move.w n_dmabit(a2),d0 - and.w mt_dmaon(pc),d0 - bne moreblockedfx - - ; sound effect sample has played, so unblock this channel again - move.b d7,n_sfxpri(a2) - endc ; !MINIMAL - -.2: tst.l (a2) ; n_note/cmd: any note or cmd set? - bne .3 - move.w n_period(a2),AUDPER(a5) -.3: move.l d6,(a2) - - moveq #15,d5 - and.b n_cmd(a2),d5 - add.w d5,d5 ; d5 cmd*2 - - moveq #0,d4 - move.b d6,d4 ; d4 cmd argument (in MSW) - swap d4 - move.w #$0ff0,d4 - and.w d6,d4 ; d4 for checking E-cmd (in LSW) - - swap d6 - move.l d6,d0 ; S...S... - clr.b d0 - rol.w #4,d0 - rol.l #4,d0 ; ....00SS - - and.w #$0fff,d6 ; d6 note - - ; get sample start address - add.w d0,d0 ; sample number * 2 - beq set_regs - move.w mult30tab(pc,d0.w),d1 ; d1 sample info table offset - lea mt_SampleStarts(a4),a0 - add.w d0,d0 - move.l -4(a0,d0.w),d2 - - ; read length, volume and repeat from sample info table - lea (a3,d1.w),a0 - move.w (a0)+,d0 ; length - bne .4 - - ifne NULL_IS_CLEARED - moveq #0,d2 ; use $0 for empty samples - else - ; use the first two bytes from the first sample for empty samples - move.l mt_SampleStarts(a4),d2 - endc - addq.w #1,d0 - -.4: move.l d2,n_start(a2) - move.w d0,n_reallength(a2) - - ; determine period table from fine-tune parameter - moveq #0,d3 - move.b (a0)+,d3 - add.w d3,d3 - move.l a0,d1 - lea mt_PerFineTune(pc),a0 - add.w (a0,d3.w),a0 - move.l a0,n_pertab(a2) - move.l d1,a0 - cmp.w #2*8,d3 - shs n_minusft(a2) - - moveq #0,d1 - move.b (a0)+,d1 ; volume - move.w d1,n_volume(a2) - move.w (a0)+,d3 ; repeat offset - beq no_offset - - ; set repeat - add.l d3,d2 - add.l d3,d2 - move.w (a0),d0 - move.w d0,n_replen(a2) - exg d0,d3 ; n_replen to d3 - add.w d3,d0 - bra set_len_start - -mult30tab: - dc.w 0*30,1*30,2*30,3*30,4*30,5*30,6*30,7*30 - dc.w 8*30,9*30,10*30,11*30,12*30,13*30,14*30,15*30 - dc.w 16*30,17*30,18*30,19*30,20*30,21*30,22*30,23*30 - dc.w 24*30,25*30,26*30,27*30,28*30,29*30,30*30,31*30 - -no_offset: - move.w (a0),d3 - ifne NULL_IS_CLEARED - cmp.w #1,d3 - beq .1 - bhi set_replen - else - bne set_replen - endc - ; repeat length zero means idle-looping - addq.w #1,d3 -.1: moveq #0,d2 ; expect two zero bytes at $0 -set_replen: - move.w d3,n_replen(a2) -set_len_start: - move.w d0,n_length(a2) - move.l d2,n_loopstart(a2) - move.l d2,n_wavestart(a2) - - ifeq MINIMAL - move.l mt_MasterVolTab(a4),a0 - move.b (a0,d1.w),d1 - and.b n_enable(a2),d1 - endc - move.w d1,AUDVOL(a5) - - ; remember if sample is looped - ; @@@ FIXME: also need to check if n_loopstart equals n_start - subq.w #1,d3 - sne n_looped(a2) - -set_regs: -; d4 = cmd argument | masked E-cmd -; d5 = cmd*2 -; d6 = cmd.w | note.w - - move.w d4,d3 ; d3 masked E-cmd - swap d4 ; d4 cmd argument into LSW - - tst.w d6 - beq checkmorefx ; no new note - - cmp.w #$0e50,d3 - beq set_finetune - - move.w prefx_tab(pc,d5.w),d0 - jmp prefx_tab(pc,d0.w) - -prefx_tab: - dc.w set_period-prefx_tab,set_period-prefx_tab,set_period-prefx_tab - dc.w set_toneporta-prefx_tab ; $3 - dc.w set_period-prefx_tab - dc.w set_toneporta-prefx_tab ; $5 - dc.w set_period-prefx_tab,set_period-prefx_tab,set_period-prefx_tab - dc.w set_sampleoffset-prefx_tab ; $9 - dc.w set_period-prefx_tab,set_period-prefx_tab,set_period-prefx_tab - dc.w set_period-prefx_tab,set_period-prefx_tab,set_period-prefx_tab - - -mt_sampleoffset: -; cmd 9 x y (xy = offset in 256 bytes) -; d4 = xy - - moveq #0,d0 - move.b d4,d0 - bne .1 - move.b n_sampleoffset(a2),d0 - bra .2 -.1: move.b d0,n_sampleoffset(a2) - -.2: lsl.w #7,d0 - cmp.w n_length(a2),d0 - bhs .3 - sub.w d0,n_length(a2) - add.w d0,d0 - add.l d0,n_start(a2) - rts - -.3: move.w #1,n_length(a2) - rts - - -set_sampleoffset: - bsr mt_sampleoffset - bra set_period - -set_finetune: - lea mt_PerFineTune(pc),a0 - moveq #$0f,d0 - and.b d4,d0 - add.w d0,d0 - add.w (a0,d0.w),a0 - move.l a0,n_pertab(a2) - cmp.w #2*8,d0 - shs n_minusft(a2) - -set_period: -; find nearest period for a note value, then apply finetuning -; d3 = masked E-cmd -; d4 = cmd argument -; d5 = cmd*2 -; d6 = note.w - - lea mt_PeriodTable(pc),a0 - moveq #36-1,d0 - moveq #-2,d1 -.1: addq.w #2,d1 ; table offset - cmp.w (a0)+,d6 - dbhs d0,.1 - - ; apply finetuning, set period and note-offset - move.l n_pertab(a2),a0 - move.w (a0,d1.w),d2 - move.w d2,n_period(a2) - move.w d1,n_noteoff(a2) - - ; check for notedelay - cmp.w #$0ed0,d3 ; notedelay - beq checkmorefx - - ; disable DMA - move.w n_dmabit(a2),d0 - move.w d0,DMACON(a6) - - btst #2,n_vibratoctrl(a2) - bne .2 - move.b d7,n_vibratopos(a2) - -.2: btst #2,n_tremoloctrl(a2) - bne .3 - move.b d7,n_tremolopos(a2) - -.3: move.l n_start(a2),AUDLC(a5) - move.w n_length(a2),AUDLEN(a5) - move.w d2,AUDPER(a5) - lea mt_dmaon(pc),a0 - or.w d0,(a0) - -checkmorefx: -; d4 = cmd argument -; d5 = cmd*2 -; d6 = note.w - - move.w n_funk(a2),d0 - beq .1 - bsr mt_updatefunk - -.1: move.w morefx_tab(pc,d5.w),d0 - jmp morefx_tab(pc,d0.w) - -morefx_tab: - dc.w mt_pernop-morefx_tab,mt_pernop-morefx_tab,mt_pernop-morefx_tab - dc.w mt_pernop-morefx_tab,mt_pernop-morefx_tab,mt_pernop-morefx_tab - dc.w mt_pernop-morefx_tab,mt_pernop-morefx_tab,mt_pernop-morefx_tab - dc.w mt_sampleoffset-morefx_tab ; $9 - dc.w mt_pernop-morefx_tab - dc.w mt_posjump-morefx_tab ; $B - dc.w mt_volchange-morefx_tab - dc.w mt_patternbrk-morefx_tab ; $D - dc.w mt_e_cmds-morefx_tab - dc.w mt_setspeed-morefx_tab - - -set_toneporta: - move.l n_pertab(a2),a0 ; tuned period table - - ; find first period which is less or equal the note in d6 - moveq #36-1,d0 - moveq #-2,d1 -.1: addq.w #2,d1 - cmp.w (a0)+,d6 - dbhs d0,.1 - - tst.b n_minusft(a2) ; negative fine tune? - beq .2 - tst.w d1 - beq .2 - subq.l #2,a0 ; then take previous period - subq.w #2,d1 - -.2: move.w d1,n_noteoff(a2) ; note offset in period table - move.w n_period(a2),d2 - move.w -(a0),d1 - cmp.w d1,d2 - bne .3 - moveq #0,d1 -.3: move.w d1,n_wantedperiod(a2) - - move.w n_funk(a2),d0 - beq .4 - bsr mt_updatefunk - -.4: move.w d2,AUDPER(a5) - rts - - - ifeq MINIMAL -moreblockedfx: -; d6 = note.w | cmd.w - - moveq #0,d4 - move.b d6,d4 ; cmd argument - and.w #$0f00,d6 - lsr.w #7,d6 - move.w blmorefx_tab(pc,d6.w),d0 - jmp blmorefx_tab(pc,d0.w) - -blmorefx_tab: - dc.w mt_nop-blmorefx_tab,mt_nop-blmorefx_tab - dc.w mt_nop-blmorefx_tab,mt_nop-blmorefx_tab - dc.w mt_nop-blmorefx_tab,mt_nop-blmorefx_tab - dc.w mt_nop-blmorefx_tab,mt_nop-blmorefx_tab - dc.w mt_nop-blmorefx_tab,mt_nop-blmorefx_tab - dc.w mt_nop-blmorefx_tab - dc.w mt_posjump-blmorefx_tab ; $B - dc.w mt_nop-blmorefx_tab - dc.w mt_patternbrk-blmorefx_tab ; $D - dc.w blocked_e_cmds-blmorefx_tab - dc.w mt_setspeed-blmorefx_tab ; $F - endc ; !MINIMAL - - -mt_arpeggio: -; cmd 0 x y (x = first arpeggio offset, y = second arpeggio offset) -; d4 = xy - - moveq #0,d0 - move.b mt_Counter(a4),d0 - move.b arptab(pc,d0.w),d0 - beq mt_pernop ; step 0, just use normal period - bmi .1 - - ; step 1, arpeggio by left nibble - lsr.b #4,d4 - bra .2 - - ; step 2, arpeggio by right nibble -.1: and.w #$000f,d4 - - ; offset current note -.2: add.w d4,d4 - add.w n_noteoff(a2),d4 - cmp.w #2*36,d4 - bhs .4 - - ; set period with arpeggio offset from note table - move.l n_pertab(a2),a0 - move.w (a0,d4.w),AUDPER(a5) -.4: rts - -arptab: - dc.b 0,1,-1,0,1,-1,0,1,-1,0,1,-1,0,1,-1,0 - dc.b 1,-1,0,1,-1,0,1,-1,0,1,-1,0,1,-1,0,1 - - -mt_fineportaup: -; cmd E 1 x (subtract x from period) -; d0 = x - - tst.b mt_Counter(a4) - beq do_porta_up - rts - - -mt_portaup: -; cmd 1 x x (subtract xx from period) -; d4 = xx - - move.w d4,d0 - -do_porta_up: - move.w n_period(a2),d1 - sub.w d0,d1 - cmp.w #113,d1 - bhs .1 - moveq #113,d1 -.1: move.w d1,n_period(a2) - move.w d1,AUDPER(a5) - rts - - -mt_fineportadn: -; cmd E 2 x (add x to period) -; d0 = x - - tst.b mt_Counter(a4) - beq do_porta_down - rts - - -mt_portadown: -; cmd 2 x x (add xx to period) -; d4 = xx - - move.w d4,d0 - -do_porta_down: - move.w n_period(a2),d1 - add.w d0,d1 - cmp.w #856,d1 - bls .1 - move.w #856,d1 -.1: move.w d1,n_period(a2) - move.w d1,AUDPER(a5) - rts - - -mt_toneporta: -; cmd 3 x y (xy = tone portamento speed) -; d4 = xy - - tst.b d4 - beq mt_toneporta_nc - move.w d4,n_toneportspeed(a2) - move.b d7,n_cmdlo(a2) - -mt_toneporta_nc: - move.w n_wantedperiod(a2),d1 - beq .6 - - move.w n_toneportspeed(a2),d0 - move.w n_period(a2),d2 - cmp.w d1,d2 - blo .2 - - ; tone porta up - sub.w d0,d2 - cmp.w d1,d2 - bgt .3 - move.w d1,d2 - move.w d7,n_wantedperiod(a2) - bra .3 - - ; tone porta down -.2: add.w d0,d2 - cmp.w d1,d2 - blt .3 - move.w d1,d2 - move.w d7,n_wantedperiod(a2) - -.3: move.w d2,n_period(a2) - - tst.b n_gliss(a2) - beq .5 - - ; glissando: find nearest note for new period - move.l n_pertab(a2),a0 - moveq #36-1,d0 - moveq #-2,d1 -.4: addq.w #2,d1 - cmp.w (a0)+,d2 - dbhs d0,.4 - - move.w d1,n_noteoff(a2) ; @@@ needed? - move.w -(a0),d2 - -.5: move.w d2,AUDPER(a5) -.6 rts - - -mt_vibrato: -; cmd 4 x y (x = speed, y = amplitude) -; d4 = xy - - moveq #$0f,d2 - and.b d4,d2 - beq .1 - move.b d2,n_vibratoamp(a2) - bra .2 -.1: move.b n_vibratoamp(a2),d2 - -.2: lsr.b #4,d4 - beq .3 - move.b d4,n_vibratospd(a2) - bra mt_vibrato_nc -.3: move.b n_vibratospd(a2),d4 - -mt_vibrato_nc: - ; calculate vibrato table offset: 64 * amplitude + (pos & 63) - lsl.w #6,d2 - moveq #63,d0 - and.b n_vibratopos(a2),d0 - add.w d0,d2 - - ifne ENABLE_SAWRECT - ; select vibrato waveform - moveq #3,d1 - and.b n_vibratoctrl(a2),d1 - beq .6 - subq.b #1,d1 - beq .5 - - ; ctrl 2 & 3 select a rectangle vibrato - lea mt_VibratoRectTable(pc),a0 - bra .9 - - ; ctrl 1 selects a sawtooth vibrato -.5: lea mt_VibratoSawTable(pc),a0 - bra .9 - endc ; ENABLE_SAWRECT - - ; ctrl 0 selects a sine vibrato -.6: lea mt_VibratoSineTable(pc),a0 - - ; add vibrato-offset to period -.9: move.b (a0,d2.w),d0 - ext.w d0 - add.w n_period(a2),d0 - move.w d0,AUDPER(a5) - - ; increase vibratopos by speed - add.b d4,n_vibratopos(a2) - rts - - -mt_tonevolslide: -; cmd 5 x y (x = volume-up, y = volume-down) -; d4 = xy - - pea mt_volumeslide(pc) - bra mt_toneporta_nc - - -mt_vibrvolslide: -; cmd 6 x y (x = volume-up, y = volume-down) -; d4 = xy - - move.w d4,d3 - move.b n_vibratoamp(a2),d2 - move.b n_vibratospd(a2),d4 - bsr mt_vibrato_nc - - move.w d3,d4 - bra mt_volumeslide - - -mt_tremolo: -; cmd 7 x y (x = speed, y = amplitude) -; d4 = xy - - moveq #$0f,d2 - and.b d4,d2 - beq .1 - move.b d2,n_tremoloamp(a2) - bra .2 -.1: move.b n_tremoloamp(a2),d2 - -.2: lsr.b #4,d4 - beq .3 - move.b d4,n_tremolospd(a2) - bra .4 -.3: move.b n_tremolospd(a2),d4 - - ; calculate tremolo table offset: 64 * amplitude + (pos & 63) -.4: lsl.w #6,d2 - moveq #63,d0 - and.b n_tremolopos(a2),d0 - add.w d0,d2 - - ifne ENABLE_SAWRECT - ; select tremolo waveform - moveq #3,d1 - and.b n_tremoloctrl(a2),d1 - beq .6 - subq.b #1,d1 - beq .5 - - ; ctrl 2 & 3 select a rectangle tremolo - lea mt_VibratoRectTable(pc),a0 - bra .9 - - ; ctrl 1 selects a sawtooth tremolo -.5: lea mt_VibratoSawTable(pc),a0 - bra .9 - endc ; ENABLE_SAWRECT - - ; ctrl 0 selects a sine tremolo -.6: lea mt_VibratoSineTable(pc),a0 - - ; add tremolo-offset to volume -.9: move.w n_volume(a2),d0 - add.b (a0,d2.w),d0 - bpl .10 - moveq #0,d0 -.10: cmp.w #64,d0 - bls .11 - moveq #64,d0 -.11: move.w n_period(a2),AUDPER(a5) - ifeq MINIMAL - move.l mt_MasterVolTab(a4),a0 - move.b (a0,d0.w),d0 - and.b n_enable(a2),d0 - endc - move.w d0,AUDVOL(a5) - - ; increase tremolopos by speed - add.b d4,n_tremolopos(a2) - rts - - -mt_volumeslide: -; cmd A x y (x = volume-up, y = volume-down) -; d4 = xy - - move.w n_volume(a2),d0 - moveq #$0f,d1 - and.b d4,d1 - lsr.b #4,d4 - beq vol_slide_down - - ; slide up, until 64 - add.b d4,d0 -vol_slide_up: - cmp.b #64,d0 - bls set_vol - moveq #64,d0 - bra set_vol - - ; slide down, until 0 -vol_slide_down: - sub.b d1,d0 - bpl set_vol - moveq #0,d0 - -set_vol: - move.w d0,n_volume(a2) - move.w n_period(a2),AUDPER(a5) - ifeq MINIMAL - move.l mt_MasterVolTab(a4),a0 - move.b (a0,d0.w),d0 - and.b n_enable(a2),d0 - endc - move.w d0,AUDVOL(a5) - rts - - -mt_posjump: -; cmd B x y (xy = new song position) -; d4 = xy - - move.b d4,d0 - subq.b #1,d0 - move.b d0,mt_SongPos(a4) - -jump_pos0: - move.w d7,mt_PBreakPos(a4) - st mt_PosJumpFlag(a4) - rts - - -mt_volchange: -; cmd C x y (xy = new volume) -; d4 = xy - - cmp.w #64,d4 - bls .1 - moveq #64,d4 -.1: move.w d4,n_volume(a2) - ifeq MINIMAL - move.l mt_MasterVolTab(a4),a0 - move.b (a0,d4.w),d4 - and.b n_enable(a2),d4 - endc - move.w d4,AUDVOL(a5) - rts - - -mt_patternbrk: -; cmd D x y (xy = break pos in decimal) -; d4 = xy - - moveq #$0f,d0 - and.w d4,d0 - move.w d4,d1 - lsr.w #4,d1 - add.b mult10tab(pc,d1.w),d0 - cmp.b #63,d0 - bhi jump_pos0 - - lsl.w #4,d0 - move.w d0,mt_PBreakPos(a4) - st mt_PosJumpFlag(a4) - rts - -mult10tab: - dc.b 0,10,20,30,40,50,60,70,80,90,0,0,0,0,0,0 - - -mt_setspeed: -; cmd F x y (xy<$20 new speed, xy>=$20 new tempo) -; d4 = xy - - ifeq VBLANK_MUSIC - cmp.b #$20,d4 - bhs .1 - endc - - move.b d4,mt_Speed(a4) - beq _mt_end - rts - - ifeq VBLANK_MUSIC - ; set tempo (CIA only) -.1: and.w #$00ff,d4 - move.l mt_timerval(a4),d0 - divu d4,d0 - move.b d0,CIAB+CIATALO - lsr.w #8,d0 - move.b d0,CIAB+CIATAHI - rts - endc - - -mt_e_cmds: -; cmd E x y (x=command, y=argument) -; d4 = xy - - moveq #$0f,d0 - and.w d4,d0 ; pass E-cmd argument in d0 - - move.w d4,d1 - lsr.w #4,d1 - add.w d1,d1 - move.w ecmd_tab(pc,d1.w),d1 - jmp ecmd_tab(pc,d1.w) - -ecmd_tab: - dc.w mt_filter-ecmd_tab - dc.w mt_fineportaup-ecmd_tab - dc.w mt_fineportadn-ecmd_tab - dc.w mt_glissctrl-ecmd_tab - dc.w mt_vibratoctrl-ecmd_tab - dc.w mt_finetune-ecmd_tab - dc.w mt_jumploop-ecmd_tab - dc.w mt_tremoctrl-ecmd_tab - dc.w mt_e8-ecmd_tab - dc.w mt_retrignote-ecmd_tab - dc.w mt_volfineup-ecmd_tab - dc.w mt_volfinedn-ecmd_tab - dc.w mt_notecut-ecmd_tab - dc.w mt_notedelay-ecmd_tab - dc.w mt_patterndelay-ecmd_tab - dc.w mt_funk-ecmd_tab - - -blocked_e_cmds: -; cmd E x y (x=command, y=argument) -; d4 = xy - - moveq #$0f,d0 - and.w d4,d0 ; pass E-cmd argument in d0 - - move.w d4,d1 - lsr.w #4,d1 - add.w d1,d1 - move.w blecmd_tab(pc,d1.w),d1 - jmp blecmd_tab(pc,d1.w) - -blecmd_tab: - dc.w mt_filter-blecmd_tab - dc.w mt_rts-blecmd_tab - dc.w mt_rts-blecmd_tab - dc.w mt_glissctrl-blecmd_tab - dc.w mt_vibratoctrl-blecmd_tab - dc.w mt_finetune-blecmd_tab - dc.w mt_jumploop-blecmd_tab - dc.w mt_tremoctrl-blecmd_tab - dc.w mt_e8-blecmd_tab - dc.w mt_rts-blecmd_tab - dc.w mt_rts-blecmd_tab - dc.w mt_rts-blecmd_tab - dc.w mt_rts-blecmd_tab - dc.w mt_rts-blecmd_tab - dc.w mt_patterndelay-blecmd_tab - dc.w mt_rts-blecmd_tab - - -mt_filter: -; cmd E 0 x (x=1 disable, x=0 enable) -; d0 = x - - lsr.b #1,d0 - bcs .1 - bclr #2,CIAA+CIAPRA - rts -.1: bset #2,CIAA+CIAPRA -mt_rts: - rts - - -mt_glissctrl: -; cmd E 3 x (x gliss) -; d0 = x - - move.b d0,n_gliss(a2) - rts - - -mt_vibratoctrl: -; cmd E 4 x (x = vibrato) -; d0 = x - - move.b d0,n_vibratoctrl(a2) - rts - - -mt_finetune: -; cmd E 5 x (x = finetune) -; d0 = x - - lea mt_PerFineTune(pc),a0 - add.w d0,d0 - add.w (a0,d0.w),a0 - move.l a0,n_pertab(a2) - cmp.w #2*8,d0 - shs n_minusft(a2) - rts - - -mt_jumploop: -; cmd E 6 x (x=0 loop start, else loop count) -; d0 = x - - tst.b mt_Counter(a4) - bne .4 - -.1: tst.b d0 - beq .3 ; set start - - ; otherwise we are at the end of the loop - subq.b #1,n_loopcount(a2) - beq .4 ; loop finished - bpl .2 - - ; initialize loop counter - move.b d0,n_loopcount(a2) - - ; jump back to start of loop -.2: move.w n_pattpos(a2),mt_PBreakPos(a4) - st mt_PBreakFlag(a4) - rts - - ; remember start of loop position -.3: move.w mt_PatternPos(a4),n_pattpos(a2) -.4: rts - - -mt_tremoctrl: -; cmd E 7 x (x = tremolo) -; d0 = x - - move.b d0,n_tremoloctrl(a2) - rts - - -mt_e8: -; cmd E 8 x (x = trigger value) -; d0 = x - - move.b d0,mt_E8Trigger(a4) - rts - - -mt_retrignote: -; cmd E 9 x (x = retrigger count) -; d0 = x - - tst.b d0 - beq .1 - - ; set new retrigger count when Counter=0 - tst.b mt_Counter(a4) - bne .2 - move.b d0,n_retrigcount(a2) - - ; avoid double retrigger, when Counter=0 and a note was set - move.w #$0fff,d2 - and.w (a2),d2 - beq do_retrigger -.1: rts - - ; check if retrigger count is reached -.2: subq.b #1,n_retrigcount(a2) - bne .1 - move.b d0,n_retrigcount(a2) ; reset - -do_retrigger: - ; DMA off, set sample pointer and length - move.w n_dmabit(a2),d0 - move.w d0,DMACON(a6) - move.l n_start(a2),AUDLC(a5) - move.w n_length(a2),AUDLEN(a5) - lea mt_dmaon(pc),a0 - or.w d0,(a0) - rts - - -mt_volfineup: -; cmd E A x (x = volume add) -; d0 = x - - tst.b mt_Counter(a4) - beq .1 - rts - -.1: add.w n_volume(a2),d0 - bra vol_slide_up - - -mt_volfinedn: -; cmd E B x (x = volume sub) -; d0 = x - - tst.b mt_Counter(a4) - beq .1 - rts - -.1: move.b d0,d1 - move.w n_volume(a2),d0 - bra vol_slide_down - - -mt_notecut: -; cmd E C x (x = counter to cut at) -; d0 = x - - cmp.b mt_Counter(a4),d0 - bne .1 - move.w d7,n_volume(a2) - move.w d7,AUDVOL(a5) -.1: rts - - -mt_notedelay: -; cmd E D x (x = counter to retrigger at) -; d0 = x - - cmp.b mt_Counter(a4),d0 - bne .1 - tst.w (a2) ; trigger note when given - bne .2 -.1: rts -.2: move.w n_period(a2),AUDPER(a5) - bra do_retrigger - - -mt_patterndelay: -; cmd E E x (x = delay count) -; d0 = x - - tst.b mt_Counter(a4) - bne .1 - tst.b mt_PattDelTime2(a4) - bne .1 - addq.b #1,d0 - move.b d0,mt_PattDelTime(a4) -.1: rts - - -mt_funk: -; cmd E F x (x = funk speed) -; d0 = x - - tst.b mt_Counter(a4) - bne .1 - move.w d0,n_funk(a2) - bne mt_updatefunk -.1: rts - -mt_updatefunk: -; d0 = funk speed - - move.b mt_FunkTable(pc,d0.w),d0 - add.b d0,n_funkoffset(a2) - bpl .2 - move.b d7,n_funkoffset(a2) - - move.l n_loopstart(a2),d0 - moveq #0,d1 - move.w n_replen(a2),d1 - add.l d1,d1 - add.l d0,d1 - move.l n_wavestart(a2),a0 - addq.l #1,a0 - cmp.l d1,a0 - blo .1 - move.l d0,a0 -.1: move.l a0,n_wavestart(a2) - not.b (a0) - -.2: rts - - -mt_FunkTable: - dc.b 0,5,6,7,8,10,11,13,16,19,22,26,32,43,64,128 - -mt_VibratoSineTable: - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1 - dc.b 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0 - dc.b 0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - dc.b -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0 - dc.b 0,0,0,1,1,1,2,2,2,3,3,3,3,3,3,3 - dc.b 3,3,3,3,3,3,3,3,2,2,2,1,1,1,0,0 - dc.b 0,0,0,-1,-1,-1,-2,-2,-2,-3,-3,-3,-3,-3,-3,-3 - dc.b -3,-3,-3,-3,-3,-3,-3,-3,-2,-2,-2,-1,-1,-1,0,0 - dc.b 0,0,1,1,2,2,3,3,4,4,4,5,5,5,5,5 - dc.b 5,5,5,5,5,5,4,4,4,3,3,2,2,1,1,0 - dc.b 0,0,-1,-1,-2,-2,-3,-3,-4,-4,-4,-5,-5,-5,-5,-5 - dc.b -5,-5,-5,-5,-5,-5,-4,-4,-4,-3,-3,-2,-2,-1,-1,0 - dc.b 0,0,1,2,3,3,4,5,5,6,6,7,7,7,7,7 - dc.b 7,7,7,7,7,7,6,6,5,5,4,3,3,2,1,0 - dc.b 0,0,-1,-2,-3,-3,-4,-5,-5,-6,-6,-7,-7,-7,-7,-7 - dc.b -7,-7,-7,-7,-7,-7,-6,-6,-5,-5,-4,-3,-3,-2,-1,0 - dc.b 0,0,1,2,3,4,5,6,7,7,8,8,9,9,9,9 - dc.b 9,9,9,9,9,8,8,7,7,6,5,4,3,2,1,0 - dc.b 0,0,-1,-2,-3,-4,-5,-6,-7,-7,-8,-8,-9,-9,-9,-9 - dc.b -9,-9,-9,-9,-9,-8,-8,-7,-7,-6,-5,-4,-3,-2,-1,0 - dc.b 0,1,2,3,4,5,6,7,8,9,9,10,11,11,11,11 - dc.b 11,11,11,11,11,10,9,9,8,7,6,5,4,3,2,1 - dc.b 0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-9,-10,-11,-11,-11,-11 - dc.b -11,-11,-11,-11,-11,-10,-9,-9,-8,-7,-6,-5,-4,-3,-2,-1 - dc.b 0,1,2,4,5,6,7,8,9,10,11,12,12,13,13,13 - dc.b 13,13,13,13,12,12,11,10,9,8,7,6,5,4,2,1 - dc.b 0,-1,-2,-4,-5,-6,-7,-8,-9,-10,-11,-12,-12,-13,-13,-13 - dc.b -13,-13,-13,-13,-12,-12,-11,-10,-9,-8,-7,-6,-5,-4,-2,-1 - dc.b 0,1,3,4,6,7,8,10,11,12,13,14,14,15,15,15 - dc.b 15,15,15,15,14,14,13,12,11,10,8,7,6,4,3,1 - dc.b 0,-1,-3,-4,-6,-7,-8,-10,-11,-12,-13,-14,-14,-15,-15,-15 - dc.b -15,-15,-15,-15,-14,-14,-13,-12,-11,-10,-8,-7,-6,-4,-3,-1 - dc.b 0,1,3,5,6,8,9,11,12,13,14,15,16,17,17,17 - dc.b 17,17,17,17,16,15,14,13,12,11,9,8,6,5,3,1 - dc.b 0,-1,-3,-5,-6,-8,-9,-11,-12,-13,-14,-15,-16,-17,-17,-17 - dc.b -17,-17,-17,-17,-16,-15,-14,-13,-12,-11,-9,-8,-6,-5,-3,-1 - dc.b 0,1,3,5,7,9,11,12,14,15,16,17,18,19,19,19 - dc.b 19,19,19,19,18,17,16,15,14,12,11,9,7,5,3,1 - dc.b 0,-1,-3,-5,-7,-9,-11,-12,-14,-15,-16,-17,-18,-19,-19,-19 - dc.b -19,-19,-19,-19,-18,-17,-16,-15,-14,-12,-11,-9,-7,-5,-3,-1 - dc.b 0,2,4,6,8,10,12,13,15,16,18,19,20,20,21,21 - dc.b 21,21,21,20,20,19,18,16,15,13,12,10,8,6,4,2 - dc.b 0,-2,-4,-6,-8,-10,-12,-13,-15,-16,-18,-19,-20,-20,-21,-21 - dc.b -21,-21,-21,-20,-20,-19,-18,-16,-15,-13,-12,-10,-8,-6,-4,-2 - dc.b 0,2,4,6,9,11,13,15,16,18,19,21,22,22,23,23 - dc.b 23,23,23,22,22,21,19,18,16,15,13,11,9,6,4,2 - dc.b 0,-2,-4,-6,-9,-11,-13,-15,-16,-18,-19,-21,-22,-22,-23,-23 - dc.b -23,-23,-23,-22,-22,-21,-19,-18,-16,-15,-13,-11,-9,-6,-4,-2 - dc.b 0,2,4,7,9,12,14,16,18,20,21,22,23,24,25,25 - dc.b 25,25,25,24,23,22,21,20,18,16,14,12,9,7,4,2 - dc.b 0,-2,-4,-7,-9,-12,-14,-16,-18,-20,-21,-22,-23,-24,-25,-25 - dc.b -25,-25,-25,-24,-23,-22,-21,-20,-18,-16,-14,-12,-9,-7,-4,-2 - dc.b 0,2,5,8,10,13,15,17,19,21,23,24,25,26,27,27 - dc.b 27,27,27,26,25,24,23,21,19,17,15,13,10,8,5,2 - dc.b 0,-2,-5,-8,-10,-13,-15,-17,-19,-21,-23,-24,-25,-26,-27,-27 - dc.b -27,-27,-27,-26,-25,-24,-23,-21,-19,-17,-15,-13,-10,-8,-5,-2 - dc.b 0,2,5,8,11,14,16,18,21,23,24,26,27,28,29,29 - dc.b 29,29,29,28,27,26,24,23,21,18,16,14,11,8,5,2 - dc.b 0,-2,-5,-8,-11,-14,-16,-18,-21,-23,-24,-26,-27,-28,-29,-29 - dc.b -29,-29,-29,-28,-27,-26,-24,-23,-21,-18,-16,-14,-11,-8,-5,-2 - - ifne ENABLE_SAWRECT -mt_VibratoSawTable: - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 - dc.b -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1 - dc.b 2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3 - dc.b -3,-3,-3,-3,-3,-3,-3,-3,-2,-2,-2,-2,-2,-2,-2,-2 - dc.b -1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2 - dc.b 3,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5 - dc.b -5,-5,-5,-5,-5,-5,-4,-4,-4,-4,-4,-3,-3,-3,-3,-3 - dc.b -2,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,0,0,0,0,0 - dc.b 0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3 - dc.b 4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7 - dc.b -7,-7,-7,-7,-6,-6,-6,-6,-5,-5,-5,-5,-4,-4,-4,-4 - dc.b -3,-3,-3,-3,-2,-2,-2,-2,-1,-1,-1,-1,0,0,0,0 - dc.b 0,0,0,0,1,1,1,2,2,2,3,3,3,4,4,4 - dc.b 5,5,5,5,6,6,6,7,7,7,8,8,8,9,9,9 - dc.b -9,-9,-9,-9,-8,-8,-8,-7,-7,-7,-6,-6,-6,-5,-5,-5 - dc.b -4,-4,-4,-4,-3,-3,-3,-2,-2,-2,-1,-1,-1,0,0,0 - dc.b 0,0,0,1,1,1,2,2,3,3,3,4,4,4,5,5 - dc.b 6,6,6,7,7,7,8,8,9,9,9,10,10,10,11,11 - dc.b -11,-11,-11,-10,-10,-10,-9,-9,-8,-8,-8,-7,-7,-7,-6,-6 - dc.b -5,-5,-5,-4,-4,-4,-3,-3,-2,-2,-2,-1,-1,-1,0,0 - dc.b 0,0,0,1,1,2,2,3,3,3,4,4,5,5,6,6 - dc.b 7,7,7,8,8,9,9,10,10,10,11,11,12,12,13,13 - dc.b -13,-13,-13,-12,-12,-11,-11,-10,-10,-10,-9,-9,-8,-8,-7,-7 - dc.b -6,-6,-6,-5,-5,-4,-4,-3,-3,-3,-2,-2,-1,-1,0,0 - dc.b 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7 - dc.b 8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15 - dc.b -15,-15,-14,-14,-13,-13,-12,-12,-11,-11,-10,-10,-9,-9,-8,-8 - dc.b -7,-7,-6,-6,-5,-5,-4,-4,-3,-3,-2,-2,-1,-1,0,0 - dc.b 0,0,1,1,2,2,3,3,4,5,5,6,6,7,7,8 - dc.b 9,9,10,10,11,11,12,12,13,14,14,15,15,16,16,17 - dc.b -17,-17,-16,-16,-15,-15,-14,-13,-13,-12,-12,-11,-11,-10,-10,-9 - dc.b -8,-8,-7,-7,-6,-6,-5,-4,-4,-3,-3,-2,-2,-1,-1,0 - dc.b 0,0,1,1,2,3,3,4,5,5,6,6,7,8,8,9 - dc.b 10,10,11,11,12,13,13,14,15,15,16,16,17,18,18,19 - dc.b -19,-19,-18,-18,-17,-16,-16,-15,-14,-14,-13,-13,-12,-11,-11,-10 - dc.b -9,-9,-8,-8,-7,-6,-6,-5,-4,-4,-3,-3,-2,-1,-1,0 - dc.b 0,0,1,2,2,3,4,4,5,6,6,7,8,8,9,10 - dc.b 11,11,12,13,13,14,15,15,16,17,17,18,19,19,20,21 - dc.b -21,-21,-20,-19,-19,-18,-17,-17,-16,-15,-15,-14,-13,-12,-12,-11 - dc.b -10,-10,-9,-8,-8,-7,-6,-6,-5,-4,-4,-3,-2,-1,-1,0 - dc.b 0,0,1,2,3,3,4,5,6,6,7,8,9,9,10,11 - dc.b 12,12,13,14,15,15,16,17,18,18,19,20,21,21,22,23 - dc.b -23,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,-14,-14,-13,-12 - dc.b -11,-11,-10,-9,-8,-8,-7,-6,-5,-5,-4,-3,-2,-2,-1,0 - dc.b 0,0,1,2,3,4,4,5,6,7,8,8,9,10,11,12 - dc.b 13,13,14,15,16,17,17,18,19,20,21,21,22,23,24,25 - dc.b -25,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-16,-15,-14,-13 - dc.b -12,-12,-11,-10,-9,-8,-8,-7,-6,-5,-4,-3,-3,-2,-1,0 - dc.b 0,0,1,2,3,4,5,6,7,7,8,9,10,11,12,13 - dc.b 14,14,15,16,17,18,19,20,21,21,22,23,24,25,26,27 - dc.b -27,-27,-26,-25,-24,-23,-22,-21,-20,-20,-19,-18,-17,-16,-15,-14 - dc.b -13,-13,-12,-11,-10,-9,-8,-7,-6,-6,-5,-4,-3,-2,-1,0 - dc.b 0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 - dc.b 15,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29 - dc.b -29,-28,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15 - dc.b -14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0 - -mt_VibratoRectTable: - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 - dc.b 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 - dc.b -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - dc.b -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - dc.b 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 - dc.b 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 - dc.b -3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3 - dc.b -3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3 - dc.b 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 - dc.b 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 - dc.b -5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5 - dc.b -5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5 - dc.b 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 - dc.b 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 - dc.b -7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7 - dc.b -7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7 - dc.b 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9 - dc.b 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9 - dc.b -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 - dc.b -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 - dc.b 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 - dc.b 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 - dc.b -11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11 - dc.b -11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11 - dc.b 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 - dc.b 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 - dc.b -13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13 - dc.b -13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13 - dc.b 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15 - dc.b 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15 - dc.b -15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15 - dc.b -15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15 - dc.b 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 - dc.b 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 - dc.b -17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17 - dc.b -17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17 - dc.b 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19 - dc.b 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19 - dc.b -19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 - dc.b -19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 - dc.b 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21 - dc.b 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21 - dc.b -21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21 - dc.b -21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21 - dc.b 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23 - dc.b 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23 - dc.b -23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23 - dc.b -23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23 - dc.b 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25 - dc.b 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25 - dc.b -25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25 - dc.b -25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25 - dc.b 27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27 - dc.b 27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27 - dc.b -27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27 - dc.b -27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27 - dc.b 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 - dc.b 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 - dc.b -29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29 - dc.b -29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29 - endc ; ENABLE_SAWRECT - - -mt_PerFineTune: - dc.w mt_Tuning0-mt_PerFineTune,mt_Tuning1-mt_PerFineTune - dc.w mt_Tuning2-mt_PerFineTune,mt_Tuning3-mt_PerFineTune - dc.w mt_Tuning4-mt_PerFineTune,mt_Tuning5-mt_PerFineTune - dc.w mt_Tuning6-mt_PerFineTune,mt_Tuning7-mt_PerFineTune - dc.w mt_TuningM8-mt_PerFineTune,mt_TuningM7-mt_PerFineTune - dc.w mt_TuningM6-mt_PerFineTune,mt_TuningM5-mt_PerFineTune - dc.w mt_TuningM4-mt_PerFineTune,mt_TuningM3-mt_PerFineTune - dc.w mt_TuningM2-mt_PerFineTune,mt_TuningM1-mt_PerFineTune - -mt_PeriodTable: -mt_Tuning0: ; Tuning 0, Normal c-1 - b3 - 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 -mt_Tuning1: - 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 -mt_Tuning2: - 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 -mt_Tuning3: - 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 -mt_Tuning4: - 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 -mt_Tuning5: - 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 -mt_Tuning6: - 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 -mt_Tuning7: - 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 -mt_TuningM8: - 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 -mt_TuningM7: - 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 -mt_TuningM6: - 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 -mt_TuningM5: - 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 -mt_TuningM4: - 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 -mt_TuningM3: - 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 -mt_TuningM2: - 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 -mt_TuningM1: - 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 - - ifeq MINIMAL -MasterVolTab0: - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0 -MasterVolTab1: - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 1 -MasterVolTab2: - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 - dc.b 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 - dc.b 2 -MasterVolTab3: - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1 - dc.b 1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2 - dc.b 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 - dc.b 3 -MasterVolTab4: - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - dc.b 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 - dc.b 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 - dc.b 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 - dc.b 4 -MasterVolTab5: - dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1 - dc.b 1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2 - dc.b 2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3 - dc.b 3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4 - dc.b 5 -MasterVolTab6: - dc.b 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1 - dc.b 1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2 - dc.b 3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4 - dc.b 4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5 - dc.b 6 -MasterVolTab7: - dc.b 0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1 - dc.b 1,1,1,2,2,2,2,2,2,2,2,2,3,3,3,3 - dc.b 3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5 - dc.b 5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6 - dc.b 7 -MasterVolTab8: - dc.b 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1 - dc.b 2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3 - dc.b 4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5 - dc.b 6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7 - dc.b 8 -MasterVolTab9: - dc.b 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,2 - dc.b 2,2,2,2,2,2,3,3,3,3,3,3,3,4,4,4 - dc.b 4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6 - dc.b 6,6,7,7,7,7,7,7,7,8,8,8,8,8,8,8 - dc.b 9 -MasterVolTab10: - dc.b 0,0,0,0,0,0,0,1,1,1,1,1,1,2,2,2 - dc.b 2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4 - dc.b 5,5,5,5,5,5,5,6,6,6,6,6,6,7,7,7 - dc.b 7,7,7,7,8,8,8,8,8,8,9,9,9,9,9,9 - dc.b 10 -MasterVolTab11: - dc.b 0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2 - dc.b 2,2,3,3,3,3,3,3,4,4,4,4,4,4,5,5 - dc.b 5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,8 - dc.b 8,8,8,8,8,9,9,9,9,9,9,10,10,10,10,10 - dc.b 11 -MasterVolTab12: - dc.b 0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2 - dc.b 3,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5 - dc.b 6,6,6,6,6,6,7,7,7,7,7,8,8,8,8,8 - dc.b 9,9,9,9,9,9,10,10,10,10,10,11,11,11,11,11 - dc.b 12 -MasterVolTab13: - dc.b 0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3 - dc.b 3,3,3,3,4,4,4,4,4,5,5,5,5,5,6,6 - dc.b 6,6,6,7,7,7,7,7,8,8,8,8,8,9,9,9 - dc.b 9,9,10,10,10,10,10,11,11,11,11,11,12,12,12,12 - dc.b 13 -MasterVolTab14: - dc.b 0,0,0,0,0,1,1,1,1,1,2,2,2,2,3,3 - dc.b 3,3,3,4,4,4,4,5,5,5,5,5,6,6,6,6 - dc.b 7,7,7,7,7,8,8,8,8,8,9,9,9,9,10,10 - dc.b 10,10,10,11,11,11,11,12,12,12,12,12,13,13,13,13 - dc.b 14 -MasterVolTab15: - dc.b 0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3 - dc.b 3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7 - dc.b 7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11 - dc.b 11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,14 - dc.b 15 -MasterVolTab16: - dc.b 0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3 - dc.b 4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7 - dc.b 8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11 - dc.b 12,12,12,12,13,13,13,13,14,14,14,14,15,15,15,15 - dc.b 16 -MasterVolTab17: - dc.b 0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3 - dc.b 4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8 - dc.b 8,8,9,9,9,9,10,10,10,10,11,11,11,11,12,12 - dc.b 12,13,13,13,13,14,14,14,14,15,15,15,15,16,16,16 - dc.b 17 -MasterVolTab18: - dc.b 0,0,0,0,1,1,1,1,2,2,2,3,3,3,3,4 - dc.b 4,4,5,5,5,5,6,6,6,7,7,7,7,8,8,8 - dc.b 9,9,9,9,10,10,10,10,11,11,11,12,12,12,12,13 - dc.b 13,13,14,14,14,14,15,15,15,16,16,16,16,17,17,17 - dc.b 18 -MasterVolTab19: - dc.b 0,0,0,0,1,1,1,2,2,2,2,3,3,3,4,4 - dc.b 4,5,5,5,5,6,6,6,7,7,7,8,8,8,8,9 - dc.b 9,9,10,10,10,10,11,11,11,12,12,12,13,13,13,13 - dc.b 14,14,14,15,15,15,16,16,16,16,17,17,17,18,18,18 - dc.b 19 -MasterVolTab20: - dc.b 0,0,0,0,1,1,1,2,2,2,3,3,3,4,4,4 - dc.b 5,5,5,5,6,6,6,7,7,7,8,8,8,9,9,9 - dc.b 10,10,10,10,11,11,11,12,12,12,13,13,13,14,14,14 - dc.b 15,15,15,15,16,16,16,17,17,17,18,18,18,19,19,19 - dc.b 20 -MasterVolTab21: - dc.b 0,0,0,0,1,1,1,2,2,2,3,3,3,4,4,4 - dc.b 5,5,5,6,6,6,7,7,7,8,8,8,9,9,9,10 - dc.b 10,10,11,11,11,12,12,12,13,13,13,14,14,14,15,15 - dc.b 15,16,16,16,17,17,17,18,18,18,19,19,19,20,20,20 - dc.b 21 -MasterVolTab22: - dc.b 0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5 - dc.b 5,5,6,6,6,7,7,7,8,8,8,9,9,9,10,10 - dc.b 11,11,11,12,12,12,13,13,13,14,14,14,15,15,15,16 - dc.b 16,16,17,17,17,18,18,18,19,19,19,20,20,20,21,21 - dc.b 22 -MasterVolTab23: - dc.b 0,0,0,1,1,1,2,2,2,3,3,3,4,4,5,5 - dc.b 5,6,6,6,7,7,7,8,8,8,9,9,10,10,10,11 - dc.b 11,11,12,12,12,13,13,14,14,14,15,15,15,16,16,16 - dc.b 17,17,17,18,18,19,19,19,20,20,20,21,21,21,22,22 - dc.b 23 -MasterVolTab24: - dc.b 0,0,0,1,1,1,2,2,3,3,3,4,4,4,5,5 - dc.b 6,6,6,7,7,7,8,8,9,9,9,10,10,10,11,11 - dc.b 12,12,12,13,13,13,14,14,15,15,15,16,16,16,17,17 - dc.b 18,18,18,19,19,19,20,20,21,21,21,22,22,22,23,23 - dc.b 24 -MasterVolTab25: - dc.b 0,0,0,1,1,1,2,2,3,3,3,4,4,5,5,5 - dc.b 6,6,7,7,7,8,8,8,9,9,10,10,10,11,11,12 - dc.b 12,12,13,13,14,14,14,15,15,16,16,16,17,17,17,18 - dc.b 18,19,19,19,20,20,21,21,21,22,22,23,23,23,24,24 - dc.b 25 -MasterVolTab26: - dc.b 0,0,0,1,1,2,2,2,3,3,4,4,4,5,5,6 - dc.b 6,6,7,7,8,8,8,9,9,10,10,10,11,11,12,12 - dc.b 13,13,13,14,14,15,15,15,16,16,17,17,17,18,18,19 - dc.b 19,19,20,20,21,21,21,22,22,23,23,23,24,24,25,25 - dc.b 26 -MasterVolTab27: - dc.b 0,0,0,1,1,2,2,2,3,3,4,4,5,5,5,6 - dc.b 6,7,7,8,8,8,9,9,10,10,10,11,11,12,12,13 - dc.b 13,13,14,14,15,15,16,16,16,17,17,18,18,18,19,19 - dc.b 20,20,21,21,21,22,22,23,23,24,24,24,25,25,26,26 - dc.b 27 -MasterVolTab28: - dc.b 0,0,0,1,1,2,2,3,3,3,4,4,5,5,6,6 - dc.b 7,7,7,8,8,9,9,10,10,10,11,11,12,12,13,13 - dc.b 14,14,14,15,15,16,16,17,17,17,18,18,19,19,20,20 - dc.b 21,21,21,22,22,23,23,24,24,24,25,25,26,26,27,27 - dc.b 28 -MasterVolTab29: - dc.b 0,0,0,1,1,2,2,3,3,4,4,4,5,5,6,6 - dc.b 7,7,8,8,9,9,9,10,10,11,11,12,12,13,13,14 - dc.b 14,14,15,15,16,16,17,17,18,18,19,19,19,20,20,21 - dc.b 21,22,22,23,23,24,24,24,25,25,26,26,27,27,28,28 - dc.b 29 -MasterVolTab30: - dc.b 0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7 - dc.b 7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14 - dc.b 15,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22 - dc.b 22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29 - dc.b 30 -MasterVolTab31: - dc.b 0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7 - dc.b 7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15 - dc.b 15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22 - dc.b 23,23,24,24,25,25,26,26,27,27,28,28,29,29,30,30 - dc.b 31 -MasterVolTab32: - dc.b 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7 - dc.b 8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15 - dc.b 16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23 - dc.b 24,24,25,25,26,26,27,27,28,28,29,29,30,30,31,31 - dc.b 32 -MasterVolTab33: - dc.b 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7 - dc.b 8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15 - dc.b 16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24 - dc.b 24,25,25,26,26,27,27,28,28,29,29,30,30,31,31,32 - dc.b 33 -MasterVolTab34: - dc.b 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7 - dc.b 8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16 - dc.b 17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24 - dc.b 25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33 - dc.b 34 -MasterVolTab35: - dc.b 0,0,1,1,2,2,3,3,4,4,5,6,6,7,7,8 - dc.b 8,9,9,10,10,11,12,12,13,13,14,14,15,15,16,16 - dc.b 17,18,18,19,19,20,20,21,21,22,22,23,24,24,25,25 - dc.b 26,26,27,27,28,28,29,30,30,31,31,32,32,33,33,34 - dc.b 35 -MasterVolTab36: - dc.b 0,0,1,1,2,2,3,3,4,5,5,6,6,7,7,8 - dc.b 9,9,10,10,11,11,12,12,13,14,14,15,15,16,16,17 - dc.b 18,18,19,19,20,20,21,21,22,23,23,24,24,25,25,26 - dc.b 27,27,28,28,29,29,30,30,31,32,32,33,33,34,34,35 - dc.b 36 -MasterVolTab37: - dc.b 0,0,1,1,2,2,3,4,4,5,5,6,6,7,8,8 - dc.b 9,9,10,10,11,12,12,13,13,14,15,15,16,16,17,17 - dc.b 18,19,19,20,20,21,21,22,23,23,24,24,25,26,26,27 - dc.b 27,28,28,29,30,30,31,31,32,32,33,34,34,35,35,36 - dc.b 37 -MasterVolTab38: - dc.b 0,0,1,1,2,2,3,4,4,5,5,6,7,7,8,8 - dc.b 9,10,10,11,11,12,13,13,14,14,15,16,16,17,17,18 - dc.b 19,19,20,20,21,21,22,23,23,24,24,25,26,26,27,27 - dc.b 28,29,29,30,30,31,32,32,33,33,34,35,35,36,36,37 - dc.b 38 -MasterVolTab39: - dc.b 0,0,1,1,2,3,3,4,4,5,6,6,7,7,8,9 - dc.b 9,10,10,11,12,12,13,14,14,15,15,16,17,17,18,18 - dc.b 19,20,20,21,21,22,23,23,24,24,25,26,26,27,28,28 - dc.b 29,29,30,31,31,32,32,33,34,34,35,35,36,37,37,38 - dc.b 39 -MasterVolTab40: - dc.b 0,0,1,1,2,3,3,4,5,5,6,6,7,8,8,9 - dc.b 10,10,11,11,12,13,13,14,15,15,16,16,17,18,18,19 - dc.b 20,20,21,21,22,23,23,24,25,25,26,26,27,28,28,29 - dc.b 30,30,31,31,32,33,33,34,35,35,36,36,37,38,38,39 - dc.b 40 -MasterVolTab41: - dc.b 0,0,1,1,2,3,3,4,5,5,6,7,7,8,8,9 - dc.b 10,10,11,12,12,13,14,14,15,16,16,17,17,18,19,19 - dc.b 20,21,21,22,23,23,24,24,25,26,26,27,28,28,29,30 - dc.b 30,31,32,32,33,33,34,35,35,36,37,37,38,39,39,40 - dc.b 41 -MasterVolTab42: - dc.b 0,0,1,1,2,3,3,4,5,5,6,7,7,8,9,9 - dc.b 10,11,11,12,13,13,14,15,15,16,17,17,18,19,19,20 - dc.b 21,21,22,22,23,24,24,25,26,26,27,28,28,29,30,30 - dc.b 31,32,32,33,34,34,35,36,36,37,38,38,39,40,40,41 - dc.b 42 -MasterVolTab43: - dc.b 0,0,1,2,2,3,4,4,5,6,6,7,8,8,9,10 - dc.b 10,11,12,12,13,14,14,15,16,16,17,18,18,19,20,20 - dc.b 21,22,22,23,24,24,25,26,26,27,28,28,29,30,30,31 - dc.b 32,32,33,34,34,35,36,36,37,38,38,39,40,40,41,42 - dc.b 43 -MasterVolTab44: - dc.b 0,0,1,2,2,3,4,4,5,6,6,7,8,8,9,10 - dc.b 11,11,12,13,13,14,15,15,16,17,17,18,19,19,20,21 - dc.b 22,22,23,24,24,25,26,26,27,28,28,29,30,30,31,32 - dc.b 33,33,34,35,35,36,37,37,38,39,39,40,41,41,42,43 - dc.b 44 -MasterVolTab45: - dc.b 0,0,1,2,2,3,4,4,5,6,7,7,8,9,9,10 - dc.b 11,11,12,13,14,14,15,16,16,17,18,18,19,20,21,21 - dc.b 22,23,23,24,25,26,26,27,28,28,29,30,30,31,32,33 - dc.b 33,34,35,35,36,37,37,38,39,40,40,41,42,42,43,44 - dc.b 45 -MasterVolTab46: - dc.b 0,0,1,2,2,3,4,5,5,6,7,7,8,9,10,10 - dc.b 11,12,12,13,14,15,15,16,17,17,18,19,20,20,21,22 - dc.b 23,23,24,25,25,26,27,28,28,29,30,30,31,32,33,33 - dc.b 34,35,35,36,37,38,38,39,40,40,41,42,43,43,44,45 - dc.b 46 -MasterVolTab47: - dc.b 0,0,1,2,2,3,4,5,5,6,7,8,8,9,10,11 - dc.b 11,12,13,13,14,15,16,16,17,18,19,19,20,21,22,22 - dc.b 23,24,24,25,26,27,27,28,29,30,30,31,32,33,33,34 - dc.b 35,35,36,37,38,38,39,40,41,41,42,43,44,44,45,46 - dc.b 47 -MasterVolTab48: - dc.b 0,0,1,2,3,3,4,5,6,6,7,8,9,9,10,11 - dc.b 12,12,13,14,15,15,16,17,18,18,19,20,21,21,22,23 - dc.b 24,24,25,26,27,27,28,29,30,30,31,32,33,33,34,35 - dc.b 36,36,37,38,39,39,40,41,42,42,43,44,45,45,46,47 - dc.b 48 -MasterVolTab49: - dc.b 0,0,1,2,3,3,4,5,6,6,7,8,9,9,10,11 - dc.b 12,13,13,14,15,16,16,17,18,19,19,20,21,22,22,23 - dc.b 24,25,26,26,27,28,29,29,30,31,32,32,33,34,35,35 - dc.b 36,37,38,39,39,40,41,42,42,43,44,45,45,46,47,48 - dc.b 49 -MasterVolTab50: - dc.b 0,0,1,2,3,3,4,5,6,7,7,8,9,10,10,11 - dc.b 12,13,14,14,15,16,17,17,18,19,20,21,21,22,23,24 - dc.b 25,25,26,27,28,28,29,30,31,32,32,33,34,35,35,36 - dc.b 37,38,39,39,40,41,42,42,43,44,45,46,46,47,48,49 - dc.b 50 -MasterVolTab51: - dc.b 0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11 - dc.b 12,13,14,15,15,16,17,18,19,19,20,21,22,23,23,24 - dc.b 25,26,27,27,28,29,30,31,31,32,33,34,35,35,36,37 - dc.b 38,39,39,40,41,42,43,43,44,45,46,47,47,48,49,50 - dc.b 51 -MasterVolTab52: - dc.b 0,0,1,2,3,4,4,5,6,7,8,8,9,10,11,12 - dc.b 13,13,14,15,16,17,17,18,19,20,21,21,22,23,24,25 - dc.b 26,26,27,28,29,30,30,31,32,33,34,34,35,36,37,38 - dc.b 39,39,40,41,42,43,43,44,45,46,47,47,48,49,50,51 - dc.b 52 -MasterVolTab53: - dc.b 0,0,1,2,3,4,4,5,6,7,8,9,9,10,11,12 - dc.b 13,14,14,15,16,17,18,19,19,20,21,22,23,24,24,25 - dc.b 26,27,28,28,29,30,31,32,33,33,34,35,36,37,38,38 - dc.b 39,40,41,42,43,43,44,45,46,47,48,48,49,50,51,52 - dc.b 53 -MasterVolTab54: - dc.b 0,0,1,2,3,4,5,5,6,7,8,9,10,10,11,12 - dc.b 13,14,15,16,16,17,18,19,20,21,21,22,23,24,25,26 - dc.b 27,27,28,29,30,31,32,32,33,34,35,36,37,37,38,39 - dc.b 40,41,42,43,43,44,45,46,47,48,48,49,50,51,52,53 - dc.b 54 -MasterVolTab55: - dc.b 0,0,1,2,3,4,5,6,6,7,8,9,10,11,12,12 - dc.b 13,14,15,16,17,18,18,19,20,21,22,23,24,24,25,26 - dc.b 27,28,29,30,30,31,32,33,34,35,36,36,37,38,39,40 - dc.b 41,42,42,43,44,45,46,47,48,48,49,50,51,52,53,54 - dc.b 55 -MasterVolTab56: - dc.b 0,0,1,2,3,4,5,6,7,7,8,9,10,11,12,13 - dc.b 14,14,15,16,17,18,19,20,21,21,22,23,24,25,26,27 - dc.b 28,28,29,30,31,32,33,34,35,35,36,37,38,39,40,41 - dc.b 42,42,43,44,45,46,47,48,49,49,50,51,52,53,54,55 - dc.b 56 -MasterVolTab57: - dc.b 0,0,1,2,3,4,5,6,7,8,8,9,10,11,12,13 - dc.b 14,15,16,16,17,18,19,20,21,22,23,24,24,25,26,27 - dc.b 28,29,30,31,32,32,33,34,35,36,37,38,39,40,40,41 - dc.b 42,43,44,45,46,47,48,48,49,50,51,52,53,54,55,56 - dc.b 57 -MasterVolTab58: - dc.b 0,0,1,2,3,4,5,6,7,8,9,9,10,11,12,13 - dc.b 14,15,16,17,18,19,19,20,21,22,23,24,25,26,27,28 - dc.b 29,29,30,31,32,33,34,35,36,37,38,38,39,40,41,42 - dc.b 43,44,45,46,47,48,48,49,50,51,52,53,54,55,56,57 - dc.b 58 -MasterVolTab59: - dc.b 0,0,1,2,3,4,5,6,7,8,9,10,11,11,12,13 - dc.b 14,15,16,17,18,19,20,21,22,23,23,24,25,26,27,28 - dc.b 29,30,31,32,33,34,35,35,36,37,38,39,40,41,42,43 - dc.b 44,45,46,47,47,48,49,50,51,52,53,54,55,56,57,58 - dc.b 59 -MasterVolTab60: - dc.b 0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 - dc.b 15,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29 - dc.b 30,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44 - dc.b 45,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59 - dc.b 60 -MasterVolTab61: - dc.b 0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 - dc.b 15,16,17,18,19,20,20,21,22,23,24,25,26,27,28,29 - dc.b 30,31,32,33,34,35,36,37,38,39,40,40,41,42,43,44 - dc.b 45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60 - dc.b 61 -MasterVolTab62: - dc.b 0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 - dc.b 15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 - dc.b 31,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45 - dc.b 46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61 - dc.b 62 -MasterVolTab63: - dc.b 0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 - dc.b 15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 - dc.b 31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46 - dc.b 47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62 - dc.b 63 -MasterVolTab64: - dc.b 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 - dc.b 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 - dc.b 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47 - dc.b 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63 - dc.b 64 - even - endc ; !MINIMAL - - - ifd SDATA - - section __MERGED,bss - -mt_chan1: - ds.b n_sizeof -mt_chan2: - ds.b n_sizeof -mt_chan3: - ds.b n_sizeof -mt_chan4: - ds.b n_sizeof - -mt_SampleStarts: - ds.l 31 - -mt_mod: - ds.l 1 -mt_oldLev6: - ds.l 1 -mt_timerval: - ds.l 1 -mt_oldtimers: - ds.b 4 -mt_Lev6Int: - ds.l 1 -mt_Lev6Ena: - ds.w 1 -mt_PatternPos: - ds.w 1 -mt_PBreakPos: - ds.w 1 -mt_PosJumpFlag: - ds.b 1 -mt_PBreakFlag: - ds.b 1 -mt_Speed: - ds.b 1 -mt_Counter: - ds.b 1 -mt_SongPos: - ds.b 1 -mt_PattDelTime: - ds.b 1 -mt_PattDelTime2: - ds.b 1 - - ifeq MINIMAL -mt_SilCntValid: - ds.b 1 -mt_MasterVolTab: - ds.l 1 - endc - - xdef _mt_Enable -_mt_Enable: -mt_Enable: - ds.b 1 - - xdef _mt_E8Trigger -_mt_E8Trigger: -mt_E8Trigger: - ds.b 1 - - ifeq MINIMAL - xdef _mt_MusicChannels -_mt_MusicChannels: -mt_MusicChannels: - ds.b 1 - - xdef _mt_SongEnd -_mt_SongEnd: -mt_SongEnd: - ds.b 1 - endc ; !MINIMAL - - else ; !SDATA : single section with local base register - - rsreset -mt_chan1 rs.b n_sizeof -mt_chan2 rs.b n_sizeof -mt_chan3 rs.b n_sizeof -mt_chan4 rs.b n_sizeof -mt_SampleStarts rs.l 31 -mt_mod rs.l 1 -mt_oldLev6 rs.l 1 -mt_timerval rs.l 1 -mt_oldtimers rs.b 4 -mt_Lev6Int rs.l 1 -mt_Lev6Ena rs.w 1 -mt_PatternPos rs.w 1 -mt_PBreakPos rs.w 1 -mt_PosJumpFlag rs.b 1 -mt_PBreakFlag rs.b 1 -mt_Speed rs.b 1 -mt_Counter rs.b 1 -mt_SongPos rs.b 1 -mt_PattDelTime rs.b 1 -mt_PattDelTime2 rs.b 1 - ifeq MINIMAL -mt_SilCntValid rs.b 1 -mt_MasterVolTab rs.l 1 - endc -mt_Enable rs.b 1 ; exported as _mt_Enable -mt_E8Trigger rs.b 1 ; exported as _mt_E8Trigger -mt_MusicChannels rs.b 1 ; exported as _mt_MusicChannels -mt_SongEnd rs.b 1 ; exported as _mt_SongEnd - -mt_data: - ds.b mt_Enable - xdef _mt_Enable -_mt_Enable: - ds.b 1 - xdef _mt_E8Trigger -_mt_E8Trigger: - ds.b 1 - ifeq MINIMAL - xdef _mt_MusicChannels -_mt_MusicChannels: - ds.b 1 - xdef _mt_SongEnd -_mt_SongEnd: - ds.b 1 - endc ; !MINIMAL - - endc ; SDATA/!SDATA - - end +;************************************************** +;* ----- Protracker V2.3B Playroutine ----- * +;************************************************** +; +; Version 6.1 +; Written by Frank Wille in 2013, 2016, 2017, 2018, 2019, 2020. +; +; I, the copyright holder of this work, hereby release it into the +; public domain. This applies worldwide. +; +; 6.1 minimal (unofficial) - Antiriad's mods for small executable size +; - Removed SDATA code. +; - mt_data is in BSS (no longer completely PC relative, focused on exe size) +; - Period and finetune table generated in code saving about 1KB. +; - Vibrato sine table generate in code saving about 1KB. +; - VUMeter trigger added in _mt_VUMeter which allows for demo/music sync effects with playing notes +; +; The default version (single section, local base register) should +; work with most assemblers. Tested are: Devpac, vasm, PhxAss, +; Barfly-Asm, SNMA, AsmOne, AsmPro. +; +; Exported functions and variables: +; (CUSTOM is the custom-chip register set base address $dff000.) +; +; _mt_install_cia(a6=CUSTOM, a0=VectorBase, d0=PALflag.b) +; Install a CIA-B interrupt for calling _mt_music or mt_sfxonly. +; The music module is replayed via _mt_music when _mt_Enable is non-zero. +; Otherwise the interrupt handler calls mt_sfxonly to play sound +; effects only. VectorBase is 0 for 68000, otherwise set it to the CPU's +; VBR register. A non-zero PALflag selects PAL-clock for the CIA timers +; (NTSC otherwise). +; +; _mt_remove_cia(a6=CUSTOM) +; Remove the CIA-B music interrupt, restore the previous handler and +; reset the CIA timer registers to their original values. +; +; _mt_init(a6=CUSTOM, a0=TrackerModule, a1=Samples|NULL, d0=InitialSongPos.b) +; Initialize a new module. +; Reset speed to 6, tempo to 125 and start at the given song position. +; Master volume is at 64 (maximum). +; When a1 is NULL the samples are assumed to be stored after the patterns. +; +; _mt_end(a6=CUSTOM) +; Stop playing current module and sound effects. +; +; _mt_soundfx(a6=CUSTOM, a0=SamplePointer, +; d0=SampleLength.w, d1=SamplePeriod.w, d2=SampleVolume.w) +; Request playing of an external sound effect on the most unused channel. +; This function is for compatibility with the old API only. +; You should call _mt_playfx instead. !MINIMAL only. +; +; channelStatus = _mt_playfx(a6=CUSTOM, a0=SfxStructurePointer) +; Request playing of a prioritized external sound effect, either on a +; fixed channel or on the most unused one. +; Structure layout of SfxStructure: +; void *sfx_ptr (pointer to sample start in Chip RAM, even address) +; WORD sfx_len (sample length in words) +; WORD sfx_per (hardware replay period for sample) +; WORD sfx_vol (volume 0..64, is unaffected by the song's master volume) +; BYTE sfx_cha (0..3 selected replay channel, -1 selects best channel) +; BYTE sfx_pri (priority, must be in the range 1..127) +; When multiple samples are assigned to the same channel the lower +; priority sample will be replaced. When priorities are the same, then +; the older sample is replaced. +; The chosen channel is blocked for music until the effect has +; completely been replayed. +; Returns a pointer to a channel-status structure when the sample +; is scheduled for playing, and NULL when the request was ignored. +; !MINIMAL only. +; +; _mt_loopfx(a6=CUSTOM, a0=SfxStructurePointer) +; Request playing of a looped sound effect on a fixed channel, which +; will be blocked for music until the effect is stopped (_mt_stopfx). +; It uses the same sfx-structure as _mt_playfx, but the priority is +; ignored. A looped sound effect has always highest priority and will +; replace a previous effect on the same channel. No automatic channel +; selection possible! +; Also make sure the sample starts with a zero-word, which is used +; for idling when the effect is stopped. This word is included in the +; total length calculation, but excluded when actually playing the loop. +; !MINIMAL only. +; +; _mt_stopfx(a6=CUSTOM, d0=Channel.b) +; Immediately stop a currently playing sound effect on a channel (0..3) +; and make it available for music, or other effects, again. This is the +; only way to stop a looped sound effect (_mt_loopfx), besides stopping +; replay completely (_mt_end). !MINIMAL only. +; +; _mt_musicmask(a6=CUSTOM, d0=ChannelMask.b) +; Bits set in the mask define which specific channels are reserved +; for music only. Set bit 0 for channel 0, ..., bit 3 for channel 3. +; When calling _mt_soundfx or _mt_playfx with automatic channel selection +; (sfx_cha=-1) then these masked channels will never be picked. +; The mask defaults to 0. !MINIMAL only. +; +; _mt_mastervol(a6=CUSTOM, d0=MasterVolume.w) +; Set a master volume from 0 to 64 for all music channels. +; Note that the master volume does not affect the volume of external +; sound effects (which is desired). !MINIMAL only. +; +; _mt_samplevol(d0=SampleNumber.w, d1=Volume.b) +; Redefine a sample's volume. May also be done while the song is playing. +; Warning: Does not check arguments for valid range! You must have done +; _mt_init before calling this function! +; The new volume is persistent. Even when the song is restarted. +; !MINIMAL only. +; +; _mt_music(a6=CUSTOM) +; The replayer routine. Is called automatically after _mt_install_cia. +; +; Byte Variables: +; +; _mt_Enable +; Set this byte to non-zero to play music, zero to pause playing. +; Note that you can still play sound effects, while music is stopped. +; It is set to 0 by _mt_install_cia. +; +; _mt_E8Trigger +; This byte reflects the value of the last E8 command. +; It is reset to 0 after _mt_init. +; +; _mt_MusicChannels +; This byte defines the number of channels which should be dedicated +; for playing music. So sound effects will never use more +; than 4 - _mt_MusicChannels channels at once. Defaults to 0. +; !MINIMAL only. +; + +; Optionally you can build a minimal version, which includes just +; the player. No sound effects insert, no master volume, no sample +; volume, etc. Define the symbol MINIMAL=1 for it. + ifnd MINIMAL +MINIMAL equ 1 + endc + +; You may disable sawtooth and rectangle vibratos/tremolos here, which +; will be replaced by sine-waves. They are rarely used and disabling +; them will free a lot of memory for the tables. + ifnd ENABLE_SAWRECT +ENABLE_SAWRECT equ 0 + endc + +; Set this if you can guarantee that the word at $0 is cleared and if +; you want to use if for idle-looping of samples. + ifnd NULL_IS_CLEARED +NULL_IS_CLEARED equ 0 + endc + +;Antiriad: Added vumeter polling for syncing demos + ifnd ENABLE_VUMETER +ENABLE_VUMETER equ 1 + endc + +; Delay in CIA-ticks, which guarantees that at least one Audio-DMA +; took place, even with the lowest periods. +; 496 should be the correct value. But there are some A1200 which +; need at least 550. +DMADELAY equ 576 ; was 496 + + +; Custom chip registers - try and catch predefined EQUs - if it fails sort this +; out yourself :) + ifnd CUSTOM +CUSTOM equ $dff000 + endc ;CUSTOM + + ifnd INTREQR +INTREQR equ $01e +INTENAR equ $01c +DMACON equ $096 +INTENA equ $09a +INTREQ equ $09c + endc ;INTREQR + + ifnd AUD0LC +AUD0LC equ $0a0 +AUD0LEN equ $0a4 +AUD0VOL equ $0a8 +AUD1LC equ $0b0 +AUD1LEN equ $0b4 +AUD1VOL equ $0b8 +AUD2LC equ $0c0 +AUD2LEN equ $0c4 +AUD2VOL equ $0c8 +AUD3LC equ $0d0 +AUD3LEN equ $0d4 +AUD3VOL equ $0d8 + endc ;AUD0LC + +; Audio channel registers + ifnd AUDLC +AUDLC equ 0 +AUDLEN equ 4 +AUDPER equ 6 +AUDVOL equ 8 + endc ;AUDLC + +; CIA registers + ifnd CIAA +CIAA equ $bfe001 +CIAB equ $bfd000 + endc ;CIAA + + ifnd CIATALO +CIAPRA equ $000 +CIATALO equ $400 +CIATAHI equ $500 +CIATBLO equ $600 +CIATBHI equ $700 +CIAICR equ $d00 +CIACRA equ $e00 +CIACRB equ $f00 + endc ;CIATALO + +; Sound effects structure, passed into _mt_playfx + rsreset +sfx_ptr rs.l 1 +sfx_len rs.w 1 +sfx_per rs.w 1 +sfx_vol rs.w 1 +sfx_cha rs.b 1 +sfx_pri rs.b 1 +sfx_sizeof rs.b 0 + + +; Channel Status + rsreset +n_note rs.w 1 +n_cmd rs.b 1 +n_cmdlo rs.b 1 +n_index rs.b 1 +n_sfxpri rs.b 1 +n_reserved1 rs.b 2 +n_start rs.l 1 +n_loopstart rs.l 1 +n_length rs.w 1 +n_replen rs.w 1 +n_period rs.w 1 +n_volume rs.w 1 +n_pertab rs.l 1 +n_dmabit rs.w 1 +n_noteoff rs.w 1 +n_toneportspeed rs.w 1 +n_wantedperiod rs.w 1 +n_pattpos rs.w 1 +n_funk rs.w 1 +n_wavestart rs.l 1 +n_reallength rs.w 1 +n_intbit rs.w 1 +n_sfxptr rs.l 1 +n_sfxlen rs.w 1 +n_sfxper rs.w 1 +n_sfxvol rs.w 1 +n_looped rs.b 1 +n_minusft rs.b 1 +n_vibratoamp rs.b 1 +n_vibratospd rs.b 1 +n_vibratopos rs.b 1 +n_vibratoctrl rs.b 1 +n_tremoloamp rs.b 1 +n_tremolospd rs.b 1 +n_tremolopos rs.b 1 +n_tremoloctrl rs.b 1 +n_gliss rs.b 1 +n_sampleoffset rs.b 1 +n_loopcount rs.b 1 +n_funkoffset rs.b 1 +n_retrigcount rs.b 1 + ifeq MINIMAL +n_freecnt rs.b 1 +n_musiconly rs.b 1 +n_reserved2 rs.b 1 + else +n_reserved2 rs.b 3 + endc +n_sizeof rs.b 0 + +;--------------------------------------------------------------------------- + xdef _mt_install_cia +_mt_install_cia: +; Install a CIA-B interrupt for calling _mt_music. +; a6 = CUSTOM +; a0 = VectorBase +; d0 = PALflag.b (0 is NTSC) + + move.l a4,-(sp) + lea mt_data,a4 + + clr.b mt_Enable(a4) + + ; remember level 6 vector and interrupt enable + lea $78(a0),a0 + move.l a0,mt_Lev6Int(a4) + move.w #$2000,d1 + and.w INTENAR(a6),d1 + or.w #$8000,d1 + move.w d1,mt_Lev6Ena(a4) + + ; disable level 6 EXTER interrupts, set player interrupt vector + move.w #$2000,INTENA(a6) + move.l (a0),mt_oldLev6(a4) + lea mt_TimerAInt(pc),a1 + move.l a1,(a0) + + ; reset TimerB toggle + lea TB_toggle(pc),a0 + clr.b (a0) + + ; disable CIA-B interrupts, stop and save all timers + lea CIAB,a0 + moveq #0,d1 + move.b #$7f,CIAICR(a0) + move.b d1,CIACRA(a0) + move.b d1,CIACRB(a0) + lea mt_oldtimers(a4),a1 + move.b CIATALO(a0),(a1)+ + move.b CIATAHI(a0),(a1)+ + move.b CIATBLO(a0),(a1)+ + move.b CIATBHI(a0),(a1) + + ; determine if 02 clock for timers is based on PAL or NTSC + tst.b d0 + bne .1 + move.l #1789773,d0 ; NTSC + bra .2 +.1: move.l #1773447,d0 ; PAL +.2: move.l d0,mt_timerval(a4) + + ; load TimerA in continuous mode for the default tempo of 125 + divu #125,d0 + move.b d0,CIATALO(a0) + lsr.w #8,d0 + move.b d0,CIATAHI(a0) + move.b #$11,CIACRA(a0) ; load timer, start continuous + + ; load TimerB with DMADELAY ticks for setting DMA and repeat + move.b #DMADELAY&255,CIATBLO(a0) + move.b #DMADELAY>>8,CIATBHI(a0) + + ; Ack. pending interrupts, TimerA and TimerB interrupt enable + tst.b CIAICR(a0) + move.w #$2000,INTREQ(a6) + move.b #$83,CIAICR(a0) + + ; enable level 6 interrupts + move.w #$a000,INTENA(a6) + + bra mt_reset + + +;--------------------------------------------------------------------------- + xdef _mt_remove_cia +_mt_remove_cia: +; Remove CIA-B music interrupt and restore the old vector. +; a6 = CUSTOM + + move.l a4,-(sp) + lea mt_data,a4 + + ; disable level 6 and CIA-B interrupts + lea CIAB,a0 + move.w #$2000,d0 + move.b #$7f,CIAICR(a0) + move.w d0,INTENA(a6) + tst.b CIAICR(a0) + move.w d0,INTREQ(a6) + + ; restore old timer values + lea mt_oldtimers(a4),a1 + move.b (a1)+,CIATALO(a0) + move.b (a1)+,CIATAHI(a0) + move.b (a1)+,CIATBLO(a0) + move.b (a1),CIATBHI(a0) + move.b #$10,CIACRA(a0) + move.b #$10,CIACRB(a0) + + ; restore original level 6 interrupt vector + move.l mt_Lev6Int(a4),a1 + move.l mt_oldLev6(a4),(a1) + + ; reenable CIA-B ALRM interrupt, which was set by AmigaOS + move.b #$84,CIAICR(a0) + + ; reenable previous level 6 interrupt + move.w mt_Lev6Ena(a4),INTENA(a6) + + move.l (sp)+,a4 + rts + + +;--------------------------------------------------------------------------- +mt_TimerAInt: +; TimerA interrupt calls _mt_music at a selectable tempo (Fxx command), +; which defaults to 50 times per second. + + ; check for TB interrupt and clear CIAB interrupt flags + btst #1,CIAB+CIAICR + bne mt_TimerBInt + + ; Now it should be a TA interrupt. + ; Other level 6 interrupt sources have to be handled elsewhere. + movem.l d0-d7/a0-a6,-(sp) + lea CUSTOM,a6 + lea mt_data,a4 + + ; clear EXTER interrupt flag + move.w #$2000,INTREQ(a6) + + ; do music when enabled + tst.b mt_Enable(a4) + ifeq MINIMAL + beq .2 + else + beq .1 + endc + + bsr _mt_music ; music with sfx inserted +.1: movem.l (sp)+,d0-d7/a0-a6 + nop + rte + + ifeq MINIMAL +.2: bsr mt_sfxonly ; no music, only sfx + movem.l (sp)+,d0-d7/a0-a6 + nop + rte + endc + + +;--------------------------------------------------------------------------- +mt_TimerBInt: +; Handle one-shot TimerB interrupt. +; TB_toggle-technique suggested by Ross/EAB. + + move.l a0,-(sp) + lea TB_toggle(pc),a0 + not.b (a0) + lea CUSTOM+INTREQ,a0 + beq mt_TimerBsetrep + + ; restart timer for repeat, enable audio DMA after DMADELAY ticks + move.w #$2000,(a0) ; clear EXTER interrupt flag + move.b #$19,CIAB+CIACRB + move.w mt_dmaon(pc),DMACON-INTREQ(a0) + + move.l (sp)+,a0 + nop + rte + +mt_dmaon: + dc.w $8000 +TB_toggle: + dc.b 0 + even + + +;--------------------------------------------------------------------------- +mt_TimerBsetrep: +; Oneshot TimerB interrupt to set repeat samples after another DMADELAY ticks. +; a0 = INTREQ + + ; clear EXTER and possible audio interrupt flags + move.l a4,-(sp) + move.l d0,a4 + moveq #$2000>>7,d0 ; EXTER-flag + or.b mt_dmaon+1(pc),d0 + lsl.w #7,d0 + move.w d0,(a0) + move.l a4,d0 + + ; set repeat sample pointers and lengths + lea mt_data,a4 + move.l mt_chan1+n_loopstart(a4),AUD0LC-INTREQ(a0) + move.w mt_chan1+n_replen(a4),AUD0LEN-INTREQ(a0) + move.l mt_chan2+n_loopstart(a4),AUD1LC-INTREQ(a0) + move.w mt_chan2+n_replen(a4),AUD1LEN-INTREQ(a0) + move.l mt_chan3+n_loopstart(a4),AUD2LC-INTREQ(a0) + move.w mt_chan3+n_replen(a4),AUD2LEN-INTREQ(a0) + move.l mt_chan4+n_loopstart(a4),AUD3LC-INTREQ(a0) + move.w mt_chan4+n_replen(a4),AUD3LEN-INTREQ(a0) + + move.l (sp)+,a4 + move.l (sp)+,a0 + nop + rte + + +;--------------------------------------------------------------------------- +; Antiriad: +; Generates an accurate period/finetune table in ~140 bytes +; In: a4, mt_data +; +; See: https://eab.abime.net/showpost.php?p=1416034&postcount=47 + +mt_generate_period_table: + movem.l d2-d5,-(sp) + + lea mt_PeriodTable(a4),a0 + lea .seeds(pc),a1 + moveq #0,d3 + moveq #16-1,d5 ;16 tuning tables +.tloop: + move.w (a1)+,d0 ;get 'patched' semitone-up period *64 + move.l (a1)+,d2 ;get correction bitmap + moveq #36-1,d4 ;36 words per table +.loop1: + mulu #$F1A8,d0 ;~1/(2^(1/12))*65536 - 0.16 fixed point + swap.w d0 ;/65536 + move.w d0,d1 + lsr.w #6,d1 ;/64 + add.l d2,d2 + subx.w d3,d1 + move.w d1,(a0)+ + dbf d4,.loop1 + dbf d5,.tloop + + ; Create the finetune lookup table. This is a word offset like so: +;mt_PerFineTune: (16 words) +; dc.w mt_Tuning0-mt_PerFineTune,mt_Tuning1-mt_PerFineTune +; dc.w mt_Tuning2-mt_PerFineTune,mt_Tuning3-mt_PerFineTune +; dc.w mt_Tuning4-mt_PerFineTune,mt_Tuning5-mt_PerFineTune +; dc.w mt_Tuning6-mt_PerFineTune,mt_Tuning7-mt_PerFineTune +; dc.w mt_TuningM8-mt_PerFineTune,mt_TuningM7-mt_PerFineTune +; dc.w mt_TuningM6-mt_PerFineTune,mt_TuningM5-mt_PerFineTune +; dc.w mt_TuningM4-mt_PerFineTune,mt_TuningM3-mt_PerFineTune +; dc.w mt_TuningM2-mt_PerFineTune,mt_TuningM1-mt_PerFineTune +;mt_PeriodTable: +;mt_Tuning0: + + ;mt_PerfFineTune is 16 words, each tuning table is 36 words + lea mt_PerFineTune(a4),a0 + moveq #16*2,d0 ;First offset is just the size of mt_PerfFineTune + moveq #16-1,d1 ;16 tables + moveq #36*2,d2 ;table size +.floop: + move.w d0,(a0)+ + add.w d2,d0 + dbf d1,.floop + + movem.l (sp)+,d2-d5 + rts + +.seeds: + dc.w $E2B4,$0FC0,$F920 ;mt_Tuning0 + dc.w $E159,$69D5,$E000 ;mt_Tuning1 + dc.w $DF8C,$0000,$0000 ;mt_Tuning2 + dc.w $DE31,$3B67,$A080 ;mt_Tuning3 + dc.w $DC64,$0006,$0000 ;mt_Tuning4 + dc.w $DAC2,$0000,$0400 ;mt_Tuning5 + dc.w $D977,$F5F2,$C840 ;mt_Tuning6 + dc.w $D7AF,$1200,$0000 ;mt_Tuning7 + dc.w $F036,$07E0,$7C90 ;mt_TuningM8 + dc.w $EE85,$0200,$1120 ;mt_TuningM7 + dc.w $ECCC,$0000,$0000 ;mt_TuningM6 + dc.w $EB62,$9DB3,$D040 ;mt_TuningM5 + dc.w $E96E,$0023,$0000 ;mt_TuningM4 + dc.w $E7BF,$0000,$0200 ;mt_TuningM3 + dc.w $E632,$9868,$4000 ;mt_TuningM2 + dc.w $E461,$0000,$0000 ;mt_TuningM1 + + +;--------------------------------------------------------------------------- +; Antiriad: +; Generates the sine vibrato table. Thanks to a/b. +; In: a4, mt_data +; +; See: https://eab.abime.net/showpost.php?p=1465997&postcount=132 + +mt_generate_vib_sine_table: + move.l d2,-(sp) + + lea (mt_VibratoSineTable_End-64)(a4),a1 + moveq #15*2,d2 +.VTLoop1 + lea (.table,pc),a0 + moveq #64/2-1,d1 +.VTLoop2 + move.w (a0)+,d0 + mulu.w d2,d0 + swap d0 + move.b d0,(a1)+ + neg.b d0 + move.b d0,(32-1,a1) + dbf d1,.VTLoop2 + lea (-64/2-64,a1),a1 + subq.w #1*2,d2 + bge.b .VTLoop1 + + move.l (sp)+,d2 + rts + +.table + dc.w $0000,$1800,$3100,$4a00,$6100,$7800,$8d00,$a100 + dc.w $b400,$c500,$d400,$e000,$eb00,$f400,$fa00,$fd00 + dc.w $ff00,$fd00,$fa00,$f400,$eb00,$e000,$d400,$c500 + dc.w $b400,$a100,$8d00,$7800,$6100,$4a00,$3100,$1800 + + +;--------------------------------------------------------------------------- + + xdef _mt_init +_mt_init: +; Initialize new module. +; Reset speed to 6, tempo to 125 and start at given song position. +; Master volume is at 64 (maximum). +; a6 = CUSTOM +; a0 = module pointer +; a1 = sample pointer (NULL means samples are stored within the module) +; d0 = initial song position + + move.l a4,-(sp) + lea mt_data,a4 + + move.l a0,mt_mod(a4) + movem.l d2/a2,-(sp) + + ; set initial song position + cmp.b 950(a0),d0 + blo .1 + moveq #0,d0 +.1: move.b d0,mt_SongPos(a4) + + move.l a1,d0 ; sample data location is given? + bne .4 + + ; get number of highest pattern + lea 952(a0),a1 ; song arrangement list + moveq #127,d0 + moveq #0,d2 +.2: move.b (a1)+,d1 + cmp.b d2,d1 + bls .3 + move.b d1,d2 +.3: dbf d0,.2 + addq.b #1,d2 ; number of patterns + + ; now we can calculate the base address of the sample data + moveq #10,d0 + asl.l d0,d2 + lea (a0,d2.l),a1 + ;add.w #1084,a1 + lea 1084(a1),a1 ;Antiriad + + ; save start address of each sample and do some fixes for broken mods +.4: lea mt_SampleStarts(a4),a2 + moveq #1,d2 + moveq #31-1,d0 +.5: move.l a1,(a2)+ + moveq #0,d1 + move.w 42(a0),d1 + cmp.w d2,d1 ; length 0 and 1 define unused samples + bls .6 + add.l d1,d1 + add.l d1,a1 + bra .7 +.6: clr.w 42(a0) ; length 1 means zero -> no sample +.7: lea 30(a0),a0 + dbf d0,.5 + + movem.l (sp)+,d2/a2 + + ; reset CIA timer A to default (125) + move.l mt_timerval(a4),d0 + divu #125,d0 + move.b d0,CIAB+CIATALO + lsr.w #8,d0 + move.b d0,CIAB+CIATAHI + + ;Antiriad - generator code + bsr mt_generate_period_table ;Create period table + bsr mt_generate_vib_sine_table ;Create sine vibrato table + ;Antiriad - end + ;Fallthrough to mt_reset + +mt_reset: +; a4 must be initialised with base register + + ; reset speed and counters + move.b #6,mt_Speed(a4) + clr.b mt_Counter(a4) + clr.w mt_PatternPos(a4) + + ; disable the filter + or.b #2,CIAA+CIAPRA + + ifeq MINIMAL + ; set master volume to 64 + lea MasterVolTab64(pc),a0 + move.l a0,mt_MasterVolTab(a4) + endc + + ; set channel index + clr.b mt_chan1+n_index(a4) + move.b #1,mt_chan2+n_index(a4) + move.b #2,mt_chan3+n_index(a4) + move.b #3,mt_chan4+n_index(a4) + + ; initialise channel DMA and interrupt bits + move.w #$0001,mt_chan1+n_dmabit(a4) + move.w #$0002,mt_chan2+n_dmabit(a4) + move.w #$0004,mt_chan3+n_dmabit(a4) + move.w #$0008,mt_chan4+n_dmabit(a4) + move.w #$0080,mt_chan1+n_intbit(a4) + move.w #$0100,mt_chan2+n_intbit(a4) + move.w #$0200,mt_chan3+n_intbit(a4) + move.w #$0400,mt_chan4+n_intbit(a4) + + ; make sure n_period doesn't start as 0 + move.w #320,d0 + move.w d0,mt_chan1+n_period(a4) + move.w d0,mt_chan2+n_period(a4) + move.w d0,mt_chan3+n_period(a4) + move.w d0,mt_chan4+n_period(a4) + + ; disable sound effects + clr.w mt_chan1+n_sfxlen(a4) + clr.w mt_chan2+n_sfxlen(a4) + clr.w mt_chan3+n_sfxlen(a4) + clr.w mt_chan4+n_sfxlen(a4) + + clr.b mt_E8Trigger(a4) + ifeq MINIMAL + clr.b mt_SongEnd(a4) + clr.b mt_SilCntValid(a4) + endc + + move.l (sp)+,a4 + + +;--------------------------------------------------------------------------- + xdef _mt_end +_mt_end: +; Stop playing current module. +; a6 = CUSTOM + + lea mt_data,a0 + clr.b mt_Enable(a0) + clr.w mt_chan1+n_volume(a0) + clr.w mt_chan2+n_volume(a0) + clr.w mt_chan3+n_volume(a0) + clr.w mt_chan4+n_volume(a0) + + moveq #0,d0 + move.w d0,AUD0VOL(a6) + move.w d0,AUD1VOL(a6) + move.w d0,AUD2VOL(a6) + move.w d0,AUD3VOL(a6) + move.w #$000f,DMACON(a6) + rts + + + ifeq MINIMAL +;--------------------------------------------------------------------------- + xdef _mt_soundfx +_mt_soundfx: +; Request playing of an external sound effect on the most unused channel. +; This function is for compatibility with the old API only! +; You should call _mt_playfx instead! +; a6 = CUSTOM +; a0 = sample pointer +; d0.w = sample length in words +; d1.w = sample period +; d2.w = sample volume + + lea -sfx_sizeof(sp),sp + move.l a0,sfx_ptr(sp) + movem.w d0-d2,sfx_len(sp) + move.w #$ff01,sfx_cha(sp) ; any channel, priority=1 + move.l sp,a0 + bsr _mt_playfx + lea sfx_sizeof(sp),sp + rts + + +;--------------------------------------------------------------------------- + xdef _mt_playfx +_mt_playfx: +; Request playing of a prioritized external sound effect, either on a +; fixed channel or on the most unused one. +; A negative channel specification means to use the best one. +; The priority is unsigned and should be greater than zero. +; This channel will be blocked for music until the effect has finished. +; a6 = CUSTOM +; a0 = sfx-structure pointer with the following layout: +; 0: ptr, 4: len.w, 6: period.w, 8: vol.w, 10: channel.b, 11: priority.b +; -> d0 = pointer to channel status or NULL when sample was ignored + + movem.l d2-d7/a0-a5,-(sp) + lea mt_data,a4 + + move.w #$4000,INTENA(a6) + moveq #0,d0 + move.b sfx_cha(a0),d0 + bpl channelsfx ; use fixed channel for effect + + ; Did we already calculate the n_freecnt values for all channels? + tst.b mt_SilCntValid(a4) + bne freecnt_valid + + ; Look at the next 8 pattern steps to find the longest sequence + ; of silence (no new note or instrument). + moveq #8,d2 + move.l #$fffff000,d3 ; mask to ignore effects + + ; reset freecnts for all channels + moveq #0,d0 + move.b d0,mt_chan1+n_freecnt(a4) + move.b d0,mt_chan2+n_freecnt(a4) + move.b d0,mt_chan3+n_freecnt(a4) + move.b d0,mt_chan4+n_freecnt(a4) + moveq #-1,d4 + moveq #-1,d5 + moveq #-1,d6 + moveq #-1,d7 + + ; get pattern pointer + move.l mt_mod(a4),a3 ; a3 mod pointer + lea 952(a3),a5 ; a5 song arrangement list + move.w mt_PatternPos(a4),d1 + move.b mt_SongPos(a4),d0 +.1: move.b (a5,d0.w),d0 + swap d0 + lea 1084(a3),a1 + lsr.l #6,d0 + add.l d0,a1 + lea 1024(a1),a2 ; a2 end of pattern + add.w d1,a1 ; a1 current pattern pos + +.2: moveq #0,d0 + + move.l (a1)+,d1 + and.l d3,d1 + sne d1 + and.b d1,d4 + sub.b d4,mt_chan1+n_freecnt(a4) + add.b d4,d0 + + move.l (a1)+,d1 + and.l d3,d1 + sne d1 + and.b d1,d5 + sub.b d5,mt_chan2+n_freecnt(a4) + add.b d5,d0 + + move.l (a1)+,d1 + and.l d3,d1 + sne d1 + and.b d1,d6 + sub.b d6,mt_chan3+n_freecnt(a4) + add.b d6,d0 + + move.l (a1)+,d1 + and.l d3,d1 + sne d1 + and.b d1,d7 + sub.b d7,mt_chan4+n_freecnt(a4) + add.b d7,d0 + + ; break the loop when no channel has any more free pattern steps + beq .7 + + ; otherwise break after 8 pattern steps + subq.w #1,d2 + beq .7 + + ; End of pattern reached? Then load next pattern pointer. + cmp.l a2,a1 + blo .2 + moveq #0,d1 + moveq #1,d0 + add.b mt_SongPos(a4),d0 + and.w #$007f,d0 + cmp.b 950(a3),d0 ; end of song reached? + blo .1 + moveq #0,d0 + bra .1 + +.7: st mt_SilCntValid(a4) + +freecnt_valid: + sub.l a2,a2 + move.b sfx_pri(a0),d2 + + ; Determine which channels are already allocated for sound + ; effects and check if the limit was reached. In this case only + ; replace sound effect channels by higher priority. + moveq #3,d0 + sub.b mt_MusicChannels(a4),d0 + move.b mt_chan1+n_sfxpri(a4),d4 + or.b mt_chan1+n_musiconly(a4),d4 + sne d1 + add.b d1,d0 + move.b mt_chan2+n_sfxpri(a4),d5 + or.b mt_chan2+n_musiconly(a4),d5 + sne d1 + add.b d1,d0 + move.b mt_chan3+n_sfxpri(a4),d6 + or.b mt_chan3+n_musiconly(a4),d6 + sne d1 + add.b d1,d0 + move.b mt_chan4+n_sfxpri(a4),d7 + or.b mt_chan4+n_musiconly(a4),d7 + sne d1 + add.b d1,d0 + bmi .overwrite ; all channels reserved/playing effects + + ; We will prefer a music channel which had an audio interrupt, + ; because that means the last instrument sample has been played + ; completely, and the channel is now in an idle loop. + ; Also exclude channels which have set a repeat loop. + ; Try not to break them! + moveq #0,d3 + tst.b mt_chan1+n_looped(a4) + bne .1 + or.w #$0080,d3 +.1: tst.b mt_chan2+n_looped(a4) + bne .2 + or.w #$0100,d3 +.2: tst.b mt_chan3+n_looped(a4) + bne .3 + or.w #$0200,d3 +.3: tst.b mt_chan4+n_looped(a4) + bne .4 + or.w #$0400,d3 +.4: move.w INTREQR(a6),d1 + and.w d3,d1 + bne .6 + + ; All channels are busy. Then break the non-looped ones first... + move.w d3,d1 + bne .6 + + ; ..except there are none. Then it doesn't matter. :| + move.w #$0780,d1 + + ; first look for the best unused channel +.6: moveq #0,d3 + btst #7,d1 + seq d0 + or.b d4,d0 + bne .7 + lea mt_chan1+n_freecnt(a4),a1 + cmp.b (a1),d3 + bhi .7 + move.l a1,a2 + move.b (a1),d3 +.7: btst #8,d1 + seq d0 + or.b d5,d0 + bne .8 + lea mt_chan2+n_freecnt(a4),a1 + cmp.b (a1),d3 + bhi .8 + move.l a1,a2 + move.b (a1),d3 +.8: btst #9,d1 + seq d0 + or.b d6,d0 + bne .9 + lea mt_chan3+n_freecnt(a4),a1 + cmp.b (a1),d3 + bhi .9 + move.l a1,a2 + move.b (a1),d3 +.9: btst #10,d1 + seq d0 + or.b d7,d0 + bne .10 + lea mt_chan4+n_freecnt(a4),a1 + cmp.b (a1),d3 + bhi .10 + move.l a1,a2 + bra found_sfx_ch + +.10: move.l a2,d3 + bne found_sfx_ch + +.overwrite: + ; finally try to overwrite a sound effect with lower/equal priority + moveq #0,d3 + tst.b d4 + beq .11 + cmp.b d4,d2 + blo .11 + lea mt_chan1+n_freecnt(a4),a1 + cmp.b (a1),d3 + bhi .11 + move.l a1,a2 + move.b (a1),d3 +.11: tst.b d5 + beq .12 + cmp.b d5,d2 + blo .12 + lea mt_chan2+n_freecnt(a4),a1 + cmp.b (a1),d3 + bhi .12 + move.l a1,a2 + move.b (a1),d3 +.12: tst.b d6 + beq .13 + cmp.b d6,d2 + blo .13 + lea mt_chan3+n_freecnt(a4),a1 + cmp.b (a1),d3 + bhi .13 + move.l a1,a2 + move.b (a1),d3 +.13: tst.b d7 + beq .14 + cmp.b d7,d2 + blo .14 + lea mt_chan4+n_freecnt(a4),a1 + cmp.b (a1),d3 + bhi .14 + move.l a1,a2 + +.14: move.l a2,d3 + beq exit_playfx ; ignore new sfx due to low priority + +found_sfx_ch: + lea -n_freecnt(a2),a2 + bra set_sfx + +channelsfx: +; a0 = sfx structure +; d0 = fixed channel for new sound effect + add.w d0,d0 + lea mt_chan1(a4),a2 + add.w channel_offsets(pc,d0.w),a2 + + ; priority high enough to replace a present effect on this channel? + move.b sfx_pri(a0),d2 + cmp.b n_sfxpri(a2),d2 + bhs set_sfx + sub.l a2,a2 + bra exit_playfx + +set_sfx: +; activate the sound effect on this channel +; a0 = sfx structure +; d2 = sfx priority +; a2 = channel status + move.l (a0)+,n_sfxptr(a2) ; sfx_ptr + move.w (a0)+,n_sfxlen(a2) ; sfx_len + move.w (a0)+,n_sfxper(a2) ; sfx_per + move.w (a0),n_sfxvol(a2) ; sfx_vol + move.b d2,n_sfxpri(a2) + +exit_playfx: + move.w #$c000,INTENA(a6) + move.l a2,d0 ; ptr to selected channel or NULL + + movem.l (sp)+,d2-d7/a0-a5 + rts + +channel_offsets: + dc.w 0*n_sizeof,1*n_sizeof,2*n_sizeof,3*n_sizeof + + +;--------------------------------------------------------------------------- + xdef _mt_loopfx +_mt_loopfx: +; Request playing of a looped sound effect on a fixed channel, which +; will be blocked for music until the effect is stopped (_mt_stopfx). +; It uses the same sfx-structure as _mt_playfx, but the priority is +; ignored. A looped sound effect has always highest priority and will +; replace a previous effect on the same channel. No automatic channel +; selection possible! +; Also make sure the sample starts with a zero-word, which is used +; for idling when the effect is stopped. This word is included in the +; total length calculation, but excluded when actually playing the loop. +; a6 = CUSTOM +; a0 = sfx-structure pointer with the following layout: +; 0: ptr, 4: len.w, 6: period.w, 8: vol.w, 10: channel.b + + lea mt_data+mt_chan1,a1 + + moveq #3,d0 + and.b sfx_cha(a0),d0 + add.w d0,d0 + add.w channel_offsets(pc,d0.w),a1 + + move.w #$4000,INTENA(a6) + move.l (a0)+,n_sfxptr(a1) ; sfx_ptr + move.w (a0)+,n_sfxlen(a1) ; sfx_len + move.w (a0)+,n_sfxper(a1) ; sfx_per + move.w (a0),n_sfxvol(a1) ; sfx_vol + st n_sfxpri(a1) ; sfx_pri -1 enables looped mode + move.w #$c000,INTENA(a6) + + rts + + +;--------------------------------------------------------------------------- + xdef _mt_stopfx +_mt_stopfx: +; Immediately stop a currently playing sound effect on a channel. +; a6 = CUSTOM +; d0.b = channel (0..3) + + lea mt_data+mt_chan1,a0 + + and.w #3,d0 + add.w d0,d0 + add.w channel_offsets(pc,d0.w),a0 + + move.w #$4000,INTENA(a6) + tst.b n_sfxpri(a0) + beq .1 ; no sfx playing anyway + moveq #1,d0 + move.b d0,n_sfxpri(a0) + move.w d0,n_sfxlen(a0) ; idle loop + move.w #108,n_sfxper(a0) ; enter idle as quickly as possible + clr.w n_sfxvol(a0) ; and cut volume + ifne NULL_IS_CLEARED + clr.b n_looped(a0) + clr.l n_sfxptr(a0) ; use $0 for idle-looping + else + tst.b n_looped(a0) + beq .1 + clr.b n_looped(a0) + subq.l #2,n_sfxptr(a0) ; idle loop at sample-start - 2 + endc +.1: move.w #$c000,INTENA(a6) + + rts + + +;--------------------------------------------------------------------------- + xdef _mt_musicmask +_mt_musicmask: +; Set bits in the mask define which specific channels are reserved +; for music only. +; a6 = CUSTOM +; d0.b = channel-mask (bit 0 for channel 0, ..., bit 3 for channel 3) + + move.l a4,-(sp) + lea mt_data,a4 + + move.w #$4000,INTENA(a6) + + lsl.b #5,d0 + scs mt_chan4+n_musiconly(a4) + add.b d0,d0 + scs mt_chan3+n_musiconly(a4) + add.b d0,d0 + scs mt_chan2+n_musiconly(a4) + add.b d0,d0 + scs mt_chan1+n_musiconly(a4) + + move.w #$c000,INTENA(a6) + + move.l (sp)+,a4 + rts + + +;--------------------------------------------------------------------------- + xdef _mt_mastervol +_mt_mastervol: +; Set a master volume from 0 to 64 for all music channels. +; Note that the master volume does not affect the volume of external +; sound effects (which is desired). +; a6 = CUSTOM +; d0.w = master volume + + move.l a4,-(sp) + lea mt_data,a4 + + ; stingray, since each volume table has a size of 65 bytes + ; we simply multiply (optimised of course) by 65 to get the + ; offset to the correct table + lea MasterVolTab0(pc),a0 + add.w d0,a0 + lsl.w #6,d0 + add.w d0,a0 + + move.w #$4000,INTENA(a6) + + ; adapt all channel volumes immediately + move.l a0,mt_MasterVolTab(a4) + move.w mt_chan1+n_volume(a4),d0 + move.b (a0,d0.w),d0 + move.w d0,AUD0VOL(a6) + move.w mt_chan2+n_volume(a4),d0 + move.b (a0,d0.w),d0 + move.w d0,AUD1VOL(a6) + move.w mt_chan3+n_volume(a4),d0 + move.b (a0,d0.w),d0 + move.w d0,AUD2VOL(a6) + move.w mt_chan4+n_volume(a4),d0 + move.b (a0,d0.w),d0 + move.w d0,AUD3VOL(a6) + + move.w #$c000,INTENA(a6) + + move.l (sp)+,a4 + rts + + +;--------------------------------------------------------------------------- + xdef _mt_samplevol +_mt_samplevol: +; Redefine a sample's volume. May also be done while the song is playing. +; Warning: Does not check arguments for valid range! You must have done +; _mt_init before calling this function! +; The new volume is persistent. Even when the song is restarted. +; d0.w = sample number (0-31) +; d1.b = volume (0-64) + + move.l mt_data+mt_mod,a0 + + swap d1 + move.w d0,d1 + add.w d1,d1 + lsl.w #5,d0 + sub.w d1,d0 ; table index: sample number * 30 + swap d1 + move.b d1,12+3(a0,d0.w) ; set sample's volume + rts + endc ; !MINIMAL + + +;--------------------------------------------------------------------------- + xdef _mt_music +_mt_music: +; Called from interrupt. +; Play next position when Counter equals Speed. +; Effects are always handled. +; a6 = CUSTOM + + moveq #0,d7 ; d7 is always zero + + lea mt_dmaon+1(pc),a0 + move.b d7,(a0) + + addq.b #1,mt_Counter(a4) + + move.b mt_Counter(a4),d0 + cmp.b mt_Speed(a4),d0 + blo no_new_note + + ; handle a new note + move.b d7,mt_Counter(a4) + tst.b mt_PattDelTime2(a4) + beq get_new_note + + ; we have a pattern delay, check effects then step + lea AUD0LC(a6),a5 + lea mt_chan1(a4),a2 + bsr mt_checkfx + lea AUD1LC(a6),a5 + lea mt_chan2(a4),a2 + bsr mt_checkfx + lea AUD2LC(a6),a5 + lea mt_chan3(a4),a2 + bsr mt_checkfx + lea AUD3LC(a6),a5 + lea mt_chan4(a4),a2 + bsr mt_checkfx + bra settb_step + +no_new_note: + ; no new note, just check effects, don't step to next position + lea AUD0LC(a6),a5 + lea mt_chan1(a4),a2 + bsr mt_checkfx + lea AUD1LC(a6),a5 + lea mt_chan2(a4),a2 + bsr mt_checkfx + lea AUD2LC(a6),a5 + lea mt_chan3(a4),a2 + bsr mt_checkfx + lea AUD3LC(a6),a5 + lea mt_chan4(a4),a2 + bsr mt_checkfx + + ; set one-shot TimerB interrupt for enabling DMA, when needed + move.b mt_dmaon+1(pc),d0 + beq same_pattern + move.b #$19,CIAB+CIACRB ; load/start timer B, one-shot + bra same_pattern + +get_new_note: + ; determine pointer to current pattern line + move.l mt_mod(a4),a0 + lea 12(a0),a3 ; sample info table + lea 1084(a0),a1 ; pattern data + lea 952(a0),a0 + moveq #0,d0 + move.b mt_SongPos(a4),d0 + move.b (a0,d0.w),d0 ; current pattern number + swap d0 + lsr.l #6,d0 + add.l d0,a1 ; pattern base + add.w mt_PatternPos(a4),a1 ; a1 pattern line + + ; play new note for each channel, apply some effects + lea AUD0LC(a6),a5 + lea mt_chan1(a4),a2 + bsr mt_playvoice + lea AUD1LC(a6),a5 + lea mt_chan2(a4),a2 + bsr mt_playvoice + lea AUD2LC(a6),a5 + lea mt_chan3(a4),a2 + bsr mt_playvoice + lea AUD3LC(a6),a5 + lea mt_chan4(a4),a2 + bsr mt_playvoice + +;Antiriad: Check which channels are playing new notes and set bitmask in _mt_VUMeter +;chan1 = 1, chan2 = 2, chan3 = 4, chan4 = 8 +;Note up to the caller to clear _mt_VUMeter when reading. + ifne ENABLE_VUMETER + moveq #0,d0 +.vu1: + tst.w mt_chan1(a4) + beq.s .vu2 + addq.b #1,d0 +.vu2: + tst.w mt_chan2(a4) + beq.s .vu3 + addq.b #2,d0 +.vu3: + tst.w mt_chan3(a4) + beq.s .vu4 + addq.b #4,d0 +.vu4: + tst.w mt_chan4(a4) + beq.s .vuwrite + addq.b #8,d0 +.vuwrite: + or.b d0,mt_VUMeter(a4) ;merge final flag + endc ;ENABLE_VUMETER + +settb_step: + ; set one-shot TimerB interrupt for enabling DMA, when needed + move.b mt_dmaon+1(pc),d0 + beq pattern_step + move.b #$19,CIAB+CIACRB ; load/start timer B, one-shot + +pattern_step: + ; next pattern line, handle delay and break + ifeq MINIMAL + clr.b mt_SilCntValid(a4) ; recalculate silence counters + endc + moveq #16,d2 ; offset to next pattern line + + move.b mt_PattDelTime2(a4),d1 + move.b mt_PattDelTime(a4),d0 + beq .1 + move.b d0,d1 + move.b d7,mt_PattDelTime(a4) +.1: tst.b d1 + beq .3 + subq.b #1,d1 + beq .2 + moveq #0,d2 ; do not advance to next line +.2: move.b d1,mt_PattDelTime2(a4) + +.3: add.w mt_PatternPos(a4),d2 ; d2 PatternPos + + ; check for break + bclr d7,mt_PBreakFlag(a4) + beq .4 + move.w mt_PBreakPos(a4),d2 + move.w d7,mt_PBreakPos(a4) + + ; check whether end of pattern is reached +.4: move.w d2,mt_PatternPos(a4) + cmp.w #1024,d2 + blo same_pattern + +song_step: + move.w mt_PBreakPos(a4),mt_PatternPos(a4) + move.w d7,mt_PBreakPos(a4) + move.b d7,mt_PosJumpFlag(a4) + + ; next position in song + moveq #1,d0 + add.b mt_SongPos(a4),d0 + and.w #$007f,d0 + move.l mt_mod(a4),a0 + cmp.b 950(a0),d0 ; end of song reached? + blo .1 + moveq #0,d0 ; restart the song from the beginning + ifeq MINIMAL + addq.b #1,mt_SongEnd(a4) + bne .2 + clr.b mt_Enable(a4) ; stop the song when mt_SongEnd was -1 +.2: and.b #$7f,mt_SongEnd(a4) + endc +.1: move.b d0,mt_SongPos(a4) + +same_pattern: + tst.b mt_PosJumpFlag(a4) + bne song_step + + rts + + + ifeq MINIMAL +;--------------------------------------------------------------------------- +mt_sfxonly: +; Called from interrupt. +; Plays sound effects on free channels. +; a6 = CUSTOM + + moveq #0,d7 ; d7 is always zero + + lea mt_dmaon+1(pc),a0 + move.b d7,(a0) + + lea AUD0LC(a6),a5 + lea mt_chan1(a4),a2 + bsr chan_sfx_only + lea AUD1LC(a6),a5 + lea mt_chan2(a4),a2 + bsr chan_sfx_only + lea AUD2LC(a6),a5 + lea mt_chan3(a4),a2 + bsr chan_sfx_only + lea AUD3LC(a6),a5 + lea mt_chan4(a4),a2 + bsr chan_sfx_only + + move.b mt_dmaon+1(pc),d0 + beq .1 + move.b #$19,CIAB+CIACRB ; load/start timer B, one-shot + +.1: rts + + +chan_sfx_only: +; Check for new sound samples. Check if previous ones are finished. +; a2 = channel data +; a5 = audio registers + + tst.b n_sfxpri(a2) + beq .1 + + move.w n_sfxlen(a2),d0 + bne start_sfx + tst.b n_looped(a2) + bne .1 + + move.w n_intbit(a2),d0 + and.w INTREQR(a6),d0 + beq .1 + move.w n_dmabit(a2),d0 + and.w mt_dmaon(pc),d0 + bne .1 + + ; last sound effect sample has played, so unblock this channel again + move.b d7,n_sfxpri(a2) + +.1: rts + + +;--------------------------------------------------------------------------- +start_sfx: +; d0 = sfx_len in words +; a2 = channel data +; a5 = audio registers + + ; play new sound effect on this channel + move.w n_dmabit(a2),d1 + move.w d1,DMACON(a6) + + move.l n_sfxptr(a2),a0 + tst.b n_sfxpri(a2) + bpl .1 + + ; looped sound effect + st n_looped(a2) + addq.l #2,a0 ; skip first word, used for idling + subq.w #1,d0 + move.l a0,AUDLC(a5) + move.w d0,AUDLEN(a5) + bra .2 + + ; normal sound effect +.1: move.b d7,n_looped(a2) + move.l a0,AUDLC(a5) + move.w d0,AUDLEN(a5) + moveq #1,d0 ; idles after playing once + ifne NULL_IS_CLEARED + sub.l a0,a0 + endc + + ; save repeat and period for TimerB interrupt +.2: move.l a0,n_loopstart(a2) + move.w d0,n_replen(a2) + move.w n_sfxper(a2),d0 + move.w d0,AUDPER(a5) + move.w d0,n_period(a2) + move.w n_sfxvol(a2),AUDVOL(a5) + + move.w d7,n_sfxlen(a2) ; don't call start_sfx again + + lea mt_dmaon(pc),a0 + or.w d1,(a0) ; DMA-channel to enable on TimerB + rts + endc ; !MINIMAL + + +;--------------------------------------------------------------------------- +mt_checkfx: +; a2 = channel data +; a5 = audio registers + + ifeq MINIMAL + tst.b n_sfxpri(a2) + beq .3 + + move.w n_sfxlen(a2),d0 + beq .2 + bsr start_sfx + + ; channel is blocked, only check some E-commands +.1: move.w #$0fff,d4 + and.w n_cmd(a2),d4 + move.w d4,d0 + clr.b d0 + cmp.w #$0e00,d0 + bne mt_nop + and.w #$00ff,d4 + bra blocked_e_cmds + +.2: tst.b n_looped(a2) + bne .1 + move.w n_intbit(a2),d0 + and.w INTREQR(a6),d0 + beq .1 + move.w n_dmabit(a2),d0 + and.w mt_dmaon(pc),d0 + bne .1 + + ; sound effect sample has played, so unblock this channel again + move.b d7,n_sfxpri(a2) + endc ; !MINIMAL + + ; do channel effects between notes +.3: move.w n_funk(a2),d0 + beq .4 + bsr mt_updatefunk + +.4: move.w #$0fff,d4 + and.w n_cmd(a2),d4 + beq mt_pernop + and.w #$00ff,d4 + + moveq #$0f,d0 + and.b n_cmd(a2),d0 + add.w d0,d0 + move.w fx_tab(pc,d0.w),d0 + jmp fx_tab(pc,d0.w) + +fx_tab: + dc.w mt_arpeggio-fx_tab ; $0 + dc.w mt_portaup-fx_tab + dc.w mt_portadown-fx_tab + dc.w mt_toneporta-fx_tab + dc.w mt_vibrato-fx_tab ; $4 + dc.w mt_tonevolslide-fx_tab + dc.w mt_vibrvolslide-fx_tab + dc.w mt_tremolo-fx_tab + dc.w mt_nop-fx_tab ; $8 + dc.w mt_nop-fx_tab + dc.w mt_volumeslide-fx_tab + dc.w mt_nop-fx_tab + dc.w mt_nop-fx_tab ; $C + dc.w mt_nop-fx_tab + dc.w mt_e_cmds-fx_tab + dc.w mt_nop-fx_tab + + +mt_pernop: +; just set the current period + + move.w n_period(a2),AUDPER(a5) +mt_nop: + rts + + +;--------------------------------------------------------------------------- +mt_playvoice: +; a1 = pattern ptr +; a2 = channel data +; a3 = sample info table +; a5 = audio registers + + move.l (a1)+,d6 ; d6 current note/cmd words + + ifeq MINIMAL + ; channel blocked by external sound effect? + tst.b n_sfxpri(a2) + beq .2 + + move.w n_sfxlen(a2),d0 + beq .1 + bsr start_sfx + bra moreblockedfx + + ; do only some limited commands, while sound effect is in progress +.1: tst.b n_looped(a2) + bne moreblockedfx + move.w n_intbit(a2),d0 + and.w INTREQR(a6),d0 + beq moreblockedfx + move.w n_dmabit(a2),d0 + and.w mt_dmaon(pc),d0 + bne moreblockedfx + + ; sound effect sample has played, so unblock this channel again + move.b d7,n_sfxpri(a2) + endc ; !MINIMAL + +.2: tst.l (a2) ; n_note/cmd: any note or cmd set? + bne .3 + move.w n_period(a2),AUDPER(a5) +.3: move.l d6,(a2) + + moveq #15,d5 + and.b n_cmd(a2),d5 + add.w d5,d5 ; d5 cmd*2 + + moveq #0,d4 + move.b d6,d4 ; d4 cmd argument (in MSW) + swap d4 + move.w #$0ff0,d4 + and.w d6,d4 ; d4 for checking E-cmd (in LSW) + + swap d6 + move.l d6,d0 ; S...S... + clr.b d0 + rol.w #4,d0 + rol.l #4,d0 ; ....00SS + + and.w #$0fff,d6 ; d6 note + + ; get sample start address + add.w d0,d0 ; sample number * 2 + beq set_regs + move.w mult30tab(pc,d0.w),d1 ; d1 sample info table offset + lea mt_SampleStarts(a4),a0 + add.w d0,d0 + move.l -4(a0,d0.w),d2 + + ; read length, volume and repeat from sample info table + lea (a3,d1.w),a0 + move.w (a0)+,d0 ; length + bne .4 + + ifne NULL_IS_CLEARED + moveq #0,d2 ; use $0 for empty samples + else + ; use the first two bytes from the first sample for empty samples + move.l mt_SampleStarts(a4),d2 + endc + addq.w #1,d0 + +.4: move.l d2,n_start(a2) + move.w d0,n_reallength(a2) + + ; determine period table from fine-tune parameter + moveq #0,d3 + move.b (a0)+,d3 + add.w d3,d3 + move.l a0,d1 + lea mt_PerFineTune(a4),a0 ;Antiriad: Finetune table is generated and in mt_data section + add.w (a0,d3.w),a0 + move.l a0,n_pertab(a2) + move.l d1,a0 + cmp.w #2*8,d3 + shs n_minusft(a2) + + moveq #0,d1 + move.b (a0)+,d1 ; volume + move.w d1,n_volume(a2) + move.w (a0)+,d3 ; repeat offset + beq no_offset + + ; set repeat + add.l d3,d2 + add.l d3,d2 + move.w (a0),d0 + move.w d0,n_replen(a2) + exg d0,d3 ; n_replen to d3 + add.w d3,d0 + bra set_len_start + +mult30tab: + dc.w 0*30,1*30,2*30,3*30,4*30,5*30,6*30,7*30 + dc.w 8*30,9*30,10*30,11*30,12*30,13*30,14*30,15*30 + dc.w 16*30,17*30,18*30,19*30,20*30,21*30,22*30,23*30 + dc.w 24*30,25*30,26*30,27*30,28*30,29*30,30*30,31*30 + +no_offset: + move.w (a0),d3 + ifne NULL_IS_CLEARED + cmp.w #1,d3 + beq .1 + bhi set_replen + else + bne set_replen + endc + ; repeat length zero means idle-looping + addq.w #1,d3 +.1: moveq #0,d2 ; expect two zero bytes at $0 +set_replen: + move.w d3,n_replen(a2) +set_len_start: + move.w d0,n_length(a2) + move.l d2,n_loopstart(a2) + move.l d2,n_wavestart(a2) + + ; Virgill: deleted volume here for fixing the clickerfuck bug at low volumes + ifeq MINIMAL + move.l mt_MasterVolTab(a4),a0 + move.b (a0,d1.w),d1 + endc + move.w d1,AUDVOL(a5) ; + + + + ; remember if sample is looped + ; @@@ FIXME: also need to check if n_loopstart equals n_start + subq.w #1,d3 + sne n_looped(a2) + +set_regs: +; d4 = cmd argument | masked E-cmd +; d5 = cmd*2 +; d6 = cmd.w | note.w + + move.w d4,d3 ; d3 masked E-cmd + swap d4 ; d4 cmd argument into LSW + + tst.w d6 + beq checkmorefx ; no new note + + cmp.w #$0e50,d3 + beq set_finetune + + move.w prefx_tab(pc,d5.w),d0 + jmp prefx_tab(pc,d0.w) + +prefx_tab: + dc.w set_period-prefx_tab,set_period-prefx_tab,set_period-prefx_tab + dc.w set_toneporta-prefx_tab ; $3 + dc.w set_period-prefx_tab + dc.w set_toneporta-prefx_tab ; $5 + dc.w set_period-prefx_tab,set_period-prefx_tab,set_period-prefx_tab + dc.w set_sampleoffset-prefx_tab ; $9 + dc.w set_period-prefx_tab,set_period-prefx_tab,set_period-prefx_tab + dc.w set_period-prefx_tab,set_period-prefx_tab,set_period-prefx_tab + +set_toneporta: + move.l n_pertab(a2),a0 ; tuned period table + + ; find first period which is less or equal the note in d6 + moveq #36-1,d0 + moveq #-2,d1 +.1: addq.w #2,d1 + cmp.w (a0)+,d6 + dbhs d0,.1 + + tst.b n_minusft(a2) ; negative fine tune? + beq .2 + tst.w d1 + beq .2 + subq.l #2,a0 ; then take previous period + subq.w #2,d1 + +.2: move.w d1,n_noteoff(a2) ; note offset in period table + move.w n_period(a2),d2 + move.w -(a0),d1 + cmp.w d1,d2 + bne .3 + moveq #0,d1 +.3: move.w d1,n_wantedperiod(a2) + + move.w n_funk(a2),d0 + beq .4 + bsr mt_updatefunk + +.4: move.w d2,AUDPER(a5) + rts + +set_sampleoffset: +; cmd 9 x y (xy = offset in 256 bytes) +; d4 = xy + moveq #0,d0 + move.b d4,d0 + bne .1 + move.b n_sampleoffset(a2),d0 + bra .2 +.1: move.b d0,n_sampleoffset(a2) + +.2: lsl.w #7,d0 + cmp.w n_length(a2),d0 + bhs .3 + sub.w d0,n_length(a2) + add.w d0,d0 + add.l d0,n_start(a2) + bra set_period + +.3: move.w #1,n_length(a2) + bra set_period + +set_finetune: + lea mt_PerFineTune(a4),a0 ;Antiriad: Finetune table is generated and in mt_data section + moveq #$0f,d0 + and.b n_cmdlo(a2),d0 + add.w d0,d0 + add.w (a0,d0.w),a0 + move.l a0,n_pertab(a2) + cmp.w #2*8,d0 + shs n_minusft(a2) + +set_period: +; find nearest period for a note value, then apply finetuning +; d3 = masked E-cmd +; d4 = cmd argument +; d5 = cmd*2 +; d6 = note.w + + lea mt_PeriodTable(a4),a0 ;Antiriad: Finetune table is generated and in mt_data section + moveq #36-1,d0 + moveq #-2,d1 +.1: addq.w #2,d1 ; table offset + cmp.w (a0)+,d6 + dbhs d0,.1 + + ; apply finetuning, set period and note-offset + move.l n_pertab(a2),a0 + move.w (a0,d1.w),d2 + move.w d2,n_period(a2) + move.w d1,n_noteoff(a2) + + ; check for notedelay + cmp.w #$0ed0,d3 ; notedelay + beq checkmorefx + + ; disable DMA + move.w n_dmabit(a2),d0 + move.w d0,DMACON(a6) + + btst #2,n_vibratoctrl(a2) + bne .2 + move.b d7,n_vibratopos(a2) + +.2: btst #2,n_tremoloctrl(a2) + bne .3 + move.b d7,n_tremolopos(a2) + +.3: move.l n_start(a2),AUDLC(a5) + move.w n_length(a2),AUDLEN(a5) + move.w d2,AUDPER(a5) + + ; Virgill: added volume here for fixing the clickerfuck bug + ; move.w n_volume(a2),AUDVOL(a5) + + lea mt_dmaon(pc),a0 + or.w d0,(a0) + +checkmorefx: +; d4 = cmd argument +; d5 = cmd*2 +; d6 = note.w + + move.w n_funk(a2),d0 + beq .1 + bsr mt_updatefunk + +.1: move.w morefx_tab(pc,d5.w),d0 + jmp morefx_tab(pc,d0.w) + +morefx_tab: + dc.w mt_pernop-morefx_tab,mt_pernop-morefx_tab,mt_pernop-morefx_tab + dc.w mt_pernop-morefx_tab,mt_pernop-morefx_tab,mt_pernop-morefx_tab + dc.w mt_pernop-morefx_tab,mt_pernop-morefx_tab,mt_pernop-morefx_tab + dc.w mt_pernop-morefx_tab ; $9 + dc.w mt_pernop-morefx_tab + dc.w mt_posjump-morefx_tab ; $B + dc.w mt_volchange-morefx_tab + dc.w mt_patternbrk-morefx_tab ; $D + dc.w mt_e_cmds-morefx_tab + dc.w mt_setspeed-morefx_tab + + + ifeq MINIMAL +moreblockedfx: +; d6 = note.w | cmd.w + + moveq #0,d4 + move.b d6,d4 ; cmd argument + and.w #$0f00,d6 + lsr.w #7,d6 + move.w blmorefx_tab(pc,d6.w),d0 + jmp blmorefx_tab(pc,d0.w) + +blmorefx_tab: + dc.w mt_nop-blmorefx_tab,mt_nop-blmorefx_tab + dc.w mt_nop-blmorefx_tab,mt_nop-blmorefx_tab + dc.w mt_nop-blmorefx_tab,mt_nop-blmorefx_tab + dc.w mt_nop-blmorefx_tab,mt_nop-blmorefx_tab + dc.w mt_nop-blmorefx_tab,mt_nop-blmorefx_tab + dc.w mt_nop-blmorefx_tab + dc.w mt_posjump-blmorefx_tab ; $B + dc.w mt_nop-blmorefx_tab + dc.w mt_patternbrk-blmorefx_tab ; $D + dc.w blocked_e_cmds-blmorefx_tab + dc.w mt_setspeed-blmorefx_tab ; $F + endc ; !MINIMAL + + +mt_arpeggio: +; cmd 0 x y (x = first arpeggio offset, y = second arpeggio offset) +; d4 = xy + + moveq #0,d0 + move.b mt_Counter(a4),d0 + move.b arptab(pc,d0.w),d0 + beq mt_pernop ; step 0, just use normal period + bmi .1 + + ; step 1, arpeggio by left nibble + lsr.b #4,d4 + bra .2 + + ; step 2, arpeggio by right nibble +.1: and.w #$000f,d4 + + ; offset current note +.2: add.w d4,d4 + add.w n_noteoff(a2),d4 + cmp.w #2*36,d4 + bhs .4 + + ; set period with arpeggio offset from note table + move.l n_pertab(a2),a0 + move.w (a0,d4.w),AUDPER(a5) +.4: rts + +arptab: + dc.b 0,1,-1,0,1,-1,0,1,-1,0,1,-1,0,1,-1,0 + dc.b 1,-1,0,1,-1,0,1,-1,0,1,-1,0,1,-1,0,1 + + +mt_fineportaup: +; cmd E 1 x (subtract x from period) +; d0 = x + + tst.b mt_Counter(a4) + beq do_porta_up + rts + + +mt_portaup: +; cmd 1 x x (subtract xx from period) +; d4 = xx + + move.w d4,d0 + +do_porta_up: + move.w n_period(a2),d1 + sub.w d0,d1 + cmp.w #113,d1 + bhs .1 + moveq #113,d1 +.1: move.w d1,n_period(a2) + move.w d1,AUDPER(a5) + rts + + +mt_fineportadn: +; cmd E 2 x (add x to period) +; d0 = x + + tst.b mt_Counter(a4) + beq do_porta_down + rts + + +mt_portadown: +; cmd 2 x x (add xx to period) +; d4 = xx + + move.w d4,d0 + +do_porta_down: + move.w n_period(a2),d1 + add.w d0,d1 + cmp.w #856,d1 + bls .1 + move.w #856,d1 +.1: move.w d1,n_period(a2) + move.w d1,AUDPER(a5) + rts + + +mt_toneporta: +; cmd 3 x y (xy = tone portamento speed) +; d4 = xy + + tst.b d4 + beq mt_toneporta_nc + move.w d4,n_toneportspeed(a2) + move.b d7,n_cmdlo(a2) + +mt_toneporta_nc: + move.w n_wantedperiod(a2),d1 + beq .6 + + move.w n_toneportspeed(a2),d0 + move.w n_period(a2),d2 + cmp.w d1,d2 + blo .2 + + ; tone porta up + sub.w d0,d2 + cmp.w d1,d2 + bgt .3 + move.w d1,d2 + move.w d7,n_wantedperiod(a2) + bra .3 + + ; tone porta down +.2: add.w d0,d2 + cmp.w d1,d2 + blt .3 + move.w d1,d2 + move.w d7,n_wantedperiod(a2) + +.3: move.w d2,n_period(a2) + + tst.b n_gliss(a2) + beq .5 + + ; glissando: find nearest note for new period + move.l n_pertab(a2),a0 + moveq #36-1,d0 + moveq #-2,d1 +.4: addq.w #2,d1 + cmp.w (a0)+,d2 + dbhs d0,.4 + + move.w d1,n_noteoff(a2) ; @@@ needed? + move.w -(a0),d2 + +.5: move.w d2,AUDPER(a5) +.6 rts + + +mt_vibrato: +; cmd 4 x y (x = speed, y = amplitude) +; d4 = xy + + moveq #$0f,d2 + and.b d4,d2 + beq .1 + move.b d2,n_vibratoamp(a2) + bra .2 +.1: move.b n_vibratoamp(a2),d2 + +.2: lsr.b #4,d4 + beq .3 + move.b d4,n_vibratospd(a2) + bra mt_vibrato_nc +.3: move.b n_vibratospd(a2),d4 + +mt_vibrato_nc: + ; calculate vibrato table offset: 64 * amplitude + (pos & 63) + lsl.w #6,d2 + moveq #63,d0 + and.b n_vibratopos(a2),d0 + add.w d0,d2 + + ifne ENABLE_SAWRECT + ; select vibrato waveform + moveq #3,d1 + and.b n_vibratoctrl(a2),d1 + beq .6 + subq.b #1,d1 + beq .5 + + ; ctrl 2 & 3 select a rectangle vibrato + lea mt_VibratoRectTable(pc),a0 + bra .9 + + ; ctrl 1 selects a sawtooth vibrato +.5: lea mt_VibratoSawTable(pc),a0 + bra .9 + endc ; ENABLE_SAWRECT + + ; ctrl 0 selects a sine vibrato +.6: lea mt_VibratoSineTable(a4),a0 + + ; add vibrato-offset to period +.9: move.b (a0,d2.w),d0 + ext.w d0 + add.w n_period(a2),d0 + move.w d0,AUDPER(a5) + + ; increase vibratopos by speed + add.b d4,n_vibratopos(a2) + rts + + +mt_tonevolslide: +; cmd 5 x y (x = volume-up, y = volume-down) +; d4 = xy + + pea mt_volumeslide(pc) + bra mt_toneporta_nc + + +mt_vibrvolslide: +; cmd 6 x y (x = volume-up, y = volume-down) +; d4 = xy + + move.w d4,d3 + move.b n_vibratoamp(a2),d2 + move.b n_vibratospd(a2),d4 + bsr mt_vibrato_nc + + move.w d3,d4 + bra mt_volumeslide + + +mt_tremolo: +; cmd 7 x y (x = speed, y = amplitude) +; d4 = xy + + moveq #$0f,d2 + and.b d4,d2 + beq .1 + move.b d2,n_tremoloamp(a2) + bra .2 +.1: move.b n_tremoloamp(a2),d2 + +.2: lsr.b #4,d4 + beq .3 + move.b d4,n_tremolospd(a2) + bra .4 +.3: move.b n_tremolospd(a2),d4 + + ; calculate tremolo table offset: 64 * amplitude + (pos & 63) +.4: lsl.w #6,d2 + moveq #63,d0 + and.b n_tremolopos(a2),d0 + add.w d0,d2 + + ifne ENABLE_SAWRECT + ; select tremolo waveform + moveq #3,d1 + and.b n_tremoloctrl(a2),d1 + beq .6 + subq.b #1,d1 + beq .5 + + ; ctrl 2 & 3 select a rectangle tremolo + lea mt_VibratoRectTable(pc),a0 + bra .9 + + ; ctrl 1 selects a sawtooth tremolo +.5: lea mt_VibratoSawTable(pc),a0 + bra .9 + endc ; ENABLE_SAWRECT + + ; ctrl 0 selects a sine tremolo +.6: lea mt_VibratoSineTable(a4),a0 + + ; add tremolo-offset to volume +.9: move.w n_volume(a2),d0 + add.b (a0,d2.w),d0 + bpl .10 + moveq #0,d0 +.10: cmp.w #64,d0 + bls .11 + moveq #64,d0 +.11: move.w n_period(a2),AUDPER(a5) + ifeq MINIMAL + move.l mt_MasterVolTab(a4),a0 + move.b (a0,d0.w),d0 + endc + move.w d0,AUDVOL(a5) + + ; increase tremolopos by speed + add.b d4,n_tremolopos(a2) + rts + + +mt_volumeslide: +; cmd A x y (x = volume-up, y = volume-down) +; d4 = xy + + move.w n_volume(a2),d0 + moveq #$0f,d1 + and.b d4,d1 + lsr.b #4,d4 + beq vol_slide_down + + ; slide up, until 64 + add.b d4,d0 +vol_slide_up: + cmp.b #64,d0 + bls set_vol + moveq #64,d0 + bra set_vol + + ; slide down, until 0 +vol_slide_down: + sub.b d1,d0 + bpl set_vol + moveq #0,d0 + +set_vol: + move.w d0,n_volume(a2) + move.w n_period(a2),AUDPER(a5) + ifeq MINIMAL + move.l mt_MasterVolTab(a4),a0 + move.b (a0,d0.w),d0 + endc + move.w d0,AUDVOL(a5) + rts + + +mt_posjump: +; cmd B x y (xy = new song position) +; d4 = xy + + move.b d4,d0 + subq.b #1,d0 + move.b d0,mt_SongPos(a4) + +jump_pos0: + move.w d7,mt_PBreakPos(a4) + st mt_PosJumpFlag(a4) + rts + + +mt_volchange: +; cmd C x y (xy = new volume) +; d4 = xy + + cmp.w #64,d4 + bls .1 + moveq #64,d4 +.1: move.w d4,n_volume(a2) + ifeq MINIMAL + move.l mt_MasterVolTab(a4),a0 + move.b (a0,d4.w),d4 + endc + move.w d4,AUDVOL(a5) + rts + + +mt_patternbrk: +; cmd D x y (xy = break pos in decimal) +; d4 = xy + + moveq #$0f,d0 + and.w d4,d0 + move.w d4,d1 + lsr.w #4,d1 + add.b mult10tab(pc,d1.w),d0 + cmp.b #63,d0 + bhi jump_pos0 + + lsl.w #4,d0 + move.w d0,mt_PBreakPos(a4) + st mt_PosJumpFlag(a4) + rts + +mult10tab: + dc.b 0,10,20,30,40,50,60,70,80,90,0,0,0,0,0,0 + + +mt_setspeed: +; cmd F x y (xy<$20 new speed, xy>=$20 new tempo) +; d4 = xy + + cmp.b #$20,d4 + bhs .1 + move.b d4,mt_Speed(a4) + beq _mt_end + rts + + ; set tempo (CIA only) +.1: and.w #$00ff,d4 + move.l mt_timerval(a4),d0 + divu d4,d0 + move.b d0,CIAB+CIATALO + lsr.w #8,d0 + move.b d0,CIAB+CIATAHI + rts + + +mt_e_cmds: +; cmd E x y (x=command, y=argument) +; d4 = xy + + moveq #$0f,d0 + and.w d4,d0 ; pass E-cmd argument in d0 + + move.w d4,d1 + lsr.w #4,d1 + add.w d1,d1 + move.w ecmd_tab(pc,d1.w),d1 + jmp ecmd_tab(pc,d1.w) + +ecmd_tab: + dc.w mt_filter-ecmd_tab + dc.w mt_fineportaup-ecmd_tab + dc.w mt_fineportadn-ecmd_tab + dc.w mt_glissctrl-ecmd_tab + dc.w mt_vibratoctrl-ecmd_tab + dc.w mt_finetune-ecmd_tab + dc.w mt_jumploop-ecmd_tab + dc.w mt_tremoctrl-ecmd_tab + dc.w mt_e8-ecmd_tab + dc.w mt_retrignote-ecmd_tab + dc.w mt_volfineup-ecmd_tab + dc.w mt_volfinedn-ecmd_tab + dc.w mt_notecut-ecmd_tab + dc.w mt_notedelay-ecmd_tab + dc.w mt_patterndelay-ecmd_tab + dc.w mt_funk-ecmd_tab + + +blocked_e_cmds: +; cmd E x y (x=command, y=argument) +; d4 = xy + + moveq #$0f,d0 + and.w d4,d0 ; pass E-cmd argument in d0 + + move.w d4,d1 + lsr.w #4,d1 + add.w d1,d1 + move.w blecmd_tab(pc,d1.w),d1 + jmp blecmd_tab(pc,d1.w) + +blecmd_tab: + dc.w mt_filter-blecmd_tab + dc.w mt_rts-blecmd_tab + dc.w mt_rts-blecmd_tab + dc.w mt_glissctrl-blecmd_tab + dc.w mt_vibratoctrl-blecmd_tab + dc.w mt_finetune-blecmd_tab + dc.w mt_jumploop-blecmd_tab + dc.w mt_tremoctrl-blecmd_tab + dc.w mt_e8-blecmd_tab + dc.w mt_rts-blecmd_tab + dc.w mt_rts-blecmd_tab + dc.w mt_rts-blecmd_tab + dc.w mt_rts-blecmd_tab + dc.w mt_rts-blecmd_tab + dc.w mt_patterndelay-blecmd_tab + dc.w mt_rts-blecmd_tab + + +mt_filter: +; cmd E 0 x (x=1 disable, x=0 enable) +; d0 = x + + lsr.b #1,d0 + bcs .1 + bclr #2,CIAA+CIAPRA + rts +.1: bset #2,CIAA+CIAPRA +mt_rts: + rts + + +mt_glissctrl: +; cmd E 3 x (x gliss) +; d0 = x + + move.b d0,n_gliss(a2) + rts + + +mt_vibratoctrl: +; cmd E 4 x (x = vibrato) +; d0 = x + + move.b d0,n_vibratoctrl(a2) + rts + + +mt_finetune: +; cmd E 5 x (x = finetune) +; d0 = x + + lea mt_PerFineTune(a4),a0 ;Antiriad: Finetune table is generated and in mt_data section + add.w d0,d0 + add.w (a0,d0.w),a0 + move.l a0,n_pertab(a2) + cmp.w #2*8,d0 + shs n_minusft(a2) + rts + + +mt_jumploop: +; cmd E 6 x (x=0 loop start, else loop count) +; d0 = x + + tst.b mt_Counter(a4) + bne .4 + +.1: tst.b d0 + beq .3 ; set start + + ; otherwise we are at the end of the loop + subq.b #1,n_loopcount(a2) + beq .4 ; loop finished + bpl .2 + + ; initialize loop counter + move.b d0,n_loopcount(a2) + + ; jump back to start of loop +.2: move.w n_pattpos(a2),mt_PBreakPos(a4) + st mt_PBreakFlag(a4) + rts + + ; remember start of loop position +.3: move.w mt_PatternPos(a4),n_pattpos(a2) +.4: rts + + +mt_tremoctrl: +; cmd E 7 x (x = tremolo) +; d0 = x + + move.b d0,n_tremoloctrl(a2) + rts + + +mt_e8: +; cmd E 8 x (x = trigger value) +; d0 = x + + move.b d0,mt_E8Trigger(a4) + rts + + +mt_retrignote: +; cmd E 9 x (x = retrigger count) +; d0 = x + + tst.b d0 + beq .1 + + ; set new retrigger count when Counter=0 + tst.b mt_Counter(a4) + bne .2 + move.b d0,n_retrigcount(a2) + + ; avoid double retrigger, when Counter=0 and a note was set + move.w #$0fff,d2 + and.w (a2),d2 + beq do_retrigger +.1: rts + + ; check if retrigger count is reached +.2: subq.b #1,n_retrigcount(a2) + bne .1 + move.b d0,n_retrigcount(a2) ; reset + +do_retrigger: + ; DMA off, set sample pointer and length + move.w n_dmabit(a2),d0 + move.w d0,DMACON(a6) + move.l n_start(a2),AUDLC(a5) + move.w n_length(a2),AUDLEN(a5) + lea mt_dmaon(pc),a0 + or.w d0,(a0) + rts + + +mt_volfineup: +; cmd E A x (x = volume add) +; d0 = x + + tst.b mt_Counter(a4) + beq .1 + rts + +.1: add.w n_volume(a2),d0 + bra vol_slide_up + + +mt_volfinedn: +; cmd E B x (x = volume sub) +; d0 = x + + tst.b mt_Counter(a4) + beq .1 + rts + +.1: move.b d0,d1 + move.w n_volume(a2),d0 + bra vol_slide_down + + +mt_notecut: +; cmd E C x (x = counter to cut at) +; d0 = x + + cmp.b mt_Counter(a4),d0 + bne .1 + move.w d7,n_volume(a2) + move.w d7,AUDVOL(a5) +.1: rts + + +mt_notedelay: +; cmd E D x (x = counter to retrigger at) +; d0 = x + + cmp.b mt_Counter(a4),d0 + bne .1 + tst.w (a2) ; trigger note when given + bne .2 +.1: rts +.2: move.w n_period(a2),AUDPER(a5) + bra do_retrigger + + +mt_patterndelay: +; cmd E E x (x = delay count) +; d0 = x + + tst.b mt_Counter(a4) + bne .1 + tst.b mt_PattDelTime2(a4) + bne .1 + addq.b #1,d0 + move.b d0,mt_PattDelTime(a4) +.1: rts + + +mt_funk: +; cmd E F x (x = funk speed) +; d0 = x + + tst.b mt_Counter(a4) + bne .1 + move.w d0,n_funk(a2) + bne mt_updatefunk +.1: rts + +mt_updatefunk: +; d0 = funk speed + + move.b mt_FunkTable(pc,d0.w),d0 + add.b d0,n_funkoffset(a2) + bpl .2 + move.b d7,n_funkoffset(a2) + + move.l n_loopstart(a2),d0 + moveq #0,d1 + move.w n_replen(a2),d1 + add.l d1,d1 + add.l d0,d1 + move.l n_wavestart(a2),a0 + addq.l #1,a0 + cmp.l d1,a0 + blo .1 + move.l d0,a0 +.1: move.l a0,n_wavestart(a2) + not.b (a0) + +.2: rts + + +mt_FunkTable: + dc.b 0,5,6,7,8,10,11,13,16,19,22,26,32,43,64,128 + + ifne ENABLE_SAWRECT +mt_VibratoSawTable: + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + dc.b -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1 + dc.b 2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3 + dc.b -3,-3,-3,-3,-3,-3,-3,-3,-2,-2,-2,-2,-2,-2,-2,-2 + dc.b -1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2 + dc.b 3,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5 + dc.b -5,-5,-5,-5,-5,-5,-4,-4,-4,-4,-4,-3,-3,-3,-3,-3 + dc.b -2,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,0,0,0,0,0 + dc.b 0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3 + dc.b 4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7 + dc.b -7,-7,-7,-7,-6,-6,-6,-6,-5,-5,-5,-5,-4,-4,-4,-4 + dc.b -3,-3,-3,-3,-2,-2,-2,-2,-1,-1,-1,-1,0,0,0,0 + dc.b 0,0,0,0,1,1,1,2,2,2,3,3,3,4,4,4 + dc.b 5,5,5,5,6,6,6,7,7,7,8,8,8,9,9,9 + dc.b -9,-9,-9,-9,-8,-8,-8,-7,-7,-7,-6,-6,-6,-5,-5,-5 + dc.b -4,-4,-4,-4,-3,-3,-3,-2,-2,-2,-1,-1,-1,0,0,0 + dc.b 0,0,0,1,1,1,2,2,3,3,3,4,4,4,5,5 + dc.b 6,6,6,7,7,7,8,8,9,9,9,10,10,10,11,11 + dc.b -11,-11,-11,-10,-10,-10,-9,-9,-8,-8,-8,-7,-7,-7,-6,-6 + dc.b -5,-5,-5,-4,-4,-4,-3,-3,-2,-2,-2,-1,-1,-1,0,0 + dc.b 0,0,0,1,1,2,2,3,3,3,4,4,5,5,6,6 + dc.b 7,7,7,8,8,9,9,10,10,10,11,11,12,12,13,13 + dc.b -13,-13,-13,-12,-12,-11,-11,-10,-10,-10,-9,-9,-8,-8,-7,-7 + dc.b -6,-6,-6,-5,-5,-4,-4,-3,-3,-3,-2,-2,-1,-1,0,0 + dc.b 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7 + dc.b 8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15 + dc.b -15,-15,-14,-14,-13,-13,-12,-12,-11,-11,-10,-10,-9,-9,-8,-8 + dc.b -7,-7,-6,-6,-5,-5,-4,-4,-3,-3,-2,-2,-1,-1,0,0 + dc.b 0,0,1,1,2,2,3,3,4,5,5,6,6,7,7,8 + dc.b 9,9,10,10,11,11,12,12,13,14,14,15,15,16,16,17 + dc.b -17,-17,-16,-16,-15,-15,-14,-13,-13,-12,-12,-11,-11,-10,-10,-9 + dc.b -8,-8,-7,-7,-6,-6,-5,-4,-4,-3,-3,-2,-2,-1,-1,0 + dc.b 0,0,1,1,2,3,3,4,5,5,6,6,7,8,8,9 + dc.b 10,10,11,11,12,13,13,14,15,15,16,16,17,18,18,19 + dc.b -19,-19,-18,-18,-17,-16,-16,-15,-14,-14,-13,-13,-12,-11,-11,-10 + dc.b -9,-9,-8,-8,-7,-6,-6,-5,-4,-4,-3,-3,-2,-1,-1,0 + dc.b 0,0,1,2,2,3,4,4,5,6,6,7,8,8,9,10 + dc.b 11,11,12,13,13,14,15,15,16,17,17,18,19,19,20,21 + dc.b -21,-21,-20,-19,-19,-18,-17,-17,-16,-15,-15,-14,-13,-12,-12,-11 + dc.b -10,-10,-9,-8,-8,-7,-6,-6,-5,-4,-4,-3,-2,-1,-1,0 + dc.b 0,0,1,2,3,3,4,5,6,6,7,8,9,9,10,11 + dc.b 12,12,13,14,15,15,16,17,18,18,19,20,21,21,22,23 + dc.b -23,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,-14,-14,-13,-12 + dc.b -11,-11,-10,-9,-8,-8,-7,-6,-5,-5,-4,-3,-2,-2,-1,0 + dc.b 0,0,1,2,3,4,4,5,6,7,8,8,9,10,11,12 + dc.b 13,13,14,15,16,17,17,18,19,20,21,21,22,23,24,25 + dc.b -25,-25,-24,-23,-22,-21,-21,-20,-19,-18,-17,-16,-16,-15,-14,-13 + dc.b -12,-12,-11,-10,-9,-8,-8,-7,-6,-5,-4,-3,-3,-2,-1,0 + dc.b 0,0,1,2,3,4,5,6,7,7,8,9,10,11,12,13 + dc.b 14,14,15,16,17,18,19,20,21,21,22,23,24,25,26,27 + dc.b -27,-27,-26,-25,-24,-23,-22,-21,-20,-20,-19,-18,-17,-16,-15,-14 + dc.b -13,-13,-12,-11,-10,-9,-8,-7,-6,-6,-5,-4,-3,-2,-1,0 + dc.b 0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 + dc.b 15,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29 + dc.b -29,-28,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,-16,-15 + dc.b -14,-13,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0 + +mt_VibratoRectTable: + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + dc.b 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + dc.b -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + dc.b -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + dc.b 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 + dc.b 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 + dc.b -3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3 + dc.b -3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3 + dc.b 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 + dc.b 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 + dc.b -5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5 + dc.b -5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5 + dc.b 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 + dc.b 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 + dc.b -7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7 + dc.b -7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7 + dc.b 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9 + dc.b 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9 + dc.b -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 + dc.b -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 + dc.b 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 + dc.b 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 + dc.b -11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11 + dc.b -11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11 + dc.b 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 + dc.b 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 + dc.b -13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13 + dc.b -13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13,-13 + dc.b 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15 + dc.b 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15 + dc.b -15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15 + dc.b -15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15,-15 + dc.b 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 + dc.b 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 + dc.b -17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17 + dc.b -17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17 + dc.b 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19 + dc.b 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19 + dc.b -19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 + dc.b -19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 + dc.b 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21 + dc.b 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21 + dc.b -21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21 + dc.b -21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21 + dc.b 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23 + dc.b 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23 + dc.b -23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23 + dc.b -23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23,-23 + dc.b 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25 + dc.b 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25 + dc.b -25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25 + dc.b -25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25,-25 + dc.b 27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27 + dc.b 27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27 + dc.b -27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27 + dc.b -27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27,-27 + dc.b 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 + dc.b 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 + dc.b -29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29 + dc.b -29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29,-29 + endc ; ENABLE_SAWRECT + + + + ifeq MINIMAL +MasterVolTab0: + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0 +MasterVolTab1: + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 1 +MasterVolTab2: + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + dc.b 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + dc.b 2 +MasterVolTab3: + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1 + dc.b 1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2 + dc.b 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 + dc.b 3 +MasterVolTab4: + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + dc.b 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + dc.b 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 + dc.b 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 + dc.b 4 +MasterVolTab5: + dc.b 0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1 + dc.b 1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2 + dc.b 2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3 + dc.b 3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4 + dc.b 5 +MasterVolTab6: + dc.b 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1 + dc.b 1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2 + dc.b 3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4 + dc.b 4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5 + dc.b 6 +MasterVolTab7: + dc.b 0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1 + dc.b 1,1,1,2,2,2,2,2,2,2,2,2,3,3,3,3 + dc.b 3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5 + dc.b 5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6 + dc.b 7 +MasterVolTab8: + dc.b 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1 + dc.b 2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3 + dc.b 4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5 + dc.b 6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7 + dc.b 8 +MasterVolTab9: + dc.b 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,2 + dc.b 2,2,2,2,2,2,3,3,3,3,3,3,3,4,4,4 + dc.b 4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6 + dc.b 6,6,7,7,7,7,7,7,7,8,8,8,8,8,8,8 + dc.b 9 +MasterVolTab10: + dc.b 0,0,0,0,0,0,0,1,1,1,1,1,1,2,2,2 + dc.b 2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4 + dc.b 5,5,5,5,5,5,5,6,6,6,6,6,6,7,7,7 + dc.b 7,7,7,7,8,8,8,8,8,8,9,9,9,9,9,9 + dc.b 10 +MasterVolTab11: + dc.b 0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2 + dc.b 2,2,3,3,3,3,3,3,4,4,4,4,4,4,5,5 + dc.b 5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,8 + dc.b 8,8,8,8,8,9,9,9,9,9,9,10,10,10,10,10 + dc.b 11 +MasterVolTab12: + dc.b 0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2 + dc.b 3,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5 + dc.b 6,6,6,6,6,6,7,7,7,7,7,8,8,8,8,8 + dc.b 9,9,9,9,9,9,10,10,10,10,10,11,11,11,11,11 + dc.b 12 +MasterVolTab13: + dc.b 0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3 + dc.b 3,3,3,3,4,4,4,4,4,5,5,5,5,5,6,6 + dc.b 6,6,6,7,7,7,7,7,8,8,8,8,8,9,9,9 + dc.b 9,9,10,10,10,10,10,11,11,11,11,11,12,12,12,12 + dc.b 13 +MasterVolTab14: + dc.b 0,0,0,0,0,1,1,1,1,1,2,2,2,2,3,3 + dc.b 3,3,3,4,4,4,4,5,5,5,5,5,6,6,6,6 + dc.b 7,7,7,7,7,8,8,8,8,8,9,9,9,9,10,10 + dc.b 10,10,10,11,11,11,11,12,12,12,12,12,13,13,13,13 + dc.b 14 +MasterVolTab15: + dc.b 0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3 + dc.b 3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7 + dc.b 7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11 + dc.b 11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,14 + dc.b 15 +MasterVolTab16: + dc.b 0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3 + dc.b 4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7 + dc.b 8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11 + dc.b 12,12,12,12,13,13,13,13,14,14,14,14,15,15,15,15 + dc.b 16 +MasterVolTab17: + dc.b 0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3 + dc.b 4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8 + dc.b 8,8,9,9,9,9,10,10,10,10,11,11,11,11,12,12 + dc.b 12,13,13,13,13,14,14,14,14,15,15,15,15,16,16,16 + dc.b 17 +MasterVolTab18: + dc.b 0,0,0,0,1,1,1,1,2,2,2,3,3,3,3,4 + dc.b 4,4,5,5,5,5,6,6,6,7,7,7,7,8,8,8 + dc.b 9,9,9,9,10,10,10,10,11,11,11,12,12,12,12,13 + dc.b 13,13,14,14,14,14,15,15,15,16,16,16,16,17,17,17 + dc.b 18 +MasterVolTab19: + dc.b 0,0,0,0,1,1,1,2,2,2,2,3,3,3,4,4 + dc.b 4,5,5,5,5,6,6,6,7,7,7,8,8,8,8,9 + dc.b 9,9,10,10,10,10,11,11,11,12,12,12,13,13,13,13 + dc.b 14,14,14,15,15,15,16,16,16,16,17,17,17,18,18,18 + dc.b 19 +MasterVolTab20: + dc.b 0,0,0,0,1,1,1,2,2,2,3,3,3,4,4,4 + dc.b 5,5,5,5,6,6,6,7,7,7,8,8,8,9,9,9 + dc.b 10,10,10,10,11,11,11,12,12,12,13,13,13,14,14,14 + dc.b 15,15,15,15,16,16,16,17,17,17,18,18,18,19,19,19 + dc.b 20 +MasterVolTab21: + dc.b 0,0,0,0,1,1,1,2,2,2,3,3,3,4,4,4 + dc.b 5,5,5,6,6,6,7,7,7,8,8,8,9,9,9,10 + dc.b 10,10,11,11,11,12,12,12,13,13,13,14,14,14,15,15 + dc.b 15,16,16,16,17,17,17,18,18,18,19,19,19,20,20,20 + dc.b 21 +MasterVolTab22: + dc.b 0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5 + dc.b 5,5,6,6,6,7,7,7,8,8,8,9,9,9,10,10 + dc.b 11,11,11,12,12,12,13,13,13,14,14,14,15,15,15,16 + dc.b 16,16,17,17,17,18,18,18,19,19,19,20,20,20,21,21 + dc.b 22 +MasterVolTab23: + dc.b 0,0,0,1,1,1,2,2,2,3,3,3,4,4,5,5 + dc.b 5,6,6,6,7,7,7,8,8,8,9,9,10,10,10,11 + dc.b 11,11,12,12,12,13,13,14,14,14,15,15,15,16,16,16 + dc.b 17,17,17,18,18,19,19,19,20,20,20,21,21,21,22,22 + dc.b 23 +MasterVolTab24: + dc.b 0,0,0,1,1,1,2,2,3,3,3,4,4,4,5,5 + dc.b 6,6,6,7,7,7,8,8,9,9,9,10,10,10,11,11 + dc.b 12,12,12,13,13,13,14,14,15,15,15,16,16,16,17,17 + dc.b 18,18,18,19,19,19,20,20,21,21,21,22,22,22,23,23 + dc.b 24 +MasterVolTab25: + dc.b 0,0,0,1,1,1,2,2,3,3,3,4,4,5,5,5 + dc.b 6,6,7,7,7,8,8,8,9,9,10,10,10,11,11,12 + dc.b 12,12,13,13,14,14,14,15,15,16,16,16,17,17,17,18 + dc.b 18,19,19,19,20,20,21,21,21,22,22,23,23,23,24,24 + dc.b 25 +MasterVolTab26: + dc.b 0,0,0,1,1,2,2,2,3,3,4,4,4,5,5,6 + dc.b 6,6,7,7,8,8,8,9,9,10,10,10,11,11,12,12 + dc.b 13,13,13,14,14,15,15,15,16,16,17,17,17,18,18,19 + dc.b 19,19,20,20,21,21,21,22,22,23,23,23,24,24,25,25 + dc.b 26 +MasterVolTab27: + dc.b 0,0,0,1,1,2,2,2,3,3,4,4,5,5,5,6 + dc.b 6,7,7,8,8,8,9,9,10,10,10,11,11,12,12,13 + dc.b 13,13,14,14,15,15,16,16,16,17,17,18,18,18,19,19 + dc.b 20,20,21,21,21,22,22,23,23,24,24,24,25,25,26,26 + dc.b 27 +MasterVolTab28: + dc.b 0,0,0,1,1,2,2,3,3,3,4,4,5,5,6,6 + dc.b 7,7,7,8,8,9,9,10,10,10,11,11,12,12,13,13 + dc.b 14,14,14,15,15,16,16,17,17,17,18,18,19,19,20,20 + dc.b 21,21,21,22,22,23,23,24,24,24,25,25,26,26,27,27 + dc.b 28 +MasterVolTab29: + dc.b 0,0,0,1,1,2,2,3,3,4,4,4,5,5,6,6 + dc.b 7,7,8,8,9,9,9,10,10,11,11,12,12,13,13,14 + dc.b 14,14,15,15,16,16,17,17,18,18,19,19,19,20,20,21 + dc.b 21,22,22,23,23,24,24,24,25,25,26,26,27,27,28,28 + dc.b 29 +MasterVolTab30: + dc.b 0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7 + dc.b 7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14 + dc.b 15,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22 + dc.b 22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29 + dc.b 30 +MasterVolTab31: + dc.b 0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7 + dc.b 7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15 + dc.b 15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22 + dc.b 23,23,24,24,25,25,26,26,27,27,28,28,29,29,30,30 + dc.b 31 +MasterVolTab32: + dc.b 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7 + dc.b 8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15 + dc.b 16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23 + dc.b 24,24,25,25,26,26,27,27,28,28,29,29,30,30,31,31 + dc.b 32 +MasterVolTab33: + dc.b 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7 + dc.b 8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15 + dc.b 16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24 + dc.b 24,25,25,26,26,27,27,28,28,29,29,30,30,31,31,32 + dc.b 33 +MasterVolTab34: + dc.b 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7 + dc.b 8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16 + dc.b 17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24 + dc.b 25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33 + dc.b 34 +MasterVolTab35: + dc.b 0,0,1,1,2,2,3,3,4,4,5,6,6,7,7,8 + dc.b 8,9,9,10,10,11,12,12,13,13,14,14,15,15,16,16 + dc.b 17,18,18,19,19,20,20,21,21,22,22,23,24,24,25,25 + dc.b 26,26,27,27,28,28,29,30,30,31,31,32,32,33,33,34 + dc.b 35 +MasterVolTab36: + dc.b 0,0,1,1,2,2,3,3,4,5,5,6,6,7,7,8 + dc.b 9,9,10,10,11,11,12,12,13,14,14,15,15,16,16,17 + dc.b 18,18,19,19,20,20,21,21,22,23,23,24,24,25,25,26 + dc.b 27,27,28,28,29,29,30,30,31,32,32,33,33,34,34,35 + dc.b 36 +MasterVolTab37: + dc.b 0,0,1,1,2,2,3,4,4,5,5,6,6,7,8,8 + dc.b 9,9,10,10,11,12,12,13,13,14,15,15,16,16,17,17 + dc.b 18,19,19,20,20,21,21,22,23,23,24,24,25,26,26,27 + dc.b 27,28,28,29,30,30,31,31,32,32,33,34,34,35,35,36 + dc.b 37 +MasterVolTab38: + dc.b 0,0,1,1,2,2,3,4,4,5,5,6,7,7,8,8 + dc.b 9,10,10,11,11,12,13,13,14,14,15,16,16,17,17,18 + dc.b 19,19,20,20,21,21,22,23,23,24,24,25,26,26,27,27 + dc.b 28,29,29,30,30,31,32,32,33,33,34,35,35,36,36,37 + dc.b 38 +MasterVolTab39: + dc.b 0,0,1,1,2,3,3,4,4,5,6,6,7,7,8,9 + dc.b 9,10,10,11,12,12,13,14,14,15,15,16,17,17,18,18 + dc.b 19,20,20,21,21,22,23,23,24,24,25,26,26,27,28,28 + dc.b 29,29,30,31,31,32,32,33,34,34,35,35,36,37,37,38 + dc.b 39 +MasterVolTab40: + dc.b 0,0,1,1,2,3,3,4,5,5,6,6,7,8,8,9 + dc.b 10,10,11,11,12,13,13,14,15,15,16,16,17,18,18,19 + dc.b 20,20,21,21,22,23,23,24,25,25,26,26,27,28,28,29 + dc.b 30,30,31,31,32,33,33,34,35,35,36,36,37,38,38,39 + dc.b 40 +MasterVolTab41: + dc.b 0,0,1,1,2,3,3,4,5,5,6,7,7,8,8,9 + dc.b 10,10,11,12,12,13,14,14,15,16,16,17,17,18,19,19 + dc.b 20,21,21,22,23,23,24,24,25,26,26,27,28,28,29,30 + dc.b 30,31,32,32,33,33,34,35,35,36,37,37,38,39,39,40 + dc.b 41 +MasterVolTab42: + dc.b 0,0,1,1,2,3,3,4,5,5,6,7,7,8,9,9 + dc.b 10,11,11,12,13,13,14,15,15,16,17,17,18,19,19,20 + dc.b 21,21,22,22,23,24,24,25,26,26,27,28,28,29,30,30 + dc.b 31,32,32,33,34,34,35,36,36,37,38,38,39,40,40,41 + dc.b 42 +MasterVolTab43: + dc.b 0,0,1,2,2,3,4,4,5,6,6,7,8,8,9,10 + dc.b 10,11,12,12,13,14,14,15,16,16,17,18,18,19,20,20 + dc.b 21,22,22,23,24,24,25,26,26,27,28,28,29,30,30,31 + dc.b 32,32,33,34,34,35,36,36,37,38,38,39,40,40,41,42 + dc.b 43 +MasterVolTab44: + dc.b 0,0,1,2,2,3,4,4,5,6,6,7,8,8,9,10 + dc.b 11,11,12,13,13,14,15,15,16,17,17,18,19,19,20,21 + dc.b 22,22,23,24,24,25,26,26,27,28,28,29,30,30,31,32 + dc.b 33,33,34,35,35,36,37,37,38,39,39,40,41,41,42,43 + dc.b 44 +MasterVolTab45: + dc.b 0,0,1,2,2,3,4,4,5,6,7,7,8,9,9,10 + dc.b 11,11,12,13,14,14,15,16,16,17,18,18,19,20,21,21 + dc.b 22,23,23,24,25,26,26,27,28,28,29,30,30,31,32,33 + dc.b 33,34,35,35,36,37,37,38,39,40,40,41,42,42,43,44 + dc.b 45 +MasterVolTab46: + dc.b 0,0,1,2,2,3,4,5,5,6,7,7,8,9,10,10 + dc.b 11,12,12,13,14,15,15,16,17,17,18,19,20,20,21,22 + dc.b 23,23,24,25,25,26,27,28,28,29,30,30,31,32,33,33 + dc.b 34,35,35,36,37,38,38,39,40,40,41,42,43,43,44,45 + dc.b 46 +MasterVolTab47: + dc.b 0,0,1,2,2,3,4,5,5,6,7,8,8,9,10,11 + dc.b 11,12,13,13,14,15,16,16,17,18,19,19,20,21,22,22 + dc.b 23,24,24,25,26,27,27,28,29,30,30,31,32,33,33,34 + dc.b 35,35,36,37,38,38,39,40,41,41,42,43,44,44,45,46 + dc.b 47 +MasterVolTab48: + dc.b 0,0,1,2,3,3,4,5,6,6,7,8,9,9,10,11 + dc.b 12,12,13,14,15,15,16,17,18,18,19,20,21,21,22,23 + dc.b 24,24,25,26,27,27,28,29,30,30,31,32,33,33,34,35 + dc.b 36,36,37,38,39,39,40,41,42,42,43,44,45,45,46,47 + dc.b 48 +MasterVolTab49: + dc.b 0,0,1,2,3,3,4,5,6,6,7,8,9,9,10,11 + dc.b 12,13,13,14,15,16,16,17,18,19,19,20,21,22,22,23 + dc.b 24,25,26,26,27,28,29,29,30,31,32,32,33,34,35,35 + dc.b 36,37,38,39,39,40,41,42,42,43,44,45,45,46,47,48 + dc.b 49 +MasterVolTab50: + dc.b 0,0,1,2,3,3,4,5,6,7,7,8,9,10,10,11 + dc.b 12,13,14,14,15,16,17,17,18,19,20,21,21,22,23,24 + dc.b 25,25,26,27,28,28,29,30,31,32,32,33,34,35,35,36 + dc.b 37,38,39,39,40,41,42,42,43,44,45,46,46,47,48,49 + dc.b 50 +MasterVolTab51: + dc.b 0,0,1,2,3,3,4,5,6,7,7,8,9,10,11,11 + dc.b 12,13,14,15,15,16,17,18,19,19,20,21,22,23,23,24 + dc.b 25,26,27,27,28,29,30,31,31,32,33,34,35,35,36,37 + dc.b 38,39,39,40,41,42,43,43,44,45,46,47,47,48,49,50 + dc.b 51 +MasterVolTab52: + dc.b 0,0,1,2,3,4,4,5,6,7,8,8,9,10,11,12 + dc.b 13,13,14,15,16,17,17,18,19,20,21,21,22,23,24,25 + dc.b 26,26,27,28,29,30,30,31,32,33,34,34,35,36,37,38 + dc.b 39,39,40,41,42,43,43,44,45,46,47,47,48,49,50,51 + dc.b 52 +MasterVolTab53: + dc.b 0,0,1,2,3,4,4,5,6,7,8,9,9,10,11,12 + dc.b 13,14,14,15,16,17,18,19,19,20,21,22,23,24,24,25 + dc.b 26,27,28,28,29,30,31,32,33,33,34,35,36,37,38,38 + dc.b 39,40,41,42,43,43,44,45,46,47,48,48,49,50,51,52 + dc.b 53 +MasterVolTab54: + dc.b 0,0,1,2,3,4,5,5,6,7,8,9,10,10,11,12 + dc.b 13,14,15,16,16,17,18,19,20,21,21,22,23,24,25,26 + dc.b 27,27,28,29,30,31,32,32,33,34,35,36,37,37,38,39 + dc.b 40,41,42,43,43,44,45,46,47,48,48,49,50,51,52,53 + dc.b 54 +MasterVolTab55: + dc.b 0,0,1,2,3,4,5,6,6,7,8,9,10,11,12,12 + dc.b 13,14,15,16,17,18,18,19,20,21,22,23,24,24,25,26 + dc.b 27,28,29,30,30,31,32,33,34,35,36,36,37,38,39,40 + dc.b 41,42,42,43,44,45,46,47,48,48,49,50,51,52,53,54 + dc.b 55 +MasterVolTab56: + dc.b 0,0,1,2,3,4,5,6,7,7,8,9,10,11,12,13 + dc.b 14,14,15,16,17,18,19,20,21,21,22,23,24,25,26,27 + dc.b 28,28,29,30,31,32,33,34,35,35,36,37,38,39,40,41 + dc.b 42,42,43,44,45,46,47,48,49,49,50,51,52,53,54,55 + dc.b 56 +MasterVolTab57: + dc.b 0,0,1,2,3,4,5,6,7,8,8,9,10,11,12,13 + dc.b 14,15,16,16,17,18,19,20,21,22,23,24,24,25,26,27 + dc.b 28,29,30,31,32,32,33,34,35,36,37,38,39,40,40,41 + dc.b 42,43,44,45,46,47,48,48,49,50,51,52,53,54,55,56 + dc.b 57 +MasterVolTab58: + dc.b 0,0,1,2,3,4,5,6,7,8,9,9,10,11,12,13 + dc.b 14,15,16,17,18,19,19,20,21,22,23,24,25,26,27,28 + dc.b 29,29,30,31,32,33,34,35,36,37,38,38,39,40,41,42 + dc.b 43,44,45,46,47,48,48,49,50,51,52,53,54,55,56,57 + dc.b 58 +MasterVolTab59: + dc.b 0,0,1,2,3,4,5,6,7,8,9,10,11,11,12,13 + dc.b 14,15,16,17,18,19,20,21,22,23,23,24,25,26,27,28 + dc.b 29,30,31,32,33,34,35,35,36,37,38,39,40,41,42,43 + dc.b 44,45,46,47,47,48,49,50,51,52,53,54,55,56,57,58 + dc.b 59 +MasterVolTab60: + dc.b 0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 + dc.b 15,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29 + dc.b 30,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44 + dc.b 45,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59 + dc.b 60 +MasterVolTab61: + dc.b 0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 + dc.b 15,16,17,18,19,20,20,21,22,23,24,25,26,27,28,29 + dc.b 30,31,32,33,34,35,36,37,38,39,40,40,41,42,43,44 + dc.b 45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60 + dc.b 61 +MasterVolTab62: + dc.b 0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 + dc.b 15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 + dc.b 31,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45 + dc.b 46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61 + dc.b 62 +MasterVolTab63: + dc.b 0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 + dc.b 15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 + dc.b 31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46 + dc.b 47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62 + dc.b 63 +MasterVolTab64: + dc.b 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + dc.b 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 + dc.b 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47 + dc.b 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63 + dc.b 64 + even + endc ; !MINIMAL + + +***************************************************************************** + + section __MERGED,bss + + rsreset +; Antiriad - put this at the start of mt_data to avoid alignment issues with the rs.b near the end +mt_PerFineTune rs.w 16 +mt_PeriodTable rs.w 0 +mt_Tuning0 rs.w 36 +mt_Tuning1 rs.w 36 +mt_Tuning2 rs.w 36 +mt_Tuning3 rs.w 36 +mt_Tuning4 rs.w 36 +mt_Tuning5 rs.w 36 +mt_Tuning6 rs.w 36 +mt_Tuning7 rs.w 36 +mt_TuningM8 rs.w 36 +mt_TuningM7 rs.w 36 +mt_TuningM6 rs.w 36 +mt_TuningM5 rs.w 36 +mt_TuningM4 rs.w 36 +mt_TuningM3 rs.w 36 +mt_TuningM2 rs.w 36 +mt_TuningM1 rs.w 36 +; Antiriad - end of periodtable + +; Antiriad - vibrato sine table +mt_VibratoSineTable rs.b 16*64 +mt_VibratoSineTable_End rs.b 0 +; Antiriad - end of vibrato sine table + +mt_chan1 rs.b n_sizeof +mt_chan2 rs.b n_sizeof +mt_chan3 rs.b n_sizeof +mt_chan4 rs.b n_sizeof +mt_SampleStarts rs.l 31 +mt_mod rs.l 1 +mt_oldLev6 rs.l 1 +mt_timerval rs.l 1 +mt_oldtimers rs.b 4 +mt_Lev6Int rs.l 1 +mt_Lev6Ena rs.w 1 +mt_PatternPos rs.w 1 +mt_PBreakPos rs.w 1 +mt_PosJumpFlag rs.b 1 +mt_PBreakFlag rs.b 1 +mt_Speed rs.b 1 +mt_Counter rs.b 1 +mt_SongPos rs.b 1 +mt_PattDelTime rs.b 1 +mt_PattDelTime2 rs.b 1 + + ifeq MINIMAL +mt_SilCntValid rs.b 1 +mt_MasterVolTab rs.l 1 + endc ; !MINIMAL +mt_Enable rs.b 1 ; exported as _mt_Enable +mt_E8Trigger rs.b 1 ; exported as _mt_E8Trigger + ifeq MINIMAL +mt_MusicChannels rs.b 1 ; exported as _mt_MusicChannels +mt_SongEnd rs.b 1 ; exported as _mt_SongEnd + endc ; !MINIMAL + ifne ENABLE_VUMETER +mt_VUMeter rs.b 1 ; exported as _mt_VUMeter + endc ;ENABLE_VUMETER + + +mt_data: + ds.b mt_Enable + xdef _mt_Enable +_mt_Enable: + ds.b 1 + xdef _mt_E8Trigger +_mt_E8Trigger: + ds.b 1 + + ifeq MINIMAL + xdef _mt_MusicChannels +_mt_MusicChannels: + ds.b 1 + xdef _mt_SongEnd +_mt_SongEnd: + ds.b 1 + endc ; !MINIMAL + + ifne ENABLE_VUMETER + xdef _mt_VUMeter +_mt_VUMeter: + ds.b 1 + endc ;ENABLE_VUMETER