]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Unfinished UAESND AHI driver added.
authorToni Wilen <twilen@winuae.net>
Sat, 21 Aug 2021 17:14:18 +0000 (20:14 +0300)
committerToni Wilen <twilen@winuae.net>
Sat, 21 Aug 2021 17:14:18 +0000 (20:14 +0300)
uaesnd_ahi.s [new file with mode: 0644]

diff --git a/uaesnd_ahi.s b/uaesnd_ahi.s
new file mode 100644 (file)
index 0000000..545e5d7
--- /dev/null
@@ -0,0 +1,1322 @@
+
+       ; Amiga-side full featured AHI driver for WinUAE 4.3.1+ UAESND sound board.
+       ; by Toni Wilen (c) 2019-2020
+
+       ; License: GPL version 2 or any later version.
+       
+       incdir  sys:programming/asm/includes/
+
+       include exec/exec.i
+       include exec/exec_lib.i
+       include exec/libraries.i
+       include exec/ports.i
+       include devices/ahi.i
+       include libraries/ahi_sub.i
+       include libraries/configregs.i
+       include libraries/configvars.i
+       include utility/hooks.i
+       include hardware/intbits.i
+       include utility/utility.i
+       include utility/hooks.i
+
+DEBUG EQU 1
+DEBUG_ADDR EQU $bfff00
+
+VERSION EQU 4
+REVISION EQU 1
+VERSION_STRUCT EQU 1
+
+call MACRO
+       jsr     _LVO\1(a6)
+       ENDM
+
+       STRUCTURE UAESNDHW,$80
+       ULONG base_uae_version
+       UWORD base_snd_version
+       UWORD base_snd_revision
+       ULONG base_frequency
+       UBYTE base_max_channels
+       UBYTE base_max_actual_channels
+       UBYTE base_max_streams
+       UBYTE base_pad1
+       ULONG base_ram_offset
+       ULONG base_ram_size
+       STRUCT base_reserved1,$48
+       ULONG base_stream_allocate
+       ULONG base_stream_latch
+       ULONG base_stream_unlatch
+       ULONG base_pad2
+       ULONG base_stream_enable
+       ULONG base_stream_intena
+       ULONG base_stream_intreq
+
+       STRUCTURE UAESNDSet,0
+       UWORD set_flags
+       UWORD set_format
+       APTR set_pointer
+       ULONG set_length
+       ULONG set_frequency
+       APTR set_repeat_pointer
+       ULONG set_repeat_length
+       UWORD set_repeat_count
+       UWORD set_volume
+       APTR set_next_pointer
+       UBYTE set_channels
+       UBYTE set_type
+       UBYTE set_intena
+       UBYTE set_mask
+       UWORD set_hpan
+       UWORD set_dpan
+       APTR set_pointer_original
+       ULONG set_length_original
+       ; extra
+       ULONG set_offset
+       UWORD set_sample_size
+       LABEL UAESNDSet_SIZEOF  
+
+STREAM_START = $100
+STREAM_OFFSET = $100
+
+       STRUCTURE UAESNDStream,0
+       STRUCT UAESNDSetCurrent,$40
+       STRUCT UAESNDSetLatched,$40
+       APTR stream_sample_pointer
+       UBYTE stream_pad01
+       UBYTE stream_pad02
+       UBYTE stream_pad03
+       UBYTE stream_intreq
+       UBYTE stream_pad04
+       UBYTE stream_pad05
+       UBYTE stream_pad06
+       UBYTE stream_alt_intreq
+       UBYTE stream_pad07
+       UBYTE stream_pad08
+       UBYTE stream_pad09
+       UBYTE stream_master_intena
+       UBYTE stream_pad10
+       UBYTE stream_pad11
+       UBYTE stream_pad12
+       UBYTE stream_status
+       ULONG stream_timer1_frequency
+       ULONG stream_pad13
+       ULONG stream_pad14
+       APTR stream_sample_pointer_imm
+
+       STRUCTURE sound,0
+       APTR    so_Address
+       ULONG   so_Length
+       UWORD so_Type
+       UWORD so_Samplesize
+       LABEL   sound_SIZEOF
+
+       STRUCTURE channel,0
+       APTR ch_set_current
+       STRUCT ch_UAESNDSet1,UAESNDSet_SIZEOF
+       STRUCT ch_SndMsg,AHISoundMessage_SIZEOF
+       LABEL   channel_SIZEOF
+
+       STRUCTURE UAESNDBase,LIB_SIZE
+       UBYTE   ub_Flags
+       UBYTE   ub_Pad1
+       UWORD   ub_Pad2
+       APTR    ub_SysLib
+       ULONG   ub_SegList
+       ULONG   ub_Base
+       APTR    ub_ConfigDev
+       APTR    ub_UtilBase
+       LABEL   UAESNDBase_SIZEOF
+
+       STRUCTURE UAESND,0
+       ULONG   p_Base
+       APTR p_UAESNDBase
+       UWORD p_DisableCount
+       BOOL p_intadded
+       APTR p_AudioCtrl
+       ULONG p_SoundSize
+       APTR    p_Sounds
+       APTR p_Channels
+       ULONG p_ChannelSize
+       ULONG p_DriverDataSize
+       APTR p_ChannelInfo
+       UWORD p_StreamCnt
+       UWORD p_Pad1
+       STRUCT p_Interrupt,IS_SIZE
+       LABEL UAESND_SIZEOF     
+
+Start:
+       moveq   #-1,d0
+       rts
+
+RomTag:
+       DC.W RTC_MATCHWORD
+       DC.L RomTag
+       DC.L EndCode
+       DC.B RTF_AUTOINIT
+       DC.B 4                          ;version
+       DC.B NT_LIBRARY
+       DC.B 0                          ;pri
+       DC.L LibName
+       DC.L IDString
+       DC.L InitTable
+
+LibName:
+       dc.b "uaesnd.audio",0
+       dc.b "$VER:"
+IDString:
+       dc.b "uaesnd.audio 4.1 (11.04.2020)",0
+       cnop 0,4
+
+InitTable:
+       DC.L UAESNDBase_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
+
+       IFD DEBUG=1
+debugreturn
+       move.l d0,DEBUG_ADDR
+       move.l #debug_return,DEBUG_ADDR+4
+       rts
+debug_return
+       dc.b "-> %x\n",0
+       even
+       ENDC
+
+       IFD DEBUG=1
+debug_setvol
+       dc.b "SetVol(%u,%x,%x,%p,%x)\n",0
+       even
+       ENDC
+
+       ; UWORD channel D0
+       ; Fixed volume D1
+       ; sposition pan D2
+       ; struct AHIAudioCtrlDrv* A2
+       ; ULONG Flags D3
+
+AHIsub_SetVol
+       movem.l d2/a2,-(sp)
+
+       IFD DEBUG=1
+       lea DEBUG_ADDR,a0
+       move.w d0,(a0)
+       move.l d1,(a0)
+       move.l d2,(a0)
+       move.l a2,(a0)
+       move.l d3,(a0)
+       move.l #debug_setvol,4(a0)
+       ENDC
+
+       move.l ahiac_DriverData(a2),a2
+
+       move.w d0,d2
+       mulu #channel_SIZEOF,d0
+       move.l p_Channels(a2),a1
+       add.l d0,a1
+       asr.l #1,d1
+       bpl.s .pos
+       neg.l d1
+.pos
+       cmp.l #32767,d1
+       bcs.s .large
+       move.w #32767,d1
+.large
+       move.l ch_set_current(a1),a0
+       move.w d1,set_volume(a0)
+
+       btst #AHISB_IMM,d3
+       beq.s .noimm
+
+       move.l p_Base(a2),a0
+       mulu #STREAM_OFFSET,d2
+       add.l d2,a0
+       move.w d1,STREAM_START+UAESNDSetCurrent+set_volume(a0)
+
+.noimm
+       movem.l (sp)+,d2/a2
+       moveq #0,d0
+
+       IFD DEBUG=1
+       bsr debugreturn
+       ENDC
+
+       rts
+
+       IFD DEBUG=1
+debug_setfreq
+       dc.b "SetFreq(%u,%x,%p,%x)\n",0
+       even
+       ENDC
+
+       ; UWORD channel D0
+       ; ULONG freq D1
+       ; struct AHIAudioCtrlDrv* A2
+       ; ULONG Flags D2
+
+AHIsub_SetFreq
+       movem.l d3/a2,-(sp)
+
+       IFD DEBUG=1
+       lea DEBUG_ADDR,a0
+       move.w d0,(a0)
+       move.l d1,(a0)
+       move.l d2,(a0)
+       move.l d2,(a0)
+       move.l #debug_setfreq,4(a0)
+       ENDC
+
+       move.l ahiac_DriverData(a2),a2
+
+       move.w d0,d3
+       mulu #channel_SIZEOF,d0
+       move.l p_Channels(a2),a1
+       add.l d0,a1
+       asl.l #8,d1
+
+       move.l ch_set_current(a1),a0
+       move.l d1,set_frequency(a0)
+
+       btst #AHISB_IMM,d2
+       beq.s .noimm
+
+       move.l p_Base(a2),a0
+       mulu #STREAM_OFFSET,d3
+       add.l d3,a0
+       move.l d1,STREAM_START+UAESNDSetCurrent+set_frequency(a0)
+
+.noimm
+       movem.l (sp)+,d3/a2
+       moveq #0,d0
+
+       IFD DEBUG=1
+       bsr debugreturn
+       ENDC
+
+       rts
+       
+       IFD DEBUG=1
+debug_setsound
+       dc.b "SetSound(%u,%u,%x,%d,%p,%x)\n",0
+       even
+       ENDC
+       
+       ; UWORD channel D0
+       ; UWORD sound D1
+       ; ULONG offset D2
+       ; LONG length D3
+       ; struct AHIAudioCtrlDrv* A2
+       ; ULONG Flags D4
+       
+AHIsub_SetSound
+       movem.l d2-d5/a2-a5,-(sp)
+
+       IFD DEBUG=1
+       lea DEBUG_ADDR,a0
+       move.w d0,(a0)
+       move.w d1,(a0)
+       move.l d2,(a0)
+       move.l d3,(a0)
+       move.l a2,(a0)
+       move.l d4,(a0)
+       move.l #debug_setsound,4(a0)
+       ENDC
+
+       move.l ahiac_DriverData(a2),a3
+
+       move.w d0,d5
+       mulu #channel_SIZEOF,d0
+       move.l p_Channels(a3),a1
+       add.l d0,a1
+       move.l ch_set_current(a1),a4
+
+       move.l p_Base(a3),a5
+       add.w #STREAM_START,a5
+       mulu #STREAM_OFFSET,d5
+       add.l d5,a5
+
+       cmp.w #AHI_NOSOUND,d1
+       bne.s .sound_ok
+       moveq #0,d2
+       moveq #0,d3
+       lea empty_sound(pc),a2
+       bra.s .update_channel
+
+.sound_ok
+       move.w d1,d0
+       mulu #sound_SIZEOF,d0
+       move.l p_Sounds(a3),a2
+       add.l d0,a2
+       tst.l d3
+       bne.s .length_ok
+       move.l so_Length(a2),d3
+.length_ok
+
+.update_channel
+
+       move.b so_Type+0(a2),set_channels(a4)
+       move.b so_Type+1(a2),set_type(a4)
+       moveq #0,d0
+       move.w so_Samplesize(a2),d0
+       move.w d0,set_sample_size(a4)
+       mulu.l d0,d2
+       move.l d2,set_offset(a4)
+       move.l so_Address(a2),d0
+       move.l d0,set_repeat_pointer(a4)
+       add.l  d2,d0
+       move.l d0,set_pointer(a4)
+       move.l d3,set_length(a4)
+       move.w #-1,set_repeat_count(a4)
+       move.b #3,set_mask(a4)
+       move.l a4,set_next_pointer(a4)
+
+       bset #0,stream_master_intena(a5)
+
+       btst #AHISB_IMM,d4
+       bne.s .doimm
+
+       ; tell the sound hardware that next set is ready
+       ; to play when previous one has finished (or has
+       ; already started looping)
+
+       move.b #1,stream_status(a5)
+       bra.s .noimm
+
+.doimm
+
+       ; start stream immediately
+       move.l a4,stream_sample_pointer_imm(a5)
+
+.noimm
+
+       movem.l (sp)+,d2-d5/a2-a5
+       moveq #0,d0
+
+       IFD DEBUG=1
+       bsr debugreturn
+       ENDC
+
+       rts
+
+empty_sound
+       dc.l 0,0
+       dc.w 0,0
+
+       IFD DEBUG=1
+debug_seteffect
+       dc.b "SetEffect(%p,%p)\n",0
+       even
+       ENDC
+
+       ; Effect* A0
+       ; struct AHIAudioCtrlDrv* A2
+
+AHIsub_SetEffect
+       move.l a3,-(sp)
+
+       IFD DEBUG=1
+       lea DEBUG_ADDR,a1
+       move.l a0,(a1)
+       move.l a2,(a1)
+       move.l #debug_seteffect,4(a1)
+       ENDC
+
+       moveq #AHIE_OK,d1
+       move.l ahiac_DriverData(a2),a3
+       move.l ahie_Effect(a0),d0
+       cmp.l #AHIET_MASTERVOLUME,d0
+       bne.s .nmastervolume
+       nop
+       bra.s .end      
+.nmastervolume
+       cmp.l #AHIET_CANCEL|AHIET_MASTERVOLUME,d0
+       bne.s .nmastervolume_off
+       nop
+       bra.s .end
+.nmastervolume_off
+       cmp.l #AHIET_CHANNELINFO,d0
+       bne.s .nchannelinfo
+       move.l a0,p_ChannelInfo(a3)
+       bra.s .end
+.nchannelinfo
+       cmp.l #AHIET_CANCEL|AHIET_CHANNELINFO,d0
+       bne.s .nchannelinfo_off
+       clr.l p_ChannelInfo(a3)
+       bra.s .end
+.nchannelinfo_off
+       moveq   #AHIE_UNKNOWN,d1
+.end
+       move.l (sp)+,a3
+       move.l d1,d0
+
+       IFD DEBUG=1
+       bsr debugreturn
+       ENDC
+
+       rts
+
+update_playerfunc
+
+       movem.l a2/a3,-(sp)
+       move.l a0,a3
+       move.l ahiac_DriverData(a3),a2
+       move.l p_Base(a2),a0
+       move.l ahiac_PlayerFreq(a3),d0
+       cmp.l #$10000,d0
+       bcs.s .notfixed
+       lsr.l #8,d0
+.notfixed
+       bset.b #4,STREAM_START+stream_master_intena(a0)
+       move.l d0,STREAM_START+stream_timer1_frequency(a0)
+       movem.l (sp)+,a2/a3
+       rts
+
+       ; ULONG Flags D0
+       ; struct AHIAudioCtrlDrv* A2
+
+AHIsub_Update
+       
+       move.l a3,-(sp)
+
+       move.l ahiac_DriverData(a2),a3
+       move.l p_Base(a3),a0
+       bsr.w uaesnd_disable
+       
+       move.l a2,a0
+       bsr.w update_playerfunc
+
+       move.l p_Base(a3),a0
+       bsr.w uaesnd_enable
+       
+       move.l (sp)+,a3
+       rts
+
+       IFD DEBUG=1
+debug_loadsound
+       dc.b "LoadSound(%u,%x,%p,%p)\n",0
+       even
+       ENDC
+       
+       ; UWORD Sound D0
+       ; ULONG Type D1
+       ; APTR Info A0
+       ; struct AHIAudioCtrlDrv* A2
+
+AHIsub_LoadSound
+       movem.l d2/d5/a2/a3,-(sp)
+       
+       IFD DEBUG=1
+       lea DEBUG_ADDR,a1
+       move.w d0,(a1)
+       move.l d1,(a1)
+       move.l a0,(a1)
+       move.l a2,(a1)
+       move.l #debug_loadsound,4(a1)
+       ENDC
+
+       move.l ahiac_DriverData(a2),a3
+
+       move.l p_Sounds(a3),a2
+       mulu #sound_SIZEOF,d0
+       add.l d0,a2
+       
+       moveq #AHIE_BADSOUNDTYPE,d5
+       cmp.w #AHIST_SAMPLE,d1
+       beq.s .sample
+       cmp.w #AHIST_DYNAMICSAMPLE,d1
+       bne.s .exit
+.sample
+       moveq #AHIE_BADSAMPLETYPE,d5
+       move.l ahisi_Type(a0),d0
+       lea sampletypes(pc),a1
+       moveq #-1,d1
+.next
+       move.l (a1),d2
+       cmp.l d2,d1
+       beq.s .exit
+       cmp.l d2,d0
+       beq.s .samplefound
+       addq.l #4+2+2,a1
+       bra.s .next
+.samplefound
+
+       move.w 4(a1),so_Type(a2)
+       move.w 6(a1),so_Samplesize(a2)
+       move.l ahisi_Address(a0),so_Address(a2)
+       move.l ahisi_Length(a0),so_Length(a2)
+       moveq #AHIE_OK,d5
+.exit
+       move.l d5,d0
+
+       IFD DEBUG=1
+       bsr debugreturn
+       ENDC
+
+       movem.l (sp)+,d2/d5/a2/a3
+       rts
+
+       IFD DEBUG=1
+debug_unloadsound
+       dc.b "UnloadSound(%u,%p)\n",0
+       even
+       ENDC
+
+       ; UWORD Sound D0
+       ; struct AHIAudioCtrlDrv* A2
+
+AHIsub_UnloadSound
+       
+       IFD DEBUG=1
+       lea DEBUG_ADDR,a0
+       move.w d0,(a0)
+       move.l a2,(a0)
+       move.l #debug_unloadsound,4(a0)
+       ENDC
+
+       move.l ahiac_DriverData(a2),a0
+       move.l p_Sounds(a0),a0
+       mulu #sound_SIZEOF,d0
+       add.l d0,a0
+       clr.w so_Type(a0)
+       moveq #0,d0
+
+       IFD DEBUG=1
+       bsr debugreturn
+       ENDC
+
+       rts
+
+sampletypes
+       dc.l AHIST_M8S
+       dc.b 1, 0, 0, 1
+       dc.l AHIST_S8S
+       dc.b 2, 0, 0, 2
+       dc.l AHIST_M16S
+       dc.b 1, 1, 0, 2
+       dc.l AHIST_S16S
+       dc.b 2, 1, 0, 4
+       dc.l AHIST_M32S
+       dc.b 1, 3, 0, 4
+       dc.l AHIST_S32S
+       dc.b 2, 3, 0, 8
+       dc.l AHIST_L7_1
+       dc.b 8, 3, 0, 32
+       dc.l -1
+
+uaesnd_enable
+       move.l base_stream_enable(a0),base_stream_intena(a0)
+       rts
+
+uaesnd_disable
+       clr.l base_stream_intena(a0)
+       rts
+
+       ; struct AHIAudioCtrlDrv* A2
+
+AHIsub_Disable
+       move.l ahiac_DriverData(a2),a0
+       addq.w #1,p_DisableCount(a0)
+       move.l p_Base(a0),a0
+       bsr uaesnd_disable
+       rts
+
+       ; struct AHIAudioCtrlDrv* A2
+
+AHIsub_Enable
+       move.l ahiac_DriverData(a2),a0
+       subq.w  #1,p_DisableCount(a0)
+       bne.s .exit
+       move.l p_Base(a0),a0
+       bsr uaesnd_enable
+.exit
+       rts
+
+reset_ch
+       move.l p_ChannelSize(a0),d0
+       beq.s .res0
+       move.l p_Channels(a0),a0
+       moveq #channel_SIZEOF,d1
+.res1
+       clr.l ch_UAESNDSet1+set_next_pointer(a0)
+       sub.l d1,d0
+       add.l d1,a0
+       bne.s .res1
+.res0
+       rts
+
+reset_hw
+       clr.l base_stream_intena(a0)
+       clr.l base_stream_enable(a0)
+       clr.l STREAM_START+stream_timer1_frequency(a0)
+       rts
+
+       IFD DEBUG=1
+debug_start
+       dc.b "Start(%x,%p)\n",0
+       even
+       ENDC
+       
+       ; ULONG Flags D0
+       ; struct AHIAudioCtrlDrv* A2
+
+AHIsub_Start
+
+       IFD DEBUG=1
+       lea DEBUG_ADDR,a0
+       move.l d0,(a0)
+       move.l a2,(a0)
+       move.l #debug_start,4(a0)
+       ENDC
+
+       move.l ahiac_DriverData(a2),a1
+       move.l p_Base(a1),a0
+       bsr reset_hw
+
+       move.l a2,a0
+       bsr.w update_playerfunc
+
+       move.l ahiac_DriverData(a2),a1
+       move.l p_Base(a1),a0
+       moveq #1,d0
+       move.b base_max_streams(a0),d1
+       lsl.l d1,d0
+       subq.l #1,d0
+       move.l d0,base_stream_enable(a0)
+       move.l d0,base_stream_intena(a0)
+       moveq #AHIE_OK,d0
+
+       IFD DEBUG=1
+       bsr debugreturn
+       ENDC
+
+       rts     
+
+       IFD DEBUG=1
+debug_stop
+       dc.b "Stop(%x,%p)\n",0
+       even
+       ENDC
+
+       ; ULONG Flags D0
+       ; struct AHIAudioCtrlDrv* A2
+
+AHIsub_Stop:
+
+       IFD DEBUG=1
+       lea DEBUG_ADDR,a0
+       move.l d0,(a0)
+       move.l a2,(a0)
+       move.l #debug_stop,4(a0)
+       ENDC
+
+       move.l ahiac_DriverData(a2),a0
+       move.l p_Base(a0),a0
+       bsr reset_hw
+
+       move.l ahiac_DriverData(a2),a0
+       bsr.w reset_ch
+
+       moveq #AHIE_OK,d0
+       rts
+
+       IFD DEBUG=1
+debug_allocaudio
+       dc.b "AllocAudio(%p,%p)\n",0
+       even
+       ENDC
+
+       ; struct TagItem* A1
+       ; struct AHIAudioCtrlDrv* a2
+
+AHIsub_AllocAudio
+       movem.l d2-d3/d7/a3-a6,-(sp)
+
+       IFD DEBUG=1
+       lea DEBUG_ADDR,a0
+       move.l a1,(a0)
+       move.l a2,(a0)
+       move.l #debug_allocaudio,4(a0)
+       ENDC
+
+       moveq #AHISF_ERROR,d7
+       
+       move.l a6,a5
+       move.l a1,d3
+
+       move.l ub_SysLib(a5),a6
+
+       move.l #UAESND_SIZEOF,d0
+       move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
+       call AllocMem
+       move.l d0,ahiac_DriverData(a2)
+       beq .error
+       move.l d0,a3
+
+       move.l a5,p_UAESNDBase(a3)
+       move.l ub_Base(a5),a4
+       moveq #0,d0
+       move.b base_max_streams(a4),d0
+       move.w d0,p_StreamCnt(a3)
+       move.l a4,p_Base(a3)
+       move.l a2,p_AudioCtrl(a3)
+       
+       moveq #0,d0
+       move.b base_max_streams(a4),d0
+       cmp.w ahiac_Channels(a2),d0
+       bcs .error
+
+       mulu #channel_SIZEOF,d0
+       move.l d0,p_ChannelSize(a3)
+       move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
+       call AllocMem
+       move.l d0,p_Channels(a3)
+       beq     .error
+
+       move.l d0,a1
+       move.w ahiac_Channels(a2),d1
+       subq.w #1,d1
+.setch
+       lea ch_UAESNDSet1(a1),a0
+       move.l a0,ch_set_current(a1)
+       add.w #channel_SIZEOF,a1
+       dbf d1,.setch
+
+       move.w ahiac_Sounds(a2),d0
+       mulu.w #sound_SIZEOF,d0
+       move.l d0,p_SoundSize(a3)
+       move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
+       call AllocMem
+       move.l d0,p_Sounds(a3)
+       beq     .error
+
+       move.l a3,a0
+       bsr.w reset_ch
+
+       move.l a4,a0
+       bsr.w reset_hw
+
+       lea p_Interrupt(a3),a1
+       lea interrupt_code(pc),a0
+       move.l a0,IS_CODE(a1)
+       lea intname(pc),a0
+       move.l a0,LN_NAME(a1)
+       move.b #NT_INTERRUPT,LN_TYPE(a1)
+       move.b #40,LN_PRI(a1)
+       move.l a3,IS_DATA(a1)
+       moveq #INTB_EXTER,d0
+       call AddIntServer
+       st p_intadded(a3)
+
+       move.l a4,a0
+       moveq #1,d0
+       move.w p_StreamCnt(a3),d1
+       lsl.l d1,d0
+       subq.l #1,d0
+       move.l d0,base_stream_allocate(a0)
+
+       move.l #AHISF_KNOWSTEREO|AHISF_KNOWHIFI|AHISF_KNOWMULTICHANNEL,d7
+
+.error
+       move.l d7,d0
+
+       IFD DEBUG=1
+       bsr debugreturn
+       ENDC
+
+       movem.l (sp)+,d2-d3/d7/a3-a6
+       rts
+
+       IFD DEBUG=1
+debug_freeaudio
+       dc.b "FreeAudio(%p)\n",0
+       even
+       ENDC
+
+AHIsub_FreeAudio
+       movem.l a3/a5/a6,-(sp)
+
+       IFD DEBUG=1
+       lea DEBUG_ADDR,a0
+       move.l a2,(a0)
+       move.l #debug_freeaudio,4(a0)
+       ENDC
+
+       move.l a6,a5
+       move.l ub_SysLib(a5),a6
+       move.l ahiac_DriverData(a2),d0
+       beq.s .noaudio
+       move.l d0,a3
+       
+       tst.b p_intadded(a3)
+       beq.s .noint
+       lea p_Interrupt(a3),a1
+       moveq #INTB_EXTER,d0
+       call RemIntServer       
+
+       move.l p_Base(a3),a0
+       bsr.w reset_hw
+       clr.l base_stream_allocate(a0)
+.noint
+       
+       move.l p_Sounds(a3),d0
+       beq.s .nosounds
+       move.l d0,a1
+       move.l p_SoundSize(a3),d0
+       call FreeMem
+.nosounds
+
+       move.l p_Channels(a3),d0
+       beq.s .nochannels
+       move.l d0,a1
+       move.l p_ChannelSize(a3),d0
+       call FreeMem
+.nochannels
+       
+       move.l a3,a1
+       move.l p_DriverDataSize(a3),d0
+       call FreeMem
+
+       clr.l ahiac_DriverData(a2)
+       
+.noaudio
+       movem.l (sp)+,a3/a5/a6
+       rts
+
+       IFD DEBUG=1
+debug_getattr
+       dc.b "GetAttr(%x,%x,%x,%p,%p)\n",0
+       even
+       ENDC
+
+       ; ULONG Attribute D0
+       ; LONG Argument D1
+       ; LONG DefValue D2
+       ; struct TagItem* A1
+       ; struct AHIAudioCtrlDrv* A2
+
+AHIsub_GetAttr
+       move.l d2,-(sp)
+
+       IFD DEBUG=1
+       lea DEBUG_ADDR,a0
+       move.l d0,(a0)
+       move.l d1,(a0)
+       move.l d2,(a0)
+       move.l a1,(a0)
+       move.l a2,(a0)
+       move.l #debug_getattr,4(a0)
+       ENDC
+
+       cmp.l #AHIDB_Frequency,d0
+       bne.s .notfreq
+       lea tag_frequencies(pc),a0
+       move.l 0(a0,d1.w*4),d2
+       bra.s .exit
+.notfreq
+       cmp.l #AHIDB_Index,d0
+       bne.s .notindex
+       lea tag_frequencies(pc),a0
+       moveq #0,d2
+.freqnext
+       tst.l (a0)
+       beq.s .freqexit
+       cmp.l (a0)+,d1
+       bls.s .exit
+       addq.l #1,d2
+       bra.s .freqnext
+.freqexit
+       moveq #FREQUENCIES-1,d2
+       bra.s .exit
+.notindex
+       lea GetAttrTags(pc),a0
+.next
+       tst.l (a0)
+       beq.s .exit
+       cmp.l (a0),d0
+       addq.l #4+4,a0
+       bne.s .next
+       move.l -4(a0),d2
+.exit
+       move.l d2,d0
+       
+       IFD DEBUG=1
+       bsr debugreturn
+       ENDC
+       
+       move.l (sp)+,d2
+       rts
+
+tag_frequencies
+       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
+       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
+       dc.l 56000
+       dc.l 96000
+FREQUENCIES EQU (*-tag_frequencies)>>2 
+tag_frequencies_end
+       dc.l 0
+
+GetAttrTags
+       dc.l AHIDB_Bits, 32
+       dc.l AHIDB_Frequencies, FREQUENCIES
+       dc.l AHIDB_MaxChannels, 8
+       dc.l AHIDB_Author, tag_author
+       dc.l AHIDB_Copyright, tag_copyright
+       dc.l AHIDB_Version, IDString
+       dc.l AHIDB_Record, 0
+       dc.l AHIDB_Outputs, 1
+       dc.l AHIDB_Output, tag_output
+       dc.l AHIDB_PingPong, 1
+       dc.l AHIDB_Realtime, 1
+       dc.l AHIDB_MinOutputVolume, 0
+       dc.l AHIDB_MaxOutputVolume, $10000
+       dc.l 0
+
+tag_author
+       dc.b "Toni Wilen",0
+tag_copyright
+       dc.b "© 2020 Toni Wilen",0
+tag_output
+       dc.b "UAE",0
+       even
+
+       IFD DEBUG=1
+debug_hardwarecontrol
+       dc.b "HardwareControl(%x,%x,%p)\n",0
+       even
+       ENDC
+
+       ; ULONG Attribute D0
+       ; LONG Argument D1
+       ; struct AHIAudioCtrlDrv* A2
+
+AHIsub_HardwareControl
+
+       IFD DEBUG=1
+       lea DEBUG_ADDR,a0
+       move.l d0,(a0)
+       move.l d1,(a0)
+       move.l a2,(a0)
+       move.l #debug_hardwarecontrol,4(a0)
+       ENDC
+
+       move.l ahiac_DriverData(a2),a0
+       move.l p_Base(a0),a0
+
+       cmp.l #AHIC_MonitorVolume,d0
+       bne.s .dontsetmonvol
+       nop
+       bra.s .done
+.dontsetmonvol
+       cmp.l #AHIC_MonitorVolume_Query,d0
+       bne.s .dontgetmonvol
+       moveq #1,d0
+       swap d0
+       bra.s .doneout
+.dontgetmonvol
+       cmp.l #AHIC_OutputVolume,d0
+       bne.s .dontsetoutvol
+       lsr.l #1,d1
+       nop
+       bra.s .done
+.dontsetoutvol
+       cmp.l #AHIC_OutputVolume_Query,d0
+       bne.s .dontgetoutvol
+       
+       moveq #1,d0
+       swap d0
+       bra.s .doneout
+.dontgetoutvol
+       cmp.l #AHIC_InputGain,d0
+       bne.s .dontsetinputgain
+       nop
+       bra.s .done
+.dontsetinputgain
+       cmp.l #AHIC_InputGain_Query,d0
+       bne.s .dontgetinputgain
+       moveq #1,d0
+       swap d0
+       bra.s .doneout
+.dontgetinputgain
+       cmp.l #AHIC_Input,d0
+       bne.s .dontsetinput
+       nop
+       bra.s .done
+.dontsetinput
+       cmp.l #AHIC_Input_Query,d0
+       bne.b .dontgetinput
+       moveq #0,d0
+       bra.s .doneout
+.dontgetinput
+       cmp.l #AHIC_Output,d0
+       bne.s .dontsetoutput
+       nop
+       bra.s .done
+.dontsetoutput
+       cmp.l #AHIC_Output_Query,d0
+       bne.b .dontgetoutput
+       moveq #0,d0
+       bra.s .doneout
+.dontgetoutput
+       moveq #0,d0
+       bra.s .doneout
+.done
+       moveq #1,d0
+.doneout
+       rts
+
+       ; d0.w = channel
+       ; a0 = AHIAudioCtrlDrv
+callsoundfunc:
+       movem.l a2/a6,-(sp)
+       move.l a0,a2
+       move.l ahiac_SoundFunc(a2),d1
+       beq.s .nosoundfunc
+       move.l d1,a0
+       move.l ahiac_DriverData(a2),a1
+       move.l p_Channels(a1),a1
+       move.w d0,d1
+       mulu #channel_SIZEOF,d1
+       add.l d1,a1
+       add.w #ch_SndMsg,a1
+       move.w d0,(a1)
+       ext.l d0
+       move.l h_Entry(a0),a6
+       jsr     (a6)
+.nosoundfunc
+       movem.l (sp)+,a2/a6
+       rts
+
+       ; a1 = UAESND
+interrupt_code
+       move.l p_Base(a1),a0
+       move.l base_stream_intreq(a0),d0
+       beq.s .notours
+
+       movem.l d2-d7/a2-a4,-(sp)
+       move.l d0,d7
+       move.l a1,a5
+       move.l p_AudioCtrl(a5),a2
+       move.l ahiac_DriverData(a2),a3
+       lea STREAM_START(a0),a4
+
+       moveq #0,d6
+.cont
+       btst d6,d7
+       beq.s .next
+
+       ; read and clear interrupt status
+       move.b stream_intreq(a4),d2
+       bpl.s .next
+       btst #4,d2
+       beq.s .notimer
+
+       move.l p_ChannelInfo(a3),d0
+       beq.s .noci
+       move.l d0,a0
+       lea     ahieci_Offset(a0),a1
+       move.w ahieci_Channels(a0),d0
+       subq.w #1,d0
+       bmi.s .noci
+       move.l p_Channels(a3),a6
+       move.l a4,a0
+.loop
+       move.l set_length_original(a0),d1
+       sub.l set_length(a0),d1
+       move.l d1,(a1)+
+       add.w #STREAM_OFFSET,a0
+       dbf d0,.loop
+       
+       move.l p_ChannelInfo(a3),a1
+       move.l ahieci_Func(a1),d0
+       beq.s .noci
+       move.l d0,a0
+       move.l h_Entry(a0),a6
+       jsr     (a6)
+.noci
+
+       ; playerfunc
+       move.l ahiac_PlayerFunc(a2),d0
+       beq.s .noplayerfunc
+       move.l d0,a0
+       sub.l a1,a1
+       move.l h_Entry(a0),a6
+       jsr (a6)
+.noplayerfunc
+       
+.notimer
+
+       ; sample started interrupt?
+       btst #0,d2
+       beq.s .next
+       
+       ; soundfunc
+       move.w d6,d0
+       move.l a2,a0
+       bsr.w callsoundfunc
+
+.next
+       add.w #STREAM_OFFSET,a4
+       addq.w #1,d6
+       cmp.w p_StreamCnt(a3),d6
+       bne.s .cont
+       
+       movem.l (sp)+,d2-d7/a2-a4
+       moveq #0,d0
+       rts
+.notours
+       moveq #1,d0
+       rts
+
+initRoutine:
+       movem.l d1/a0/a1/a4/a5/a6,-(sp)
+       sub.l a4,a4
+       move.l d0,a5
+       move.l a6,ub_SysLib(a5)
+       move.l a0,ub_SegList(a5)
+
+       lea utilname(pc),a1
+       moveq #0,d0
+       call OpenLibrary
+       move.l d0,ub_UtilBase(a5)
+       beq.s .end
+
+       lea expname(pc),a1
+       moveq #0,d0
+       call OpenLibrary
+       tst.l d0
+       beq.s .end
+       move.l d0,a6
+       sub.l a0,a0
+       move.w #6502,d0
+       moveq #2,d1
+       jsr -$048(a6) ; FindConfigDev
+       move.l d0,ub_ConfigDev(a5)
+       move.l a6,a1
+       move.l ub_SysLib(a5),a6
+       call CloseLibrary
+
+       move.l ub_ConfigDev(a5),d0
+       beq.s .end
+       move.l d0,a0
+       move.l cd_BoardAddr(a0),ub_Base(a5)
+
+       move.l a5,a4
+.end
+       move.l a4,d0
+       movem.l (sp)+,d1/a0/a1/a4/a5/a6
+       rts
+
+Open:
+       addq.w #1,LIB_OPENCNT(a6)
+       bclr.b #LIBB_DELEXP,ub_Flags(a6)
+       move.l a6,d0
+       rts
+
+Close:
+       moveq #0,d0
+       subq.w #1,LIB_OPENCNT(a6)
+       bne.b .exit
+       btst.b #LIBB_DELEXP,ub_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 ub_SysLib(a5),a6
+       tst.w LIB_OPENCNT(a5)
+       beq.b .notopen
+       bset.b #LIBB_DELEXP,ub_Flags(a5)
+       moveq #0,d0
+       bra.b .Expunge_end
+.notopen:
+
+       move.l a5,a1
+       call Remove
+
+       move.l ub_UtilBase(a5),d0
+       beq.s .noutil
+       move.l d0,a1
+       call CloseLibrary
+.noutil
+
+       move.l ub_SegList(a5),d2
+       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
+
+expname
+       dc.b "expansion.library",0
+utilname
+       dc.b "utility.library",0
+intname
+       dc.b "uaesnd_ahi",0
+       cnop 0,4
+
+EndCode: