home *** CD-ROM | disk | FTP | other *** search
- * MultiPlayer
- * Copyright (C) 1992 Bryan Ford
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * See Player.doc for info on contacting the author.
- *
- * Note: This playroutine was not originally written by me. In general
- * these playroutines are public domain, so I am bringing the versions
- * modified for MultiPlayer under the General Public License. In the
- * few cases of already-copyrighted playroutines, the above copyright
- * notice applies only to the parts of the file written by me.
- *
- * $Id: dssplay.asm,v 4.1 92/07/12 10:40:43 BAF Exp $
- *
-
- include "player.i"
-
- code text
-
- xref modmem,dmawait
-
- xdef dssstart
-
- dssstart:
- plstartret .gmod
-
- cnop 0,4
- dc.l gmod_Hook
- .gmod
- gmodnop
- gmodbra InitPlay ; StartMusic
- gmodbra RemovePlayer ; StopMusic
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop ; GetFrequency
- gmodnop ; TimerTick
- lea name(a4),a0 ; GetMakerName
- move.l a0,d0
- rts
-
-
- ;**************************************************************************
- ;*
- ;* DSS MODULE PLAY ROUTINE
- ;* -----------------------
- ;*
- ;* If you wish to use some DSS Tracker Modules into your own programs,
- ;* you can read the following listing...
- ;*
- ;* This file contains the needed functions for playing a DSS Module.
- ;* You have to allocate, to load and to free the memory (CHIP) yourself.
- ;*
- ;* >Once the Module is loaded in CHIP memory:
- ;*
- ;* -Set the [ SongPointer ] pointer (at the end of this file) with the
- ;* Module's address.
- ;* -Call the [ InitPlay() ] function.
- ;*
- ;* >To stop the Module, you just have to call the [ RemovePlayer() ]
- ;* function.
- ;*
- ;* This program has been writen for the Aztec C 3.6 assembler.
- ;* It can be easily adapted to another assembler.
- ;*
- ;**************************************************************************
-
- ;----- Amiga function ------
-
- _LVOOpenResource EQU -498
- _LVOAddICRVector EQU -6
- _LVORemICRVector EQU -12
-
- ;------- ExecBase ----
-
- SysBase EQU 4
- PAL EQU 50
- eb_PowerSupplyFreq EQU 531
-
- ;------- CIAA --------
-
- CIAAPRA EQU $bfe001
- CIABTALO EQU $bfd400
- CIABTAHI EQU $bfd500
- CIABICR EQU $bfdd00
- CIABCRA EQU $bfde00
-
- CIABTBLO EQU $bfd600
- CIABTBHI EQU $bfd700
- CIABCRB EQU $bfdf00
-
- ;------ Song ----------
-
- sng_Tempo EQU 8
- sng_Instr0 EQU 10
- sng_Len EQU 1436
- sng_Seq EQU 1438
- sng_Data EQU 1566
-
- ;------ InstrData -----
-
- MAXINSTR EQU 30
- SIZEOF_insdt EQU 46
-
- instr_Name EQU 0
- instr_Start EQU 30
- instr_Len EQU 34
- instr_RStart EQU 36
- instr_RLen EQU 40
- instr_Vol EQU 42
- instr_Freq EQU 44
-
- ;------- AudioData -
-
- SIZEOF_ad EQU 24
-
- ad_SampPer EQU 0
- ad_Effet EQU 2
- ad_Info EQU 3
- ad_Volume EQU 4
- ad_SmpAdr EQU 6
- ad_SmpLen EQU 10
- ad_RepAdr EQU 12
- ad_RepLen EQU 16
- ad_ArpPer EQU 18
- ad_DMABit EQU 20
- ad_PitchPer EQU 22
-
- ;------- AudioChips -------
-
- DMACON EQU $dff096
- DMASET EQU $8000
-
- AUD0LCH EQU $dff0a0
- AUD1LCH EQU $dff0b0
- AUD2LCH EQU $dff0c0
- AUD3LCH EQU $dff0d0
- AUDxLEN EQU $4
- AUDxPER EQU $6
- AUDxVOL EQU $8
- AUDxDAT EQU $a
- SIZEOF_AUD EQU $10
-
- ;------ Block ---------
-
- NEXTTRACK EQU 4
- NEXTLINE EQU 16
- BLOCKSIZE EQU 1024
- MAXTRACK EQU 4
-
- ;------- Notes -------
-
- DO2 EQU 1712
- SI5 EQU 113
- STOP EQU $7ff
-
- ;------- Effects -----
-
- MASK_EFF EQU 7
- MASK_VAL EQU $f
-
- ARPEGGIO EQU 0
- PITCHUP EQU 1
- PITCHDOWN EQU 2
- VOLUME EQU 3
- MASTERVOL EQU 4
- TEMPO EQU 5
- JUMP EQU 6
- FILTER EQU 7
-
- MAX_VOL EQU 64
- BREAK EQU $ff
-
-
- ;------------------ functions to call -----------------
-
- ; Timer interruption installation and Player initialization routines
- ; Return 0 (zero) if successful.
- ; Return 1 if the installation is not possible.
-
- InitPlay:
- lea clrstart,a0
- moveq #(clrend-clrstart)/2-1,d0
- .clr
- clr.w (a0)+
- dbra d0,.clr
-
- movem.l d1-d2/a0-a3/a6,-(sp)
- move.l SysBase,a6
- lea CiabName,a1
- moveq #0,d0
- jsr _LVOOpenResource(a6)
- move.l d0,CiabBase
- beq.s InitPlayError
- cmp.b #PAL,eb_PowerSupplyFreq(a6)
- beq.s initsong
- move.w #2,IsNTSC
- initsong:
- bsr InitSampleAdr
- bsr InitSamples
- bsr InitInterrupt
- tst.l d0
- beq EndInitPlay
- InitPlayError:
- moveq #1,d0
- EndInitPlay:
- movem.l (sp)+,d1-d2/a0-a3/a6
- rts
-
- ; Stop to play the module
-
- RemovePlayer:
- movem.l d0-d1/a0-a1/a6,-(sp)
- bsr DisablePlayer
- move.l CiabBase,a6
- lea TimerInt,a1
- moveq #1,d0
- jsr _LVORemICRVector(a6)
- bclr #1,CIAAPRA
- movem.l (sp)+,d0-d1/a0-a1/a6
- rts
-
- ;-------------- internal functions -----------------
-
- InitInterrupt:
- bsr EnablePlayer
- move.l CiabBase,a6
- lea TimerInt,a1
- moveq #1,d0
- jsr _LVOAddICRVector(a6)
- tst.l d0
- bne.s InitInterruptEnd
- move.b CIABCRB,d0
- and.b #%10000000,d0
- or.b #1,d0
- move.b d0,CIABCRB
- move.b #$82,CIABICR
- lea TimerTable,a0
- move.w IsNTSC,d0
- move.b 1(a0,d0),CIABTBLO
- move.b 0(a0,d0),CIABTBHI
- moveq #0,d0
- InitInterruptEnd:
- rts
-
- InitSampleAdr:
- move.l modmem,a1
- lea sng_Len(a1),a0
- move.w (a0)+,d0 ; d0 = songlen
- subq.w #1,d0
- moveq #0,d1
- move.l d1,d2
- SeekLastBlockLoop:
- move.b (a0)+,d2
- cmp.b d2,d1
- bhi.s NotLastBlock
- move.b d2,d1
- NotLastBlock:
- dbra d0,SeekLastBlockLoop
- addq.w #1,d1
- moveq #10,d0
- lsl.l d0,d1 ; d1 = block size
- lea sng_Data(a1),a0
- add.l d1,a0 ; a0 -> first sample
- lea sng_Instr0(a1),a2 ; a2 -> first instrument
- lea SampleAdrTable,a3
- moveq #MAXINSTR,d0
- InitAdrLoop:
- moveq #0,d1
- move.w instr_Len(a2),d1 ; len ?
- beq.s InitNextAdr
- InitThisAdr:
- move.l a0,(a3)
- moveq #0,d2
- cmp.w #1,instr_RLen(a2) ; rlen
- beq.s GetSampleSize
- move.w instr_RLen(a2),d2
- add.l d2,d1
- GetSampleSize:
- add.l d1,d1
- bclr #0,instr_Start+3(a2) ; align instr_Start on a word
- add.l instr_Start(a2),d1 ; Start
- add.l d1,a0 ; a0 -> nextsample
- InitNextAdr:
- addq.l #4,a3
- add.l #SIZEOF_insdt,a2
- dbra d0,InitAdrLoop
- rts
-
- InitSamples:
- lea SampleAdrTable,a0
- moveq #MAXINSTR,d0
- InitSamplesLoop:
- move.l (a0)+,d1
- beq.s InitSamplesLoopEnd
- move.l d1,a1
- moveq #3,d2
- Clear4Bytes:
- clr.b (a1)+
- dbra d2,Clear4Bytes
- InitSamplesLoopEnd:
- dbra d0,InitSamplesLoop
- rts
-
-
- DisablePlayer:
- clr.w AUD0LCH+AUDxVOL
- clr.w AUD1LCH+AUDxVOL
- clr.w AUD2LCH+AUDxVOL
- clr.w AUD3LCH+AUDxVOL
- move.w #$0f,DMACON
- rts
-
- EnablePlayer:
- clr.w AUD0LCH+AUDxVOL
- clr.w AUD1LCH+AUDxVOL
- clr.w AUD2LCH+AUDxVOL
- clr.w AUD3LCH+AUDxVOL
- rts
-
- TimerIntRoutine:
- movem.l d1-d7/a0-a6,-(sp)
- bsr.s PlayRoutine
- movem.l (sp)+,d1-d7/a0-a6
- moveq #0,d0
- rts
-
- PlayRoutine:
- move.l modmem,a6
- move.w 8(a6),d0
- addq.w #1,PlayTimer
- cmp.w PlayTimer,d0 ; tempo == playtimer ?
- bne.s PlayEffects ; no, play effects
- clr.w PlayTimer ; yes, reset timer to zero
- bra PlaySound ; play note
-
- PlayEffects:
- lea ChannelData0,a0
- lea AUD0LCH,a1
- moveq #MAXTRACK-1,d3 ; 4 tracks
- PlayEffLoop:
- move.w (a0),d0
- and.w #$7ff,d0
- cmp.w #STOP,d0 ; note == STOP ?
- beq.s PlayEffLoopEnd
- tst.b ad_Info(a0) ; effect value == 0 ?
- beq.s PlayEffLoopEnd
- bsr.s MakeEffects
- PlayEffLoopEnd:
- add.l #SIZEOF_ad,a0 ; a0 -> next channeldata
- add.w #SIZEOF_AUD,a1 ; a1 -> next audio register
- dbra d3,PlayEffLoop
- rts
-
- MakeEffects:
- move.b ad_Effet(a0),d0
- beq.s EffArpeggio
- cmp.b #PITCHUP,d0
- beq.s EffPitchUp
- cmp.b #PITCHDOWN,d0
- beq.s EffPitchDown
- rts
-
- EffArpeggio:
- moveq #0,d0
- move.w PlayTimer,d0
- cmp.w #1,d0
- beq.s EffArpOne
- cmp.w #2,d0
- beq.s EffArpTwo
- cmp.w #3,d0
- beq.s EffArpThree
- cmp.w #4,d0
- beq.s EffArpTwo
- cmp.w #5,d0
- beq.s EffArpOne
- rts
-
- EffArpOne:
- move.b ad_Info(a0),d0
- lsr.b #4,d0 ; d0 = high nibble value
- bra.s EffArpSeek
- EffArpTwo:
- move.b ad_Info(a0),d0
- and.b #MASK_VAL,d0 ; d0 = low nibble value
- bra.s EffArpSeek
- EffArpThree:
- move.w ad_ArpPer(a0),d2 ; d2 = normal period
- bra.s EffArpFound
- EffArpSeek:
- add.w d0,d0 ; d0 = offset notetable
- move.w ad_ArpPer(a0),d1 ; d1 = normal period
- lea NoteTable,a2
- EffArpLoop:
- move.w 0(a2,d0.w),d2 ; d2 = new period
- cmp.w (a2)+,d1 ; (a2) == normal period
- bne.s EffArpLoop
- EffArpFound:
- move.w d2,AUDxPER(a1)
- rts
-
- EffPitchUp:
- moveq #0,d0
- move.b ad_Info(a0),d0 ; d0 = effect value
- sub.w d0,ad_PitchPer(a0)
- cmp.w #SI5,ad_PitchPer(a0) ; less than lowest period ?
- bpl.s EffPitchOK
- move.w #SI5,ad_PitchPer(a0)
- bra.s EffPitchOK
- EffPitchDown:
- moveq #0,d0
- move.b ad_Info(a0),d0
- add.w d0,ad_PitchPer(a0)
- cmp.w #DO2,ad_PitchPer(a0) ; more than highest period ?
- bmi.s EffPitchOK
- move.w #DO2,ad_PitchPer(a0)
- EffPitchOK:
- move.w ad_PitchPer(a0),AUDxPER(a1)
- rts
-
- PlaySound:
- lea sng_Data(a6),a0
- lea sng_Seq(a6),a1
- move.w CurrentPos,d0
- move.w d0,NewPosJump
- moveq #0,d1
- move.b 0(a1,d0.w),d1 ; d1 = block number
- moveq #10,d0
- lsl.l d0,d1
- add.l OffsetBlock,d1 ; d1 = offset into block data
- clr.w AudioDMA
-
- lea AUD0LCH,a3
- lea ChannelData0,a4
- moveq #MAXTRACK-1,d7 ; 4 tracks
- PlayLoop:
- bsr PlayInstr
- add.w #SIZEOF_AUD,a3
- add.l #SIZEOF_ad,a4
- dbra d7,PlayLoop
-
- move.w AudioDMA,d0 ; start audio DMA
- or.w #DMASET,d0
- move.w d0,DMACON
-
- move.b CIABCRA,d1 ; wait loop
- move.b d1,d0
- and.b #%11000000,d0
- or.b #%00001000,d0
- move.b d0,CIABCRA
- move.b #$2f,CIABTALO
- move.b #1,CIABTAHI
- PlayDelay1:
- btst.b #0,CIABCRA
- bne.s PlayDelay1
- move.b d1,CIABCRA
- move.b #%00000001,CIABICR
-
- lea ChannelData0,a0 ; set new value into audio registers
- lea AUD0LCH,a1
- moveq #MAXTRACK-1,d0
- SetNewValue:
- move.l ad_RepAdr(a0),(a1)
- move.w ad_RepLen(a0),AUDxLEN(a1)
- add.l #SIZEOF_ad,a0
- add.w #SIZEOF_AUD,a1
- dbra d0,SetNewValue
- cmp.l #BLOCKSIZE-NEXTLINE,OffsetBlock ; end of block ?
- beq.s ChangePosition
- add.l #NEXTLINE,OffsetBlock ; modif. offsetblock
- tst.w BreakStatus ; jump or break ?
- beq.s PlaySoundEnd
- clr.w BreakStatus
- ChangePosition:
- clr.l OffsetBlock ; offset block = 0
- move.w NewPosJump,CurrentPos
- addq.w #1,CurrentPos ; new position
- move.w sng_Len(a6),d0
- move.w CurrentPos,d1
- cmp.w d0,d1 ; end of song ?
- bne.s PlaySoundEnd
- clr.w CurrentPos ; position = 0
- PlaySoundEnd:
- rts
-
- PlayInstr:
- lea sng_Instr0(a6),a2
- move.l 0(a0,d1.l),ad_SampPer(a4)
- addq.l #NEXTTRACK,d1
- moveq #0,d0
- move.b ad_SampPer(a4),d0
- lsr.b #3,d0 ; d0 = instrument number
- tst.b d0 ; d0 == 0 ?
- beq.s NoSampleChange
-
- lea SampleAdrTable,a5
- subq.b #1,d0
- move.l d0,d3
- lsl.w #2,d0 ; d0 = SampleAdrTable offset
- mulu #SIZEOF_insdt,d3
- add.l #instr_Start,d3
- add.l d3,a2 ; a2 -> Start InstrData
- move.l 0(a5,d0.w),d4
- add.l (a2)+,d4 ; Start
- move.l d4,ad_SmpAdr(a4)
- beq.s NoSampleChange
- move.w (a2)+,ad_SmpLen(a4) ; Len
- move.l (a2)+,d5 ; RStart
- move.w (a2)+,d2 ; RLen
- bne.s SetRepeat
- moveq #1,d2
- moveq #0,d5
- SetRepeat:
- move.w d2,ad_RepLen(a4)
- add.l ad_SmpAdr(a4),d5
- move.l d5,ad_RepAdr(a4)
- move.w (a2),ad_Volume(a4) ; Volume
- NoSampleChange:
- move.w ad_SampPer(a4),d6
- and.w #$7ff,d6 ; note == 0 ?
- beq.s TestEffects
- move.w d6,ad_ArpPer(a4)
- move.w ad_DMABit(a4),d0
- move.w d0,DMACON ; cut DMA audio for this track
-
- move.b CIABCRA,d2 ; wait loop
- move.b d2,d3
- and.b #%11000000,d3
- or.b #%00001000,d3
- move.b d3,CIABCRA
- move.b #$2f,CIABTALO
- move.b #1,CIABTAHI
- PlayDelay2:
- btst.b #0,CIABCRA
- bne.s PlayDelay2
- move.b d2,CIABCRA
- move.b #%00000001,CIABICR
-
- cmp.w #STOP,d6 ; note == 'OFF' ?
- bne.s SetPlayRegs
- clr.w AUDxVOL(a3) ; set audio volume to 0
- or.w d0,AudioDMA
- rts
-
- SetPlayRegs:
- move.l ad_SmpAdr(a4),(a3) ; sample address == NULL ?
- beq.s TestEffects
- move.w ad_SmpLen(a4),AUDxLEN(a3)
- move.w d6,AUDxPER(a3)
- or.w d0,AudioDMA
- move.w d6,ad_PitchPer(a4)
- TestEffects:
- move.b ad_Effet(a4),d0 ; d0 = effect
- bsr.s EffVolume
- tst.b d0
- beq.s TestEffectsEnd
- cmp.b #FILTER,d0
- beq EffFilter
- cmp.b #MASTERVOL,d0
- beq.s EffMaster
- cmp.b #TEMPO,d0
- beq.s EffSpeed
- cmp.b #JUMP,d0
- beq.s EffJump
- TestEffectsEnd:
- rts
-
- EffVolume: ; modify volume
- cmp.w #VOLUME,d0
- bne.s UseInstrVol
- moveq #0,d2
- move.b ad_Info(a4),d2 ; d0 = new volume
- bra.s SetInstrVol
- UseInstrVol:
- tst.w d6
- beq.s EffVolumeEnd
- move.w ad_Volume(a4),d2
- SetInstrVol:
- sub.w MasterVolume,d2 ; new volume - master >= 0
- bge.s SetVolumeReg
- moveq #0,d2 ; new volume = 0
- SetVolumeReg:
- move.w d2,AUDxVOL(a3) ; new volume into audio reg
- EffVolumeEnd:
- rts
-
- EffMaster: ; modify master volume
- moveq #MAX_VOL,d2
- move.b ad_Info(a4),d0
- sub.b d0,d2
- blt.s EffMasterEnd
- move.b d2,MasterVolume+1
- EffMasterEnd:
- rts
-
- EffSpeed: ; modify tempo
- move.b ad_Info(a4),d0
- beq.s EffSpeedEnd
- clr.w PlayTimer
- move.b d0,sng_Tempo+1(a6)
- EffSpeedEnd:
- rts
-
- EffJump: ; jump or break
- move.w #1,BreakStatus
- move.b ad_Info(a4),d0
- cmp.b #BREAK,d0
- beq.s EffBreak
- subq.b #2,d0
- ext.w d0
- move.w d0,NewPosJump
- rts
- EffBreak:
- move.w CurrentPos,NewPosJump
- rts
-
- EffFilter: ; filter on/off
- move.b ad_Info(a4),d0
- bne.s SetFilter
- bset #1,CIAAPRA
- rts
- SetFilter:
- bclr #1,CIAAPRA
- rts
-
- data __MERGED
-
- CiabBase: dc.l 0
- IsNTSC: dc.w 0
-
- CiabName: dc.b 'ciab.resource',0
- TimerIntName: dc.b 'DSS Tracker Player',0
- cnop 0,2
-
- TimerInt:
- dc.l 0 ; Interrupt.is_Node.ln_Succ
- dc.l 0 ; Interrupt.is_Node.ln_Pred
- dc.b 2 ; Interrupt.is_Node.ln_Type = NT_INTERRUPT
- dc.b -10 ; Interrupt.is_Node.ln_Pri
- dc.l TimerIntName ; Interrupt.is_Node.ln_Name
- dc.l 0 ; Interrupt.is_Data
- dc.l TimerIntRoutine ; Interrupt.is_Code
-
- clrstart
-
- PlayOn: dc.w 0
- PlayTimer: dc.w 0
- CurrentPos: dc.w 0
- OffsetBlock: dc.l 0
- AudioDMA: dc.w 0
- MasterVolume: dc.w 0
- BreakStatus: dc.w 0
- NewPosJump: dc.w 0
-
- clrend
-
- ChannelData0:
- dc.w 0 ; Period 0
- dc.w 0 ; Sample+Info 2
- dc.w 0 ; Volume 4
- dc.l 0 ; Sample address 6
- dc.w 0 ; Sample length 10
- dc.l 0 ; Repeat address 12
- dc.w 0 ; Repeat length 16
- dc.w 0 ; Shazam period 18
- dc.w 1 ; DMA bit 20
- dc.w 0 ; Pitch period 22
- ChannelData1:
- ds.w 10
- dc.w 2
- dc.w 0
- ChannelData2:
- ds.w 10
- dc.w 4
- dc.w 0
- ChannelData3:
- ds.w 10
- dc.w 8
- dc.w 0
-
- dc.w 1712
- NoteTable:
- dc.w 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906
- 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
- dc.w 113,113,113,113,113,113,113,113,113,113,113,113
- dc.w 113,113,113,113,113,113,113,113,113,113,113,113
- dc.w 113,113,113,113,113,113
-
- TimerTable: dc.w 14187,14318
-
- SampleAdrTable: ds.l 31
-
- name dc.b "Digital Sound Studio",0
-
- end
-