** ** XModule replay routine 0.1 ** ** Copyright (C) 1995,96 Bernardo Innocenti ** ** DEBUG_VERSION EQU 0 ; Debug Code On/Off USE_CALIBRATION EQU 0 ; Calibration On/Off STAND_ALONE EQU 0 ; Start without XModule MAXCHANNELS EQU 32 MACHINE 68020 VersionTag MACRO dc.b '$VER: XModule_Replay 0.1 (6.1.96) © 1995,96 by Bernardo Innocenti.',$a endm incdir Include: include exec/types.i include exec/io.i include exec/macros.i include exec/memory.i include exec/tasks.i include exec/execbase.i include exec/funcdef.i include hardware/intbits.i include hardware/custom.i include devices/audio.i include dos/dos.i include dos/dosextens.i include graphics/gfxbase.i include libraries/songclass.i include Guru.i include Player.i xref _DATA_BAS_ custom EQU $dff000 ShowDebug MACRO IFNE '\2','' move.l \2,-(sp) ENDC lea .msg\@(pc),a0 move.l sp,a1 ; Arguments array xref KPrintF jsr KPrintF IFNE '\2','' lea 4(sp),sp ; Fix stack ENDC bra.s .cont .msg\@ dc.b \1,$a,0 even .cont ENDM * An harmless Enforcer hit to help debugging operations :-) Enforcer MACRO suba.l \1,\1 clr.l (\1) ENDM *************************************************************************** * Start *************************************************************************** SECTION XMPlay,code Start: lea _DATA_BAS_+32766,a4 NEAR a4 * Initialize SysBase move.l 4.w,a6 move a6,_SysBase(a4) * D3 is the return code for the startup message moveq #RETURN_OK,d3 * Find this task's process structure suba.l a1,a1 JSRLIB FindTask move.l d0,MyTask(a4) move.l d0,a2 * Calculate ClockBase move.l ex_EClockFrequency(a6),d0 move.l d0,d1 lsl.l #2,d1 ; #3 for panning support add.l d1,d0 move.l d0,ClockBase ; Clock constant * Open graphics.library lea GFXName(pc),a1 moveq.l #0,d0 ; Library version JSRLIB OpenLibrary move.l d0,_GFXBase(a4) bne.s .gfx_ok move.l #ERROR_INVALID_RESIDENT_LIBRARY,d3 .gfx_ok IFEQ STAND_ALONE * Wait for startup message lea pr_MsgPort(a2),a2 ; a2 still contains our Process structure. move.l a2,a0 JSRLIB WaitPort * Get startup message move.l a2,a0 JSRLIB GetMsg move.l d0,a1 * Get parent task address move.l MN_REPLYPORT(a1),a0 move.l MP_SIGTASK(a0),ParentTask(a4) * Reply startup message move.l d3,pcmd_Err(a1) ; Put returncode JSRLIB ReplyMsg ENDC STAND_ALONE tst.l d3 ; Error? bne.s Exit * Go ahead to MainLoop *************************************************************************** * Main loop *************************************************************************** MainLoop: IFEQ STAND_ALONE moveq #0,d1 moveq #0,d0 move.b MP_SIGBIT(a2),d1 bset.l d1,d0 bset.l #SIGBREAKB_CTRL_C,d0 JSRLIB Wait move.l d0,d2 ; Save signal bits * Check message port .checkmsg move.l a2,a0 JSRLIB GetMsg tst.l d0 beq.s .nomsg move.l d0,a3 ELSE moveq #0,d0 ENDC STAND_ALONE * Command Dispatcher move.l pcmd_ID(a3),d0 cmp.l #PCMD_COUNT,d0 ; Check if command is supported bge.s .unknown_msg * Switch (pcmd_ID) lsl.l #2,d0 move.l a3,a0 move.l .jumptable(pc,d0),a1 jsr (a1) .reply_msg IFEQ STAND_ALONE move.l d0,pcmd_Err(a3) ; Set returncode move.l a3,a1 JSRLIB ReplyMsg ; Return message to parent... bra.s .checkmsg ; ...and check for more messages ELSE bra.s Exit ENDC STAND_ALONE .unknown_msg moveq #PERR_UNKNOWN_COMMAND,d0 bra.s .reply_msg .jumptable dc.l CmdInit dc.l CmdPlay .nomsg * Check for abort signal btst.l #SIGBREAKB_CTRL_C,d2 beq.s MainLoop * Note: I'm falling down to Exit. *************************************************************************** * Cleanup and Exit *************************************************************************** Exit: * Close graphics.library move.l _GFXBase(a4),d0 beq.s .noclose move.l d0,a1 JSRLIB CloseLibrary .noclose * Exit point. * This rts will remove our process and call UnLoadSeg() on us. rts VersionTag GFXName dc.b 'graphics.library',0 AudioDevName dc.b 'audio.device',0 EVEN *************************************************************************** * LONG error = CmdInit (struct PlayerCmd *pcmd, struct ExecBase *SysBase) * D0 A0 A6 *************************************************************************** CmdInit move.l a3,-(a7) ; Save a3 move.l pcmd_Data(a0),a3 ; get SongInfo * Allocate audio channels moveq #0,d0 moveq #0,d1 lea AudioDevName(pc),a0 lea AllocIORequest(a4),a1 JSRLIB OpenDevice tst.l d0 bne .AllocFail ; Error * Set audio interrupts move.w AttnFlags(a6),d0 btst.l #AFB_68020,d0 ; >= 68020 CPU ? bne.s .CPU68020 ; yes ! .CPU68000 moveq #INTB_AUD0,d0 lea Audio0IRQ_000(a4),a1 JSRLIB SetIntVector ; set new Audio0-IRQ move.l d0,_OldAudio0(a4) moveq #INTB_AUD1,d0 lea Audio1IRQ_000(a4),a1 JSRLIB SetIntVector ; set new Audio1-IRQ move.l d0,_OldAudio1(a4) bra.s .CalcScale .CPU68020 moveq #INTB_AUD0,d0 lea Audio0IRQ_020(a4),a1 JSRLIB SetIntVector ; set new Audio0-IRQ move.l d0,_OldAudio0(a4) moveq #INTB_AUD1,d0 lea Audio1IRQ_020(a4),a1 JSRLIB SetIntVector ; set new Audio1-IRQ move.l d0,_OldAudio1(a4) .CalcScale * Initialize ScaleFactor move.w si_MaxTracks(a3),d1 move.w d1,ChannelNum(a4) lsr.w #1,d1 ; !!! moveq #32,d0 ; max. channels (16 for no panning!) divu d1,d0 move.w d0,ScaleFactor ; set ScaleFactor * Initialize player. Warning: these calls will trash all registrers! movem.l d2-d7/a2-a6,-(a7) jsr InitSVolTable(pc) jsr InitBoostTable(pc) jsr InitTracksNChannels(pc) bsr NewMixFreq ; MixPeriod berechnen movem.l (sp)+,d2-d7/a2-a6 * Audio hardware twiddling lea custom,a0 move.w #$000f,dmacon(a0) ; Audio-DMA aus move.w #$00ff,adkcon(a0) move.w #$0780,intreq(a0) ; Audio-Req. löschen move.w #$0780,intena(a0) ; Audio-Int. aus moveq #RETURN_OK,d0 move.l (a7)+,a3 rts .AllocFail moveq #PERR_NO_AUDIO,d0 move.l (a7)+,a3 rts *************************************************************************** * LONG error = CmdPlay (struct PlayerCmd *pcmd, struct ExecBase *SysBase) * D0 A0 A6 *************************************************************************** CmdPlay move.l pcmd_Data(a0),a0 ; get SongInfo move.l a0,SongInfo move.w si_MaxTracks(a0),mt_NumCh(a4) ; set channels lea mt_ChanTemp,a0 moveq #MAXCHANNELS-1,d0 moveq #0,d1 mt_clear move.l d1,(a0)+ move.l d1,(a0)+ move.l d1,(a0)+ move.l d1,(a0)+ move.l d1,(a0)+ move.l d1,(a0)+ move.l d1,(a0)+ move.l d1,(a0)+ move.l d1,(a0)+ move.l d1,(a0)+ dbra d0,mt_clear bsr mt_init2 moveq #RETURN_OK,d0 rts FAR *************************************************************************** * void SetTimer (timeval) * D0 *************************************************************************** SetTimer RTS ; !!! *************************************************************************** * void SetTimer (void) * *************************************************************************** SongEnd RTS ; !!! *-----------------------------------------------------------------------* ; ; Next Pattern NPatt ; move.l dtg_StopInt(a5),a0 ; jsr (a0) !!!!!!!!!!!!!!!!!!! clr.w mt_counter clr.w mt_PBreakPos clr.b mt_PosJumpFlag clr.w mt_PatternPos addq.w #1,mt_SongPos move.w mt_MaxPos,d0 cmp.w mt_SongPos,d0 bne.s NEnd clr.w mt_SongPos NEnd ; move.l dtg_StartInt(a5),a0 ; jsr (a0) !!!!!!!!!!!!!!!!!!! rts *-----------------------------------------------------------------------* ; ; Previous Pattern PPatt ; move.l dtg_StopInt(a5),a0 !!!!!!!!!!!!!!!!!!! ; jsr (a0) clr.w mt_counter clr.w mt_PBreakPos clr.b mt_PosJumpFlag clr.w mt_PatternPos subq.w #1,mt_SongPos bcc.s PEnd move.w mt_MaxPos,d0 subq.w #1,d0 move.w d0,mt_SongPos PEnd ; move.l dtg_StartInt(a5),a0 !!!!!!!!!!!!!!!!!! ; jsr (a0) rts *-----------------------------------------------------------------------* ; ; TakeTracker - Replay ;******************************************** ;* ----- Protracker V1.1B Playroutine ----- * ;* Lars "Zap" Hamre/Amiga Freelancers 1991 * ;* Bekkeliveien 10, N-2010 STRØMMEN, Norway * ;******************************************** ;---- Tempo ---- SetTempo move.l _SysBase,a4 move.l ex_EClockFrequency(a4),d1 add.l d1,d1 add.l d1,d1 add.l ex_EClockFrequency(a4),d1 lsr.l #1,d1 cmp.w #32,d0 bhs.s setemsk moveq #32,d0 setemsk divu d0,d1 move.l d1,d0 jsr SetTimer rts ;---- Playroutine ---- STRUCTURE PlayNote,0 UBYTE pn_Note UBYTE pn_Inst UBYTE pn_Cmd UBYTE pn_Val APTR pn_Start ULONG pn_Length LONG pn_LoopStart LONG pn_Replen ULONG pn_WaveStart ULONG pn_RealLength UWORD pn_Period UWORD pn_WantedPeriod UBYTE pn_FineTune UBYTE pn_Volume UBYTE pn_TonePortDirec UBYTE pn_TonePortSpeed UBYTE pn_VibratoCmd UBYTE pn_VibratoPos UBYTE pn_TremoloCmd UBYTE pn_TremoloPos UBYTE pn_WaveControl UBYTE pn_GlissFunk UBYTE pn_SampleOffset UBYTE pn_PattPos UBYTE pn_LoopCount UBYTE pn_FunkOffset LABEL pn_SIZEOF mt_init2 MOVE.L songinfo,a0 move.w si_Length(a0),mt_MaxPos moveq #0,d0 MOVE.W si_GlobalTempo(a0),d0 BSR SetTempo MOVE.W si_GlobalSpeed(a0),mt_speed CLR.W mt_counter CLR.W mt_SongPos CLR.W mt_PBreakPos CLR.B mt_PosJumpFlag CLR.B mt_PBreakFlag CLR.B mt_LowMask CLR.B mt_PattDelTime CLR.B mt_PattDelTime2 CLR.B mt_Reset CLR.W mt_PatternPos RTS mt_music MOVEM.L D2-D7/A2-A6,-(SP) TST.B mt_Reset BEQ.S mt_mus JSR SongEnd SUBQ.B #1,mt_Reset BEQ mt_exit BSR mt_init2 CLR.B mt_Reset BRA mt_exit mt_mus ADDQ.W #1,mt_counter MOVE.W mt_counter,d0 CMP.W mt_speed,d0 BLO.S mt_NoNewNote CLR.W mt_counter TST.B mt_PattDelTime2 BEQ mt_GetNewNote BSR.S mt_NoNewAllChannels BRA mt_dskip mt_NoNewNote BSR.S mt_NoNewAllChannels BRA mt_NoNewPosYet mt_NoNewAllChannels move.l NoteStructure,a5 lea mt_ChanTemp,a6 move.w mt_NumCh,d5 subq.w #1,d5 mt_NoNewLoop bsr mt_CheckEfx lea NoteChannel_SIZE(a5),a5 lea pn_SIZEOF(a6),a6 dbra d5,mt_NoNewLoop RTS mt_GetNewNote move.l songinfo,a0 move.l si_Patt(a0),a1 move.l si_Sequence(a0),a0 moveq #0,d0 move.w mt_SongPos,d0 add.w d0,d0 move.w (a0,d0.w),d0 ; Put current patt number in d0 mulu #pa_SIZEOF,d0 move.l pa_Notes(a0,d0),a0 ; Get pointer to tracks array move.l NoteStructure,a5 lea mt_ChanTemp,a6 move.w mt_NumCh,d5 subq.w #1,d5 mt_GetNewLoop bsr mt_PlayVoice lea NoteChannel_SIZE(a5),a5 lea pn_SIZEOF(a6),a6 dbra d5,mt_GetNewLoop BRA mt_dskip mt_PlayVoice CMP.W #NCHD_Ignore,nch_Stereo(a5) BEQ mt_PerNop TST.L (A6) BNE.S mt_plvskip BSR mt_PerNop mt_plvskip move.l (a0)+,a4 moveq #0,d0 move.w d5,d0 add.l d0,d0 add.l d0,d0 move.l (a4,d0),a4 ; Pointer to channel moveq #0,d0 move.w mt_PatternPos,d0 add.l d0,d0 add.l d0,d0 move.l (a4,d0),(a6) ; Current note in (a6) moveq #0,d2 move.b note_Inst(a6),d2 ; Instrument number in d2 TST.W d2 BEQ mt_SetRegs MOVEQ #0,d3 * Retrieve Instrument structure move.l songinfo,a1 lea si_Instr(a1),a1 mulu #in_SIZEOF,d2 lea (a1,d2),a1 move.l in_SampleData(a1),pn_Start(a6) move.l in_Length(a1),pn_Length(a6) move.l in_Length(a1),pn_RealLength(a6) move.b in_FineTune+1(a1),pn_FineTune(a6) move.b in_Volume(a1),pn_Volume(a6) move.l in_Repeat(a1),d3 ; Get repeat tst.l D3 beq.s mt_NoLoop move.l pn_Start(a6),d2 ; Get start add.l D3,D2 ; Add repeat move.l D2,pn_LoopStart(a6) move.l D2,pn_WaveStart(a6) move.l in_Repeat(a1),d0 ; Get repeat add.l in_Replen(a1),d0 ; Add replen move.l d0,pn_Length(A6) move.l in_Replen(a1),pn_Replen(a6) ; Save replen MOVEQ #0,D0 MOVE.B pn_Volume(A6),D0 move.w d0,nch_Volume(a5) bset.b #NCHB_Volume,nch_Changed(a5) BRA.S mt_SetRegs mt_NoLoop MOVE.L pn_Start(a6),d2 ADD.L D3,D2 MOVE.L D2,pn_LoopStart(A6) MOVE.L D2,pn_WaveStart(A6) MOVE.L in_Replen(a1),pn_Replen(a6) ; Save replen MOVEQ #0,D0 MOVE.B pn_Volume(A6),D0 move.w d0,nch_Volume(a5) bset.b #NCHB_Volume,nch_Changed(a5) mt_SetRegs move.b pn_Note(a6),d0 beq mt_CheckMoreEfx2 ; If no note move.w pn_Cmd(a6),D0 AND.W #$FFF0,D0 CMP.W #$0E50,D0 ; Check for E5 beq.s mt_DoSetFineTune move.b pn_Cmd(A6),D0 cmp.b #EFF_TONEPORTAMENTO,d0 ; TonePortamento beq.s mt_ChkTonePorta cmp.b #EFF_TONEPVOLSLIDE,d0 beq.s mt_ChkTonePorta cmp.b #EFF_SAMPLEOFFSET,d0 ; Sample Offset BNE.S mt_SetPeriod BSR mt_CheckMoreEfx BRA.S mt_SetPeriod mt_DoSetFineTune bsr mt_SetFineTune bra.s mt_SetPeriod mt_ChkTonePorta bsr mt_SetTonePorta bra mt_CheckMoreEfx2 mt_SetPeriod MOVEM.L D0-D1/A0-A1,-(SP) moveq #0,d1 move.b pn_Note(a6),d1 ; Find note period sub.b #24,d1 ; Less octaves!!! add.l d1,d1 ; Look up period table move.l d1,d0 lea mt_PeriodTable,a1 MOVEQ #0,D1 move.b pn_FineTune(a6),d1 MULU #MAXNOTES*2,D1 ADD.L D1,A1 move.w (a1,d0.w),pn_Period(a6) movem.l (sp)+,d0-d1/a0-a1 MOVE.W 2(A6),D0 AND.W #$0FF0,D0 CMP.W #$0ED0,D0 ; Notedelay BEQ mt_CheckMoreEfx2 BTST #2,pn_WaveControl(A6) BNE.S mt_vibnoc CLR.B pn_VibratoPos(A6) mt_vibnoc BTST #6,pn_WaveControl(A6) BNE.S mt_trenoc CLR.B pn_TremoloPos(A6) mt_trenoc move.l pn_Start(a6),nch_SampleStart(a5) move.l pn_Length(a6),d0 move.l d0,nch_SampleLength(a5) bset.b #NCHB_Sample,nch_Changed(a5) move.w pn_Period(A6),nch_Frequency(a5) bset.b #NCHB_Frequency,nch_Changed(a5) mt_CheckMoreEfx2 move.l pn_LoopStart(A6),nch_RepeatStart(a5) move.l pn_Replen(A6),d0 move.l d0,nch_RepeatLength(a5) bset.b #NCHB_Repeat,nch_Changed(a5) bra mt_CheckMoreEfx mt_dskip MOVE.W mt_rsize,d0 ; !!! ADD.W d0,mt_PatternPos MOVE.B mt_PattDelTime,d0 BEQ.S mt_dskc MOVE.B d0,mt_PattDelTime2 CLR.B mt_PattDelTime mt_dskc TST.B mt_PattDelTime2 BEQ.S mt_dska SUBQ.B #1,mt_PattDelTime2 BEQ.S mt_dska MOVE.W mt_rsize,D0 SUB.W D0,mt_PatternPos mt_dska TST.B mt_PBreakFlag BEQ.S mt_nnpysk SF mt_PBreakFlag MOVEQ #0,D0 MOVE.W mt_PBreakPos,D0 CLR.W mt_PBreakPos MULU mt_rsize,D0 MOVE.W D0,mt_PatternPos mt_nnpysk MOVE.W mt_PatternPos,d0 CMP.W mt_psize,d0 BLO.S mt_NoNewPosYet mt_NextPosition MOVE.W mt_PBreakPos,d0 MULU mt_rsize,d0 MOVE.W D0,mt_PatternPos CLR.W mt_PBreakPos CLR.B mt_PosJumpFlag ADDQ.W #1,mt_SongPos MOVE.W mt_SongPos,d1 CMP.W mt_MaxPos,d1 BLO.S mt_NoNewPosYet MOVE.W mt_StartPos,mt_SongPos MOVE.B #2,mt_Reset mt_NoNewPosYet TST.B mt_PosJumpFlag BNE.S mt_NextPosition jsr NoteSignal mt_exit MOVEM.L (SP)+,D2-D7/A2-A6 RTS mt_CheckEfx CMP.W #NCHD_Ignore,nch_Stereo(a5) BEQ mt_Return BSR mt_UpdateFunk moveq #0,d0 move.b pn_Cmd(a6),d0 beq.s mt_PerNop cmpi.b #EFF_COUNT,d0 bge.s mt_PerNop move.l efftable(pc),a0 add.l d0,d0 add.l d0,d0 move.l (a0,d0),a0 jmp (a0) SetBack move.w pn_Period(a6),nch_Frequency(a5) bset.b #NCHB_Frequency,nch_Changed(a5) mt_Return RTS efftable dc.l mt_PerNop ; EFF_NULL dc.l mt_PortaUp ; EFF_PORTAMENTOUP dc.l mt_PortaDown ; EFF_PORTAMENTODOWN dc.l mt_TonePortamento ; EFF_TONEPORTAMENTO dc.l mt_Vibrato ; EFF_VIBRATO dc.l mt_TonePlusVolSlide ; EFF_TONEPVOLSLIDE dc.l mt_VibratoPlusVolSlide ; EFF_VIBRATOVOLSLIDE dc.l mt_Tremolo ; EFF_TREMOLO dc.l mt_PerNop ; EFF_UNUSED dc.l mt_PerNop ; EFF_SAMPLEOFFSET dc.l mt_VolumeSlide ; EFF_VOLSLIDE dc.l mt_PerNop ; EFF_POSJUMP dc.l mt_PerNop ; EFF_SETVOLUME dc.l mt_PerNop ; EFF_PATTERNBREAK dc.l mt_E_Commands ; EFF_MISC dc.l mt_PerNop ; EFF_SETSPEED dc.l mt_PerNop ; EFF_SETTEMPO dc.l mt_Arpeggio ; EFF_ARPEGGIO mt_PerNop move.w pn_Period(A6),nch_Frequency(a5) bset.b #NCHB_Frequency,nch_Changed(a5) RTS mt_Arpeggio MOVEQ #0,D0 MOVE.W mt_counter,D0 DIVS #3,D0 SWAP D0 CMP.W #0,D0 BEQ.S mt_Arpeggio2 CMP.W #2,D0 BEQ.S mt_Arpeggio1 MOVEQ #0,D0 MOVE.B pn_Val(A6),D0 LSR.B #4,D0 BRA.S mt_Arpeggio3 mt_Arpeggio1 MOVEQ #0,D0 MOVE.B pn_Val(A6),D0 AND.B #15,D0 BRA.S mt_Arpeggio3 mt_Arpeggio2 MOVE.W pn_Period(A6),D2 BRA.S mt_Arpeggio4 mt_Arpeggio3 ASL.W #1,D0 MOVEQ #0,D1 MOVE.B pn_FineTune(A6),D1 MULU #36*2,D1 LEA mt_PeriodTable,A0 ADD.L D1,A0 MOVEQ #0,D1 MOVE.W pn_Period(A6),D1 MOVEQ #35,D3 ; bugfix !!! mt_arploop MOVE.W (A0,D0.W),D2 CMP.W (A0),D1 BHS.S mt_Arpeggio4 ADDQ.L #2,A0 DBRA D3,mt_arploop RTS mt_Arpeggio4 move.w d2,nch_Frequency(a5) bset.b #NCHB_Frequency,nch_Changed(a5) ; MOVE.W D2,6(A5) RTS mt_FinePortaUp TST.W mt_counter BNE mt_Return MOVE.B #$0F,mt_LowMask mt_PortaUp MOVEQ #0,D0 MOVE.B pn_Val(A6),D0 AND.B mt_LowMask,D0 MOVE.B #$FF,mt_LowMask SUB.W D0,pn_Period(A6) MOVE.W pn_Period(A6),D0 AND.W #$0FFF,D0 CMP.W #113,D0 BPL.S mt_PortaUskip AND.W #$F000,pn_Period(A6) OR.W #113,pn_Period(A6) mt_PortaUskip MOVE.W pn_Period(A6),D0 AND.W #$0FFF,D0 move.w d0,nch_Frequency(a5) bset.b #NCHB_Frequency,nch_Changed(a5) RTS mt_FinePortaDown TST.W mt_counter BNE mt_Return MOVE.B #$0F,mt_LowMask mt_PortaDown CLR.W D0 MOVE.B pn_Val(A6),D0 AND.B mt_LowMask,D0 MOVE.B #$FF,mt_LowMask ADD.W D0,pn_Period(A6) MOVE.W pn_Period(A6),D0 AND.W #$0FFF,D0 CMP.W #856,D0 BMI.S mt_PortaDskip AND.W #$F000,pn_Period(A6) OR.W #856,pn_Period(A6) mt_PortaDskip MOVE.W pn_Period(A6),D0 AND.W #$0FFF,D0 move.w d0,nch_Frequency(a5) bset.b #NCHB_Frequency,nch_Changed(a5) RTS mt_SetTonePorta MOVE.L a0,-(sp) MOVE.W (A6),D2 AND.W #$0FFF,D2 MOVEQ #0,D0 MOVE.B pn_FineTune(A6),D0 MULU #36*2,D0 ; bugfix !!! LEA mt_PeriodTable,A0 ADD.L D0,A0 MOVEQ #0,D0 mt_StpLoop CMP.W (A0,D0.W),D2 BHS.S mt_StpFound ADDQ.W #2,D0 CMP.W #36*2,D0 ; bugfix !!! BLO.S mt_StpLoop MOVEQ #35*2,D0 mt_StpFound MOVE.B pn_FineTune(A6),D2 AND.B #8,D2 BEQ.S mt_StpGoss TST.W D0 BEQ.S mt_StpGoss SUBQ.W #2,D0 mt_StpGoss MOVE.W (A0,D0.W),D2 MOVE.L (SP)+,A0 MOVE.W D2,pn_WantedPeriod(A6) MOVE.W pn_Period(A6),D0 CLR.B pn_TonePortDirec(A6) CMP.W D0,D2 BEQ.S mt_ClearTonePorta BGE mt_Return MOVE.B #1,pn_TonePortDirec(A6) RTS mt_ClearTonePorta CLR.W pn_WantedPeriod(A6) RTS mt_TonePortamento MOVE.B pn_Val(A6),D0 BEQ.S mt_TonePortNoChange MOVE.B D0,pn_TonePortSpeed(A6) CLR.B pn_Val(A6) mt_TonePortNoChange TST.W pn_WantedPeriod(A6) BEQ mt_Return MOVEQ #0,D0 MOVE.B pn_TonePortSpeed(A6),D0 TST.B pn_TonePortDirec(A6) BNE.S mt_TonePortaUp mt_TonePortaDown ADD.W D0,pn_Period(A6) MOVE.W pn_WantedPeriod(A6),D0 CMP.W pn_Period(A6),D0 BGT.S mt_TonePortaSetPer MOVE.W pn_WantedPeriod(A6),pn_Period(A6) CLR.W pn_WantedPeriod(A6) BRA.S mt_TonePortaSetPer mt_TonePortaUp SUB.W D0,pn_Period(A6) MOVE.W pn_WantedPeriod(A6),D0 CMP.W pn_Period(A6),D0 BLT.S mt_TonePortaSetPer MOVE.W pn_WantedPeriod(A6),pn_Period(A6) CLR.W pn_WantedPeriod(A6) mt_TonePortaSetPer MOVE.W pn_Period(A6),D2 MOVE.B pn_GlissFunk(A6),D0 AND.B #$0F,D0 BEQ.S mt_GlissSkip MOVEQ #0,D0 MOVE.B pn_FineTune(A6),D0 MULU #36*2,D0 LEA mt_PeriodTable,A0 ADD.L D0,A0 MOVEQ #0,D0 mt_GlissLoop CMP.W (A0,D0.W),D2 BHS.S mt_GlissFound ADDQ.W #2,D0 CMP.W #36*2,D0 BLO.S mt_GlissLoop MOVEQ #35*2,D0 mt_GlissFound MOVE.W (A0,D0.W),D2 mt_GlissSkip move.w d2,nch_Frequency(a5) bset.b #NCHB_Frequency,nch_Changed(a5) RTS mt_Vibrato MOVE.B pn_Val(A6),D0 BEQ.S mt_Vibrato2 MOVE.B pn_VibratoCmd(A6),D2 AND.B #$0F,D0 BEQ.S mt_vibskip AND.B #$F0,D2 OR.B D0,D2 mt_vibskip MOVE.B pn_Val(A6),D0 AND.B #$F0,D0 BEQ.S mt_vibskip2 AND.B #$0F,D2 OR.B D0,D2 mt_vibskip2 MOVE.B D2,pn_VibratoCmd(A6) mt_Vibrato2 MOVE.B pn_VibratoPos(A6),D0 LEA mt_VibratoTable,A4 LSR.W #2,D0 AND.W #$001F,D0 MOVEQ #0,D2 MOVE.B pn_WaveControl(A6),D2 AND.B #$03,D2 BEQ.S mt_vib_sine LSL.B #3,D0 CMP.B #1,D2 BEQ.S mt_vib_rampdown MOVE.B #255,D2 BRA.S mt_vib_set mt_vib_rampdown TST.B pn_VibratoPos(A6) BPL.S mt_vib_rampdown2 MOVE.B #255,D2 SUB.B D0,D2 BRA.S mt_vib_set mt_vib_rampdown2 MOVE.B D0,D2 BRA.S mt_vib_set mt_vib_sine MOVE.B (A4,D0.W),D2 mt_vib_set MOVE.B pn_VibratoCmd(A6),D0 AND.W #15,D0 MULU D0,D2 LSR.W #7,D2 MOVE.W pn_Period(A6),D0 TST.B pn_VibratoPos(A6) BMI.S mt_VibratoNeg ADD.W D2,D0 BRA.S mt_Vibrato3 mt_VibratoNeg SUB.W D2,D0 mt_Vibrato3 move.w d0,nch_Frequency(a5) bset.b #NCHB_Frequency,nch_Changed(a5) MOVE.B pn_VibratoCmd(A6),D0 LSR.W #2,D0 AND.W #$003C,D0 ADD.B D0,pn_VibratoPos(A6) RTS mt_TonePlusVolSlide BSR mt_TonePortNoChange BRA mt_VolumeSlide mt_VibratoPlusVolSlide BSR.S mt_Vibrato2 BRA mt_VolumeSlide mt_Tremolo MOVE.B pn_Val(A6),D0 BEQ.S mt_Tremolo2 MOVE.B pn_TremoloCmd(A6),D2 AND.B #$0F,D0 BEQ.S mt_treskip AND.B #$F0,D2 OR.B D0,D2 mt_treskip MOVE.B pn_Val(A6),D0 AND.B #$F0,D0 BEQ.S mt_treskip2 AND.B #$0F,D2 OR.B D0,D2 mt_treskip2 MOVE.B D2,pn_TremoloCmd(A6) mt_Tremolo2 MOVE.B pn_TremoloPos(A6),D0 LEA mt_VibratoTable,A4 LSR.W #2,D0 AND.W #$001F,D0 MOVEQ #0,D2 MOVE.B pn_WaveControl(A6),D2 LSR.B #4,D2 AND.B #$03,D2 BEQ.S mt_tre_sine LSL.B #3,D0 CMP.B #1,D2 BEQ.S mt_tre_rampdown MOVE.B #255,D2 BRA.S mt_tre_set mt_tre_rampdown TST.B pn_VibratoPos(A6) BPL.S mt_tre_rampdown2 MOVE.B #255,D2 SUB.B D0,D2 BRA.S mt_tre_set mt_tre_rampdown2 MOVE.B D0,D2 BRA.S mt_tre_set mt_tre_sine MOVE.B (A4,D0.W),D2 mt_tre_set MOVE.B pn_TremoloCmd(A6),D0 AND.W #15,D0 MULU D0,D2 LSR.W #6,D2 MOVEQ #0,D0 MOVE.B pn_Volume(A6),D0 TST.B pn_TremoloPos(A6) BMI.S mt_TremoloNeg ADD.W D2,D0 BRA.S mt_Tremolo3 mt_TremoloNeg SUB.W D2,D0 mt_Tremolo3 BPL.S mt_TremoloSkip CLR.W D0 mt_TremoloSkip CMP.W #$40,D0 BLS.S mt_TremoloOk MOVE.W #$40,D0 mt_TremoloOk move.w d0,nch_Volume(a5) bset.b #NCHB_Volume,nch_Changed(a5) MOVE.B pn_TremoloCmd(A6),D0 LSR.W #2,D0 AND.W #$003C,D0 ADD.B D0,pn_TremoloPos(A6) RTS mt_SampleOffset MOVEQ #0,D0 MOVE.B pn_Val(A6),D0 BEQ.S mt_sononew MOVE.B D0,pn_SampleOffset(A6) mt_sononew MOVE.B pn_SampleOffset(A6),D0 LSL.L #7,D0 CMP.L pn_Length(A6),D0 BGE.S mt_sofskip SUB.L D0,pn_Length(A6) LSL.L #1,D0 ADD.L D0,pn_Start(A6) RTS mt_sofskip MOVE.L #$0001,pn_Length(A6) RTS mt_VolumeSlide MOVEQ #0,D0 MOVE.B pn_Val(A6),D0 LSR.B #4,D0 TST.B D0 BEQ.S mt_VolSlideDown mt_VolSlideUp ADD.B D0,pn_Volume(A6) CMP.B #$40,pn_Volume(A6) BMI.S mt_vsuskip MOVE.B #$40,pn_Volume(A6) mt_vsuskip MOVE.B pn_Volume(A6),D0 move.w d0,nch_Volume(a5) bset.b #NCHB_Volume,nch_Changed(a5) RTS mt_VolSlideDown MOVEQ #0,D0 MOVE.B pn_Val(A6),D0 AND.B #$0F,D0 mt_VolSlideDown2 SUB.B D0,pn_Volume(A6) BPL.S mt_vsdskip CLR.B pn_Volume(A6) mt_vsdskip MOVE.B pn_Volume(A6),D0 move.w d0,nch_Volume(a5) bset.b #NCHB_Volume,nch_Changed(a5) RTS mt_PositionJump MOVE.W mt_SongPos,D0 ADDQ.W #1,D0 CMP.W mt_MaxPos,D0 BNE.S mt_pj1 MOVE.B #1,mt_Reset mt_pj1 MOVE.B pn_Val(A6),D0 CMP.W mt_SongPos,D0 BNE.S mt_pj0 MOVE.B #1,mt_Reset TST.W mt_PatternPos BNE.S mt_pj0 MOVE.B #2,mt_Reset mt_pj0 SUBQ.B #1,D0 MOVE.W D0,mt_SongPos BPL.S mt_pj2 MOVE.B #2,mt_Reset mt_pj2 CLR.W mt_PBreakPos ST mt_PosJumpFlag RTS mt_VolumeChange MOVEQ #0,D0 MOVE.B pn_Val(A6),D0 CMP.B #$40,D0 BLS.S mt_VolumeOk MOVEQ #$40,D0 mt_VolumeOk MOVE.B D0,pn_Volume(A6) move.w d0,nch_Volume(a5) bset.b #NCHB_Volume,nch_Changed(a5) RTS mt_PatternBreak MOVEQ #0,D0 MOVE.B pn_Val(A6),D0 MOVE.L D0,D2 LSR.W #4,D0 MULU #10,D0 AND.W #$0F,D2 ADD.W D2,D0 CMP.W #63,D0 BHI.S mt_pj2 MOVE.W D0,mt_PBreakPos ST.B mt_PosJumpFlag RTS mt_SetSpeed MOVEQ #0,D0 MOVE.B 3(A6),D0 BNE.S mt_SetSpd CMP.W #32,D0 BHS SetTempo mt_SetSpd TST.W D0 BEQ.S mt_SetBack CLR.W mt_counter MOVE.W D0,mt_speed mt_SetBack RTS mt_CheckMoreEfx BSR mt_UpdateFunk MOVE.B 2(A6),D0 AND.B #$0F,D0 CMP.B #$9,D0 BEQ mt_SampleOffset CMP.B #$B,D0 BEQ mt_PositionJump CMP.B #$D,D0 BEQ mt_PatternBreak CMP.B #$E,D0 BEQ.S mt_E_Commands CMP.B #$F,D0 BEQ.S mt_SetSpeed CMP.B #$C,D0 BEQ mt_VolumeChange BRA mt_PerNop mt_E_Commands MOVE.B pn_Val(A6),D0 ; !!! AND.B #$F0,D0 LSR.B #4,D0 ; BEQ.S mt_FilterOnOff CMP.B #1,D0 BEQ mt_FinePortaUp CMP.B #2,D0 BEQ mt_FinePortaDown CMP.B #3,D0 BEQ.S mt_SetGlissControl CMP.B #4,D0 BEQ.S mt_SetVibratoControl CMP.B #5,D0 BEQ.S mt_SetFineTune CMP.B #6,D0 BEQ.S mt_JumpLoop CMP.B #7,D0 BEQ mt_SetTremoloControl CMP.B #9,D0 BEQ mt_RetrigNote CMP.B #$A,D0 BEQ mt_VolumeFineUp CMP.B #$B,D0 BEQ mt_VolumeFineDown CMP.B #$C,D0 BEQ mt_NoteCut CMP.B #$D,D0 BEQ mt_NoteDelay CMP.B #$E,D0 BEQ mt_PatternDelay CMP.B #$F,D0 BEQ mt_FunkIt RTS mt_FilterOnOff ; MOVE.B pn_Val(A6),D0 ; AND.B #1,D0 ; ASL.B #1,D0 ; AND.B #$FD,$BFE001 ; OR.B D0,$BFE001 ; RTS mt_SetGlissControl MOVE.B pn_Val(A6),D0 AND.B #$0F,D0 AND.B #$F0,pn_GlissFunk(A6) OR.B D0,pn_GlissFunk(A6) RTS mt_SetVibratoControl MOVE.B pn_Val(A6),D0 AND.B #$0F,D0 AND.B #$F0,pn_WaveControl(A6) OR.B D0,pn_WaveControl(A6) RTS mt_SetFineTune MOVE.B pn_Val(A6),D0 AND.B #$0F,D0 MOVE.B D0,pn_FineTune(A6) RTS mt_JumpLoop TST.W mt_counter BNE mt_Return MOVE.B pn_Val(A6),D0 AND.B #$0F,D0 BEQ.S mt_SetLoop TST.B pn_LoopCount(A6) BEQ.S mt_jumpcnt SUBQ.B #1,pn_LoopCount(A6) BEQ mt_Return mt_jmploop MOVE.W pn_PattPos(A6),mt_PBreakPos ST mt_PBreakFlag RTS mt_jumpcnt MOVE.B D0,pn_LoopCount(A6) BRA.S mt_jmploop mt_SetLoop MOVE.W mt_PatternPos,D0 LSR.W #4,D0 MOVE.B D0,pn_PattPos(A6) RTS mt_SetTremoloControl MOVE.B pn_Val(A6),D0 AND.B #$0F,D0 LSL.B #4,D0 AND.B #$0F,pn_WaveControl(A6) OR.B D0,pn_WaveControl(A6) RTS mt_RetrigNote MOVE.L D1,-(SP) MOVEQ #0,D0 MOVE.B pn_Val(A6),D0 AND.B #$0F,D0 BEQ.S mt_rtnend MOVEQ #0,D1 MOVE.W mt_counter,D1 BNE.S mt_rtnskp MOVE.W (A6),D1 AND.W #$0FFF,D1 BNE.S mt_rtnend MOVEQ #0,D1 MOVE.W mt_counter,D1 mt_rtnskp DIVU D0,D1 SWAP D1 TST.W D1 BNE.S mt_rtnend mt_DoRetrig move.l pn_Start(a6),nch_SampleStart(a5) move.l pn_Length(a6),d0 move.l d0,nch_SampleLength(a5) bset.b #NCHB_Sample,nch_Changed(a5) move.l pn_LoopStart(A6),nch_RepeatStart(a5) move.l pn_Replen(A6),d0 move.l d0,nch_RepeatLength(a5) bset.b #NCHB_Repeat,nch_Changed(a5) move.w pn_Period(A6),nch_Frequency(a5) bset.b #NCHB_Frequency,nch_Changed(a5) mt_rtnend move.l (sp)+,d1 rts mt_VolumeFineUp TST.W mt_counter BNE mt_Return MOVEQ #0,D0 MOVE.B pn_Val(A6),D0 AND.B #$F,D0 BRA mt_VolSlideUp mt_VolumeFineDown TST.W mt_counter BNE mt_Return MOVEQ #0,D0 MOVE.B pn_Val(A6),D0 AND.B #$0F,D0 BRA mt_VolSlideDown2 mt_NoteCut MOVEQ #0,D0 MOVE.B pn_Val(A6),D0 AND.B #$0F,D0 CMP.W mt_counter,D0 BNE mt_Return CLR.B pn_Volume(A6) MOVEQ #0,D0 move.w d0,nch_Volume(a5) bset.b #NCHB_Volume,nch_Changed(a5) RTS mt_NoteDelay MOVEQ #0,D0 MOVE.B pn_Val(A6),D0 AND.B #$0F,D0 CMP.W mt_counter,D0 BNE mt_Return MOVE.W (A6),D0 BEQ mt_Return MOVE.L D1,-(SP) BRA mt_DoRetrig mt_PatternDelay TST.W mt_counter BNE mt_Return MOVEQ #0,D0 MOVE.B pn_Val(A6),D0 AND.B #$0F,D0 TST.B mt_PattDelTime2 BNE mt_Return ADDQ.B #1,D0 MOVE.B D0,mt_PattDelTime RTS mt_FunkIt TST.W mt_counter BNE mt_Return MOVE.B pn_Val(A6),D0 AND.B #$0F,D0 LSL.B #4,D0 AND.B #$0F,pn_GlissFunk(A6) OR.B D0,pn_GlissFunk(A6) TST.B D0 BEQ mt_Return mt_UpdateFunk MOVEM.L A0/D1,-(SP) MOVEQ #0,D0 MOVE.B pn_GlissFunk(A6),D0 LSR.B #4,D0 BEQ.S mt_funkend LEA mt_FunkTable,A0 MOVE.B (A0,D0.W),D0 ADD.B D0,pn_FunkOffset(A6) BTST #7,pn_FunkOffset(A6) BEQ.S mt_funkend CLR.B pn_FunkOffset(A6) MOVE.L pn_LoopStart(A6),D0 move.l pn_Replen(a6),d1 ADD.L D1,D0 ADD.L D1,D0 MOVE.L pn_WaveStart(A6),A0 ADDQ.L #1,A0 CMP.L D0,A0 BLO.S mt_funkok MOVE.L pn_LoopStart(A6),A0 mt_funkok MOVE.L A0,pn_WaveStart(A6) MOVEQ #-1,D0 SUB.B (A0),D0 MOVE.B D0,(A0) mt_funkend MOVEM.L (SP)+,A0/D1 RTS mt_FunkTable dc.b 0,5,6,7,8,10,11,13,16,19,22,26,32,43,64,128 mt_VibratoTable dc.b 000,024,049,074,097,120,141,161 dc.b 180,197,212,224,235,244,250,253 dc.b 255,253,250,244,235,224,212,197 dc.b 180,161,141,120,097,074,049,024 mt_PeriodTable ; Tuning 0, Normal dc.w 856,808,762,720,678,640,604,570,538,508,480,453 dc.w 428,404,381,360,339,320,302,285,269,254,240,226 dc.w 214,202,190,180,170,160,151,143,135,127,120,113 ; Tuning 1 dc.w 850,802,757,715,674,637,601,567,535,505,477,450 dc.w 425,401,379,357,337,318,300,284,268,253,239,225 dc.w 213,201,189,179,169,159,150,142,134,126,119,113 ; Tuning 2 dc.w 844,796,752,709,670,632,597,563,532,502,474,447 dc.w 422,398,376,355,335,316,298,282,266,251,237,224 dc.w 211,199,188,177,167,158,149,141,133,125,118,112 ; Tuning 3 dc.w 838,791,746,704,665,628,592,559,528,498,470,444 dc.w 419,395,373,352,332,314,296,280,264,249,235,222 dc.w 209,198,187,176,166,157,148,140,132,125,118,111 ; Tuning 4 dc.w 832,785,741,699,660,623,588,555,524,495,467,441 dc.w 416,392,370,350,330,312,294,278,262,247,233,220 dc.w 208,196,185,175,165,156,147,139,131,124,117,110 ; Tuning 5 dc.w 826,779,736,694,655,619,584,551,520,491,463,437 dc.w 413,390,368,347,328,309,292,276,260,245,232,219 dc.w 206,195,184,174,164,155,146,138,130,123,116,109 ; Tuning 6 dc.w 820,774,730,689,651,614,580,547,516,487,460,434 dc.w 410,387,365,345,325,307,290,274,258,244,230,217 dc.w 205,193,183,172,163,154,145,137,129,122,115,109 ; Tuning 7 dc.w 814,768,725,684,646,610,575,543,513,484,457,431 dc.w 407,384,363,342,323,305,288,272,256,242,228,216 dc.w 204,192,181,171,161,152,144,136,128,121,114,108 ; Tuning -8 dc.w 907,856,808,762,720,678,640,604,570,538,508,480 dc.w 453,428,404,381,360,339,320,302,285,269,254,240 dc.w 226,214,202,190,180,170,160,151,143,135,127,120 ; Tuning -7 dc.w 900,850,802,757,715,675,636,601,567,535,505,477 dc.w 450,425,401,379,357,337,318,300,284,268,253,238 dc.w 225,212,200,189,179,169,159,150,142,134,126,119 ; Tuning -6 dc.w 894,844,796,752,709,670,632,597,563,532,502,474 dc.w 447,422,398,376,355,335,316,298,282,266,251,237 dc.w 223,211,199,188,177,167,158,149,141,133,125,118 ; Tuning -5 dc.w 887,838,791,746,704,665,628,592,559,528,498,470 dc.w 444,419,395,373,352,332,314,296,280,264,249,235 dc.w 222,209,198,187,176,166,157,148,140,132,125,118 ; Tuning -4 dc.w 881,832,785,741,699,660,623,588,555,524,494,467 dc.w 441,416,392,370,350,330,312,294,278,262,247,233 dc.w 220,208,196,185,175,165,156,147,139,131,123,117 ; Tuning -3 dc.w 875,826,779,736,694,655,619,584,551,520,491,463 dc.w 437,413,390,368,347,328,309,292,276,260,245,232 dc.w 219,206,195,184,174,164,155,146,138,130,123,116 ; Tuning -2 dc.w 868,820,774,730,689,651,614,580,547,516,487,460 dc.w 434,410,387,365,345,325,307,290,274,258,244,230 dc.w 217,205,193,183,172,163,154,145,137,129,122,115 ; Tuning -1 dc.w 862,814,768,725,684,646,610,575,543,513,484,457 dc.w 431,407,384,363,342,323,305,288,272,256,242,228 dc.w 216,203,192,181,171,161,152,144,136,128,121,114 ;/* End of File */ *-----------------------------------------------------------------------* ; ; 14Bit/32Voices-NotePlayer NoteSignal movem.l a2-a4,-(sp) move.l NoteInfo,d0 ; get NoteStructure beq AO_End move.l d0,a4 move.l nst_Channels(a4),d0 ; pointer to first channel in list AO_PlayLoop move.l d0,a2 ; ^NoteChannel cmpi.w #NCHD_Ignore,nch_Stereo(a2) ; skip this channel ? beq AO_PlayNext ; yes ! move.l nch_NotePlayer(a2),d0 ; channel array beq AO_PlayNext ; no array ! move.l d0,a3 move.l (a3),a0 tst.l (a0) ; Channel disabled ? beq AO_PlayNext ; yes ! move.l 4(a3),a3 ; ^TrackStructure AO_Sample btst.b #NCHB_Sample,nch_Changed(a2) beq.s AO_Repeat ; no new sample ! move.l nch_SampleStart(a2),a0 move.l nch_SampleLength(a2),d0 add.l d0,a0 move.l a0,td_SPtr(a3) ; Pointer auf das Sampleende neg.l d0 move.l d0,td_SLen(a3) ; negative Sample-Restbytes clr.l td_LLen(a3) ; Kein LoopSample vorhanden clr.w td_FreC(a3) ; -> Kein Überlauf bei erstem Samplebyte! AO_Repeat btst.b #NCHB_Repeat,nch_Changed(a2) beq.s AO_Frequency ; no new repeat ! move.l nch_RepeatStart(a2),a0 move.l nch_RepeatLength(a2),d0 moveq #2,d1 cmp.l d0,d1 ; Repeat-Length only 1 Word ? bne.s AO_RepSamp ; No ! move.l a0,a1 move.b (a1)+,d1 cmp.b (a1)+,d1 ; Is it a NullSample ? bne.s AO_RepSamp ; No ! moveq #0,d0 AO_RepSamp add.l d0,a0 move.l a0,td_LPtr(a3) ; LoopSample-Endadr. neg.l d0 move.l d0,td_LLen(a3) ; negative LoopSample-Länge AO_Frequency btst.b #NCHB_Frequency,nch_Changed(a2) beq.s AO_Volume ; no new freq ! move.l nch_Frequency(a2),td_Fre(a3) ; Frequency for this channel AO_Volume btst.b #NCHB_Volume,nch_Changed(a2) beq.s AO_PlayNext ; no new vol ! moveq #0,d0 move.w nch_Volume(a2),d0 lsl.l #6,d0 divu nst_MaxVolume(a4),d0 move.w d0,td_Vol(a3) ; Volume for this channel AO_PlayNext move.l nch_NextChannel(a2),d0 bne AO_PlayLoop ; next channel AO_End movem.l (sp)+,a2-a4 rts *-----------------------------------------------------------------------* ; ; Set the master volume/balance ;SetVolBal ; move.l NoteInfo,d0 ; get NoteStructure ; beq .End ; move.l d0,a4 ; move.l delibase,a5 ; get DeliBase ; ; move.w dtg_SndVol(a5),d0 ; mulu dtg_SndLBal(a5),d0 ; lsr.w #6,d0 ; move.w d0,Volume07 ; left volume ; ; move.w dtg_SndVol(a5),d0 ; mulu dtg_SndRBal(a5),d0 ; lsr.w #6,d0 ; move.w d0,Volume8F ; right volume ;.End ; rts *-----------------------------------------------------------------------* ; ; Set the mixing frequency NewMixFreq: move.l ClockBase(pc),d0 move.l PlayFreq,d1 divu d1,d0 move.w d0,MixPeriod move.l ClockBase(pc),d1 divu d0,d1 move.w d1,MixFreq rts *-----------------------------------------------------------------------* ; ; Shut down the NotePlayer NoteFinish move.l NoteInfo,d0 ; get NoteStructure beq .End move.l d0,a4 ; copy Ptr lea custom,a0 move.w #$000f,dmacon(a0) ; Audio-DMA aus move.w #$00ff,adkcon(a0) move.w #$0780,intreq(a0) ; Audio-Req. löschen move.w #$0780,intena(a0) ; Audio-Int. aus move.l nst_Channels(a4),d0 ; pointer to first channel in list .FreeChan move.l d0,a0 clr.l nch_NotePlayer(a0) ; clear channel array pointer .FreeNext move.l nch_NextChannel(a0),d0 bne.s .FreeChan ; next channel moveq #INTB_AUD1,d0 move.l _OldAudio1,a1 JSRLIB SetIntVector ; set old Audio1-IRQ moveq #INTB_AUD0,d0 move.l _OldAudio0,a1 JSRLIB SetIntVector ; set old Audio0-IRQ lea AllocIORequest,a1 ; close audio.device JSRLIB CloseDevice clr.l NoteInfo ; shutdown complete .End moveq #0,d0 rts *-----------------------------------------------------------------------* ; ; Boost-Value automatisch berechnen CalcBoostValue tst.l BoostFlag ; Boost-Wert automatisch berechnen ? beq.s .End ; nein, dann raus ! moveq #0,d0 move.w ChannelNum,d0 lsl.w #7,d0 add.w #128+256,d0 move.w d0,d1 lsr.w #1,d1 sub.w d1,d0 move.w #8*256,d1 cmp.w d0,d1 bcc.s .End move.w d1,d0 .End rts *-----------------------------------------------------------------------* ; ; 14Bit-Output-Tabelle erzeugen (14Bit Routine by Markus "maw" Weichselbaum) IFEQ USE_CALIBRATION InitBoostTable lea BitTable,a0 ; 14Bit-Tabelle erzeugen move.w #32768-1,d0 move.w #-32768,d1 move.l BoostFactor,d2 .Loop move.w d1,d3 muls d2,d3 asr.l #8,d3 move.l #-32768,d4 cmp.l d3,d4 bgt.s .Fail move.l #32767,d4 cmp.l d3,d4 bgt.s .Okay .Fail move.w d4,d3 .Okay move.w d3,d4 ; ist das 16 bit sample negativ? bmi.s .IsNeg .IsPos lsr.w #8,d3 ; hi byte fertig machen lsr.b #2,d4 ; vom lo nehmen wir nur die oberen 6 bits bra.s .Write .IsNeg neg.w d3 ; erstmal auf positiv lsr.w #8,d3 ; das hi byte fertig machen neg.b d3 ; hi byte zurueck auf negativ neg.w d4 ; nochmal auf positiv lsr.b #2,d4 ; runter schieben neg.w d4 ; jetzt noch zurueck auf negativ .Write move.b d3,(a0)+ ; hier haben wir das hi byte move.b d4,(a0)+ ; hier haben wir das lo byte addq.w #2,d1 dbra d0,.Loop rts ENDC *-----------------------------------------------------------------------* ; ; 14Bit-Output-Tabelle erzeugen (14Bit Routine by Christian Buchner) IFNE USE_CALIBRATION TABLE_ENTRIES EQU 32768 InitBoostTable movem.l a2-a3/d2-d7,-(sp) lea CalibData+128,a2 .negative move.l a2,a1 ; count the number of steps moveq #128-1,d0 ; in the negative range moveq #0,d5 .count1 move.b -(a1),d1 ext.w d1 ext.l d1 add.l d1,d5 dbra d0,.count1 ; d5=number of steps move.l #256*TABLE_ENTRIES/2,d6 divu BoostFactor+2,d6 ; divide by boost factor divu d6,d5 ; calculate stepsize (d5) and moveq #0,d7 swap d5 move.w d5,d7 ; fractional part (d7) clr.w d5 swap d5 move.w d6,a3 lea BTable,a0 ; place at the middle of table move.w #TABLE_ENTRIES/2-1,d0 ; number of negative values -1 moveq #-1,d1 ; HI value moveq #-1,d2 ; LO value moveq #0,d3 ; counter .fetchnext1 move.b (a2,d1.w),d4 ; add calibtable to counter ext.w d4 add.w d4,d3 add.w d4,d2 ; maximize LO value .outerloop1 tst.w d3 bgt.s .positive1 .negative1 subq.w #1,d1 cmp.w #$FF7F,d1 beq.s .fillup1 bra.s .fetchnext1 .positive1 move.b d2,-(a0) ; store LO and HI value move.b d1,-(a0) sub.w d5,d2 ; subtract step size sub.w d5,d3 ; decrement counter sub.w d7,d6 ; sum up fractional part bpl.s .repeat1 add.w a3,d6 subq.w #1,d2 ; decrement lo value subq.w #1,d3 ; decrement counter .repeat1 dbra d0,.outerloop1 bra.s .positive .fillup1 move.w #$8000,-(a0) ; fill up the rest of the dbra d0,.fillup1 ; table with negative minimum .positive move.l a2,a1 ; count the number of steps moveq #128-1,d0 ; in the positive range moveq #0,d5 .count2 move.b (a1)+,d1 ext.w d1 ext.l d1 add.l d1,d5 dbra d0,.count2 ; d5=number of steps move.l #256*TABLE_ENTRIES/2,d6 divu BoostFactor+2,d6 ; divide by boost factor divu d6,d5 ; calculate stepsize (d5) and moveq #0,d7 swap d5 move.w d5,d7 ; fractional part (d7) clr.w d5 swap d5 move.w d6,a3 lea BTable,a0 ; place at the middle of table move.w #TABLE_ENTRIES/2-1,d0 ; number of positive values -1 moveq #0,d1 ; HI value moveq #0,d2 ; LO value moveq #0,d3 ; counter .fetchnext2 move.b (a2,d1.w),d4 ; add calibtable to counter ext.w d4 add.w d4,d3 .outerloop2 tst.w d3 bgt.s .positive2 .negative2 addq.w #1,d1 ; increment HI value cmp.w #$80,d1 beq.s .fillup2 sub.w d4,d2 ; reset LO value bra.s .fetchnext2 .positive2 move.b d1,(a0)+ ; store HI and LO value move.b d2,(a0)+ add.w d5,d2 ; add step size sub.w d5,d3 ; decrement counter sub.w d7,d6 ; sum up fractional part bpl.s .repeat2 add.w a3,d6 addq.w #1,d2 ; increment LO value subq.w #1,d3 ; decrement counter .repeat2 dbra d0,.outerloop2 bra.s .finished .fillup2 move.w #$7F7E,(a0)+ ; fill up the rest of the dbra d0,.fillup2 ; table with positive maximum .finished movem.l (sp)+,a2-a3/d2-d7 rts ENDC *-----------------------------------------------------------------------* ; ; Volume-Tabelle (signed) erzeugen InitSVolTable lea VTable,a0 ; Volume-Tabelle erzeugen moveq #65-1,d2 moveq #0,d4 move.w ScaleFactor,d5 .Loop1 moveq #0,d0 move.w #256-1,d1 .Loop2 move.w d0,d3 ext.w d3 muls d4,d3 ; Tabellennummer (0...64) * Samplewert lsr.l #2,d3 andi.w #~1,d3 move.w d3,(a0)+ addq.w #1,d0 dbra d1,.Loop2 add.w d5,d4 ; > 1 = Oversampling dbra d2,.Loop1 rts *-----------------------------------------------------------------------* ; ; Volume-Tabelle (unsigned) erzeugen InitUVolTable lea VTable,a0 ; Volume-Tabelle erzeugen moveq #65-1,d2 moveq #0,d4 move.w ScaleFactor,d5 .Loop1 moveq #-128,d0 move.w #256-1,d1 .Loop2 move.w d0,d3 ext.w d3 muls d4,d3 ; Tabellennummer (0...64) * Samplewert lsr.l #2,d3 andi.w #~1,d3 move.w d3,(a0)+ addq.w #1,d0 dbra d1,.Loop2 add.w d5,d4 ; > 1 = Oversampling dbra d2,.Loop1 rts *-----------------------------------------------------------------------* ; ; Alle 32 Software-Tracks initialisieren InitTracksNChannels lea T00Data(pc),a0 lea QuietInstr(pc),a1 moveq #32-1,d0 .Loop move.l (a1),td_SPtr(a0) ; Zum Abspielen vorbereiten move.l 4(a1),td_SLen(a0) move.l 8(a1),td_LPtr(a0) move.l 12(a1),td_LLen(a0) move.w #64,td_Vol(a0) ; Volle Lautstärke move.l #8287,td_Fre(a0) ; C 0 clr.w td_FreC(a0) lea td_SIZE(a0),a0 dbra d0,.Loop * Alle 4 Audiokanäle initialisieren: lea custom+aud0,a0 moveq #4-1,d0 .Init move.l #EmptyCBuf,ac_ptr(a0) ; Erstmal nichts spielen! move.w #MBuf_SIZE/2,ac_len(a0) move.w MixPeriod(pc),ac_per(a0) move.w #0,ac_vol(a0) adda.w #ac_SIZEOF,a0 dbra d0,.Init clr.w C03BufOff ; Erste Songdaten kommen in Buffer 0 clr.w C12BufOff rts *-----------------------------------------------------------------------* ; ; Init Sound InitSnd move.l NoteInfo,d0 ; get NoteStructure beq.s .End move.l d0,a4 bsr InitTracksNChannels IFNE DEBUG_VERSION move.l #InitSndTxt,-(sp) lea InformationFmt(pc),a0 bsr WriteInfoTxt addq.w #4,sp ENDC .End rts *-----------------------------------------------------------------------* ; ; Remove Sound EndSnd move.l NoteInfo,d0 ; get NoteStructure beq.s .End move.l d0,a4 bsr InitTracksNChannels IFNE DEBUG_VERSION move.l #EndSndTxt,-(sp) lea InformationFmt(pc),a0 bsr WriteInfoTxt addq.w #4,sp ENDC .End rts *-----------------------------------------------------------------------* ; ; Start playing StartSnd lea custom,a0 move.w #$800f,dmacon(a0) ; Audio-DMA an move.w #$00ff,adkcon(a0) move.w #$0780,intreq(a0) ; Audio-Req. löschen move.w #$8180,intena(a0) ; Audio-Int. an moveq #64,d0 move.w d0,aud0+ac_vol(a0) move.w d0,aud1+ac_vol(a0) moveq #1,d0 move.w d0,aud2+ac_vol(a0) move.w d0,aud3+ac_vol(a0) .End rts *-----------------------------------------------------------------------* ; ; Stop playing StopSnd lea custom,a0 move.w #$000f,dmacon(a0) ; Audio-DMA aus move.w #$00ff,adkcon(a0) move.w #$0780,intreq(a0) ; Audio-Req. löschen move.w #$0780,intena(a0) ; Audio-Int. aus .End rts *-----------------------------------------------------------------------* ; ; Audio-Interrupts für 68000 und 68010 * Tracks 00-0F zusammenmischen: Int0_000: * Achtung! Soeben begann das Abspielen des beim * letzten Interrupt gefüllten Channel-Buffers! move.w MixPeriod(pc),d0 lea Softy0IRQ_000,a1 cmpi.b #NT_SOFTINT,LN_TYPE(a1) bne.s .Period addi.w #32,d0 ; step down move.w d0,MixPeriod move.l ClockBase(pc),d1 divu d0,d1 move.w d1,MixFreq .Period move.w d0,aud0+ac_per(a0) move.w d0,aud3+ac_per(a0) move.w d0,aud1+ac_per(a0) move.w d0,aud2+ac_per(a0) JSRLIB Cause move.w #INTF_AUD0,custom+intreq ; AudioInt-Request löschen rts Soft0_000: movem.l d2-d7/a2-a6,-(sp) * Das rechenaufwendige Mixen passiert im Softint lea custom,a0 ; move.w #$f00,color(a0) lea T00Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T01Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T02Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T03Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T04Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T05Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T06Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T07Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T08Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T09Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T0AData(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T0BData(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T0CData(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T0DData(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T0EData(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 lea T0FData(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_000 ; move.w #$00f,color(a0) lea C0Buf,a2 ; Mix-Buffer konvertieren & löschen adda.w C03BufOff(pc),a2 move.l a2,aud0+ac_ptr(a0) lea C3Buf,a3 adda.w C03BufOff(pc),a3 move.l a3,aud3+ac_ptr(a0) lea MBuffer,a4 lea BTable,a5 move.w #MBuf_SIZE/2-1,d0 moveq #0,d1 .Convert movem.w (a4),d2-d3 move.l d1,(a4)+ move.b 0(a5,d2.w),(a2)+ ; hier haben wir das hi byte move.b 0(a5,d3.w),(a2)+ move.b 1(a5,d2.w),(a3)+ ; hier haben wir das lo byte move.b 1(a5,d3.w),(a3)+ dbra d0,.Convert eor.w #MBuf_SIZE,C03BufOff ; Buffer flippen ; move.w #$000,color(a0) movem.l (sp)+,d2-d7/a2-a6 rts * Tracks 10-1F zusammenmischen: Int1_000: * Achtung! Soeben begann das Abspielen des beim * letzten Interrupt gefüllten Channel-Buffers! move.w MixPeriod(pc),d0 lea Softy1IRQ_000,a1 cmpi.b #NT_SOFTINT,LN_TYPE(a1) bne.s .Period addi.w #32,d0 ; step down move.w d0,MixPeriod move.l ClockBase(pc),d1 divu d0,d1 move.w d1,MixFreq .Period move.w d0,aud0+ac_per(a0) move.w d0,aud3+ac_per(a0) move.w d0,aud1+ac_per(a0) move.w d0,aud2+ac_per(a0) JSRLIB Cause move.w #INTF_AUD1,custom+intreq ; AudioInt-Request löschen rts Soft1_000: movem.l d2-d7/a2-a6,-(sp) * Das rechenaufwendige Mixen passiert im Softint lea custom,a0 ; move.w #$0f0,color(a0) lea T10Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T11Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T12Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T13Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T14Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T15Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T16Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T17Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T18Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T19Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T1AData(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T1BData(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T1CData(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T1DData(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T1EData(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 lea T1FData(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_000 ; move.w #$00f,color(a0) lea C1Buf,a2 ; Mix-Buffer konvertieren & löschen adda.w C12BufOff(pc),a2 move.l a2,aud1+ac_ptr(a0) lea C2Buf,a3 adda.w C12BufOff(pc),a3 move.l a3,aud2+ac_ptr(a0) lea MBuffer,a4 lea BTable,a5 move.w #MBuf_SIZE/2-1,d0 moveq #0,d1 .Convert movem.w (a4),d2-d3 move.l d1,(a4)+ move.b 0(a5,d2.w),(a2)+ ; hier haben wir das hi byte move.b 0(a5,d3.w),(a2)+ move.b 1(a5,d2.w),(a3)+ ; hier haben wir das lo byte move.b 1(a5,d3.w),(a3)+ dbra d0,.Convert eor.w #MBuf_SIZE,C12BufOff ; Buffer flippen ; move.w #$000,color(a0) movem.l (sp)+,d2-d7/a2-a6 rts * * Ein Sample zum Play-Buffer dazumixen * * D2 = Gesamt-Volume des Channels * A2 = ^TrackData des zu mixenden Tracks * MixChannel_000: move.l td_SPtr(a2),a3 ; Pointer auf das Sampleende move.l td_SLen(a2),d3 ; negative Restbytes des Samples bmi.s .MxCalc ; noch nicht am Sampleende angekommen! move.l td_LLen(a2),d3 ; ist ein Loop-Sample vorhanden ? bpl .MxEnd ; Kein Loopsample da, also raus! move.l td_LPtr(a2),a3 ; Pointer auf das Loopende .MxCalc mulu.w td_Vol(a2),d2 ; Volume des Samples lsr.w #6,d2 add.w d2,d2 lsl.w #8,d2 lea VTable,a4 ; ^Volume-Table adda.l d2,a4 move.l td_Fre(a2),d5 ; individuelle Sample-Frequency divu MixFreq(pc),d5 ; globale Mix-Frequency moveq #0,d4 move.w d5,d4 ; Period-Vorkommastellen clr.w d5 divu MixFreq(pc),d5 ; Period-Nachkommastellen moveq #0,d6 move.w td_FreC(a2),d6 ; Period-Nachkomma-Zähler move.w d4,d7 mulu #MBuf_SIZE,d7 move.w d5,d0 mulu #MBuf_SIZE,d0 add.l d6,d0 clr.w d0 swap d0 add.l d0,d7 add.l d3,d7 ; Restbytes nach dem Mixen * * Hauptschleife - Registerbelegung: * D0.W = Temp.Register für die Samplebytes * D1.W = Temp.Register für die Samplewords * D2.W = Zähler für die MixLoop * D3.L = Restbytes vom Sample * D4.L = Vorkomma Faktor * D5.W = Nachkomma Faktor * D6.W = Nachkomma Zähler * D7 = Restbytes nach dem Mixen * A0 = * A1 = * A2 = Zeiger auf TrackData des Tracks * A3 = Zeiger auf das Ende des Samples * A4 = Zeiger auf Volume-Tabelle des Samples * A5 = Zeiger auf den Mix-Buffer * A6 = * .MxSamp lea MBuffer,a5 ; Pointer auf den Mix-Buffer move.w #MBuf_SIZE/2-1,d2 ; Zähler, bis MixBuffer voll tst.l d7 ; wird das Sampleende beim Mixen erreicht ? bmi .MxTst2 ; Nein, dann schnelle Mix-Routine benutzen! .MxTst1 tst.w d4 ; Period-Vorkommastellen Null? bne.s .MxLop3 ; Nein, dann normale Mix-Routine benutzen! moveq #1,d4 adda.l d3,a3 moveq #0,d0 move.b (a3)+,d0 ; erstes Samplebyte holen add.w d0,d0 move.w 0(a4,d0.w),d1 .MxLop0 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten bcc.s .MxLop1 add.l d4,d3 bmi.s .MxGet1 ; noch nicht am Sampleende angekommen! add.l td_LLen(a2),d3 ; ist ein Loop-Sample vorhanden ? bpl.s .MxPerC ; Kein Loopsample da, also raus! move.l td_LPtr(a2),a3 ; Pointer auf das Loopende adda.l d3,a3 .MxGet1 moveq #0,d0 move.b (a3)+,d0 ; ein Sample zum Buffer dazumixen add.w d0,d0 move.w 0(a4,d0.w),d1 .MxLop1 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten bcc.s .MxLop2 add.l d4,d3 bmi.s .MxGet2 ; noch nicht am Sampleende angekommen! add.l td_LLen(a2),d3 ; ist ein Loop-Sample vorhanden ? bpl.s .MxPerC ; Kein Loopsample da, also raus! move.l td_LPtr(a2),a3 ; Pointer auf das Loopende adda.l d3,a3 .MxGet2 moveq #0,d0 move.b (a3)+,d0 ; ein Sample zum Buffer dazumixen add.w d0,d0 move.w 0(a4,d0.w),d1 .MxLop2 dbra d2,.MxLop0 ; bis MixBuffer voll add.l d3,d4 suba.l d4,a3 bra.s .MxPerC .MxLop3 moveq #0,d0 move.b 0(a3,d3.l),d0 ; ein Sample zum Buffer dazumixen add.w d0,d0 move.w 0(a4,d0.w),d1 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten addx.l d4,d3 bmi.s .MxLop4 ; noch nicht am Sampleende angekommen! add.l td_LLen(a2),d3 ; ist ein Loop-Sample vorhanden ? bpl.s .MxPerC ; Kein Loopsample da, also raus! move.l td_LPtr(a2),a3 ; Pointer auf das Loopende .MxLop4 moveq #0,d0 move.b 0(a3,d3.l),d0 ; ein Sample zum Buffer dazumixen add.w d0,d0 move.w 0(a4,d0.w),d1 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten addx.l d4,d3 bmi.s .MxLop5 ; noch nicht am Sampleende angekommen! add.l td_LLen(a2),d3 ; ist ein Loop-Sample vorhanden ? bpl.s .MxPerC ; Kein Loopsample da, also raus! move.l td_LPtr(a2),a3 ; Pointer auf das Loopende .MxLop5 dbra d2,.MxLop3 ; bis MixBuffer voll .MxPerC move.w d6,td_FreC(a2) ; Neuer Stand des Runtersample-Zählers .MxSPtr move.l a3,td_SPtr(a2) ; Endadresse des Samples sichern .MxSLen move.l d3,td_SLen(a2) ; Neue Position im Sample erreicht .MxEnd rts .MxTst2 tst.w d4 ; Period-Vorkommastellen Null? bne.s .MxLop9 ; Nein, dann normale Mix-Routine benutzen! moveq #1,d4 adda.l d3,a3 move.l d7,d3 moveq #0,d0 move.b (a3)+,d0 ; erstes Samplebyte holen add.w d0,d0 move.w 0(a4,d0.w),d1 .MxLop6 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten bcc.s .MxLop7 moveq #0,d0 move.b (a3)+,d0 ; ein Sample zum Buffer dazumixen add.w d0,d0 move.w 0(a4,d0.w),d1 .MxLop7 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten bcc.s .MxLop8 moveq #0,d0 move.b (a3)+,d0 ; ein Sample zum Buffer dazumixen add.w d0,d0 move.w 0(a4,d0.w),d1 .MxLop8 dbra d2,.MxLop6 ; bis MixBuffer voll add.l d3,d4 suba.l d4,a3 bra.s .MxPerC .MxLop9 moveq #0,d0 move.b 0(a3,d3.l),d0 ; ein Sample zum Buffer dazumixen add.w d0,d0 move.w 0(a4,d0.w),d1 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten addx.l d4,d3 moveq #0,d0 move.b 0(a3,d3.l),d0 ; ein Sample zum Buffer dazumixen add.w d0,d0 move.w 0(a4,d0.w),d1 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten addx.l d4,d3 dbra d2,.MxLop9 ; bis MixBuffer voll bra.s .MxPerC *-----------------------------------------------------------------------* ; ; Audio-Interrupts für 68020 und höher * Tracks 00-0F zusammenmischen: Int0_020: * Achtung! Soeben begann das Abspielen des beim * letzten Interrupt gefüllten Channel-Buffers! move.w MixPeriod(pc),d0 lea Softy0IRQ_020,a1 cmpi.b #NT_SOFTINT,LN_TYPE(a1) bne.s .Period addi.w #32,d0 ; step down move.w d0,MixPeriod move.l ClockBase(pc),d1 divu d0,d1 move.w d1,MixFreq .Period move.w d0,aud0+ac_per(a0) move.w d0,aud3+ac_per(a0) move.w d0,aud1+ac_per(a0) move.w d0,aud2+ac_per(a0) JSRLIB Cause move.w #INTF_AUD0,custom+intreq ; AudioInt-Request löschen rts Soft0_020: movem.l d2-d7/a2-a6,-(sp) * Das rechenaufwendige Mixen passiert im Softint lea custom,a0 ; move.w #$f00,color(a0) lea T00Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T01Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T02Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T03Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T04Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T05Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T06Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T07Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T08Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T09Data(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T0AData(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T0BData(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T0CData(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T0DData(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T0EData(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 lea T0FData(pc),a2 move.w Volume07(pc),d2 bsr MixChannel_020 ; move.w #$00f,color(a0) lea C0Buf,a2 ; Mix-Buffer konvertieren & löschen adda.w C03BufOff(pc),a2 move.l a2,aud0+ac_ptr(a0) lea C3Buf,a3 adda.w C03BufOff(pc),a3 move.l a3,aud3+ac_ptr(a0) lea MBuffer,a4 lea BTable,a5 move.w #MBuf_SIZE/2-1,d0 moveq #0,d1 .Convert movem.w (a4),d2-d3 move.l d1,(a4)+ move.b 0(a5,d2.w),(a2)+ ; hier haben wir das hi byte move.b 0(a5,d3.w),(a2)+ move.b 1(a5,d2.w),(a3)+ ; hier haben wir das lo byte move.b 1(a5,d3.w),(a3)+ dbra d0,.Convert eor.w #MBuf_SIZE,C03BufOff ; Buffer flippen ; move.w #$000,color(a0) movem.l (sp)+,d2-d7/a2-a6 rts * Tracks 10-1F zusammenmischen: Int1_020: * Achtung! Soeben begann das Abspielen des beim * letzten Interrupt gefüllten Channel-Buffers! move.w MixPeriod(pc),d0 lea Softy1IRQ_020,a1 cmpi.b #NT_SOFTINT,LN_TYPE(a1) bne.s .Period addi.w #32,d0 ; step down move.w d0,MixPeriod move.l ClockBase(pc),d1 divu d0,d1 move.w d1,MixFreq .Period move.w d0,aud0+ac_per(a0) move.w d0,aud3+ac_per(a0) move.w d0,aud1+ac_per(a0) move.w d0,aud2+ac_per(a0) JSRLIB Cause move.w #INTF_AUD1,custom+intreq ; AudioInt-Request löschen rts Soft1_020: movem.l d2-d7/a2-a6,-(sp) * Das rechenaufwendige Mixen passiert im Softint lea custom,a0 ; move.w #$0f0,color(a0) lea T10Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T11Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T12Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T13Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T14Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T15Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T16Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T17Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T18Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T19Data(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T1AData(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T1BData(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T1CData(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T1DData(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T1EData(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 lea T1FData(pc),a2 move.w Volume8F(pc),d2 bsr MixChannel_020 ; move.w #$00f,color(a0) lea C1Buf,a2 ; Mix-Buffer konvertieren & löschen adda.w C12BufOff(pc),a2 move.l a2,aud1+ac_ptr(a0) lea C2Buf,a3 adda.w C12BufOff(pc),a3 move.l a3,aud2+ac_ptr(a0) lea MBuffer,a4 lea BTable,a5 move.w #MBuf_SIZE/2-1,d0 moveq #0,d1 .Convert movem.w (a4),d2-d3 move.l d1,(a4)+ move.b 0(a5,d2.w),(a2)+ ; hier haben wir das hi byte move.b 0(a5,d3.w),(a2)+ move.b 1(a5,d2.w),(a3)+ ; hier haben wir das lo byte move.b 1(a5,d3.w),(a3)+ dbra d0,.Convert eor.w #MBuf_SIZE,C12BufOff ; Buffer flippen ; move.w #$000,color(a0) movem.l (sp)+,d2-d7/a2-a6 rts * * Ein Sample zum Play-Buffer dazumixen * * D2 = Gesamt-Volume des Channels * A2 = ^TrackData des zu mixenden Tracks * MixChannel_020: move.l td_SPtr(a2),a3 ; Pointer auf das Sampleende move.l td_SLen(a2),d3 ; negative Restbytes des Samples bmi.s .MxCalc ; noch nicht am Sampleende angekommen! move.l td_LLen(a2),d3 ; ist ein Loop-Sample vorhanden ? bpl .MxEnd ; Kein Loopsample da, also raus! move.l td_LPtr(a2),a3 ; Pointer auf das Loopende .MxCalc mulu.w td_Vol(a2),d2 ; Volume des Samples lsr.w #6,d2 add.w d2,d2 lsl.w #8,d2 lea VTable,a4 ; ^Volume-Table adda.l d2,a4 move.l td_Fre(a2),d5 ; individuelle Sample-Frequency divu MixFreq(pc),d5 ; globale Mix-Frequency moveq #0,d4 move.w d5,d4 ; Period-Vorkommastellen clr.w d5 divu MixFreq(pc),d5 ; Period-Nachkommastellen moveq #0,d6 move.w td_FreC(a2),d6 ; Period-Nachkomma-Zähler move.w d4,d7 mulu #MBuf_SIZE,d7 move.w d5,d0 mulu #MBuf_SIZE,d0 add.l d6,d0 clr.w d0 swap d0 add.l d0,d7 add.l d3,d7 ; Restbytes nach dem Mixen * * Hauptschleife - Registerbelegung: * D0.W = Temp.Register für die Samplebytes * D1.W = Temp.Register für die Samplewords * D2.W = Zähler für die MixLoop * D3.L = Restbytes vom Sample * D4.L = Vorkomma Faktor * D5.W = Nachkomma Faktor * D6.W = Nachkomma Zähler * D7 = Restbytes nach dem Mixen * A0 = * A1 = * A2 = Zeiger auf TrackData des Tracks * A3 = Zeiger auf das Ende des Samples * A4 = Zeiger auf Volume-Tabelle des Samples * A5 = Zeiger auf den Mix-Buffer * A6 = * .MxSamp lea MBuffer,a5 ; Pointer auf den Mix-Buffer move.w #MBuf_SIZE/2-1,d2 ; Zähler, bis MixBuffer voll tst.l d7 ; wird das Sampleende beim Mixen erreicht ? bmi .MxTst2 ; Nein, dann schnelle Mix-Routine benutzen! .MxTst1 moveq #0,d0 tst.w d4 ; Period-Vorkommastellen Null? bne.s .MxLop3 ; Nein, dann normale Mix-Routine benutzen! moveq #1,d4 adda.l d3,a3 move.b (a3)+,d0 ; erstes Samplebyte holen move.w 0(a4,d0.w*2),d1 .MxLop0 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten bcc.s .MxLop1 add.l d4,d3 bmi.s .MxGet1 ; noch nicht am Sampleende angekommen! add.l td_LLen(a2),d3 ; ist ein Loop-Sample vorhanden ? bpl.s .MxPerC ; Kein Loopsample da, also raus! move.l td_LPtr(a2),a3 ; Pointer auf das Loopende adda.l d3,a3 .MxGet1 move.b (a3)+,d0 ; ein Sample zum Buffer dazumixen move.w 0(a4,d0.w*2),d1 .MxLop1 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten bcc.s .MxLop2 add.l d4,d3 bmi.s .MxGet2 ; noch nicht am Sampleende angekommen! add.l td_LLen(a2),d3 ; ist ein Loop-Sample vorhanden ? bpl.s .MxPerC ; Kein Loopsample da, also raus! move.l td_LPtr(a2),a3 ; Pointer auf das Loopende adda.l d3,a3 .MxGet2 move.b (a3)+,d0 ; ein Sample zum Buffer dazumixen move.w 0(a4,d0.w*2),d1 .MxLop2 dbra d2,.MxLop0 ; bis MixBuffer voll add.l d3,d4 suba.l d4,a3 bra.s .MxPerC .MxLop3 move.b 0(a3,d3.l),d0 ; ein Sample zum Buffer dazumixen move.w 0(a4,d0.w*2),d1 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten addx.l d4,d3 bmi.s .MxLop4 ; noch nicht am Sampleende angekommen! add.l td_LLen(a2),d3 ; ist ein Loop-Sample vorhanden ? bpl.s .MxPerC ; Kein Loopsample da, also raus! move.l td_LPtr(a2),a3 ; Pointer auf das Loopende .MxLop4 move.b 0(a3,d3.l),d0 ; ein Sample zum Buffer dazumixen move.w 0(a4,d0.w*2),d1 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten addx.l d4,d3 bmi.s .MxLop5 ; noch nicht am Sampleende angekommen! add.l td_LLen(a2),d3 ; ist ein Loop-Sample vorhanden ? bpl.s .MxPerC ; Kein Loopsample da, also raus! move.l td_LPtr(a2),a3 ; Pointer auf das Loopende .MxLop5 dbra d2,.MxLop3 ; bis MixBuffer voll .MxPerC move.w d6,td_FreC(a2) ; Neuer Stand des Runtersample-Zählers .MxSPtr move.l a3,td_SPtr(a2) ; Endadresse des Samples sichern .MxSLen move.l d3,td_SLen(a2) ; Neue Position im Sample erreicht .MxEnd rts .MxTst2 moveq #0,d0 tst.w d4 ; Period-Vorkommastellen Null? bne.s .MxLop9 ; Nein, dann normale Mix-Routine benutzen! moveq #1,d4 adda.l d3,a3 move.l d7,d3 move.b (a3)+,d0 ; erstes Samplebyte holen move.w 0(a4,d0.w*2),d1 .MxLop6 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten bcc.s .MxLop7 move.b (a3)+,d0 ; ein Sample zum Buffer dazumixen move.w 0(a4,d0.w*2),d1 .MxLop7 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten bcc.s .MxLop8 move.b (a3)+,d0 ; ein Sample zum Buffer dazumixen move.w 0(a4,d0.w*2),d1 .MxLop8 dbra d2,.MxLop6 ; bis MixBuffer voll add.l d3,d4 suba.l d4,a3 bra.s .MxPerC .MxLop9 move.b 0(a3,d3.l),d0 ; ein Sample zum Buffer dazumixen move.w 0(a4,d0.w*2),d1 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten addx.l d4,d3 move.b 0(a3,d3.l),d0 ; ein Sample zum Buffer dazumixen move.w 0(a4,d0.w*2),d1 add.w d1,(a5)+ add.w d5,d6 ; Sample fortschalten addx.l d4,d3 dbra d2,.MxLop9 ; bis MixBuffer voll bra.s .MxPerC *-----------------------------------------------------------------------* ; ; Daten für die Audio-Interrupt Routine CNOP 0,4 ClockBase: dc.l 0 ;Clock-Konstante MixPeriod: dc.w 256 ;Gesamt-Period für alle Kanäle MixFreq: dc.w 8287 ;Gesamt-Frequenz für alle Kanäle * Variablen der Audio-Interrupt-Routine: Volume07: dc.w 64 ;Channel-Volumes für links und rechts Volume8F: dc.w 64 C03BufOff: dc.w 0 ;Buffer-Flip-Offset (0 oder MBuf_SIZE) C12BufOff: dc.w 0 * 32 Track-Data-Strukturen: rsreset td_SPtr rs.l 1 ; Zeiger auf das Sampleende td_SLen rs.l 1 ; negative Sample-Restbytes td_LPtr rs.l 1 ; Endadr. des Loopteils td_LLen rs.l 1 ; negative Länge des Loopteils td_Vol rs.w 1 ; Volume-Wert 0...64 td_Fre rs.l 1 ; Frequenz-Wert td_FreC rs.w 1 ; Frequenz-Nachkomma-Zähler td_SIZE rs.l 0 T00Data: ds.b td_SIZE T01Data: ds.b td_SIZE T02Data: ds.b td_SIZE T03Data: ds.b td_SIZE T04Data: ds.b td_SIZE T05Data: ds.b td_SIZE T06Data: ds.b td_SIZE T07Data: ds.b td_SIZE T08Data: ds.b td_SIZE T09Data: ds.b td_SIZE T0AData: ds.b td_SIZE T0BData: ds.b td_SIZE T0CData: ds.b td_SIZE T0DData: ds.b td_SIZE T0EData: ds.b td_SIZE T0FData: ds.b td_SIZE T10Data: ds.b td_SIZE T11Data: ds.b td_SIZE T12Data: ds.b td_SIZE T13Data: ds.b td_SIZE T14Data: ds.b td_SIZE T15Data: ds.b td_SIZE T16Data: ds.b td_SIZE T17Data: ds.b td_SIZE T18Data: ds.b td_SIZE T19Data: ds.b td_SIZE T1AData: ds.b td_SIZE T1BData: ds.b td_SIZE T1CData: ds.b td_SIZE T1DData: ds.b td_SIZE T1EData: ds.b td_SIZE T1FData: ds.b td_SIZE * Stummes Instrument: QuietInstr: dc.l QuietInstr ; Endadresse dc.l 0 ; Restlänge dc.l QuietInstr ; Ende LoopSample dc.l 0 ; Länge LoopSample *-----------------------------------------------------------------------* ; ; SECTION GenieTabBuff,BSS ; ; * Umrechnungs-Tabelle für versch. Lautstärken: * (wird durch NoteInit initialisiert) VTable: ds.w 256*65 *-----------------------------------------------------------------------* ; ; SECTION GenieBitBuff,BSS ; ; * Umrechnungs-Tabelle für 14Bit Ausgabe: * (wird beim Start initialisiert) BitTable: ds.b 256*128 BTable: ds.b 256*128 *-----------------------------------------------------------------------* ; ; SECTION GenieMixBuff,BSS ; ; * Mix-Buffer: MBuf_SIZE equ 200 MBuffer: ds.w MBuf_SIZE MBufferEnd: *-----------------------------------------------------------------------* ; ; NoteChannels - From TakeTracker player ; ; SECTION NoteChan,BSS ; ; NoteChannels ds.b NoteChannel_SIZE*32 *-----------------------------------------------------------------------* ; ; SECTION GenieSampBuff,BSS_C ; ; * Channel-Buffer: CBuffers: C0Buf: ds.b MBuf_SIZE ds.b MBuf_SIZE ;Für Double-Buffering! C1Buf: ds.b MBuf_SIZE ds.b MBuf_SIZE ;Für Double-Buffering! C2Buf: ds.b MBuf_SIZE ds.b MBuf_SIZE ;Für Double-Buffering! C3Buf: ds.b MBuf_SIZE ds.b MBuf_SIZE ;Für Double-Buffering! CBuffersEnd: EmptyCBuf: ds.b MBuf_SIZE *-----------------------------------------------------------------------* section __MERGED,data ********************************************************************** * Player Data ********************************************************************** MyTask dc.l 0 ParentTask dc.l 0 ; Library bases _SysBase dc.l 0 _GFXBase dc.l 0 retval dc.l 0 _OldAudio0: dc.l 0 ; Old audio interrupt vectors _OldAudio1: dc.l 0 NoteInfo: dc.l 0 PlayFreq dc.l 14433 ScaleFactor dc.w 0 ChannelNum dc.w 0 BoostFlag dc.l 1 ; Automatic Volume Boost Calculation BoostFactor dc.l 0 ********************************************************************** * From TakeTracker player ********************************************************************** delibase dc.l 0 songinfo dc.l 0 mt_size dc.l 0 mt_NumCh dc.w 0 mt_rsize dc.w 0 mt_psize dc.w 0 NotePlay dc.l NoteStructure NoteStructure dc.l NoteChannels ; NoteChannel Array dc.l NSTF_Period!NSTF_Signed!NSTF_8Bit ; 8-Bit signed sample data dc.l 28867 ; max. frequency dc.w 64 ; max. volume dcb.b 18,0 mt_ChanTemp ds.b pn_SIZEOF * MAXCHANNELS mt_speed dc.w 0 mt_counter dc.w 0 mt_SongPos dc.w 0 mt_StartPos dc.w 0 mt_MaxPos dc.w 0 mt_PBreakPos dc.w 0 mt_PatternPos dc.w 0 mt_PosJumpFlag dc.b 0 mt_PBreakFlag dc.b 0 mt_LowMask dc.b 0 mt_PattDelTime dc.b 0 mt_PattDelTime2 dc.b 0 mt_Reset dc.b 0 ********************************************************************** * AudioInterrupts ********************************************************************** Audio0IRQ_000 dc.l 0 ; Succ dc.l 0 ; Pred dc.b NT_INTERRUPT ; Type dc.b 0 ; Pri dc.l audiointname ; Name dc.l 0 ; Data dc.l Int0_000 ; Code Audio1IRQ_000 dc.l 0 ; Succ dc.l 0 ; Pred dc.b NT_INTERRUPT ; Type dc.b 0 ; Pri dc.l audiointname ; Name dc.l 0 ; Data dc.l Int1_000 ; Code Audio0IRQ_020 dc.l 0 ; Succ dc.l 0 ; Pred dc.b NT_INTERRUPT ; Type dc.b 0 ; Pri dc.l audiointname ; Name dc.l 0 ; Data dc.l Int0_020 ; Code Audio1IRQ_020 dc.l 0 ; Succ dc.l 0 ; Pred dc.b NT_INTERRUPT ; Type dc.b 0 ; Pri dc.l audiointname ; Name dc.l 0 ; Data dc.l Int1_020 ; Code ********************************************************************** * SoftInterrupts ********************************************************************** Softy0IRQ_000 dc.l 0 ; Succ dc.l 0 ; Pred dc.b NT_INTERRUPT ; Type dc.b 0 ; Pri dc.l audiointname ; Name dc.l 0 ; Data dc.l Soft0_000 ; Code Softy1IRQ_000 dc.l 0 ; Succ dc.l 0 ; Pred dc.b NT_INTERRUPT ; Type dc.b 0 ; Pri dc.l audiointname ; Name dc.l 0 ; Data dc.l Soft1_000 ; Code Softy0IRQ_020 dc.l 0 ; Succ dc.l 0 ; Pred dc.b NT_INTERRUPT ; Type dc.b 0 ; Pri dc.l audiointname ; Name dc.l 0 ; Data dc.l Soft0_020 ; Code Softy1IRQ_020 dc.l 0 ; Succ dc.l 0 ; Pred dc.b NT_INTERRUPT ; Type dc.b 0 ; Pri dc.l audiointname ; Name dc.l 0 ; Data dc.l Soft1_020 ; Code ********************************************************************** * AudioRequest ********************************************************************** AllocIORequest: dc.l 0 ; LN_SUCC dc.l 0 ; LN_PRED dc.b 0 ; LN_TYPE dc.b ADALLOC_MAXPREC ; LN_PRI dc.l 0 ; LN_NAME dc.l 0 ; message reply port dc.w 0 ; message len in bytes dc.l 0 ; device node pointer dc.l 0 ; unit (driver private) dc.w 0 ; device command dc.b 0 ; special flags dc.b 0 ; error or warning code dc.w 0 ; ioa_AllocKey dc.l ChannelMap ; ioa_Data dc.l 1 ; ioa_Length dc.w 0 ; ioa_Period dc.w 0 ; ioa_Volume dc.w 0 ; ioa_Cycles dc.l 0 ; LN_SUCC dc.l 0 ; LN_PRED dc.b 0 ; LN_TYPE dc.b 0 ; LN_PRI dc.l 0 ; LN_NAME dc.l 0 ; message reply port dc.w 0 ; message len in bytes ChannelMap dc.b $0f ; Alle Kanäle belegen audiointname dc.b 'XModule Player',0 even END