home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Best of Mecomp Multimedia 1
/
Mecomp-CD.iso
/
amiga
/
player
/
ahi
/
developer
/
drivers
/
paula
/
paula_audio.a
next >
Wrap
Text File
|
1996-11-01
|
62KB
|
2,586 lines
*** ScR ***
*** NOTES ***
* There is still room for improvements in the softint's. For example,
* try if reducing chip memory accesses increases speed. Not high priority, though.
* This driver should probably have a DMA play mode for 1-4 stereo channels.
*
* The sampler routines are just for fun. Since interrupts must not be disabled,
* there are lots of clicks. But still, I have tried to sample at 22kHz while down-
* loading files from a BBS on my A4000/040, and it worked without any serial errors.
;------------
VERSION EQU 2
REVISION EQU 4
DATE MACRO
dc.b "11.10.96"
ENDM
VERS MACRO
dc.b "paula 2.4"
ENDM
VSTRING MACRO
VERS
dc.b " ("
DATE
dc.b ")",13,10,0
ENDM
VERSTAG MACRO
dc.b 0,"$VER: "
VERS
dc.b " ("
DATE
dc.b ")",0
ENDM
incdir include:
include hardware/all.i
include exec/exec.i
include graphics/gfxbase.i
include utility/utility.i
include utility/hooks.i
include devices/audio.i
include dos/dos.i
include lvo/exec_lib.i
include lvo/utility_lib.i
include lvo/dos_lib.i
include lvo/cardres_lib.i
include devices/ahi.i
include libraries/ahi_sub.i
include resources/misc.i
include resources/card.i
include macros.i
_ciaa EQU $bfe001
_ciab EQU $bfd000
PALFREQ EQU 3546895
NTSCFREQ EQU 3579545
MINPER EQU 62
RECORDSAMPLES EQU 1024
IFD BARFLY
IFD MC020
MC68020
ENDC
ELSE
IFD MC020
auto wo AHI:user/devs/ahi/paula.audio\
ELSE
auto wo AHI:user/devs/ahi/paula.audio.000\
ENDC
ENDC * BARFLY
* paula.audio extra tags
AHIDB_Paula14Bit EQU AHIDB_UserBase+0 * Boolean
AHIDB_PaulaTable EQU AHIDB_UserBase+1 * Boolean
AHIDB_PaulaRecord EQU AHIDB_UserBase+2 * Boolean
RECORD_PARALLELMONO EQU 1
RECORD_AURA EQU 2
* paulaBase (private)
STRUCTURE paulaBase,LIB_SIZE
UBYTE pb_Flags
UBYTE pb_Pad1
UWORD pb_Pad2
APTR pb_SysLib
ULONG pb_SegList
APTR pb_GfxLib
APTR pb_UtilLib
APTR pb_DosLib
APTR pb_MiscResource
APTR pb_CardResource
LABEL paulaBase_SIZEOF
* paula (private) ahiac_DriverData points to this structure.
STRUCTURE paula,0
UBYTE p_Flags
UBYTE p_Pad
UWORD p_DisableCount
APTR p_audioport
APTR p_audioreq
ULONG p_audiodev
APTR p_DMAbuffer
APTR p_ParBitsUser
APTR p_ParPortUser
APTR p_CardHandle
STRUCT p_PlayInt,IS_SIZE
STRUCT p_PlaySoftInt,IS_SIZE
STRUCT p_RecInt,IS_SIZE
STRUCT p_RecSoftInt,IS_SIZE
UWORD p_MonitorVolume
UWORD p_Pad2
*** IS_DATA for Play Interrupt (do not change order!)
LABEL p_PlayIntData
APTR p_PlaySoftIntPtr
UWORD p_AudLen ;don't change order
UWORD p_AudPer ;
ULONG p_DoubleBufferFlag
APTR p_AudPtr1A
APTR p_AudPtr2A
APTR p_AudPtr3A
APTR p_AudPtr4A
APTR p_AudPtr1B
APTR p_AudPtr2B
APTR p_AudPtr3B
APTR p_AudPtr4B
*** IS_DATA for Play Software Interrupt (do not change order!)
LABEL p_PlaySoftIntData
APTR p_PlayerHook
ULONG p_Reserved
APTR p_AudioCtrlP
FPTR p_PlayerEntry ;p_PlayerHook->h_Entry
ULONG p_LoopTimes
APTR p_MixHook
APTR p_Mixbuffer
APTR p_AudioCtrlM
FPTR p_MixEntry ;p_MixHook->h_Entry
APTR p_AudPtrs
APTR p_CalibrationTable
*** IS_DATA for Aura Record Interrupt (do not change order!)
LABEL p_RecIntDataAura
APTR p_AuraAddress
*** IS_DATA for Paula Record Interrupt (do not change order!)
LABEL p_RecIntData
APTR p_RecFillPtr
UWORD p_RecFillCount
UWORD p_Pad3
APTR p_RecBuffer1
APTR p_RecBuffer2
APTR p_RecSoftIntPtr
LABEL p_RecordMessage
ULONG p_rmType
APTR p_rmBuffer
ULONG p_rmLength
STRUCT p_CalibrationArray,256
LABEL paula_SIZEOF
* p_Flags
BITDEF P,14BIT,0
BITDEF P,RECORD,1
PB_STEREO EQU AHIACB_STEREO ;=2
PF_STEREO EQU AHIACF_STEREO
BITDEF P,AURA,3
Start:
moveq #-1,d0
rts
RomTag:
DC.W RTC_MATCHWORD
DC.L RomTag
DC.L EndCode
DC.B RTF_AUTOINIT
DC.B VERSION ;version
DC.B NT_LIBRARY
DC.B 0 ;pri
DC.L LibName
DC.L IDString
DC.L InitTable
LibName: dc.b "paula.audio",0
IDString: VSTRING
gfxName: GRAPHICSNAME
utilName: UTILITYNAME
dosName: DOSNAME
miscName: MISCNAME
cardName: dc.b "card.resource",0
cnop 0,2
InitTable:
DC.L paulaBase_SIZEOF
DC.L funcTable
DC.L dataTable
DC.L initRoutine
funcTable:
dc.l Open
dc.l Close
dc.l Expunge
dc.l Null
*
dc.l AHIsub_AllocAudio
dc.l AHIsub_FreeAudio
dc.l AHIsub_Disable
dc.l AHIsub_Enable
dc.l AHIsub_Start
dc.l AHIsub_Update
dc.l AHIsub_Stop
dc.l AHIsub_SetVol
dc.l AHIsub_SetFreq
dc.l AHIsub_SetSound
dc.l AHIsub_SetEffect
dc.l AHIsub_LoadSound
dc.l AHIsub_UnloadSound
dc.l AHIsub_GetAttr
dc.l AHIsub_HardwareControl
dc.l -1
dataTable:
INITBYTE LN_TYPE,NT_LIBRARY
INITLONG LN_NAME,LibName
INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
INITWORD LIB_VERSION,VERSION
INITWORD LIB_REVISION,REVISION
INITLONG LIB_IDSTRING,IDString
DC.L 0
initRoutine:
movem.l d1/a0/a1/a5/a6,-(sp)
move.l d0,a5
move.l a6,pb_SysLib(a5)
move.l a0,pb_SegList(a5)
lea gfxName(pc),a1
moveq #0,d0
call OpenLibrary
move.l d0,pb_GfxLib(a5)
bne.b .gfxOK
ALERT AG_OpenLib!AO_GraphicsLib
moveq #0,d0
bra .exit
.gfxOK
lea utilName(pc),a1
moveq #0,d0
call OpenLibrary
move.l d0,pb_UtilLib(a5)
bne.b .utilOK
ALERT AG_OpenLib!AO_UtilityLib
moveq #0,d0
bra .exit
.utilOK
lea dosName(pc),a1
moveq #0,d0
call OpenLibrary
move.l d0,pb_DosLib(a5)
bne.b .dosOK
ALERT AG_OpenLib!AO_DOSLib
moveq #0,d0
bra .exit
.dosOK
lea miscName(pc),a1
call OpenResource
move.l d0,pb_MiscResource(a5)
bne.b .miscOK
ALERT AG_OpenRes!AO_MiscRsrc
moveq #0,d0
bra .exit
.miscOK
lea cardName(pc),a1
call OpenResource
move.l d0,pb_CardResource(a5) ;Don't fail on error
move.l a5,d0
.exit
movem.l (sp)+,d1/a0/a1/a5/a6
rts
Open:
moveq #0,d0
addq.w #1,LIB_OPENCNT(a6)
bclr.b #LIBB_DELEXP,pb_Flags(a6)
move.l a6,d0
.exit
rts
Close:
moveq #0,d0
subq.w #1,LIB_OPENCNT(a6)
bne.b .exit
btst.b #LIBB_DELEXP,pb_Flags(a6)
beq.b .exit
bsr Expunge
.exit
rts
Expunge:
movem.l d1/d2/a0/a1/a5/a6,-(sp)
move.l a6,a5
move.l pb_SysLib(a5),a6
tst.w LIB_OPENCNT(a5)
beq.b .notopen
bset.b #LIBB_DELEXP,pb_Flags(a5)
moveq #0,d0
bra.b .Expunge_end
.notopen
move.l pb_GfxLib(a5),a1
call CloseLibrary
move.l pb_UtilLib(a5),a1
call CloseLibrary
move.l pb_DosLib(a5),a1
call CloseLibrary
move.l pb_SegList(a5),d2
move.l a5,a1
call Remove
moveq #0,d0
move.l a5,a1
move.w LIB_NEGSIZE(a5),d0
sub.l d0,a1
add.w LIB_POSSIZE(a5),d0
call FreeMem
move.l d2,d0
.Expunge_end
movem.l (sp)+,d1/d2/a0/a1/a5/a6
rts
Null:
moveq #0,d0
rts
* BeginIO(ioRequest)(a1) (From amiga.lib)
BeginIO:
move.l a1,a0 ;probably not neccesary
push a6
move.l IO_DEVICE(a1),a6
jsr -30(a6)
pop a6
rts
******* [driver].audio/--background-- ***************************************
*
* OVERVIEW
*
* AUDIO ID NUMBERS
*
* Just some notes about selecting ID numbers for different modes:
* It is up to the driver programmer to chose which modes should be
* available to the user. Take care when selecting.
* The upper word is the hardware ID, and can only be allocated by
* Martin Blom <lcs@lysator.liu.se>. The lower word is free, but in
* order to allow enhanchments, please only use bit 0 to 3 for modes!
* Set the remaining bits to zero.
* The ID is currently used by AHI_BestAudioIDA() to select a mode.
* In order for this to work, you have to follow some rules.
* · Modes using tables should have higher IDs than modes that uses more
* CPU power.
* · Mono modes should have higher IDs than stereo modes
* · Stereo modes should have higher IDs than stereo modes with panning.
* Use AHI:Developer/Support/ScanAudioModes to have a look at the modes
* currently avalable.
*
* I do reserve the right to change the rules if I find them incorrect!
*
*****************************************************************************
*
*
******* [driver].audio/AHIsub_AllocAudio ************************************
*
* NAME
* AHIsub_AllocAudio -- Allocates and initializes the audio hardware.
*
* SYNOPSIS
* result = AHIsub_AllocAudio( tags, audioctrl);
* D0 A1 A2
*
* ULONG AHIsub_AllocAudio( struct TagItem *, struct AHIAudioCtrlDrv * );
*
* IMPLEMENTATION
* Allocate and initialize the audio hardware. Decide if and how you
* wish to use the mixing routines provided by 'ahi.device', by looking
* in the AHIAudioCtrlDrv structure and parsing the tag list for tags
* you support.
*
* 1) Use mixing routines with timing:
* You will need to be able to play any number of samples from
* about 80 up to 65535 with low overhead.
* · Update AudioCtrl->ahiac_MixFreq to nearest value that your
* hardware supports.
* · Return AHISF_MIXING|AHISF_TIMING.
* 2) Use mixing routines without timing:
* If the hardware can't play samples with any length, use this
* alternative and provide timing yourself. The buffer must
* take less than about 20 ms to play, preferable less than 10!
* · Update AudioCtrl->ahiac_MixFreq to nearest value that your
* hardware supports.
* · Store the number of samples to mix each pass in
* AudioCtrl->ahiac_BuffSamples.
* · Return AHISF_MIXING
* Alternatively, you can use the first method and call the
* mixing hook several times in a row to fill up a buffer.
* In that case, AHIsub_GetAttr(AHIDB_MaxPlaySamples) should
* return the size of the buffer plus AudioCtrl->ahiac_MaxBuffSamples.
* If the buffer is so large that it takes more than (approx.) 10 ms to
* play it for high sample frequencies, AHIsub_GetAttr(AHIDB_Realtime)
* should return FALSE.
* 3) Don't use mixing routines:
* If your hardware can handle everyting without using the CPU to
* mix the channels, you tell 'ahi.device' this by not setting
* neither the AHISB_MIXING nor the AHISB_TIMING bit.
*
* If you can handle stereo output from the mixing routines, also set
* bit AHISB_KNOWSTEREO.
*
* If you can handle hifi (32 bit) output from the mixing routines,
* set bit AHISB_KNOWHIFI.
*
* If this driver can be used to record samples, set bit AHISB_CANRECORD,
* too (regardless if you use the mixing routines in AHI or not).
*
* If the sound card has hardware to do DSP effects, you can set the
* AHISB_CANPOSTPROCESS bit. The output from the mixing routines will
* then be two separate buffers, one wet and one dry. You sould then
* apply the Fx on the wet buffer, and post-mix the two buffers before
* you send the sampels to the DAC. (V3)
*
* INPUTS
* tags - pointer to a taglist.
* audioctrl - pointer to an AHIAudioCtrlDrv structure.
*
* TAGS
* The tags are from the audio database (AHIDB_#? in <devices/ahi.h>),
* NOT the tag list the user called ahi.device/AHI_AllocAudio() with.
*
* RESULT
* Flags, defined in <libraries/ahi_sub.h>.
*
* EXAMPLE
*
* NOTES
* You don't have to clean up on failure, AHIsub_FreeAudio() will
* allways be called.
*
* BUGS
*
* SEE ALSO
* AHIsub_FreeAudio(), AHIsub_Start()
*
*****************************************************************************
*
*
AHIsub_AllocAudio:
pushm d2-d7/a2-a6
move.l a6,a5
move.l a1,d3
* Allocate the 'paula' structure (our variables)
move.l pb_SysLib(a5),a6
move.l #paula_SIZEOF,d0
move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
call AllocVec
move.l d0,ahiac_DriverData(a2)
beq .error_nopaula
move.l d0,a3
* Initialize some fields...
move.l #-1,p_audiodev(a3)
move.l #-1,p_ParBitsUser(a3)
move.l #-1,p_ParPortUser(a3)
move.l a2,p_AudioCtrlP(a3) ;player Hook
move.l a2,p_AudioCtrlM(a3) ;mixer Hook
lea p_PlaySoftInt(a3),a0
move.l a0,p_PlaySoftIntPtr(a3)
lea p_RecSoftInt(a3),a0
move.l a0,p_RecSoftIntPtr(a3)
move.l #AHIST_S16S,p_rmType(a3)
move.l #RECORDSAMPLES,p_rmLength(a3)
* Translate tags to flags
moveq #0,d2
move.l pb_UtilLib(a5),a6
move.l #AHIDB_Paula14Bit,d0
moveq #0,d1
move.l d3,a0 ;tag list
call GetTagData
tst.l d0
beq.b .no14bit
moveq #PF_14BIT,d2
.no14bit
move.l #AHIDB_PaulaRecord,d0
moveq #0,d1
move.l d3,a0 ;tag list
call GetTagData
tst.l d0
beq.b .norecord
or.b #PF_RECORD,d2
cmp.l #RECORD_AURA,d0
bne.b .noAura
or.b #PF_AURA,d2
.noAura
.norecord
move.l ahiac_Flags(a2),d0
and.b #PF_STEREO,d0 ;same as AHIACF_STEREO
or.b d2,d0
move.b p_Flags(a3),d1
and.b #~(PF_AURA|PF_STEREO|PF_RECORD|PF_14BIT),d1
or.b d0,d1
move.b d1,p_Flags(a3)
* Check if a table should be used (14 bit calibration)
move.l #AHIDB_PaulaTable,d0
moveq #0,d1
move.l d3,a0 ;tag list
call GetTagData
tst.l d0
beq .notable
* Load 'ENV:CyberSound/SoundDrivers/14Bit_Calibration', allocate
* and initialize the table.
* FIXIT: The calibration file should move to a special chunk in
* 'DEVS:AudioModes/PAULA'.
move.l pb_DosLib(a5),a6
lea .calibname(pc),a0
move.l a0,d1
move.l #MODE_OLDFILE,d2
call Open
move.l d0,d4
beq .nocalib
move.l d0,d1
lea p_CalibrationArray(a3),a0
move.l a0,d2
move.l #256,d3
call Read
cmp.l d0,d3
beq .tableloaded
.nocalib
; Fill defaults
lea p_CalibrationArray(a3),a0
move.w #254-1,d0
.initcalib
move.b #$55,(a0)+
dbf d0,.initcalib
move.b #$7f,(a0)+
.tableloaded
move.l d4,d1
beq.b .nofile
call Close
.nofile
move.l pb_SysLib(a5),a6
move.l #65536*2,d0
move.l #MEMF_PUBLIC,d1
call AllocVec
move.l d0,p_CalibrationTable(a3)
beq.b .notable
move.l d0,a0 ;table
lea p_CalibrationArray(a3),a1
bsr.w _CreateTable
.notable
* allocate audio.device
move.l pb_SysLib(a5),a6
call CreateMsgPort
move.l d0,p_audioport(a3)
beq .error_noport
moveq #ioa_SIZEOF,d0
move.l #MEMF_PUBLIC!MEMF_CLEAR,d1
call AllocVec
move.l d0,p_audioreq(a3)
beq .error_noreqmem
move.l d0,a0
move.l p_audioport(a3),MN_REPLYPORT(a0)
clr.w ioa_AllocKey(a0)
move.b #127,LN_PRI(a0) ;steal it!
lea .audiochannelarray(pc),a1
move.l a1,ioa_Data(a0)
move.l #1,ioa_Length(a0)
lea .audioname(pc),a0
moveq #0,d0
move.l p_audioreq(a3),a1
moveq #0,d1
call OpenDevice
move.l d0,p_audiodev(a3)
bne .error_noaudiodev ;somebody already owns the hardware (could be us!)
move.l p_audioreq(a3),a1
move.w #CMD_RESET,IO_COMMAND(a1)
bsr.w BeginIO ;clear attach, stop sound.
move.l p_audioport(a3),a0
call WaitPort
move.l p_audioport(a3),a0
call GetMsg
* test if mode supports recording
btst #PB_RECORD,p_Flags(a3)
beq .dontgetsampler
btst #PB_AURA,p_Flags(a3)
bne .getAura
* allocate parallel port
move.l pb_MiscResource(a5),a6
moveq #MR_PARALLELBITS,d0
lea IDString(pc),a1
jsr MR_ALLOCMISCRESOURCE(a6)
move.l d0,p_ParBitsUser(a3)
bne .error_noparbits
moveq #MR_PARALLELPORT,d0
lea IDString(pc),a1
jsr MR_ALLOCMISCRESOURCE(a6)
move.l d0,p_ParPortUser(a3)
bne .error_noparport
move.b #0,_ciaa+ciaddrb ;make PB0-PB7 inputs
bra .gotSampler
* allocate Aura sampler
.getAura
moveq #0,d2
move.l d2,p_AuraAddress(a3)
move.l pb_CardResource(a5),d0
beq .error_nocardres
move.l d0,a6
call GetCardMap
tst.l d0
beq .error_nocardmap
move.l d0,a0
move.l cmm_IOMemory(a0),d2
beq .error_nocardiomem
base exec
moveq #CardHandle_SIZEOF,d0
move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
call AllocVec
move.l d0,p_CardHandle(a3)
beq .error_nocardhandle
move.l pb_CardResource(a5),a6
move.l d0,a1
move.l #IDString,LN_NAME(a1)
move.b #CARDF_RESETREMOVE|CARDF_IFAVAILABLE,cah_CardFlags(a1)
call OwnCard
tst.l d0
bne .error_nocardavailable
move.l p_CardHandle(a3),a1
call BeginCardAccess
tst.l d0
beq .error_nocardavailable
move.l d2,p_AuraAddress(a3)
.gotSampler
.dontgetsampler
* initialize interrupts (Only dummy function pointers at this time)
* p_PlayInt (the main playback interrupt)
move.b #NT_INTERRUPT,LN_TYPE+p_PlayInt(a3)
move.l #LibName,LN_NAME+p_PlayInt(a3)
move.l #Interrupt_Dummy,IS_CODE+p_PlayInt(a3)
lea p_PlayIntData(a3),a1
move.l a1,IS_DATA+p_PlayInt(a3)
* p_PlaySoftInt (caused by p_PlayInt, here are the mixing and conversion done)
move.b #NT_INTERRUPT,LN_TYPE+p_PlaySoftInt(a3)
move.l #LibName,LN_NAME+p_PlaySoftInt(a3)
move.l #SoftInt_Dummy,IS_CODE+p_PlaySoftInt(a3)
lea p_PlaySoftIntData(a3),a1
move.l a1,IS_DATA+p_PlaySoftInt(a3)
* p_RecInt (the interrupt used for recording)
move.b #NT_INTERRUPT,LN_TYPE+p_RecInt(a3)
move.l #LibName,LN_NAME+p_RecInt(a3)
move.l #Interrupt_Dummy,IS_CODE+p_RecInt(a3)
lea p_RecIntData(a3),a1
move.l a1,IS_DATA+p_RecInt(a3)
* p_RecSoftInt (caused by p_RecInt when the record buffer has been filled)
move.b #32,LN_PRI+p_RecSoftInt(a3)
move.b #NT_INTERRUPT,LN_TYPE+p_RecSoftInt(a3)
move.l #LibName,LN_NAME+p_RecSoftInt(a3)
move.l #RecordSoftInt,IS_CODE+p_RecSoftInt(a3)
move.l a3,IS_DATA+p_RecSoftInt(a3)
* Make sure no interrupts occur until AHIsub_Start() is called
move.w #INTF_AUD0!INTF_AUD1!INTF_AUD2!INTF_AUD3,CUSTOM+INTENA
* Update ahiac_MixFreq to what the mixing/sampling frequency really is
move.l ahiac_MixFreq(a2),d1
bsr calcperiod
move.l d0,ahiac_MixFreq(a2) ;store actual freq
bset #1,$bfe001 ;turn audio filter off
moveq #AHISF_KNOWSTEREO|AHISF_CANRECORD|AHISF_MIXING|AHISF_TIMING,d0
.exit
popm d2-d7/a2-a6
rts
.error_nocardavailable
.error_nocardhandle
.error_nocardiomem
.error_nocardmap
.error_nocardres
.error_noparport
.error_noparbits
.error_noaudiodev
.error_noreqmem
.error_noport
.error_nopaula
moveq #AHISF_ERROR,d0
bra.b .exit
.audiochannelarray
dc.b 1+2+4+8
.audioname
AUDIONAME
.calibname
dc.b "ENV:CyberSound/SoundDrivers/14Bit_Calibration",0
even
.cardhandle:
dc.l 0,0 ;ln_Succ, ln_Pred
dc.b 0 ;ln_Type
dc.b 0 ;ln_Pri
dc.l IDString ;ln_Name
dc.l 0,0,0 ;cah_CardRemoved, cah_CardInserted, cah_CardStatus
dc.b (CARDF_RESETREMOVE|CARDF_IFAVAILABLE)
even
;in:
* d1 MixFreq
* a5 paulaBase
;out:
* d0 New MixFreq
* d1.w Period
;description:
* Calculate and return the best period and the actual frequency.
calcperiod:
pushm d2-d4
move.l #PALFREQ,d2 ;PAL
move.l pb_GfxLib(a5),a0
move.w gb_DisplayFlags(a0),d0
btst #REALLY_PALn,d0
bne.b .1
move.l #NTSCFREQ,d2 ;NTSC
.1
move.l d2,d0
move.l d1,d3
move.l pb_UtilLib(a5),a1
jsr _LVOUDivMod32(a1)
lsl.l #1,d1
cmp.l d3,d1
bmi.b .3
addq.l #1,d0
.3
move.w d0,d4
* d4 is now period. Check if is it a valid one, depending on current display mode
bsr checkvideo
moveq #MINPER,d1
tst.l d0
bne.b .5
moveq #MINPER*2,d1
.5
cmp.w d1,d4
bhs.b .6
move.w d1,d4
.6
moveq #0,d1
move.w d4,d1
move.l d2,d0
move.l d1,d3
jsr _LVOUDivMod32(a1)
lsl.l #1,d1
cmp.l d3,d1
bmi.b .4
addq.l #1,d0
.4
move.w d4,d1
popm d2-d4
rts
;in:
* a5 paulaBase
;out:
* d0 TRUE if current mode is double
;description:
* Checks if the current screen mode is doublescan.
* This routine is *pretty* ugly, but it does get the job
* done, even if a graphic card is used.
checkvideo:
move.l pb_GfxLib(a5),a0
cmp.w #39,LIB_VERSION(a0)
beq.b .known
cmp.w #40,LIB_VERSION(a0)
beq.b .known
bra.b .nodbl
.known
move.l gb_copinit(a0),a0
cmp.w #$01FC,copinit_fm0(a0) ;Security check (test if really FMODE)
bne.b .nodbl
move.w copinit_fm0+2(a0),d0
and.w #$c000,d0 ;Mask sprite and bitplane double bit
beq.b .nodbl
moveq #TRUE,d0
rts
.nodbl
moveq #FALSE,d0
rts
;in:
* d0 Frequency
;out:
* d0 Closest frequency
* d1 Index
findfreq:
lea freqlist(pc),a0
cmp.l (a0),d0
bls.b .2
.findfreq
cmp.l (a0)+,d0
bhi.b .findfreq
move.l -4(a0),d1
sub.l d0,d1
sub.l -8(a0),d0
cmp.l d1,d0
bhs.b .1
subq.l #4,a0
.1
subq.l #4,a0
.2
move.l (a0),d0
move.l a0,d1
sub.l #freqlist,d1
lsr.l #2,d1
rts
freqlist:
dc.l 4410 ; CD/10
dc.l 4800 ; DAT/10
dc.l 5513 ; CD/8
dc.l 6000 ; DAT/8
dc.l 7350 ; CD/6
dc.l 8000 ; µ- and A-Law, DAT/6
dc.l 9600 ; DAT/5
dc.l 11025 ; CD/4
dc.l 12000 ; DAT/4
dc.l 14700 ; CD/3
dc.l 16000 ; DAT/3
dc.l 17640 ; CD/2.5
dc.l 18900
dc.l 19200 ; DAT/2.5
dc.l 22050 ; CD/2
dc.l 24000 ; DAT/2
dc.l 27429
FREQUENCIES_OCS EQU (*-freqlist)/4
dc.l 29400 ; CD/1.5
dc.l 32000 ; DAT/1.5
dc.l 33075
dc.l 37800
dc.l 44100 ; CD
dc.l 48000 ; DAT
FREQUENCIES EQU (*-freqlist)/4
dc.l -1
* _CreateTable directly stolen from Christian Buchner's CyberSound
* audio sub system (with permission).
* _CreateTable **************************************************************
; Parameters
; a0 = Table address
; (MUST have enough space for 65536 UWORDS)
; a1 = Additive Array
; 256 UBYTEs
;
; the table is organized as follows:
; 32768 UWORDS positive range, ascending order
; 32768 UWORDS negative range, ascending order
; access: (a0,d0.l*2)
; where d0.w is signed word sample data
; and the upper word of d0.l is *cleared!*
_CreateTable movem.l a2/d2-d6,-(sp)
lea 128(a1),a2
move.l a2,a1 ; count the number of steps
moveq #128-1,d0 ; in the positive range
moveq #0,d5
.countpositive move.b (a1)+,d1
ext.w d1
ext.l d1
add.l d1,d5
dbra d0,.countpositive ; d5=number of steps
move.l #32768,d6 ; reset stretch counter
move.l a2,a1 ; middle value in calibdata
move.w #32768-1,d0 ; number of positive values -1
moveq #0,d1 ; HI value
moveq #0,d2 ; LO value
moveq #0,d3 ; counter
.fetchnext2 move.b (a1)+,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
sub.w d4,d2 ; reset LO value
bra.s .fetchnext2
.positive2 move.b d1,(a0)+ ; store HI and LO value
move.b d2,(a0)+
sub.l d5,d6 ; stretch the table
bpl.s .repeat2 ; to 32768 entries
add.l #32768,d6
addq.w #1,d2 ; increment LO value
subq.w #1,d3 ; decrement counter
.repeat2 dbra d0,.outerloop2
move.l a2,a1 ; count the number of steps
moveq #128-1,d0 ; in the negative range
moveq #0,d5
.countnegative move.b -(a1),d1
ext.w d1
ext.l d1
add.l d1,d5
dbra d0,.countnegative ; d5=number of steps
move.l #32768,d6 ; reset stretch counter
add.l #2*32768,a0 ; place at the end of the table
move.l a2,a1 ; middle value in calibdata
move.w #32768-1,d0 ; number of negative values -1
moveq #-1,d1 ; HI value
moveq #-1,d2 ; LO value
moveq #0,d3 ; counter
.fetchnext1 move.b -(a1),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
bra.s .fetchnext1
.positive1 move.b d2,-(a0) ; store LO and HI value
move.b d1,-(a0)
sub.l d5,d6 ; stretch the table
bpl.s .repeat1 ; to 32768 entries
add.l #32768,d6
subq.w #1,d2 ; decrement lo value
subq.w #1,d3 ; decrement counter
.repeat1 dbra d0,.outerloop1
movem.l (sp)+,a2/d2-d6
rts
******* [driver].audio/AHIsub_FreeAudio *************************************
*
* NAME
* AHIsub_FreeAudio -- Deallocates the audio hardware.
*
* SYNOPSIS
* AHIsub_FreeAudio( audioctrl );
* A2
*
* void AHIsub_FreeAudio( struct AHIAudioCtrlDrv * );
*
* IMPLEMENTATION
* Deallocate the audio hardware and other resources allocated in
* AHIsub_AllocAudio(). AHIsub_Stop() will always be called by
* 'ahi.device' before this call is made.
*
* INPUTS
* audioctrl - pointer to an AHIAudioCtrlDrv structure.
*
* NOTES
* It must be safe to call this routine even if AHIsub_AllocAudio()
* was never called, failed or called more than once.
*
* SEE ALSO
* AHIsub_AllocAudio()
*
*****************************************************************************
*
*
AHIsub_FreeAudio:
pushm d2-d7/a2-a6
move.l a6,a5
move.l pb_SysLib(a5),a6
move.l ahiac_DriverData(a2),d0
beq .nopaula
move.l d0,a3
move.l p_CalibrationTable(a3),d0
beq.b .notable
move.l d0,a1
call FreeVec
.notable
tst.l p_audiodev(a3)
bne.b .noaudiodev
move.l p_audioreq(a3),a1
move.w #CMD_RESET,IO_COMMAND(a1) ;Restore audio interrupts
bsr.w BeginIO
move.l p_audioport(a3),a0
call WaitPort
move.l p_audioport(a3),a0
call GetMsg
move.l p_audioreq(a3),a1
subq.l #1,p_audiodev(a3)
call CloseDevice
.noaudiodev
move.l p_audioreq(a3),d0
beq.b .noaudioreq
move.l d0,a1
call FreeVec
.noaudioreq
move.l p_audioport(a3),d0
beq.b .noaudioport
move.l d0,a0
call DeleteMsgPort
.noaudioport
move.l pb_CardResource(a5),d0
beq .noaura
move.l d0,a6
move.l p_CardHandle(a3),d0
beq .noaura
move.l d0,a1
call EndCardAccess
move.l p_CardHandle(a3),a1
moveq #CARDF_REMOVEHANDLE,d0
call ReleaseCard
.noaura
move.l pb_SysLib(a5),a6
move.l p_CardHandle(a3),d0
beq .nocardhandle
move.l d0,a1
call FreeVec
.nocardhandle
move.l pb_MiscResource(a5),a6
tst.l p_ParPortUser(a3)
bne.b .noparport
moveq #MR_PARALLELPORT,d0
jsr MR_FREEMISCRESOURCE(a6)
.noparport
tst.l p_ParBitsUser(a3)
bne.b .noparbits
moveq #MR_PARALLELBITS,d0
jsr MR_FREEMISCRESOURCE(a6)
.noparbits
move.l pb_SysLib(a5),a6
move.l a3,a1
clr.l ahiac_DriverData(a2)
call FreeVec
.nopaula
moveq #0,d0
popm d2-d7/a2-a6
rts
******* [driver].audio/AHIsub_Disable ***************************************
*
* NAME
* AHIsub_Disable -- Temporary turn off audio interrupt/task
*
* SYNOPSIS
* AHIsub_Disable( audioctrl );
* A2
*
* void AHIsub_Disable( struct AHIAudioCtrlDrv * );
*
* IMPLEMENTATION
* If you are lazy, then call exec.library/Disable().
* If you are smart, only disable your own interrupt or task.
*
* INPUTS
* audioctrl - pointer to an AHIAudioCtrlDrv structure.
*
* NOTES
* This call should be guaranteed to preserve all registers.
* This call nests.
*
* SEE ALSO
* AHIsub_Enable(), exec.library/Disable()
*
*****************************************************************************
*
*
AHIsub_Disable:
push a3
move.l ahiac_DriverData(a2),a3
addq.w #1,p_DisableCount(a3)
move.w #INTF_AUD0,CUSTOM+INTENA
pop a3
rts
******* [driver].audio/AHIsub_Enable ****************************************
*
* NAME
* AHIsub_Enable -- Turn on audio interrupt/task
*
* SYNOPSIS
* AHIsub_Enable( audioctrl );
* A2
*
* void AHIsub_Enable( struct AHIAudioCtrlDrv * );
*
* IMPLEMENTATION
* If you are lazy, then call exec.library/Enable().
* If you are smart, only enable your own interrupt or task.
*
* INPUTS
* audioctrl - pointer to an AHIAudioCtrlDrv structure.
*
* NOTES
* This call should be guaranteed to preserve all registers.
* This call nests.
*
* SEE ALSO
* AHIsub_Disable(), exec.library/Enable()
*
*****************************************************************************
*
*
AHIsub_Enable:
push a3
move.l ahiac_DriverData(a2),a3
subq.w #1,p_DisableCount(a3)
bne.b .exit
move.w #INTF_SETCLR!INTF_AUD0,CUSTOM+INTENA
.exit
pop a3
rts
******* [driver].audio/AHIsub_Start *****************************************
*
* NAME
* AHIsub_Start -- Starts playback or recording
*
* SYNOPSIS
* error = AHIsub_Start( flags, audioctrl );
* D0 D0 A2
*
* ULONG AHIsub_Start(ULONG, struct AHIAudioCtrlDrv * );
*
* IMPLEMENTATION
* What to do depends what you returned in AHIsub_AllocAudio().
*
* * First, assume bit AHISB_PLAY in flags is set. This means that you
* should begin playback.
*
* - AHIsub_AllocAudio() returned AHISF_MIXING|AHISF_TIMING:
*
* A) Allocate a mixing buffer of ahiac_BuffSize bytes.
* B) Create/start an interrupt or task that will do 1-4 over and over
* again until AHIsub_Stop() is called. Note that it is not a good
* idea to do the actual mixing and conversion in a real hardware
* interrupt. Signal a task or create a Software Interrupt to do
* the number crunching.
*
* 1) Call the user Hook ahiac_PlayerFunc with the following parameters:
* A0 - (struct Hook *)
* A2 - (struct AHIAudioCtrlDrv *)
* A1 - Set to NULL.
*
* 2) Call the mixing Hook (ahiac_MixerFunc) with the following
* parameters:
* A0 - (struct Hook *) - The Hook itself
* A2 - (struct AHIAudioCtrlDrv *)
* A1 - (WORD *[]) - The mixing buffer.
* Note that ahiac_MixerFunc preserves ALL registers.
* The user Hook ahiac_SoundFunc will be called by the mixing
* routine when a sample have been processed, so you don't have to
* worry about that.
* How the buffer will be filled is indicated by ahiac_Flags.
* It is allways filled with signed 16-bit (32 bit if AHIDBB_HIFI in
* in ahiac_Flags is set) words, even if playback is 8 bit. If
* AHIDBB_STEREO is set (in ahiac_Flags), data for left and right
* channel are interleved:
* 1st sample left channel,
* 1st sample right channel,
* 2nd sample left channel,
* ...,
* ahiac_BuffSamples:th sample left channel,
* ahiac_BuffSamples:th sample right channel.
* If AHIDBB_STEREO is cleared, the mono data is stored:
* 1st sample,
* 2nd sample,
* ...,
* ahiac_BuffSamples:th sample.
* Note that neither AHIDBB_STEREO nor AHIDBB_HIFI will be set if
* you didn't report that you understand these flags when
* AHI_AllocAudio() was called.
*
* For AHI V2, the type of buffer is also avalable in ahiac_BuffType.
* It is suggested that you use this value instead. ahiac_BuffType
* can be one of AHIST_M16S, AHIST_S16S, AHIST_M32S and AHIST_S32S.
*
* 3) Convert the buffer if needed and feed it to the audio hardware.
* Note that you may have to clear CPU caches if you are using DMA
* to play the buffer, and the buffer is not allocated in non-
* cachable RAM.
*
* 4) Wait until the whole buffer has been played, then repeat.
*
* Use double buffering if possible!
*
* You may DECREASE ahiac_BuffSamples slightly, for example to force an
* even number of samples to be mixed. By doing this you will make
* ahiac_PlayerFunc to be called at wrong frequency so be careful!
* Even if ahiac_BuffSamples is defined ULONG, it will never be greater
* than 65535.
*
* ahiac_BuffSize is the largest size of the mixing buffer that will be
* needed until AHIsub_Stop() is called.
*
* ahiac_MaxBuffSamples is the maximum number of samples that will be
* mixed (until AHIsub_Stop() is called). You can use this value if you
* need to allocate DMA buffers.
*
* ahiac_MinBuffSamples is the minimum number of samples that will be
* mixed. Most drivers will ignore it.
*
* If AHIsub_AllocAudio() returned with the AHISB_CANPOSTPROCESS bit set,
* ahiac_BuffSize is large enough to hold two buffers. The mixing buffer
* will be filled with the wet buffer first, immedeately followed by the
* dry buffer. I.e., ahiac_BuffSamples sample frames wet data, then
* ahiac_BuffSamples sample frames dry data. The DSP fx should only be
* applied to the wet buffer, and the two buffers should then be added
* together. (V3)
*
* - If AHIsub_AllocAudio() returned AHISF_MIXING, do as described above,
* except calling ahiac_PlayerFunc. ahiac_PlayerFunc should be called
* ahiac_PlayerFreq times per second, clocked by timers on your sound
* card or by using 'realtime.library'. No other Amiga resources may
* be used for timing (like direct CIA timers).
* ahiac_MinBuffSamples and ahiac_MaxBuffSamples are undefined if
* AHIsub_AllocAudio() returned AHISF_MIXING (AHISB_TIMING bit not set).
*
* - If AHIsub_AllocAudio() returned with neither the AHISB_MIXING nor
* the AHISB_TIMING bit set, then just start playback. Don't forget to
* call ahiac_PlayerFunc ahiac_PlayerFreq times per second. Only your
* own timing hardware or 'realtime.library' may be used. Note that
* ahiac_MixerFunc, ahiac_BuffSamples, ahiac_MinBuffSamples,
* ahiac_MaxBuffSamples and ahiac_BuffSize are undefined. ahiac_MixFreq
* is the frequency the user wants to use for recording, if you support
* that.
*
* * Second, assume bit AHISB_RECORD in flags is set. This means that you
* should start to sample. Create a interrupt or task that does the
* following:
*
* Allocate a buffer (you chose size, but try to keep it reasonable
* small to avoid delays - it is suggested that RecordFunc is called
* at least 4 times/second for the lowers sampling rate, and more often
* for higher rates), and fill it with the sampled data. The format
* should always be AHIST_S16S (even with 8 bit mono samplers), which
* means:
* 1st sample left channel,
* 1st sample right channel (same as prev. if mono),
* 2nd sample left channel,
* ... etc.
* Each sample is a signed word (WORD). The sample rate should be equal
* to the mixing rate.
*
* Call the ahiac_SamplerFunc Hook with the following parameters:
* A0 - (struct Hook *) - The Hook itself
* A2 - (struct AHIAudioCtrlDrv *)
* A1 - (struct AHIRecordMessage *)
* The message should be filled as follows:
* ahirm_Type - Set to AHIST_S16S.
* ahirm_Buffer - A pointer to the filled buffer.
* ahirm_Samples - How many sample frames stored.
* You must not destroy the buffer until next time the Hook is called.
*
* Repeat until AHIsub_Stop() is called.
*
* * Note that both bits may be set when this function is called.
*
* INPUTS
* flags - See <libraries/ahi_sub.h>.
* audioctrl - pointer to an AHIAudioCtrlDrv structure.
*
* RESULT
* Returns AHIE_OK if successful, else an error code as defined
* in <devices/ahi.h>. AHIsub_Stop() will always be called, even
* if this call failed.
*
* NOTES
* The driver must be able to handle multiple calls to this routine
* without preceding calls to AHIsub_Stop().
*
* SEE ALSO
* AHIsub_Update(), AHIsub_Stop()
*
*****************************************************************************
*
*
*
AHIsub_Start:
pushm d2-d7/a2-a6
move.l d0,d7
lea CUSTOM,a4
move.l ahiac_DriverData(a2),a3
btst #AHISB_PLAY,d0
beq .dont_play
**
*** AHISB_PLAY
**
moveq #AHISF_PLAY,d0
call AHIsub_Stop ;Stop current playback if any.
call AHIsub_Update ;fill variables
move.l a6,a5
move.l pb_SysLib(a5),a6
move.l ahiac_BuffSize(a2),d0
move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
call AllocVec
move.l d0,p_Mixbuffer(a3)
beq .error_nomem
move.l ahiac_MixFreq(a2),d1
bsr.w calcperiod
move.w d1,p_AudPer(a3)
* The init*bit? routines allocates p_DMAbuffer, sets up p_AudPtr, sets the volume,
* stores the correct interrupt routines in p_PlayInt's and p_PlaySoftInt's IS_CODE.
pea .1(pc)
move.b p_Flags(a3),d0
and.b #PF_STEREO!PF_14BIT,d0
beq.w init8bitM
cmp.b #PF_STEREO,d0
beq.w init8bitS
cmp.b #PF_14BIT,d0
beq.w init14bitM
bra.w init14bitS
.1
tst.l d0
bne .exit
* Install play interrupt
lea p_PlayInt(a3),a1
moveq #INTB_AUD0,d0
call SetIntVector
clr.w p_DisableCount(a3)
move.w #INTF_SETCLR!INTF_AUD0,INTENA(a4) ;enable
move.w #INTF_SETCLR!INTF_AUD0,INTREQ(a4) ;start
move.l a5,a6
.dont_play
btst #AHISB_RECORD,d7
beq .dont_record
**
*** AHISB_RECORD
**
btst #PB_RECORD,p_Flags(a3) ;Sanity check...
beq .error_unknown
moveq #AHISF_RECORD,d0
call AHIsub_Stop ;Stop current recording if any.
move.l a6,a5
move.l pb_SysLib(a5),a6
move.l #RECORDSAMPLES*4,d0
move.l #MEMF_PUBLIC,d1
call AllocVec
move.l d0,p_RecBuffer1(a3)
beq .error_nomem
move.l d0,p_RecFillPtr(a3)
move.w #RECORDSAMPLES,p_RecFillCount(a3)
move.l #RECORDSAMPLES*4,d0
move.l #MEMF_PUBLIC,d1
call AllocVec
move.l d0,p_RecBuffer2(a3)
beq .error_nomem
move.l ahiac_MixFreq(a2),d1
bsr.w calcperiod
lsr.w #1,d1 ;Period/2 => Frequency·2
move.w d1,AUD2PER(a4)
move.w d1,AUD3PER(a4)
move.w p_MonitorVolume(a3),AUD2VOL(a4)
move.w p_MonitorVolume(a3),AUD3VOL(a4)
* Install record interrupt
move.l #RecordInterrupt,IS_CODE+p_RecInt(a3)
btst #PB_AURA,p_Flags(a3)
beq.b .parsampler
tst.l p_AuraAddress(a3)
beq .error_unknown
lea p_RecIntDataAura(a3),a1
move.l a1,IS_DATA+p_RecInt(a3)
move.l #RecordInterruptAura,IS_CODE+p_RecInt(a3)
.parsampler
lea p_RecInt(a3),a1
moveq #INTB_AUD3,d0
call SetIntVector
move.w #DMAF_AUD2!DMAF_AUD3,DMACON(a4) ;disable DMA
move.w #INTF_SETCLR!INTF_AUD3,INTENA(a4) ;enable
move.w #INTF_SETCLR!INTF_AUD3,INTREQ(a4) ;start
.dont_record
.return
moveq #AHIE_OK,d0
.exit
popm d2-d7/a2-a6
rts
.error_nomem
moveq #AHIE_NOMEM,d0
bra.b .exit
.error_unknown
moveq #AHIE_UNKNOWN,d0
bra.b .exit
;in:
* a2 AudioCtrl
* a3 paula
* a4 CUSTOM
* a5 paulaBase
* a6 ExecBase
init8bitM:
move.l #AudioInterrupt2,IS_CODE+p_PlayInt(a3)
move.l #SoftInt_8bitM,IS_CODE+p_PlaySoftInt(a3)
move.l ahiac_MaxBuffSamples(a2),d0 ;Max. # of 8 bit samples
addq.l #1,d0
bclr #0,d0 ;force even
move.l d0,d2 ;d2 = channel size
lsl.l #1,d0 ;Double buffer
move.l #MEMF_CHIP!MEMF_PUBLIC|MEMF_CLEAR,d1
call AllocVec
move.l d0,p_DMAbuffer(a3)
beq .nomem
move.l d0,p_AudPtr1A(a3)
move.l d0,p_AudPtr2A(a3)
add.l d2,d0
move.l d0,p_AudPtr1B(a3)
move.l d0,p_AudPtr2B(a3)
move.w #64,AUD0VOL(a4)
move.w #64,AUD1VOL(a4)
moveq #0,d0
rts
.nomem
moveq #AHIE_NOMEM,d0
rts
;in:
* a2 AudioCtrl
* a3 paula
* a5 paulaBase
* a6 ExecBase
init8bitS:
move.l #AudioInterrupt2,IS_CODE+p_PlayInt(a3)
move.l #SoftInt_8bitS,IS_CODE+p_PlaySoftInt(a3)
move.l ahiac_MaxBuffSamples(a2),d0 ;Max. # of 8 bit samples
addq.l #1,d0
bclr #0,d0 ;force even
move.l d0,d2 ;d2 = channel size
lsl.l #2,d0 ;Double buffer + Stereo
move.l #MEMF_CHIP!MEMF_PUBLIC|MEMF_CLEAR,d1
call AllocVec
move.l d0,p_DMAbuffer(a3)
beq .nomem
move.l d0,p_AudPtr1A(a3)
add.l d2,d0
move.l d0,p_AudPtr2A(a3)
add.l d2,d0
move.l d0,p_AudPtr1B(a3)
add.l d2,d0
move.l d0,p_AudPtr2B(a3)
move.w #64,AUD0VOL(a4)
move.w #64,AUD1VOL(a4)
moveq #0,d0
rts
.nomem
moveq #AHIE_NOMEM,d0
rts
;in:
* a2 AudioCtrl
* a3 paula
* a5 paulaBase
* a6 ExecBase
init14bitM:
move.l #AudioInterrupt4,IS_CODE+p_PlayInt(a3)
lea SoftInt_14bitM(pc),a0
tst.l p_CalibrationTable(a3)
beq.b .nocalib
lea SoftInt_14CbitM(pc),a0
.nocalib
move.l a0,IS_CODE+p_PlaySoftInt(a3)
move.l ahiac_MaxBuffSamples(a2),d0 ;Max. # of 16 bit samples
addq.l #1,d0
bclr #0,d0 ;force even
move.l d0,d2 ;d2 = channel size
lsl.l #2,d0 ;Double buffer + 2×8 bit
move.l #MEMF_CHIP!MEMF_PUBLIC|MEMF_CLEAR,d1
call AllocVec
move.l d0,p_DMAbuffer(a3)
beq .nomem
move.l d0,p_AudPtr1A(a3)
move.l d0,p_AudPtr2A(a3)
add.l d2,d0
move.l d0,p_AudPtr4A(a3)
move.l d0,p_AudPtr3A(a3)
add.l d2,d0
move.l d0,p_AudPtr1B(a3)
move.l d0,p_AudPtr2B(a3)
add.l d2,d0
move.l d0,p_AudPtr4B(a3)
move.l d0,p_AudPtr3B(a3)
move.w #64,AUD0VOL(a4)
move.w #64,AUD1VOL(a4)
move.w #1,AUD2VOL(a4)
move.w #1,AUD3VOL(a4)
moveq #0,d0
rts
.nomem
moveq #AHIE_NOMEM,d0
rts
;in:
* a2 AudioCtrl
* a3 paula
* a5 paulaBase
* a6 ExecBase
init14bitS:
move.l #AudioInterrupt4,IS_CODE+p_PlayInt(a3)
lea SoftInt_14bitS(pc),a0
tst.l p_CalibrationTable(a3)
beq.b .nocalib
lea SoftInt_14CbitS(pc),a0
.nocalib
move.l a0,IS_CODE+p_PlaySoftInt(a3)
move.l ahiac_MaxBuffSamples(a2),d0 ;Max. # of 16 bit samples
addq.l #1,d0
bclr #0,d0 ;force even
move.l d0,d2 ;d2 = channel size
lsl.l #3,d0 ;Double buffer + 2×8 bit + Stereo
move.l #MEMF_CHIP!MEMF_PUBLIC|MEMF_CLEAR,d1
call AllocVec
move.l d0,p_DMAbuffer(a3)
beq .nomem
move.l d0,p_AudPtr1A(a3)
add.l d2,d0
move.l d0,p_AudPtr2A(a3)
add.l d2,d0
move.l d0,p_AudPtr3A(a3)
add.l d2,d0
move.l d0,p_AudPtr4A(a3)
add.l d2,d0
move.l d0,p_AudPtr1B(a3)
add.l d2,d0
move.l d0,p_AudPtr2B(a3)
add.l d2,d0
move.l d0,p_AudPtr3B(a3)
add.l d2,d0
move.l d0,p_AudPtr4B(a3)
move.w #64,AUD0VOL(a4)
move.w #64,AUD1VOL(a4)
move.w #1,AUD2VOL(a4)
move.w #1,AUD3VOL(a4)
moveq #0,d0
rts
.nomem
moveq #AHIE_NOMEM,d0
rts
******* [driver].audio/AHIsub_Update ****************************************
*
* NAME
* AHIsub_Update -- Update some variables
*
* SYNOPSIS
* AHIsub_Update( flags, audioctrl );
* D0 A2
*
* void AHIsub_Update(ULONG, struct AHIAudioCtrlDrv * );
*
* IMPLEMENTATION
* All you have to do is to update some variables:
* Mixing & timing: ahiac_PlayerFunc, ahiac_MixerFunc, ahiac_SamplerFunc,
* ahiac_BuffSamples (and perhaps ahiac_PlayerFreq if you use it).
* Mixing only: ahiac_PlayerFunc, ahiac_MixerFunc, ahiac_SamplerFunc and
* ahiac_PlayerFreq.
* Nothing: ahiac_PlayerFunc, ahiac_SamplerFunc and ahiac_PlayerFreq.
*
* INPUTS
* flags - Currently no flags defined.
* audioctrl - pointer to an AHIAudioCtrlDrv structure.
*
* RESULT
*
* NOTES
* This call must be safe from interrupts.
*
* SEE ALSO
* AHIsub_Start()
*
*****************************************************************************
*
*
*
AHIsub_Update:
pushm d2-d7/a2-a6
call AHIsub_Disable ;make sure we don't get an interrupt
;while updating our local variables
move.l ahiac_DriverData(a2),a3
move.l ahiac_PlayerFunc(a2),a0
move.l a0,p_PlayerHook(a3)
move.l h_Entry(a0),p_PlayerEntry(a3)
move.l ahiac_BuffSamples(a2),d0
lsr.l #1,d0 ;length in words, force even # of samples
move.w d0,p_AudLen(a3)
subq.l #1,d0
move.l d0,p_LoopTimes(a3) ;See softints. (Unrolled)
move.l ahiac_MixerFunc(a2),a0
move.l a0,p_MixHook(a3)
move.l h_Entry(a0),p_MixEntry(a3)
call AHIsub_Enable
moveq #0,d0
popm d2-d7/a2-a6
rts
******* [driver].audio/AHIsub_Stop ******************************************
*
* NAME
* AHIsub_Stop -- Stops playback.
*
* SYNOPSIS
* AHIsub_Stop( flags, audioctrl );
* D0 A2
*
* void AHIsub_Stop( ULONG, struct AHIAudioCtrlDrv * );
*
* IMPLEMENTATION
* Stop playback and/or recording, remove all resources allocated by
* AHIsub_Start().
*
* INPUTS
* flags - See <libraries/ahi_sub.h>.
* audioctrl - pointer to an AHIAudioCtrlDrv structure.
*
* NOTES
* It must be safe to call this routine even if AHIsub_Start() was never
* called, failed or called more than once.
*
* SEE ALSO
* AHIsub_Start()
*
*****************************************************************************
*
*
AHIsub_Stop:
pushm d2-d7/a2-a6
lea CUSTOM,a4
move.l a6,a5
move.l pb_SysLib(a5),a6
move.l ahiac_DriverData(a2),a3
push d0
btst #AHISB_PLAY,d0
beq .dontplay
**
*** AHISB_PLAY
**
moveq #0,d0
move.w d0,AUD0VOL(a4)
move.w d0,AUD1VOL(a4)
move.w d0,AUD2VOL(a4)
move.w d0,AUD3VOL(a4)
move.w #DMAF_AUDIO,DMACON(a4) ;disable audio DMA
move.w #INTF_AUD0,INTENA(a4)
move.w #INTF_AUD0,INTREQ(a4) ;Clear any waiting interrupts
move.l #Interrupt_Dummy,IS_CODE+p_PlayInt(a3)
lea p_PlayInt(a3),a1
moveq #INTB_AUD0,d0
call SetIntVector
move.l p_DMAbuffer(a3),d0
beq.b .nodmamem
move.l d0,a1
clr.l p_DMAbuffer(a3)
call FreeVec
.nodmamem
move.l p_Mixbuffer(a3),d0
beq.b .nomixmem
move.l d0,a1
clr.l p_Mixbuffer(a3)
call FreeVec
.nomixmem
.dontplay
pop d0
btst #AHISB_RECORD,d0
beq .dontrecord
**
*** AHISB_RECORD
**
btst #PB_RECORD,p_Flags(a3) ;Sanity check...
beq .dontrecord
move.w #INTF_AUD3,INTENA(a4)
move.w #INTF_AUD3,INTREQ(a4) ;Clear any waiting interrupts
move.l #Interrupt_Dummy,IS_CODE+p_RecInt(a3)
lea p_RecInt(a3),a1
moveq #INTB_AUD3,d0
call SetIntVector
move.w #0,AUD2VOL(a4)
move.w #0,AUD3VOL(a4)
move.l p_RecBuffer1(a3),d0
beq.b .norecmem1
move.l d0,a1
clr.l p_RecBuffer1(a3)
call FreeVec
.norecmem1
move.l p_RecBuffer2(a3),d0
beq.b .norecmem2
move.l d0,a1
clr.l p_RecBuffer2(a3)
call FreeVec
.norecmem2
.dontrecord
.return
moveq #0,d0
popm d2-d7/a2-a6
rts
******* [driver].audio/AHIsub_#? ********************************************
*
* NAME
* AHIsub_SetEffect -- Set effect.
* AHIsub_SetFreq -- Set frequency.
* AHIsub_SetSound -- Set sound.
* AHIsub_SetVol -- Set volume and stereo panning.
* AHIsub_LoadSound -- Prepare a sound for playback.
* AHIsub_UnloadSound -- Discard a sound.
*
* SYNOPSIS
* See functions in 'ahi.device'.
*
* IMPLEMENTATION
* If AHIsub_AllocAudio() did not return with bit AHISB_MIXING set,
* all user calls to these function will be routed to the driver.
*
* If AHIsub_AllocAudio() did return with bit AHISB_MIXING set, the
* calls will first be routed to the driver, and only handled by
* 'ahi.device' if the driver returned AHIS_UNKNOWN. This way it is
* possible to add effects that the sound card handles on its own, like
* filter and echo effects.
*
* For what each funtion does, see the autodocs for 'ahi.device'.
*
* INPUTS
* See functions in 'ahi.device'.
*
* NOTES
* See functions in 'ahi.device'.
*
* SEE ALSO
* ahi.device/AHI_SetEffect(), ahi.device/AHI_SetFreq(),
* ahi.device/AHI_SetSound(), ahi.device/AHI_SetVol(),
* ahi.device/AHI_LoadSound(), ahi.device/AHI_UnloadSound()
*
*
*****************************************************************************
*
*
AHIsub_SetVol:
AHIsub_SetFreq:
AHIsub_SetSound:
AHIsub_SetEffect:
AHIsub_LoadSound:
AHIsub_UnloadSound:
moveq #AHIS_UNKNOWN,d0
rts
******* [driver].audio/AHIsub_GetAttr ***************************************
*
* NAME
* AHIsub_GetAttr -- Returns information about audio modes or driver
*
* SYNOPSIS
* AHIsub_GetAttr( attribute, argument, default, taglist, audioctrl );
* D0 D0 D1 D2 A1 A2
*
* LONG AHIsub_GetAttr( ULONG, LONG, LONG, struct TagItem *,
* struct AHIAudioCtrlDrv * );
*
* IMPLEMENTATION
* Return the attribute based on a tag list and an AHIAudioCtrlDrv
* structure, which are the same that will be passed to
* AHIsub_AllocAudio() by 'ahi.device'. If the attribute is
* unknown to you, return the default.
*
* INPUTS
* attribute - Is really a Tag and can be one of the following:
* AHIDB_Bits - Return how many output bits the tag list will
* result in.
* AHIDB_MaxChannels - Return the resulting number of channels.
* AHIDB_Frequencies - Return how many mixing/sampling frequencies
* you support
* AHIDB_Frequency - Return the argument:th frequency
* Example: You support 3 frequencies 32, 44.1 and 48 kHz.
* If argument is 1, return 44100.
* AHIDB_Index - Return the index which gives the frequency closest
* to argument.
* Example: You support 3 frequencies 32, 44.1 and 48 kHz.
* If argument is 40000, return 1 (=> 44100).
* AHIDB_Author - Return pointer to name of driver author:
* "Martin 'Leviticus' Blom"
* AHIDB_Copyright - Return pointer to copyright notice, including
* the '©' character: "© 1996 Martin Blom" or "Public Domain"
* AHIDB_Version - Return pointer version string, normal Amiga
* format: "paula 1.5 (18.2.96)\r\n"
* AHIDB_Annotation - Return pointer to an annotation string, which
* can be several lines.
* AHIDB_Record - Are you a sampler, too? Return TRUE or FALSE.
* AHIDB_FullDuplex - Return TRUE or FALSE.
* AHIDB_Realtime - Return TRUE or FALSE.
* AHIDB_MaxPlaySamples - Normally, return the default. See
* AHIsub_AllocAudio(), section 2.
* AHIDB_MaxRecordSamples - Return the size of the buffer you fill
* when recoring.
*
* The following are associated with AHIsub_HardwareControl() and are
* new for V2.
* AHIDB_MinMonitorVolume
* AHIDB_MaxMonitorVolume - Return the lower/upper limit for
* AHIC_MonitorVolume. If unsupported but always 1.0, return
* 1.0 for both.
* AHIDB_MinInputGain
* AHIDB_MaxInputGain - Return the lower/upper limit for
* AHIC_InputGain. If unsupported but always 1.0, return 1.0 for
* both.
* AHIDB_MinOutputVolume
* AHIDB_MaxOutputVolume - Return the lower/upper limit for
* AHIC_OutputVolume.
* AHIDB_Inputs - Return how many inputs you have.
* AHIDB_Input - Return a short string describing the argument:th
* input. Number 0 should be the default one. Example strings
* can be "Line 1", "Mic", "Optical" or whatever.
* AHIDB_Outputs - Return how many outputs you have.
* AHIDB_Output - Return a short string describing the argument:th
* output. Number 0 should be the default one. Example strings
* can be "Line 1", "Headphone", "Optical" or whatever.
* argument - extra info for some attributes.
* default - What you should return for unknown attributes.
* taglist - Pointer to a tag list that eventually will be fed to
* AHIsub_AllocAudio(), or NULL.
* audioctrl - Pointer to an AHIAudioCtrlDrv structure that eventually
* will be fed to AHIsub_AllocAudio(), or NULL.
*
* NOTES
*
* SEE ALSO
* AHIsub_AllocAudio(), AHIsub_HardwareControl(),
* ahi.device/AHI_GetAudioAttrsA()
*
*****************************************************************************
*
*
AHIsub_GetAttr:
pushm d3/a3/a5-a6
move.l a6,a5
move.l pb_UtilLib(a5),a6
IFD MC020
tst.l a1
ELSE
cmp.l #0,a1
ENDC
beq .notaglist ;no tag list!
move.l a1,a3
pushm d0-d1
move.l #AHIDB_PaulaRecord,d0
moveq #FALSE,d1
move.l a3,a0
call GetTagData
move.l d0,d3
beq .2
* Only for AHIDB_PaulaRecord TRUE
popm d0-d1
cmp.l #AHIDB_Record,d0
bne.b .not_record1
moveq #TRUE,d0
bra .exit
.not_record1
cmp.l #AHIDB_FullDuplex,d0
bne.b .not_fullduplex1
moveq #TRUE,d0
bra .exit
.not_fullduplex1
cmp.l #AHIDB_MaxRecordSamples,d0
bne.b .not_mrs1
move.l #RECORDSAMPLES,d0
bra .exit
.not_mrs1
cmp.l #AHIDB_MinMonitorVolume,d0
bne.b .not_minmonvol1
moveq #0,d0
bra .exit
.not_minmonvol1
cmp.l #AHIDB_MaxMonitorVolume,d0
bne.b .not_maxmonvol1
move.l #$10000,d0
bra .exit
.not_maxmonvol1
cmp.l #AHIDB_MinInputGain,d0
bne.b .not_mingain1
move.l #$10000,d0
bra .exit
.not_mingain1
cmp.l #AHIDB_MaxInputGain,d0
bne.b .not_maxgain1
move.l #$10000,d0
bra .exit
.not_maxgain1
cmp.l #AHIDB_Inputs,d0
bne.b .not_inputs
moveq #1,d0
bra .exit
.not_inputs
cmp.l #AHIDB_Input,d0
bne.b .not_input
lea .input(pc),a0
move.l a0,d0
cmp.l #RECORD_AURA,d3
bne .exit
lea .input_Aura(pc),a0
move.l a0,d0
bra .exit
.not_input
bra .3
.2
* Only for AHIDB_PaulaRecord FALSE
popm d0-d1
cmp.l #AHIDB_Record,d0
bne.b .not_record2
moveq #FALSE,d0
bra .exit
.not_record2
cmp.l #AHIDB_FullDuplex,d0
bne.b .not_fullduplex2
moveq #FALSE,d0
bra .exit
.not_fullduplex2
.3
* Common tags (AHIDB_PaulaRecord does not matter)
cmp.l #AHIDB_Bits,d0
bne.b .not_bits
move.l #AHIDB_Paula14Bit,d0
moveq #FALSE,d1
move.l a3,a0
call GetTagData
tst.l d0
beq.b .no14bit
moveq #14,d0
skipw
.no14bit
moveq #8,d0
bra .exit
.not_bits
.notaglist
cmp.l #AHIDB_Frequencies,d0
bne.b .not_freqs
bsr checkvideo
tst.l d0
beq.b .f
move.l #FREQUENCIES,d0
bra .exit
.f
move.l #FREQUENCIES_OCS,d0
bra .exit
.not_freqs
cmp.l #AHIDB_Frequency,d0
bne.b .not_freq
add.w d1,d1
add.w d1,d1
lea freqlist(pc),a0
; move.l (a0,d1.w),d1
; bsr calcperiod
move.l (a0,d1.w),d0
bra .exit
.not_freq
cmp.l #AHIDB_Index,d0
bne.b .not_index
move.l d1,d0
bsr findfreq
move.l d1,d0
bra .exit
.not_index
cmp.l #AHIDB_Author,d0
bne.b .not_author
lea .author(pc),a0
move.l a0,d0
bra .exit
.not_author
cmp.l #AHIDB_Copyright,d0
bne.b .not_copyright
lea .copyright(pc),a0
move.l a0,d0
bra .exit
.not_copyright
cmp.l #AHIDB_Version,d0
bne.b .not_version
lea IDString(pc),a0
move.l a0,d0
bra .exit
.not_version
cmp.l #AHIDB_Annotation,d0
bne.b .not_anno
lea .anno(pc),a0
move.l a0,d0
bra .exit
.not_anno
cmp.l #AHIDB_Realtime,d0
bne.b .not_realtime
moveq #TRUE,d0
bra .exit
.not_realtime
cmp.l #AHIDB_Outputs,d0
bne.b .not_outputs
moveq #1,d0
bra .exit
.not_outputs
cmp.l #AHIDB_Output,d0
bne.b .not_output
lea .output(pc),a0
move.l a0,d0
bra .exit
.not_output
* Unknown attribute, return default.
move.l d2,d0
.exit
popm d3/a3/a5-a6
rts
.author dc.b "Martin 'Leviticus' Blom",0
.copyright dc.b "Public Domain",0
.anno dc.b "14 bit routines by Christian Buchner.",0
.input dc.b "Parallel port",0
.input_Aura dc.b "Aura",0
.output dc.b "Line",0
even
******* [driver].audio/AHIsub_HardwareControl *******************************
*
* NAME
* AHIsub_HardwareControl -- Modify sound card settings
*
* SYNOPSIS
* AHIsub_HardwareControl( attribute, argument, audioctrl );
* D0 D0 D1 A2
*
* LONG AHIsub_HardwareControl( ULONG, LONG, struct AHIAudioCtrlDrv * );
*
* IMPLEMENTATION
* Set or return the state of a particular hardware component. AHI uses
* AHIsub_GetAttr() to supply the user with limits and what tags are
* available.
*
* INPUTS
* attribute - Is really a Tag and can be one of the following:
* AHIC_MonitorVolume - Set the input monitor volume to argument.
* AHIC_MonitorVolume_Query - Return the current input monitor
* volume (argument is ignored).
*
* AHIC_InputGain - Set the input gain to argument. (V2)
* AHIC_InputGain_Query (V2)
*
* AHIC_OutputVolume - Set the output volume to argument. (V2)
* AHIC_OutputVolume_Query (V2)
*
* AHIC_Input - Use the argument:th input source (default is 0). (V2)
* AHIC_Input_Query (V2)
*
* AHIC_Output - Use the argument:th output destination (default
* is 0). (V2)
* AHIC_Output_Query (V2)
*
* argument - What value attribute should be set to.
* audioctrl - Pointer to an AHIAudioCtrlDrv structure.
*
* RESULT
* Return the state of selected attribute. If you were asked to set
* something, return TRUE. If attribute is unknown to you or unsupported,
* return FALSE.
*
* NOTES
* This call must be safe from interrupts.
*
* SEE ALSO
* ahi.device/AHI_ControlAudioA(), AHIsub_GetAttr()
*
*****************************************************************************
*
*
AHIsub_HardwareControl:
cmp.l #AHIC_MonitorVolume,d0
bne.b .dontsetmonvol
move.l ahiac_DriverData(a2),a1
lsr.l #8,d1
lsr.l #2,d1
move.w d1,p_MonitorVolume(a1)
bra.b .exit
.dontsetmonvol
cmp.l #AHIC_MonitorVolume_Query,d0
bne.b .dontgetmonvol
move.l ahiac_DriverData(a2),a1
moveq #0,d0
move.w p_MonitorVolume(a1),d0
lsl.l #8,d0
lsl.l #2,d0
bra.b .quit
.dontgetmonvol
moveq #FALSE,d0
.quit
rts
.exit
moveq #TRUE,d0
rts
;----------------------------------------------------------------------------
Interrupt_Dummy:
move.w #INTF_AUD0!INTF_AUD1!INTF_AUD2!INTF_AUD3,INTREQ(a0)
SoftInt_Dummy:
rts
;in:
* d0 scratch
* d1 INTENAR && INTREQR
* a0 CUSTOM
* a1 &(paulaBase->p_RecIntData)
* a5 &RecordInterrupt
* a6 ExecBase
RecordInterrupt:
* This function will be executed up to 28000 times per second - that's once per
* rasterline! It has to be as fast as possible.
move.w #INTF_AUD2!INTF_AUD3,INTREQ(a0) ;Clear the interrupt flags
moveq #0,d0
move.b _ciaa+ciaprb,d0 ;read parallel port
IFD MC020
move.l convtable(pc,d0.w*4),d0 ;1 unsigned byte -> 2 signed words
ELSE
add.w d0,d0
add.w d0,d0
move.l convtable(pc,d0.w),d0
ENDC
move.w d0,AUD2DAT(a0) ;right
move.w d0,AUD3DAT(a0) ;left
move.l (a1),a5 ;p_RecFillPtr
move.l d0,(a5)+ ;store sample in buffer
move.l a5,(a1)+ ;update pointer
subq.w #1,(a1) ;p_ReqFillCount
beq ri_Filled ;branch if buffer filled
rts
convtable
CNT SET 0
REPT 256
dc.b CNT-128,CNT-128,CNT-128,CNT-128
CNT SET CNT+1
ENDR
;in:
* d0 scratch
* d1 INTENAR && INTREQR
* a0 CUSTOM
* a1 &(paulaBase->p_RecIntDataAura)
* a5 &RecordInterrupt
* a6 ExecBase
RecordInterruptAura:
move.w #INTF_AUD2!INTF_AUD3,INTREQ(a0) ;Clear the interrupt flags
move.l (a1)+,a5
move.l (a5),d0 ;read aura sampler
eor.l #$80008000,d0
move.l (a1),a5 ;p_RecFillPtr
move.l d0,(a5)+ ;store sample in buffer
move.l a5,(a1)+ ;update pointer
move.w d0,d1
lsr.w #8,d0
move.b d0,d1
move.w d1,AUD2DAT(a0) ;right
move.w d1,AUD3DAT(a0) ;left
subq.w #1,(a1) ;p_ReqFillCount
beq ri_Filled ;branch if buffer filled
rts
ri_Filled:
* This part is only executed every RECORDSAMPLES:th time... No need to hurry.
move.l 8(a1),d0 ;p_RecBuffer2->
move.l 4(a1),8(a1) ;p_RecBuffer1->p_RecBuffer2
move.l d0,4(a1) ; ->p_RecBuffer1
move.l d0,-4(a1) ;p_RecFillPtr
move.w #RECORDSAMPLES,(a1) ;p_ReqFillCount
move.l 12(a1),a1 ;p_RecSoftIntPtr
jmp _LVOCause(a6)
;in:
* d0 scratch
* d1 scratch
* a0 scratch
* a1 paulaBase
* a5 scratch
RecordSoftInt:
* This function is not executed many times per second and is therefore not
* fully optimized... ;)
push a2
move.w p_MonitorVolume(a1),CUSTOM+AUD2VOL
move.w p_MonitorVolume(a1),CUSTOM+AUD3VOL
move.l p_RecBuffer2(a1),p_rmBuffer(a1)
move.l p_AudioCtrlP(a1),a2
lea p_RecordMessage(a1),a1
move.l ahiac_SamplerFunc(a2),a0
move.l h_Entry(a0),a5
jsr (a5)
pop a2
rts
;in:
* d0 scratch
* d1 INTENAR && INTREQR
* a0 CUSTOM
* a1 &(paulaBase->p_PlayIntData)
* a5 &AudioInterrupt
* a6 ExecBase
AudioInterrupt2: ;Two hardware channels used
movem.l (a1)+,d0/d1 ;p_PlaySoftIntPtr,p_AudLen/p_AudPer
move.l d1,AUD0LEN(a0)
move.l d1,AUD1LEN(a0)
not.l (a1)+ ;double buffering
lea p_AudPtrs-p_AudPtr1A(a1),a5
beq.b .1
add.w #4*4,a1
.1
move.l a1,(a5)
move.l (a1)+,AUD0LC(a0)
move.l (a1)+,AUD1LC(a0)
move.l d0,a1 ;p_PlaySoftInt
move.w #INTF_AUD0,INTREQ(a0) ;Clear the interrupt
jmp _LVOCause(a6) ;start PlaySoftInt
AudioInterrupt4: ;Four hardware channels used
movem.l (a1)+,d0/d1 ;p_PlaySoftIntPtr,p_AudLen/p_AudPer
move.l d1,AUD0LEN(a0)
move.l d1,AUD1LEN(a0)
move.l d1,AUD2LEN(a0)
move.l d1,AUD3LEN(a0)
not.l (a1)+ ;double buffering
lea p_AudPtrs-p_AudPtr1A(a1),a5
beq.b .1
add.w #4*4,a1
.1
move.l a1,(a5)
move.l (a1)+,AUD0LC(a0)
move.l (a1)+,AUD1LC(a0)
move.l (a1)+,AUD2LC(a0)
move.l (a1)+,AUD3LC(a0)
move.l d0,a1 ;p_PlaySoftInt
move.w #INTF_AUD0,INTREQ(a0) ;Clear the interrupt
jmp _LVOCause(a6) ;start PlaySoftInt
;in:
* d0 scratch
* d1 scratch
* a0 scratch
* a1 &(paulaBase->p_PlaySoftIntData)
* a5 scratch
SoftInt_8bitM:
pushm a2/a3
move.l a1,a5
movem.l (a5)+,a0/a1/a2/a3
jsr (a3) ;call Player Hook
movem.l (a5),d0/a0/a1/a2/a3/a5
jsr (a3) ;call Mixer Hook
* convert and transfer buffer
move.l (a5),a0
.loop
move.b (a1),(a0)+
addq.l #2,a1
move.b (a1),(a0)+
addq.l #2,a1
dbf d0,.loop
popm a2/a3
move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1,CUSTOM+DMACON
rts
;in:
* d0 scratch
* d1 scratch
* a0 scratch
* a1 &(paulaBase->p_PlaySoftIntData)
* a5 scratch
SoftInt_8bitS:
pushm a2/a3
move.l a1,a5
movem.l (a5)+,a0/a1/a2/a3
jsr (a3) ;call Player Hook
movem.l (a5),d0/a0/a1/a2/a3/a5
jsr (a3) ;call Mixer Hook
* convert and transfer buffer
movem.l (a5),a0/a2
.loop
REPT 2
;left
move.b (a1),(a0)+
;right
move.b 2(a1),(a2)+
addq.l #4,a1
ENDR
dbf d0,.loop
popm a2/a3
move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1,CUSTOM+DMACON
rts
;in:
* d0 scratch
* d1 scratch
* a0 scratch
* a1 &(paulaBase->p_PlaySoftIntData)
* a5 scratch
SoftInt_14bitM:
pushm a2/a3
move.l a1,a5
movem.l (a5)+,a0/a1/a2/a3
jsr (a3) ;call Player Hook
movem.l (a5),d0/a0/a1/a2/a3/a5
jsr (a3) ;call Mixer Hook
* convert and transfer buffer
movem.l (a5),a0/a2/a3/a5 ;a2/a3 unused
.loop
REPT 2
move.b (a1)+,(a0)+
move.b (a1)+,d1
lsr.b #2,d1
move.b d1,(a5)+
ENDR
dbf d0,.loop
popm a2/a3
move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3,CUSTOM+DMACON
rts
;in:
* d0 scratch
* d1 scratch
* a0 scratch
* a1 &(paulaBase->p_PlaySoftIntData)
* a5 scratch
SoftInt_14CbitM:
pushm a2/a3/a4
move.l a1,a5
movem.l (a5)+,a0/a1/a2/a3
jsr (a3) ;call Player Hook
movem.l (a5),d0/a0/a1/a2/a3/a4/a5
jsr (a3) ;call Mixer Hook
* convert and transfer buffer, using the table
movem.l (a4),a0/a2/a3/a4 ;a2/a3 unused
moveq #0,d1
.loop
REPT 2
IFD MC020
move.w (a1)+,d1 ;fetch 16 bit sample
move.w (a5,d1.l*2),d1
ELSE
moveq #0,d1
move.w (a1)+,d1 ;fetch 16 bit sample
add.w d1,d1
move.w (a5,d1.l),d1
ENDC
move.b d1,(a4)+ ;low byte
lsr.w #8,d1
move.b d1,(a0)+ ;high byte
ENDR
dbf d0,.loop
popm a2/a3/a4
move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3,CUSTOM+DMACON
rts
;in:
* d0 scratch
* d1 scratch
* a0 scratch
* a1 &(paulaBase->p_PlaySoftIntData)
* a5 scratch
SoftInt_14bitS:
pushm a2/a3
move.l a1,a5
movem.l (a5)+,a0/a1/a2/a3
jsr (a3) ;call Player Hook
movem.l (a5),d0/a0/a1/a2/a3/a5
jsr (a3) ;call Mixer Hook
* convert and transfer buffer
* TODO: Use a table!
movem.l (a5),a0/a2/a3/a5
.loop
REPT 2
;left
move.b (a1)+,(a0)+
move.b (a1)+,d1
lsr.b #2,d1
move.b d1,(a5)+
;right
move.b (a1)+,(a2)+
move.b (a1)+,d1
lsr.b #2,d1
move.b d1,(a3)+
ENDR
dbf d0,.loop
popm a2/a3
move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3,CUSTOM+DMACON
rts
;in:
* d0 scratch
* d1 scratch
* a0 scratch
* a1 &(paulaBase->p_PlaySoftIntData)
* a5 scratch
SoftInt_14CbitS:
pushm a2/a3/a4
move.l a1,a5
movem.l (a5)+,a0/a1/a2/a3
jsr (a3) ;call Player Hook
movem.l (a5),d0/a0/a1/a2/a3/a4/a5
jsr (a3) ;call Mixer Hook
* convert and transfer buffer, using the table
movem.l (a4),a0/a2/a3/a4
moveq #0,d1
.loop
REPT 2
;left
IFD MC020
move.w (a1)+,d1 ;fetch 16 bit sample
move.w (a5,d1.l*2),d1
ELSE
moveq #0,d1
move.w (a1)+,d1 ;fetch 16 bit sample
add.w d1,d1
move.w (a5,d1.l),d1
ENDC
move.b d1,(a4)+ ;low byte
lsr.w #8,d1
move.b d1,(a0)+ ;high byte
;right
IFD MC020
move.w (a1)+,d1 ;fetch 16 bit sample
move.w (a5,d1.l*2),d1
ELSE
moveq #0,d1
move.w (a1)+,d1 ;fetch 16 bit sample
add.w d1,d1
move.w (a5,d1.l),d1
ENDC
move.b d1,(a3)+ ;low byte
lsr.w #8,d1
move.b d1,(a2)+ ;high byte
ENDR
dbf d0,.loop
popm a2/a3/a4
move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3,CUSTOM+DMACON
rts
EndCode: