grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / devs / AHI / Drivers / Paula / paula_audio.a
blob363b5e417ae216bd3c16fe892fca6f76d5beb4e3
1 *** ScR ***
3 * $Id$
5 *** NOTES ***
7 * The sampler routines are just for fun. Since interrupts must not be disabled,
8 * there are lots of clicks.
10 ;------------
12 include version.i
14 VSTRING MACRO
15 VERS
16 dc.b " ("
17 DATE
18 dc.b ")",13,10,0
19 ENDM
20 VERSTAG MACRO
21 dc.b 0,"$VER: "
22 VERS
23 dc.b " ("
24 DATE
25 dc.b ")",0
26 ENDM
28 incdir include:
31 EXEC_MACROS_I SET 1 ; Fake a bit to avoid exec/macros.i problems
33 pushm MACRO
34 movem.l \1,-(sp)
35 ENDM
36 popm MACRO
37 movem.l (sp)+,\1
38 ENDM
40 *************************************************************************
41 IFND PRINTF
42 PRINTF MACRO ; level,<string>,...
43 IFGE DEBUG_DETAIL-\1
44 XREF kprint_macro
45 PUSHCOUNT SET 0
47 IFNC '\9',''
48 move.l \9,-(sp)
49 PUSHCOUNT SET PUSHCOUNT+4
50 ENDC
52 IFNC '\8',''
53 move.l \8,-(sp)
54 PUSHCOUNT SET PUSHCOUNT+4
55 ENDC
57 IFNC '\7',''
58 move.l \7,-(sp)
59 PUSHCOUNT SET PUSHCOUNT+4
60 ENDC
62 IFNC '\6',''
63 move.l \6,-(sp)
64 PUSHCOUNT SET PUSHCOUNT+4
65 ENDC
67 IFNC '\5',''
68 move.l \5,-(sp)
69 PUSHCOUNT SET PUSHCOUNT+4
70 ENDC
72 IFNC '\4',''
73 move.l \4,-(sp)
74 PUSHCOUNT SET PUSHCOUNT+4
75 ENDC
77 IFNC '\3',''
78 move.l \3,-(sp)
79 PUSHCOUNT SET PUSHCOUNT+4
80 ENDC
82 movem.l a0/a1,-(sp)
83 lea.l PSS\@(pc),A0
84 lea.l 4*2(SP),A1
85 BSR kprint_macro
86 movem.l (sp)+,a0/a1
87 bra.s PSE\@
89 PSS\@ dc.b \2
90 IFEQ (\1&1) ;If even, add CR/LF par...
91 dc.b 13,10
92 ENDC
93 dc.b 0
94 ds.w 0
95 PSE\@
96 lea.l PUSHCOUNT(sp),sp
97 ENDC ;IFGE DEBUG_DETAIL-\1
98 ENDM ;PRINTF MACRO
99 ENDC ;IFND PRINTF
102 include hardware/cia.i
103 include hardware/custom.i
104 include hardware/intbits.i
105 include hardware/dmabits.i
108 include devices/audio.i
109 include devices/timer.i
110 include dos/dos.i
111 include dos/dostags.i
112 include exec/exec.i
113 include graphics/gfxbase.i
114 include intuition/intuitionbase.i
115 include intuition/screens.i
116 include resources/misc.i
117 include resources/card.i
118 include utility/utility.i
119 include utility/hooks.i
121 include lvo/cardres_lib.i
122 include lvo/dos_lib.i
123 include lvo/exec_lib.i
124 include lvo/graphics_lib.i
125 include lvo/intuition_lib.i
126 include lvo/timer_lib.i
127 include lvo/utility_lib.i
129 include devices/ahi.i
130 include libraries/ahi_sub.i
131 include lvo/ahi_sub_lib.i
133 ;include macros.i
134 call MACRO
135 jsr _LVO\1(a6)
136 ENDM
137 push MACRO
138 movem.l \1,-(sp)
139 ENDM
140 pop MACRO
141 movem.l (sp)+,\1
142 ENDM
144 std equrl d2-d7/a2-a6
145 skipl MACRO
146 dc.w $0C80
147 ENDM
148 TRUE EQU 1
149 FALSE EQU 0
151 custom EQU $dff000
152 INTENA EQU intena
153 INTREQ EQU intreq
154 DMACON EQU dmacon
155 VHPOSR EQU vhposr
157 AUD0LC EQU aud0+ac_ptr
158 AUD0LEN EQU aud0+ac_len
159 AUD0PER EQU aud0+ac_per
160 AUD0VOL EQU aud0+ac_vol
161 AUD0DAT EQU aud0+ac_dat
163 AUD1LC EQU aud1+ac_ptr
164 AUD1LEN EQU aud1+ac_len
165 AUD1PER EQU aud1+ac_per
166 AUD1VOL EQU aud1+ac_vol
167 AUD1DAT EQU aud1+ac_dat
169 AUD2LC EQU aud2+ac_ptr
170 AUD2LEN EQU aud2+ac_len
171 AUD2PER EQU aud2+ac_per
172 AUD2VOL EQU aud2+ac_vol
173 AUD2DAT EQU aud2+ac_dat
175 AUD3LC EQU aud3+ac_ptr
176 AUD3LEN EQU aud3+ac_len
177 AUD3PER EQU aud3+ac_per
178 AUD3VOL EQU aud3+ac_vol
179 AUD3DAT EQU aud3+ac_dat
183 BETTERTIMING EQU 1
185 DEBUG_DETAIL SET 0
187 _ciaa EQU $bfe001
188 _ciab EQU $bfd000
190 AUD0 EQU $0A0
191 AUD1 EQU $0B0
192 AUD2 EQU $0C0
193 AUD3 EQU $0D0
194 AUDLC EQU 0
195 AUDLEN EQU 4
196 AUDPER EQU 6
197 AUDVOL EQU 8
198 AUDPERVOL EQU 6
200 INTF_AUDIO EQU INTF_AUD3|INTF_AUD2|INTF_AUD1|INTF_AUD0
202 PALFREQ EQU 3546895
203 NTSCFREQ EQU 3579545
204 MINPER EQU 62
207 DMABUFFSAMPLES EQU 512 ; 8 of these will be allocated!
208 RECORDSAMPLES EQU 1024
210 EXTRASAMPLES EQU 4
211 EXTRABUFFSIZE EQU EXTRASAMPLES*8 ; 4 samples of max size ( 2×32 bit: hifi stereo )
213 * paula.audio extra tags
214 AHIDB_Paula14Bit EQU AHIDB_UserBase+0 * Boolean
215 AHIDB_PaulaTable EQU AHIDB_UserBase+1 * Boolean
216 AHIDB_PaulaDMA EQU AHIDB_UserBase+2 * Boolean
218 * paulaBase (private)
219 STRUCTURE paulaBase,LIB_SIZE
220 UBYTE pb_Flags
221 UBYTE pb_Pad1
222 UWORD pb_Pad2
223 APTR pb_SysLib
224 ULONG pb_SegList
225 APTR pb_GfxLib
226 APTR pb_UtilLib
227 APTR pb_DosLib
228 APTR pb_IntuiLib
229 APTR pb_TimerLib
230 APTR pb_MiscResource
231 APTR pb_CardResource
232 ULONG pb_AudioFreq ;PAL/NTSC clock constant
233 APTR pb_Lock
234 LABEL paulaBase_SIZEOF
236 * channel (private) used in DMA mode
238 STRUCTURE channel,0
239 UWORD ch_IntMask ;This channels interrupt bit
240 UWORD ch_DMAMask ;This channels DMA bit
241 UWORD ch_Stereo ;0 = Left, 1 = Right
242 UWORD ch_DMALength
243 UBYTE ch_EndOfSample ;Flag
244 UBYTE ch_NoInt ;SetFreq() must not cause interrupt
245 UWORD ch_Pad
246 APTR ch_RegBase ;This channels hardware register base
248 ULONG ch_Cleared ;Samples already cleared
249 ULONG ch_Cleared2 ;Samples already cleared
251 ULONG ch_Count ;How mant samples played? (In samples)
253 APTR ch_Address ;Current sample address
254 APTR ch_NextAddress ;Next sample address
256 ULONG ch_Offset ;Where are we playing? (In samples)
257 ULONG ch_NextOffset ;Next...
259 ULONG ch_Length ;Current sample length (In samples)
260 ULONG ch_NextLength ;Next sample length
262 ULONG ch_Type ;Current sample type
263 ULONG ch_NextType ;Next sample type
265 LABEL ch_PerVol
266 UWORD ch_Period ;Current period (0 = stopped)
267 UWORD ch_Volume ;Current volume (scaled)
268 LABEL ch_NextPerVol
269 UWORD ch_NextPeriod ;Next period
270 UWORD ch_NextVolume ;Next volume (scaled)
272 ; ULONG ch_AudPerVol
274 UWORD ch_VolumeNorm
275 UWORD ch_NextVolumeNorm
277 UWORD ch_Scale ;Current frequency scale (2^ch_Scale)
278 UWORD ch_NextScale ;Next frequency scale
280 STRUCT ch_SndMsg,AHISoundMessage_SIZEOF
282 LABEL channel_SIZEOF
284 * sound (private) used in DMA mode
286 STRUCTURE sound,0
287 ULONG so_Type
288 APTR so_Address
289 ULONG so_Length
290 LABEL sound_SIZEOF
292 * paula (private) ahiac_DriverData points to this structure.
293 STRUCTURE paula,0
294 UBYTE p_Flags
295 UBYTE p_Parallel ;TRUE if parport allocated
296 UBYTE p_Filter ;TRUE if filter was on when alocating
297 UBYTE p_Pad0
298 UWORD p_DisableCount ;AHIsub_Enable/AHIsub_Disable cnt
299 UWORD p_IRQMask
301 APTR p_PaulaBase ;Pointer to library base (DMA only)
302 APTR p_AudioCtrl ;Backpointer to AudioCtrl struct.
304 UBYTE p_SwapChannels ;TRUE if left/right should be swapped
305 UBYTE p_ScreenIsDouble ;TRUE if screen mode allows >28kHz
307 UWORD p_MixTaskPri
308 APTR p_MixTask
309 APTR p_ReplyTask
311 ULONG p_MinBufferLength ;Minimum length of chipmem playbuffer
312 APTR p_CalibrationTable ;Pointer to 14 bit conversion tables
314 APTR p_DMAbuffer ;Chipmem play buffer
315 ULONG p_DoubleBufferOffset ;Buffer flag
317 LABEL p_AudPtrs ; Pointers to chipmem play buffer
318 APTR p_AudPtr1A
319 APTR p_AudPtr2A
320 APTR p_AudPtr3A
321 APTR p_AudPtr4A
322 APTR p_AudPtr1B
323 APTR p_AudPtr2B
324 APTR p_AudPtr3B
325 APTR p_AudPtr4B
327 APTR p_audioport ;For audio.device
328 APTR p_audioreq ;For audio.device
329 UBYTE p_audiodev ;For audio.device
330 UBYTE p_bpad0
331 UWORD p_wpad1
332 APTR p_ParBitsUser ;Parallel port locking
333 APTR p_ParPortUser ;Parallel port locking
334 APTR p_SerBitsUser ;Serial port locking
335 APTR p_CardHandle ;Aura PCMCIA card handle
337 STRUCT p_PlayInt,IS_SIZE ;Player hardware interrupt
338 STRUCT p_PlaySoftInt,IS_SIZE ;Player software interrupt (mixing only)
339 STRUCT p_RecInt,IS_SIZE ;Recorder hardware interrupt (mixing only)
340 STRUCT p_RecSoftInt,IS_SIZE ;Recorder software interrupt (mixing only)
342 UWORD p_AudPer ;Playback period (mixing only)
343 UWORD p_OutputVolume ;Hardware volume (mixing only)
344 UWORD p_MonitorVolume ;Monitor volume (mixing only)
345 UWORD p_Input ;Input select (mixing only)
347 IFEQ BETTERTIMING-1
348 ULONG p_LoopLeftovers ;(mixing only)
349 ULONG p_SampleFrameShift ;Size of sample fram is 2^x (mixing only)
350 ELSE
351 ULONG p_LoopTimes ;(mixing only)
352 ENDC
354 LABEL p_PlayerHookRegs ;PlayerHook
355 APTR p_PlayerHook
356 ULONG p_Reserved
357 FPTR p_PlayerEntry ;p_PlayerHook->h_Entry
359 LABEL p_MixHookRegs ;MixingHook (mixing only)
360 APTR p_MixHook
361 APTR p_Mixbuffer
362 FPTR p_MixEntry ;p_MixHook->h_Entry
364 LABEL p_RecIntDataAura ;Record data structure for Aura sampl.
365 APTR p_AuraAddress ;DO NOT CHANGE ORDER!
366 LABEL p_RecIntData ;Record data structure
367 APTR p_RecFillPtr
368 UWORD p_RecFillCount
369 UWORD p_Pad2
370 APTR p_RecBuffer1
371 APTR p_RecBuffer2
372 APTR p_RecSoftIntPtr
374 LABEL p_RecordMessage ;Message used with SamplerFunc()
375 ULONG p_rmType
376 APTR p_rmBuffer
377 ULONG p_rmLength
379 ULONG p_EClock ;System E clock freq. (DMA only)
380 ULONG p_EPeriod ;PlayerFunc() E clk period (DMA only)
381 STRUCT p_EAlarm,EV_SIZE ;E Clock to wait for (DMA only)
382 STRUCT p_TimerPort,MP_SIZE ;(DMA only)
383 STRUCT p_TimerInt,IS_SIZE ;(DMA only)
384 APTR p_TimerReq ;Used to drive PlayerFunc() (DMA only)
385 UBYTE p_TimerDev ;(DMA only)
386 UBYTE p_TimerPad
387 UWORD p_TimerCommFlag ;Used to end timer (DMA only)
389 ULONG p_MasterVolume ;Effect parameter (DMA only)
390 APTR p_ChannelInfo ;Effect structure (DMA only)
392 APTR p_Sounds
393 STRUCT p_Channels,channel_SIZEOF*4 ;DMA playback channel info
395 STRUCT p_CalibrationArray,256 ;14 bit calibration prefs
397 LABEL paula_SIZEOF
399 * p_Flags
400 BITDEF P,14BIT,0
401 BITDEF P,HIFI,1
402 PB_STEREO EQU AHIACB_STEREO ;=2
403 PF_STEREO EQU AHIACF_STEREO
404 BITDEF P,DMA,3
406 Start:
407 moveq #-1,d0
410 RomTag:
411 DC.W RTC_MATCHWORD
412 DC.L RomTag
413 DC.L EndCode
414 DC.B RTF_AUTOINIT
415 DC.B VERSION ;version
416 DC.B NT_LIBRARY
417 DC.B 0 ;pri
418 DC.L LibName
419 DC.L IDString
420 DC.L InitTable
422 LibName: dc.b "paula.audio",0
423 IDString: VSTRING
424 gfxName: GRAPHICSNAME
425 utilName: UTILITYNAME
426 dosName: DOSNAME
427 intuiName: dc.b "intuition.library",0
428 timerName: dc.b "timer.device",0
429 miscName: MISCNAME
430 cardName: dc.b "card.resource",0
431 mosName: dc.b "MorphOS",0
432 filterVar: dc.b "AHIpaulaFilterFreq",0
433 screenVar: dc.b "AHIpaulaSampleLimit",0
434 bufferVar: dc.b "AHIpaulaBufferLength",0
435 swapVar: dc.b "AHIpaulaSwapChannels",0
436 fakefreqVar: dc.b "AHIpaulaFakeMixFreq",0
437 taskVar: dc.b "AHIpaulaMixTaskPri",0
438 cnop 0,2
440 InitTable:
441 DC.L paulaBase_SIZEOF
442 DC.L funcTable
443 DC.L dataTable
444 DC.L initRoutine
446 funcTable:
447 dc.l Open
448 dc.l Close
449 dc.l Expunge
450 dc.l Null
452 dc.l AHIsub_AllocAudio
453 dc.l AHIsub_FreeAudio
454 dc.l AHIsub_Disable
455 dc.l AHIsub_Enable
456 dc.l AHIsub_Start
457 dc.l AHIsub_Update
458 dc.l AHIsub_Stop
459 dc.l AHIsub_SetVol
460 dc.l AHIsub_SetFreq
461 dc.l AHIsub_SetSound
462 dc.l AHIsub_SetEffect
463 dc.l AHIsub_LoadSound
464 dc.l AHIsub_UnloadSound
465 dc.l AHIsub_GetAttr
466 dc.l AHIsub_HardwareControl
467 dc.l -1
469 dataTable:
470 INITBYTE LN_TYPE,NT_LIBRARY
471 INITLONG LN_NAME,LibName
472 INITBYTE LIB_FLAGS,LIBF_SUMUSED|LIBF_CHANGED
473 INITWORD LIB_VERSION,VERSION
474 INITWORD LIB_REVISION,REVISION
475 INITLONG LIB_IDSTRING,IDString
476 DC.L 0
478 initRoutine:
479 movem.l d1/a0/a1/a5/a6,-(sp)
481 move.l d0,a5
482 move.l a6,pb_SysLib(a5)
483 move.l a0,pb_SegList(a5)
485 lea gfxName(pc),a1
486 moveq #37,d0
487 call OpenLibrary
488 move.l d0,pb_GfxLib(a5)
489 bne.b .gfxOK
490 ALERT AG_OpenLib|AO_GraphicsLib
491 bra .gfxFail
492 .gfxOK
493 lea utilName(pc),a1
494 moveq #37,d0
495 call OpenLibrary
496 move.l d0,pb_UtilLib(a5)
497 bne.b .utilOK
498 ALERT AG_OpenLib|AO_UtilityLib
499 bra .utilFail
500 .utilOK
501 lea dosName(pc),a1
502 moveq #37,d0
503 call OpenLibrary
504 move.l d0,pb_DosLib(a5)
505 bne.b .dosOK
506 ALERT AG_OpenLib|AO_DOSLib
507 bra .dosFail
508 .dosOK
509 lea intuiName(pc),a1
510 moveq #37,d0
511 call OpenLibrary
512 move.l d0,pb_IntuiLib(a5)
513 bne.b .intuiOK
514 ALERT AG_OpenLib|AO_Intuition
515 bra .intuiFail
516 .intuiOK
517 lea miscName(pc),a1
518 call OpenResource
519 move.l d0,pb_MiscResource(a5)
520 bne.b .miscOK
521 ALERT AG_OpenRes|AO_MiscRsrc
522 bra .miscFail
523 .miscOK
524 lea cardName(pc),a1
525 call OpenResource
526 move.l d0,pb_CardResource(a5) ;Don't fail on error
528 move.l #PALFREQ,d1 ;PAL
529 move.l pb_GfxLib(a5),a0
530 move.w gb_DisplayFlags(a0),d0
531 btst #REALLY_PALn,d0
532 bne.b .1
533 move.l #NTSCFREQ,d1 ;NTSC
535 move.l d1,pb_AudioFreq(a5)
537 move.l a5,d0
538 .exit
539 movem.l (sp)+,d1/a0/a1/a5/a6
542 .miscFail
543 move.l pb_IntuiLib(a5),a1
544 call CloseLibrary
545 .intuiFail
546 move.l pb_DosLib(a5),a1
547 call CloseLibrary
548 .dosFail
549 move.l pb_UtilLib(a5),a1
550 call CloseLibrary
551 .utilFail
552 move.l pb_GfxLib(a5),a1
553 call CloseLibrary
554 .gfxFail
555 moveq #0,d0
556 move.l a5,a1
557 move.w LIB_NEGSIZE(a5),d0
558 sub.l d0,a1
559 add.w LIB_POSSIZE(a5),d0
560 call FreeMem
562 moveq #0,d0
563 bra.b .exit
565 Open:
566 addq.w #1,LIB_OPENCNT(a6)
567 bclr.b #LIBB_DELEXP,pb_Flags(a6)
568 move.l a6,d0
571 Close:
572 moveq #0,d0
573 subq.w #1,LIB_OPENCNT(a6)
574 bne.b .exit
575 btst.b #LIBB_DELEXP,pb_Flags(a6)
576 beq.b .exit
577 bsr Expunge
578 .exit
581 Expunge:
582 movem.l d1/d2/a0/a1/a5/a6,-(sp)
583 move.l a6,a5
584 move.l pb_SysLib(a5),a6
585 tst.w LIB_OPENCNT(a5)
586 beq.b .notopen
587 bset.b #LIBB_DELEXP,pb_Flags(a5)
588 moveq #0,d0
589 bra.b .Expunge_end
590 .notopen
591 move.l pb_IntuiLib(a5),a1
592 call CloseLibrary
594 move.l pb_DosLib(a5),a1
595 call CloseLibrary
597 move.l pb_UtilLib(a5),a1
598 call CloseLibrary
600 move.l pb_GfxLib(a5),a1
601 call CloseLibrary
603 move.l a5,a1
604 call Remove
606 move.l pb_SegList(a5),d2
608 moveq #0,d0
609 move.l a5,a1
610 move.w LIB_NEGSIZE(a5),d0
611 sub.l d0,a1
612 add.w LIB_POSSIZE(a5),d0
613 call FreeMem
615 move.l d2,d0
616 .Expunge_end
617 movem.l (sp)+,d1/d2/a0/a1/a5/a6
620 Null:
621 moveq #0,d0
624 * BeginIO(ioRequest)(a1) (From amiga.lib)
625 BeginIO:
626 ;move.l a1,a0 ;probably not necessary
627 push a6
628 move.l IO_DEVICE(a1),a6
629 jsr -30(a6)
630 pop a6
633 ;in:
634 * d0 Default value
635 * a0 Environment variable to get
636 * a5 paulaBase
637 GetVarInt:
638 pushm std
640 move.l d0,d5 ;Default
642 move.l pb_DosLib(a5),a6
643 subq.l #8,sp ;local label
644 move.w #("0"<<8)|0,(sp) ;Initialize as "0"
646 move.l a0,d1
647 move.l sp,d2
648 moveq #8,d3
649 moveq #0,d4
650 call GetVar
652 addq.l #1,d0 ;cmp.l #-1,d0
653 beq .gotvar
654 move.l sp,d1
655 clr.l -(sp)
656 move.l sp,d2
657 call StrToLong
658 move.l (sp)+,d5
659 .gotvar
660 addq.l #8,sp
662 ; d5 is now the integer value
663 move.l d5,d0
664 popm std
667 ****** [driver].audio/--background-- ****************************************
669 * OVERVIEW
671 * GENERAL PROGRAMMING GUIDLINES
673 * The driver must be able to be OpenLibrary()'ed even if the
674 * hardware is not present. If a library the driver uses fails
675 * to open, it is ok to fail at the library init routine, but please
676 * avoid it if possible.
678 * Please note that this document could be much better, but since not
679 * many will ever need to read it, it will probably stay this way.
680 * Don't hesitate to contact Martin Blom when you're writing a driver!
682 * DRIVER VERSIONS
684 * The lowest supported driver version is 2. If you use any feature
685 * introduced in later versions of AHI, you should set the driver
686 * version to the same version as the features were introduced with.
687 * Example: You use PreTimer() and PostTimer(), and since these
688 * calls were added in V4 of ahi.device, your driver's version should
689 * be 4, too.
691 * Note that AHI version 4 will not open V6 drivers, for obvious
692 * reasons.
694 * AUDIO ID NUMBERS
696 * Just some notes about selecting ID numbers for different modes:
697 * It is up to the driver programmer to chose which modes should be
698 * available to the user. Take care when selecting.
700 * The upper word is the hardware ID, and can only be allocated by
701 * Martin Blom <lcs@lysator.liu.se>. The lower word is free, but in
702 * order to allow enhancements, please only use bit 0 to 4 for modes!
703 * If your driver supports multiple sound cards, use bit 12-15 to
704 * select card (first one is 0). If your sound card has multiple
705 * AD/DA converters, you can use bit 8-11 to select them (the first
706 * should be 0).
708 * Set the remaining bits to zero.
710 * Use AHI:Developer/Support/ScanAudioModes to have a look at the modes
711 * currently available. Use AHI:Developer/Support/sift to make sure your
712 * mode descriptor file is a legal IFF file.
714 * I do reserve the right to change the rules if I find them incorrect!
716 *****************************************************************************
721 ****** [driver].audio/AHIsub_AllocAudio *************************************
723 * NAME
724 * AHIsub_AllocAudio -- Allocates and initializes the audio hardware.
726 * SYNOPSIS
727 * result = AHIsub_AllocAudio( tags, audioctrl);
728 * D0 A1 A2
730 * ULONG AHIsub_AllocAudio( struct TagItem *, struct AHIAudioCtrlDrv * );
732 * IMPLEMENTATION
733 * Allocate and initialize the audio hardware. Decide if and how you
734 * wish to use the mixing routines provided by 'ahi.device', by looking
735 * in the AHIAudioCtrlDrv structure and parsing the tag list for tags
736 * you support.
738 * 1) Use mixing routines with timing:
739 * You will need to be able to play any number of samples from
740 * about 80 up to 65535 with low overhead.
741 * · Update AudioCtrl->ahiac_MixFreq to nearest value that your
742 * hardware supports.
743 * · Return AHISF_MIXING|AHISF_TIMING.
745 * 2) Use mixing routines without timing:
746 * If the hardware can't play samples with any length, use this
747 * alternative and provide timing yourself. The buffer must
748 * take less than about 20 ms to play, preferable less than 10!
749 * · Update AudioCtrl->ahiac_MixFreq to nearest value that your
750 * hardware supports.
751 * · Store the number of samples to mix each pass in
752 * AudioCtrl->ahiac_BuffSamples.
753 * · Return AHISF_MIXING
754 * Alternatively, you can use the first method and call the
755 * mixing hook several times in a row to fill up a buffer.
756 * In that case, AHIsub_GetAttr(AHIDB_MaxPlaySamples) should
757 * return the size of the buffer plus AudioCtrl->ahiac_MaxBuffSamples.
758 * If the buffer is so large that it takes more than (approx.) 10 ms to
759 * play it for high sample frequencies, AHIsub_GetAttr(AHIDB_Realtime)
760 * should return FALSE.
762 * 3) Don't use mixing routines:
763 * If your hardware can handle everything without using the CPU to
764 * mix the channels, you tell 'ahi.device' this by not setting
765 * either the AHISB_MIXING or the AHISB_TIMING bit.
767 * If you can handle stereo output from the mixing routines, also set
768 * bit AHISB_KNOWSTEREO.
770 * If you can handle hifi (32 bit) output from the mixing routines,
771 * set bit AHISB_KNOWHIFI.
773 * If this driver can be used to record samples, set bit AHISB_CANRECORD,
774 * too (regardless if you use the mixing routines in AHI or not).
776 * If the sound card has hardware to do DSP effects, you can set the
777 * AHISB_CANPOSTPROCESS bit. The output from the mixing routines will
778 * then be two separate buffers, one wet and one dry. You should then
779 * apply the Fx on the wet buffer, and post-mix the two buffers before
780 * you send the samples to the DAC. (V4)
782 * INPUTS
783 * tags - pointer to a taglist.
784 * audioctrl - pointer to an AHIAudioCtrlDrv structure.
786 * TAGS
787 * The tags are from the audio database (AHIDB_#? in <devices/ahi.h>),
788 * NOT the tag list the user called ahi.device/AHI_AllocAudio() with.
790 * RESULT
791 * Flags, defined in <libraries/ahi_sub.h>.
793 * EXAMPLE
795 * NOTES
796 * You don't have to clean up on failure, AHIsub_FreeAudio() will
797 * always be called.
799 * BUGS
801 * SEE ALSO
802 * AHIsub_FreeAudio(), AHIsub_Start()
804 *****************************************************************************
808 AHIsub_AllocAudio:
809 PRINTF 2,"\e[0;0H\e[J"
810 PRINTF 2,"AHIsub_AllocAudio()"
812 pushm std
813 move.l a6,a5
815 move.l a1,d3
818 * Allocate the 'paula' structure (our variables)
819 move.l pb_SysLib(a5),a6
820 move.l #paula_SIZEOF,d0
821 move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
822 call AllocVec
823 move.l d0,ahiac_DriverData(a2)
824 beq .error_nopaula
825 move.l d0,a3
827 * Initialize some fields...
828 st p_TimerDev(a3)
829 st p_audiodev(a3)
830 move.l #-1,p_ParBitsUser(a3)
831 move.l #-1,p_ParPortUser(a3)
832 move.l #-1,p_SerBitsUser(a3)
833 move.l a5,p_PaulaBase(a3)
834 move.l a2,p_AudioCtrl(a3)
835 lea p_RecSoftInt(a3),a0
836 move.l a0,p_RecSoftIntPtr(a3)
837 move.l #AHIST_S16S,p_rmType(a3)
838 move.l #RECORDSAMPLES,p_rmLength(a3)
839 move.w #64,p_OutputVolume(a3)
840 move.l #$10000,p_MasterVolume(a3)
842 * Translate tags to flags
843 move.l pb_UtilLib(a5),a6
845 move.l ahiac_Flags(a2),d2
846 and.b #PF_STEREO,d2 ;same as AHIACF_STEREO
848 move.l #AHIDB_Paula14Bit,d0
849 moveq #FALSE,d1
850 move.l d3,a0 ;tag list
851 call GetTagData
852 tst.l d0
853 beq.b .no14bit
854 or.b #PF_14BIT,d2
855 .no14bit
856 move.l #AHIDB_HiFi,d0
857 moveq #FALSE,d1
858 move.l d3,a0 ;tag list
859 call GetTagData
860 tst.l d0
861 beq.b .noHiFi
862 or.b #PF_HIFI,d2
863 .noHiFi
864 move.l #AHIDB_PaulaDMA,d0
865 moveq #FALSE,d1
866 move.l d3,a0 ;tag list
867 call GetTagData
868 tst.l d0
869 beq.b .noDMA
870 or.b #PF_DMA,d2
871 .noDMA
873 move.b p_Flags(a3),d1
874 and.b #~(PF_STEREO|PF_14BIT|PF_HIFI|PF_DMA),d1
875 or.b d2,d1
876 move.b d1,p_Flags(a3)
878 bsr checkvideo
879 move.b d0,p_ScreenIsDouble(a3)
881 * Check if a table should be used (14 bit calibration)
882 move.l #AHIDB_PaulaTable,d0
883 moveq #0,d1
884 move.l d3,a0 ;tag list
885 call GetTagData
886 tst.l d0
887 beq .notable
889 * Load 'ENV:CyberSound/SoundDrivers/14Bit_Calibration', allocate
890 * and initialize the table.
891 * FIXIT: The calibration file should move to a special chunk in
892 * 'DEVS:AudioModes/PAULA'.
893 move.l pb_DosLib(a5),a6
894 lea .calibname(pc),a0
895 move.l a0,d1
896 move.l #MODE_OLDFILE,d2
897 call Open
898 move.l d0,d4
899 beq .nocalib
900 move.l d0,d1
901 lea p_CalibrationArray(a3),a0
902 move.l a0,d2
903 move.l #256,d3
904 call Read
905 cmp.l d0,d3
906 beq .tableloaded
907 .nocalib
908 ; Fill defaults
909 lea p_CalibrationArray(a3),a0
910 move.w #254-1,d0
911 .initcalib
912 move.b #$55,(a0)+
913 dbf d0,.initcalib
914 move.b #$7f,(a0)+
915 .tableloaded
916 move.l d4,d1
917 beq.b .nofile
918 call Close
919 .nofile
920 move.l pb_SysLib(a5),a6
921 move.l #65536*2,d0
922 move.l #MEMF_PUBLIC,d1
923 call AllocVec
924 move.l d0,p_CalibrationTable(a3)
925 beq.b .notable
926 move.l d0,a0 ;table
927 lea p_CalibrationArray(a3),a1
928 bsr.w _CreateTable
929 .notable
931 * Get the minimum chip buffer size
932 moveq #0,d0 ;Default
933 lea bufferVar(pc),a0
934 bsr GetVarInt
935 move.l d0,p_MinBufferLength(a3)
937 * Check if we should swap left & right channels
938 moveq #0,d0 ;Default
939 lea swapVar(pc),a0
940 bsr GetVarInt
941 move.b d0,p_SwapChannels(a3)
943 * Check if we should use a task instead of a software interrupt
944 move.l #128,d0 ;Default (softint)
945 lea taskVar(pc),a0
946 bsr GetVarInt
947 move.w d0,p_MixTaskPri(a3)
949 * Check if MorphOS
950 move.l pb_SysLib(a5),a6
951 lea mosName(pc),a1
952 call FindResident
953 tst.l d0
954 beq .allocdev
956 * If MorphOS, check internal lock
957 call Forbid
958 move.l pb_Lock(a5),d0
959 bne .locked
960 move.l a3,pb_Lock(a5)
961 .locked
962 call Permit
963 tst.l d0
964 bne .error_hwinuse
965 bra .allocated
967 * allocate audio.device
968 .allocdev
969 move.l pb_SysLib(a5),a6
970 call CreateMsgPort
971 move.l d0,p_audioport(a3)
972 beq .error_noport
973 moveq #ioa_SIZEOF,d0
974 move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
975 call AllocVec
976 move.l d0,p_audioreq(a3)
977 beq .error_noreqmem
978 move.l d0,a0
979 move.l p_audioport(a3),MN_REPLYPORT(a0)
980 clr.w ioa_AllocKey(a0)
981 move.b #127,LN_PRI(a0) ;steal it!
982 lea .audiochannelarray(pc),a1
983 move.l a1,ioa_Data(a0)
984 move.l #1,ioa_Length(a0)
985 lea .audioname(pc),a0
986 moveq #0,d0
987 move.l p_audioreq(a3),a1
988 moveq #0,d1
989 call OpenDevice
990 move.b d0,p_audiodev(a3)
991 bne .error_noaudiodev ;somebody already owns the hardware (could be us!)
992 move.l p_audioreq(a3),a1
993 move.w #CMD_RESET,IO_COMMAND(a1)
994 bsr.w BeginIO ;clear attach, stop sound.
995 move.l p_audioport(a3),a0
996 call WaitPort
997 move.l p_audioport(a3),a0
998 call GetMsg
1000 move.l pb_DosLib(a5),a6
1001 moveq #1,d1
1002 call Delay
1004 .allocated
1006 * Set dummy interrupt handler
1007 move.l pb_SysLib(a5),a6
1008 move.l #Interrupt_Dummy,IS_CODE+p_PlayInt(a3)
1010 lea p_PlayInt(a3),a1
1011 moveq #INTB_AUD0,d0
1012 call SetIntVector
1013 lea p_PlayInt(a3),a1
1014 moveq #INTB_AUD1,d0
1015 call SetIntVector
1016 lea p_PlayInt(a3),a1
1017 moveq #INTB_AUD2,d0
1018 call SetIntVector
1019 lea p_PlayInt(a3),a1
1020 moveq #INTB_AUD3,d0
1021 call SetIntVector
1023 * test if mode supports recording
1024 move.b p_Flags(a3),d0
1025 and.b #PF_14BIT|PF_DMA,d0
1026 bne .dontgetsampler ;no record if 14 bit and DMA modes
1028 * try to allocate parallel port
1029 clr.b p_Parallel(a3)
1030 move.l pb_MiscResource(a5),a6
1031 moveq #MR_PARALLELBITS,d0
1032 lea IDString(pc),a1
1033 jsr MR_ALLOCMISCRESOURCE(a6)
1034 move.l d0,p_ParBitsUser(a3)
1035 bne .no_parrallel
1036 moveq #MR_PARALLELPORT,d0
1037 lea IDString(pc),a1
1038 jsr MR_ALLOCMISCRESOURCE(a6)
1039 move.l d0,p_ParPortUser(a3)
1040 bne .no_parrallel
1042 move.b #TRUE,p_Parallel(a3)
1043 move.b #0,_ciaa+ciaddrb ;make PB0-PB7 inputs
1044 .no_parrallel
1046 * allocate Aura sampler
1047 clr.l p_AuraAddress(a3)
1048 move.l pb_CardResource(a5),d0
1049 beq .no_aura
1050 move.l d0,a6
1051 call GetCardMap
1052 tst.l d0
1053 beq .no_aura
1054 move.l d0,a0
1055 move.l cmm_IOMemory(a0),d2
1056 beq .no_aura
1058 move.l pb_SysLib(a5),a6
1059 moveq #CardHandle_SIZEOF,d0
1060 move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
1061 call AllocVec
1062 move.l d0,p_CardHandle(a3)
1063 beq .no_aura
1065 move.l pb_CardResource(a5),a6
1066 move.l d0,a1
1067 move.l #IDString,LN_NAME(a1)
1068 move.b #CARDF_RESETREMOVE|CARDF_IFAVAILABLE,cah_CardFlags(a1)
1069 call OwnCard
1070 tst.l d0
1071 bne .no_aura
1073 move.l p_CardHandle(a3),a1
1074 call BeginCardAccess
1076 move.l d2,p_AuraAddress(a3)
1077 .no_aura
1078 .dontgetsampler
1082 * initialize interrupts (Only dummy function pointers at this time)
1084 * p_PlayInt (the main playback interrupt)
1085 move.b #NT_INTERRUPT,LN_TYPE+p_PlayInt(a3)
1086 move.l #LibName,LN_NAME+p_PlayInt(a3)
1087 move.l #Interrupt_Dummy,IS_CODE+p_PlayInt(a3)
1088 move.l a3,IS_DATA+p_PlayInt(a3)
1090 * p_PlaySoftInt (caused by p_PlayInt, here are the mixing and conversion done)
1091 move.b #NT_INTERRUPT,LN_TYPE+p_PlaySoftInt(a3)
1092 move.l #LibName,LN_NAME+p_PlaySoftInt(a3)
1093 move.l #SoftInt_Dummy,IS_CODE+p_PlaySoftInt(a3)
1094 move.l a3,IS_DATA+p_PlaySoftInt(a3)
1096 * p_RecInt (the interrupt used for recording)
1097 move.b #NT_INTERRUPT,LN_TYPE+p_RecInt(a3)
1098 move.l #LibName,LN_NAME+p_RecInt(a3)
1099 move.l #Interrupt_Dummy,IS_CODE+p_RecInt(a3)
1100 clr.l IS_DATA+p_RecInt(a3)
1102 * p_RecSoftInt (caused by p_RecInt when the record buffer has been filled)
1103 move.b #32,LN_PRI+p_RecSoftInt(a3)
1104 move.b #NT_INTERRUPT,LN_TYPE+p_RecSoftInt(a3)
1105 move.l #LibName,LN_NAME+p_RecSoftInt(a3)
1106 move.l #RecordSoftInt,IS_CODE+p_RecSoftInt(a3)
1107 move.l a3,IS_DATA+p_RecSoftInt(a3)
1109 * Make sure no interrupts occur until AHIsub_Start() is called
1110 move.w #INTF_AUDIO,custom+INTENA
1111 move.w #INTF_SETCLR,p_IRQMask(a3)
1113 * Update ahiac_MixFreq to what the mixing/sampling frequency really is
1114 moveq #0,d0 ;Default
1115 lea fakefreqVar(pc),a0
1116 bsr GetVarInt
1117 tst.l d0
1118 bne .skipfrequpdate
1119 move.l ahiac_MixFreq(a2),d0
1120 bsr calcperiod
1121 move.l d0,ahiac_MixFreq(a2) ;store actual freq
1122 .skipfrequpdate
1124 * Save the filter state
1125 btst #1,$bfe001
1126 seq p_Filter(a3)
1128 * Check the AHIpaulaFilterFreq variable.
1129 * If the mixing frequency is higher than this one, set disable the filter,
1130 * else enable it.
1131 moveq #0,d0 ;Default freq
1132 lea filterVar(pc),a0
1133 bsr GetVarInt
1134 cmp.l ahiac_MixFreq(a2),d0
1135 bls .no_filter
1136 bclr #1,$bfe001 ;turn audio filter on
1137 bra .filter_set
1138 .no_filter
1139 bset #1,$bfe001 ;turn audio filter off
1140 .filter_set
1142 btst.b #PB_DMA,p_Flags(a3)
1143 beq .mixing
1145 cmp.w #4,ahiac_Channels(a2)
1146 bhi .error_channels
1148 move.l pb_AudioFreq(a5),ahiac_MixFreq(a2) ;store actual freq
1150 move.l #AHIST_NOTYPE,p_Channels+channel_SIZEOF*0+ch_Type(a3)
1151 move.l #AHIST_NOTYPE,p_Channels+channel_SIZEOF*1+ch_Type(a3)
1152 move.l #AHIST_NOTYPE,p_Channels+channel_SIZEOF*2+ch_Type(a3)
1153 move.l #AHIST_NOTYPE,p_Channels+channel_SIZEOF*3+ch_Type(a3)
1154 move.l #AHIST_NOTYPE,p_Channels+channel_SIZEOF*0+ch_NextType(a3)
1155 move.l #AHIST_NOTYPE,p_Channels+channel_SIZEOF*1+ch_NextType(a3)
1156 move.l #AHIST_NOTYPE,p_Channels+channel_SIZEOF*2+ch_NextType(a3)
1157 move.l #AHIST_NOTYPE,p_Channels+channel_SIZEOF*3+ch_NextType(a3)
1158 move.w #0,p_Channels+channel_SIZEOF*0+ch_SndMsg+ahism_Channel(a3)
1159 move.w #1,p_Channels+channel_SIZEOF*1+ch_SndMsg+ahism_Channel(a3)
1160 move.w #2,p_Channels+channel_SIZEOF*2+ch_SndMsg+ahism_Channel(a3)
1161 move.w #3,p_Channels+channel_SIZEOF*3+ch_SndMsg+ahism_Channel(a3)
1163 move.l pb_SysLib(a5),a6
1164 move.w ahiac_Sounds(a2),d0
1165 mulu.w #sound_SIZEOF,d0
1166 move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
1167 call AllocVec
1168 move.l d0,p_Sounds(a3)
1169 beq .error_nosoundmem
1171 move.l d0,a0
1172 move.w ahiac_Sounds(a2),d0
1173 subq.w #1,d0
1174 .fillsounds
1175 move.l #AHIST_NOTYPE,so_Type(a0)
1176 add.w #sound_SIZEOF,a0
1177 dbf d0,.fillsounds
1179 tst.b p_SwapChannels(a3)
1180 bne .swapchannels
1181 move.l #custom+AUD1,p_Channels+channel_SIZEOF*0+ch_RegBase(a3)
1182 move.l #custom+AUD0,p_Channels+channel_SIZEOF*1+ch_RegBase(a3)
1183 move.l #custom+AUD2,p_Channels+channel_SIZEOF*2+ch_RegBase(a3)
1184 move.l #custom+AUD3,p_Channels+channel_SIZEOF*3+ch_RegBase(a3)
1185 move.w #DMAF_AUD1,p_Channels+channel_SIZEOF*0+ch_DMAMask(a3)
1186 move.w #DMAF_AUD0,p_Channels+channel_SIZEOF*1+ch_DMAMask(a3)
1187 move.w #DMAF_AUD2,p_Channels+channel_SIZEOF*2+ch_DMAMask(a3)
1188 move.w #DMAF_AUD3,p_Channels+channel_SIZEOF*3+ch_DMAMask(a3)
1189 move.w #INTF_AUD1,p_Channels+channel_SIZEOF*0+ch_IntMask(a3)
1190 move.w #INTF_AUD0,p_Channels+channel_SIZEOF*1+ch_IntMask(a3)
1191 move.w #INTF_AUD2,p_Channels+channel_SIZEOF*2+ch_IntMask(a3)
1192 move.w #INTF_AUD3,p_Channels+channel_SIZEOF*3+ch_IntMask(a3)
1193 move.w #0,p_Channels+channel_SIZEOF*0+ch_Stereo(a3)
1194 move.w #1,p_Channels+channel_SIZEOF*1+ch_Stereo(a3)
1195 move.w #1,p_Channels+channel_SIZEOF*2+ch_Stereo(a3)
1196 move.w #0,p_Channels+channel_SIZEOF*3+ch_Stereo(a3)
1197 bra .storedbase
1198 .swapchannels
1199 move.l #custom+AUD0,p_Channels+channel_SIZEOF*0+ch_RegBase(a3)
1200 move.l #custom+AUD1,p_Channels+channel_SIZEOF*1+ch_RegBase(a3)
1201 move.l #custom+AUD3,p_Channels+channel_SIZEOF*2+ch_RegBase(a3)
1202 move.l #custom+AUD2,p_Channels+channel_SIZEOF*3+ch_RegBase(a3)
1203 move.w #DMAF_AUD0,p_Channels+channel_SIZEOF*0+ch_DMAMask(a3)
1204 move.w #DMAF_AUD1,p_Channels+channel_SIZEOF*1+ch_DMAMask(a3)
1205 move.w #DMAF_AUD3,p_Channels+channel_SIZEOF*2+ch_DMAMask(a3)
1206 move.w #DMAF_AUD2,p_Channels+channel_SIZEOF*3+ch_DMAMask(a3)
1207 move.w #INTF_AUD0,p_Channels+channel_SIZEOF*0+ch_IntMask(a3)
1208 move.w #INTF_AUD1,p_Channels+channel_SIZEOF*1+ch_IntMask(a3)
1209 move.w #INTF_AUD3,p_Channels+channel_SIZEOF*2+ch_IntMask(a3)
1210 move.w #INTF_AUD2,p_Channels+channel_SIZEOF*3+ch_IntMask(a3)
1211 move.w #1,p_Channels+channel_SIZEOF*0+ch_Stereo(a3)
1212 move.w #0,p_Channels+channel_SIZEOF*1+ch_Stereo(a3)
1213 move.w #0,p_Channels+channel_SIZEOF*2+ch_Stereo(a3)
1214 move.w #1,p_Channels+channel_SIZEOF*3+ch_Stereo(a3)
1215 .storedbase
1218 moveq #0,d0
1219 bra .exit
1221 .mixing
1222 moveq #AHISF_KNOWSTEREO|AHISF_KNOWHIFI|AHISF_CANRECORD|AHISF_MIXING|AHISF_TIMING,d0
1224 .exit
1225 popm std
1228 .error_hwinuse
1229 .error_noaudiodev
1230 .error_noreqmem
1231 .error_noport
1232 .error_nopaula
1233 .error_channels
1234 .error_nosoundmem
1235 moveq #AHISF_ERROR,d0
1236 bra.b .exit
1238 .audiochannelarray
1239 dc.b 1+2+4+8
1240 .audioname
1241 AUDIONAME
1242 .calibname
1243 dc.b "ENV:CyberSound/SoundDrivers/14Bit_Calibration",0
1244 even
1245 .cardhandle:
1246 dc.l 0,0 ;ln_Succ, ln_Pred
1247 dc.b 0 ;ln_Type
1248 dc.b 0 ;ln_Pri
1249 dc.l IDString ;ln_Name
1250 dc.l 0,0,0 ;cah_CardRemoved, cah_CardInserted, cah_CardStatus
1251 dc.b (CARDF_RESETREMOVE|CARDF_IFAVAILABLE)
1252 even
1254 ;in:
1255 * d0 MixFreq
1256 * a5 paulaBase
1257 ;out:
1258 * d0 New MixFreq
1259 * d1.w Period
1260 ;description:
1261 * Calculate and return the best period and the actual frequency.
1262 calcperiod:
1263 PRINTF 2,"calcperiod()"
1264 pushm std
1265 move.l d0,d1
1266 move.l pb_AudioFreq(a5),d2
1267 move.l d2,d0
1268 move.l d1,d3
1269 move.l pb_UtilLib(a5),a1
1270 jsr _LVOUDivMod32(a1)
1271 lsl.l #1,d1
1272 cmp.l d3,d1
1273 bmi.b .3
1274 addq.l #1,d0
1276 move.w d0,d4
1277 * d4 is now period. Check if is it a valid one, depending on current display mode
1278 bsr checkvideo
1279 moveq #MINPER,d1
1280 tst.l d0
1281 bne .5
1282 moveq #MINPER*2,d1
1284 cmp.w d1,d4
1285 bhs.b .6
1286 move.w d1,d4
1288 moveq #0,d1
1289 move.w d4,d1
1290 move.l d2,d0
1291 move.l d1,d3
1292 move.l pb_UtilLib(a5),a1
1293 jsr _LVOUDivMod32(a1)
1294 lsl.l #1,d1
1295 cmp.l d3,d1
1296 bmi.b .4
1297 addq.l #1,d0
1299 move.w d4,d1
1300 popm std
1303 ;in:
1304 * a5 paulaBase
1305 ;out:
1306 * d0 TRUE if current mode is double
1307 ;description:
1308 * Checks if the current screen mode is doublescan.
1309 * This routine is a bit ugly, but it does get the job
1310 * done, even if a graphic card is used.
1311 checkvideo:
1312 PRINTF 2,"checkvideo"
1314 pushm std
1316 * Check the AHIpaulaSampleLimit variable.
1317 * If 1, allow > 28 kHz frequencies, if 0, don't. If not present,
1318 * check the screen mode.
1320 moveq #-1,d0
1321 lea screenVar(pc),a0
1322 bsr GetVarInt
1323 addq.l #1,d0 ; cmp.l #-1,d0
1324 beq .testfreq
1326 subq.l #1,d0 ; cmp.l #0,d0
1327 beq .no31k
1328 subq.l #1,d0 ; cmp.l #1,d0
1329 beq .is31k
1331 .testfreq
1333 ; Chip revision test
1335 move.l pb_GfxLib(a5),a0
1336 move.b gb_ChipRevBits0(a0),d0
1337 and.b #GFXF_HR_DENISE|GFXF_AA_LISA,d0
1338 beq .no31k ; OCS: No 31 kHz modes
1340 ; Native screen test
1342 moveq #0,d0
1343 move.l pb_IntuiLib(a5),a6
1344 call LockIBase
1345 move.l d0,d2
1346 move.l ib_FirstScreen(a6),a0
1347 lea sc_ViewPort(a0),a0
1348 move.l pb_GfxLib(a5),a6
1349 call GetVPModeID
1350 move.l d2,a0
1351 move.l d0,d2
1352 move.l pb_IntuiLib(a5),a6
1353 call UnlockIBase
1355 ; "Check" if native screen
1356 move.l d2,d0
1357 and.l #$40000000,d0
1358 bne .gfxcard
1360 ; It is!
1361 sub.w #mtr_SIZEOF,sp ;local storage
1362 suba.l a0,a0
1363 move.l sp,a1
1364 move.l #mtr_SIZEOF,d0
1365 move.l #DTAG_MNTR,d1
1366 move.l pb_GfxLib(a5),a6
1367 call GetDisplayInfoData
1369 moveq #1,d1
1370 add.w mtr_TotalRows(sp),d1
1371 sub.w mtr_MinRow(sp),d1
1372 move.w mtr_TotalColorClocks(sp),d2
1373 mulu.w mtr_TotalRows(sp),d2
1375 add.w #mtr_SIZEOF,sp ;restore stack
1376 tst.l d0
1377 beq .no31k
1378 ; Calculate TotalColorClocks*TotalRows/(2*(TotalRows-MinRow+1)
1379 add.l d1,d1
1380 beq .no31k
1381 divu d1,d2
1382 cmp.w #64,d2 ; 64 is an round nice number, no?
1383 bls .is31k
1384 bra .no31k
1386 .gfxcard
1388 ; Picasso '96 test
1390 move.l pb_SysLib(a5),a6
1391 lea .picasso96(pc),a1
1392 call Forbid ; Not required, it's just to...
1393 call FindTask
1394 call Permit ; ...make PatchWork happy.
1395 tst.l d0
1396 beq .cgfx ; Not P96, assume CyberGraphX
1398 move.l pb_DosLib(a5),a6
1399 clr.l -(sp) ;Initialize local data
1400 lea .p96amigavideo(pc),a0
1401 move.l a0,d1
1402 move.l sp,d2
1403 moveq #4,d3
1404 moveq #0,d4
1405 call GetVar
1406 move.l (sp)+,d1
1407 swap.w d1
1408 cmp.w #"31",d1
1409 beq .is31k
1410 bra .no31k
1412 .cgfx
1414 ; CybergraphX test
1416 move.l pb_GfxLib(a5),a0
1417 cmp.w #39,LIB_VERSION(a0)
1418 beq .known
1419 cmp.w #40,LIB_VERSION(a0)
1420 beq .known
1421 bra .no31k
1422 .known
1423 move.l gb_copinit(a0),a0
1424 cmp.w #$01FC,copinit_fm0(a0) ;Security check (test if really FMODE)
1425 bne .is31k ;Probably an ECS machine.
1426 ;Assume the user is clever enough
1427 ;to use "AddAudioModes DBLSCAN"....
1428 move.w copinit_fm0+2(a0),d0
1429 and.w #$c000,d0 ;Mask sprite and bitplane double bit
1430 beq .no31k
1431 .is31k
1432 moveq #TRUE,d0
1433 bra .exit
1434 .no31k
1435 moveq #FALSE,d0
1436 .exit
1437 popm std
1439 .picasso96
1440 dc.b "Picasso96",0
1441 .p96amigavideo
1442 dc.b "Picasso96/AmigaVideo",0
1443 even
1445 ;in:
1446 * d0 Frequency
1447 ;out:
1448 * d0 Closest frequency
1449 * d1 Index
1450 findfreq:
1451 lea freqlist(pc),a0
1452 cmp.l (a0),d0
1453 bls.b .2
1454 .findfreq
1455 cmp.l (a0)+,d0
1456 bhi.b .findfreq
1457 move.l -4(a0),d1
1458 sub.l d0,d1
1459 sub.l -8(a0),d0
1460 cmp.l d1,d0
1461 bhs.b .1
1462 subq.l #4,a0
1464 subq.l #4,a0
1466 move.l (a0),d0
1467 move.l a0,d1
1468 sub.l #freqlist,d1
1469 lsr.l #2,d1
1472 freqlist:
1473 dc.l 4410 ; CD/10
1474 dc.l 4800 ; DAT/10
1475 dc.l 5513 ; CD/8
1476 dc.l 6000 ; DAT/8
1477 dc.l 7350 ; CD/6
1478 dc.l 8000 ; µ- and A-Law, DAT/6
1479 dc.l 9600 ; DAT/5
1480 dc.l 11025 ; CD/4
1481 dc.l 12000 ; DAT/4
1482 dc.l 14700 ; CD/3
1483 dc.l 16000 ; DAT/3
1484 dc.l 17640 ; CD/2.5
1485 dc.l 18900
1486 dc.l 19200 ; DAT/2.5
1487 dc.l 22050 ; CD/2
1488 dc.l 24000 ; DAT/2
1489 dc.l 27429
1490 FREQUENCIES_OCS EQU (*-freqlist)>>2
1491 dc.l 29400 ; CD/1.5
1492 dc.l 32000 ; DAT/1.5
1493 dc.l 33075
1494 dc.l 37800
1495 dc.l 44100 ; CD
1496 dc.l 48000 ; DAT
1497 FREQUENCIES EQU (*-freqlist)>>2
1498 dc.l -1
1500 * _CreateTable directly stolen from Christian Buchner's CyberSound
1501 * audio sub system (with permission).
1503 * _CreateTable **************************************************************
1505 ; Parameters
1507 ; a0 = Table address
1508 ; (MUST have enough space for 65536 UWORDS)
1509 ; a1 = Additive Array
1510 ; 256 UBYTEs
1512 ; the table is organized as follows:
1513 ; 32768 UWORDS positive range, ascending order
1514 ; 32768 UWORDS negative range, ascending order
1515 ; access: (a0,d0.l*2)
1516 ; where d0.w is signed word sample data
1517 ; and the upper word of d0.l is *cleared!*
1520 _CreateTable movem.l a2/d2-d6,-(sp)
1522 lea 128(a1),a2
1524 move.l a2,a1 ; count the number of steps
1525 moveq #128-1,d0 ; in the positive range
1526 moveq #0,d5
1527 .countpositive move.b (a1)+,d1
1528 ext.w d1
1529 ext.l d1
1530 add.l d1,d5
1531 dbra d0,.countpositive ; d5=number of steps
1532 move.l #32768,d6 ; reset stretch counter
1534 move.l a2,a1 ; middle value in calibdata
1535 move.w #32768-1,d0 ; number of positive values -1
1536 moveq #0,d1 ; HI value
1537 moveq #0,d2 ; LO value
1538 moveq #0,d3 ; counter
1539 .fetchnext2 move.b (a1)+,d4 ; add calibtable to counter
1540 ext.w d4
1541 add.w d4,d3
1542 .outerloop2 tst.w d3
1543 bgt.s .positive2
1544 .negative2 addq.w #1,d1 ; increment HI value
1545 sub.w d4,d2 ; reset LO value
1546 bra.s .fetchnext2
1547 .positive2 move.b d1,(a0)+ ; store HI and LO value
1548 move.b d2,(a0)+
1549 sub.l d5,d6 ; stretch the table
1550 bpl.s .repeat2 ; to 32768 entries
1551 add.l #32768,d6
1552 addq.w #1,d2 ; increment LO value
1553 subq.w #1,d3 ; decrement counter
1554 .repeat2 dbra d0,.outerloop2
1556 move.l a2,a1 ; count the number of steps
1557 moveq #128-1,d0 ; in the negative range
1558 moveq #0,d5
1559 .countnegative move.b -(a1),d1
1560 ext.w d1
1561 ext.l d1
1562 add.l d1,d5
1563 dbra d0,.countnegative ; d5=number of steps
1564 move.l #32768,d6 ; reset stretch counter
1566 add.l #2*32768,a0 ; place at the end of the table
1567 move.l a2,a1 ; middle value in calibdata
1568 move.w #32768-1,d0 ; number of negative values -1
1569 moveq #-1,d1 ; HI value
1570 moveq #-1,d2 ; LO value
1571 moveq #0,d3 ; counter
1572 .fetchnext1 move.b -(a1),d4 ; add calibtable to counter
1573 ext.w d4
1574 add.w d4,d3
1575 add.w d4,d2 ; maximize LO value
1576 .outerloop1 tst.w d3
1577 bgt.s .positive1
1578 .negative1 subq.w #1,d1
1579 bra.s .fetchnext1
1580 .positive1 move.b d2,-(a0) ; store LO and HI value
1581 move.b d1,-(a0)
1582 sub.l d5,d6 ; stretch the table
1583 bpl.s .repeat1 ; to 32768 entries
1584 add.l #32768,d6
1585 subq.w #1,d2 ; decrement lo value
1586 subq.w #1,d3 ; decrement counter
1587 .repeat1 dbra d0,.outerloop1
1589 movem.l (sp)+,a2/d2-d6
1593 ****** [driver].audio/AHIsub_FreeAudio **************************************
1595 * NAME
1596 * AHIsub_FreeAudio -- Deallocates the audio hardware.
1598 * SYNOPSIS
1599 * AHIsub_FreeAudio( audioctrl );
1600 * A2
1602 * void AHIsub_FreeAudio( struct AHIAudioCtrlDrv * );
1604 * IMPLEMENTATION
1605 * Deallocate the audio hardware and other resources allocated in
1606 * AHIsub_AllocAudio(). AHIsub_Stop() will always be called by
1607 * 'ahi.device' before this call is made.
1609 * INPUTS
1610 * audioctrl - pointer to an AHIAudioCtrlDrv structure.
1612 * NOTES
1613 * It must be safe to call this routine even if AHIsub_AllocAudio()
1614 * was never called, failed or called more than once.
1616 * SEE ALSO
1617 * AHIsub_AllocAudio()
1619 *****************************************************************************
1623 AHIsub_FreeAudio:
1624 PRINTF 2,"AHIsub_FreeAudio()"
1625 pushm std
1627 move.l a6,a5
1628 move.l pb_SysLib(a5),a6
1630 move.l ahiac_DriverData(a2),d0
1631 beq .nopaula
1632 move.l d0,a3
1634 move.l p_Sounds(a3),d0
1635 beq.b .nosounds
1636 move.l d0,a1
1637 call FreeVec
1638 .nosounds
1640 move.l p_CalibrationTable(a3),d0
1641 beq.b .notable
1642 move.l d0,a1
1643 call FreeVec
1644 .notable
1646 tst.b p_Filter(a3)
1647 beq .no_filter
1648 bclr #1,$bfe001 ;turn audio filter on
1649 bra .filter_set
1650 .no_filter
1651 bset #1,$bfe001 ;turn audio filter off
1652 .filter_set
1655 tst.b p_audiodev(a3)
1656 bne.b .noaudiodev
1657 st p_audiodev(a3)
1658 move.l p_audioreq(a3),a1
1659 move.w #CMD_RESET,IO_COMMAND(a1) ;Restore audio interrupts
1660 bsr.w BeginIO
1661 move.l p_audioport(a3),a0
1662 call WaitPort
1663 move.l p_audioport(a3),a0
1664 call GetMsg
1665 move.l p_audioreq(a3),a1
1666 call CloseDevice
1667 .noaudiodev
1668 move.l p_audioreq(a3),d0
1669 beq.b .noaudioreq
1670 move.l d0,a1
1671 call FreeVec
1672 .noaudioreq
1673 move.l p_audioport(a3),d0
1674 beq.b .noaudioport
1675 move.l d0,a0
1676 call DeleteMsgPort
1677 .noaudioport
1679 call Forbid
1680 cmp.l pb_Lock(a5),a3
1681 bne .unlocked
1682 clr.l pb_Lock(a5)
1683 .unlocked
1684 call Permit
1686 tst.l p_AuraAddress(a3)
1687 beq .noaura
1688 move.l pb_CardResource(a5),d0
1689 beq .noaura
1690 move.l d0,a6
1691 move.l p_CardHandle(a3),d0
1692 beq .noaura
1693 move.l d0,a1
1694 call EndCardAccess
1695 move.l p_CardHandle(a3),a1
1696 moveq #CARDF_REMOVEHANDLE,d0
1697 call ReleaseCard
1698 .noaura
1699 move.l pb_SysLib(a5),a6
1700 move.l p_CardHandle(a3),d0
1701 beq .nocardhandle
1702 move.l d0,a1
1703 call FreeVec
1704 .nocardhandle
1705 move.l pb_MiscResource(a5),a6
1706 tst.l p_ParPortUser(a3)
1707 bne.b .noparport
1708 moveq #MR_PARALLELPORT,d0
1709 jsr MR_FREEMISCRESOURCE(a6)
1710 .noparport
1711 tst.l p_ParBitsUser(a3)
1712 bne.b .noparbits
1713 moveq #MR_PARALLELBITS,d0
1714 jsr MR_FREEMISCRESOURCE(a6)
1715 .noparbits
1716 tst.l p_SerBitsUser(a3)
1717 bne.b .noserbits
1718 moveq #MR_SERIALBITS,d0
1719 jsr MR_FREEMISCRESOURCE(a6)
1720 .noserbits
1721 move.l pb_SysLib(a5),a6
1722 move.l a3,a1
1723 clr.l ahiac_DriverData(a2)
1724 call FreeVec
1725 .nopaula
1726 ;moveq #0,d0 ; void function, no returncode needed
1727 popm std
1731 ****** [driver].audio/AHIsub_Disable ****************************************
1733 * NAME
1734 * AHIsub_Disable -- Temporary turn off audio interrupt/task
1736 * SYNOPSIS
1737 * AHIsub_Disable( audioctrl );
1738 * A2
1740 * void AHIsub_Disable( struct AHIAudioCtrlDrv * );
1742 * IMPLEMENTATION
1743 * If you are lazy, then call exec.library/Disable().
1744 * If you are smart, only disable your own interrupt or task.
1746 * INPUTS
1747 * audioctrl - pointer to an AHIAudioCtrlDrv structure.
1749 * NOTES
1750 * This call should be guaranteed to preserve all registers.
1751 * V6 drivers do NOT have to preserve all registers.
1752 * This call nests.
1754 * SEE ALSO
1755 * AHIsub_Enable(), exec.library/Disable()
1757 *****************************************************************************
1762 AHIsub_Disable:
1763 PRINTF 6,"AHIsub_Disable()"
1764 pushm a3/a6
1765 move.l ahiac_DriverData(a2),a3
1766 move.l p_PaulaBase(a3),a6
1767 move.l pb_SysLib(a6),a6
1768 call Disable
1769 move.w #INTF_AUDIO,custom+INTENA ; Turn off ALL audio interrupts
1770 addq.w #1,p_DisableCount(a3)
1771 ; PRINTF 0,"Disable: Wrote $%04lx to intena",#INTF_AUDIO
1772 ; PRINTF 0,"Count: %d",p_DisableCount(a3)
1773 call Enable
1774 popm a3/a6
1778 ****** [driver].audio/AHIsub_Enable *****************************************
1780 * NAME
1781 * AHIsub_Enable -- Turn on audio interrupt/task
1783 * SYNOPSIS
1784 * AHIsub_Enable( audioctrl );
1785 * A2
1787 * void AHIsub_Enable( struct AHIAudioCtrlDrv * );
1789 * IMPLEMENTATION
1790 * If you are lazy, then call exec.library/Enable().
1791 * If you are smart, only enable your own interrupt or task.
1793 * INPUTS
1794 * audioctrl - pointer to an AHIAudioCtrlDrv structure.
1796 * NOTES
1797 * This call should be guaranteed to preserve all registers.
1798 * V6 drivers do NOT have to preserve all registers.
1799 * This call nests.
1801 * SEE ALSO
1802 * AHIsub_Disable(), exec.library/Enable()
1804 *****************************************************************************
1809 AHIsub_Enable:
1810 PRINTF 6,"AHIsub_Enable()"
1811 pushm a3/a6
1812 move.l ahiac_DriverData(a2),a3
1813 move.l p_PaulaBase(a3),a6
1814 move.l pb_SysLib(a6),a6
1815 call Disable
1816 subq.w #1,p_DisableCount(a3)
1817 bne .exit
1818 move.w p_IRQMask(a3),custom+INTENA
1819 ; PRINTF 0,"Enable: Wrote $%04x to intena",p_IRQMask(a3)
1820 .exit
1821 ; PRINTF 0,"Count: %d",p_DisableCount(a3)
1822 call Enable
1823 popm a3/a6
1827 ****** [driver].audio/AHIsub_Start ******************************************
1829 * NAME
1830 * AHIsub_Start -- Starts playback or recording
1832 * SYNOPSIS
1833 * error = AHIsub_Start( flags, audioctrl );
1834 * D0 D0 A2
1836 * ULONG AHIsub_Start(ULONG, struct AHIAudioCtrlDrv * );
1838 * IMPLEMENTATION
1839 * What to do depends what you returned in AHIsub_AllocAudio().
1841 * * First, assume bit AHISB_PLAY in flags is set. This means that you
1842 * should begin playback.
1844 * - AHIsub_AllocAudio() returned AHISF_MIXING|AHISF_TIMING:
1846 * A) Allocate a mixing buffer of ahiac_BuffSize bytes. The buffer must
1847 * be long aligned!
1848 * B) Create/start an interrupt or task that will do 1-6 over and over
1849 * again until AHIsub_Stop() is called. Note that it is not a good
1850 * idea to do the actual mixing and conversion in a real hardware
1851 * interrupt. Signal a task or create a Software Interrupt to do
1852 * the number crunching.
1854 * 1) Call the user Hook ahiac_PlayerFunc with the following parameters:
1855 * A0 - (struct Hook *)
1856 * A2 - (struct AHIAudioCtrlDrv *)
1857 * A1 - Set to NULL.
1859 * 2) [Call the ahiac_PreTimer function. If it returns TRUE (Z will be
1860 * cleared so you don't have to test d0), skip step 3 and 4. This
1861 * is used to avoid overloading the CPU. This step is optional.
1862 * A2 is assumed to point to struct AHIAudioCtrlDrv. All registers
1863 * except d0 are preserved. (V4)
1865 * Starting with V6, you can also call the pre-timer Hook
1866 * (ahiac_PreTimerFunc) with the following parameters:
1867 * A0 - (struct Hook *) - The Hook itself
1868 * A2 - (struct AHIAudioCtrlDrv *)
1869 * A1 - Set to NULL.
1870 * The Hook is not guaranteed to preserve all registers and
1871 * you must check the return value and not rely on the Z flag. (V6)
1873 * This step, 2, is optional.]
1875 * 3) Call the mixing Hook (ahiac_MixerFunc) with the following
1876 * parameters:
1877 * A0 - (struct Hook *) - The Hook itself
1878 * A2 - (struct AHIAudioCtrlDrv *)
1879 * A1 - (WORD *[]) - The mixing buffer.
1880 * Note that ahiac_MixerFunc preserves ALL registers.
1881 * The user Hook ahiac_SoundFunc will be called by the mixing
1882 * routine when a sample have been processed, so you don't have to
1883 * worry about that.
1884 * How the buffer will be filled is indicated by ahiac_Flags.
1885 * It is always filled with signed 16-bit (32 bit if AHIACB_HIFI in
1886 * in ahiac_Flags is set) words, even if playback is 8 bit. If
1887 * AHIDBB_STEREO is set (in ahiac_Flags), data for left and right
1888 * channel are interleaved:
1889 * 1st sample left channel,
1890 * 1st sample right channel,
1891 * 2nd sample left channel,
1892 * ...,
1893 * ahiac_BuffSamples:th sample left channel,
1894 * ahiac_BuffSamples:th sample right channel.
1895 * If AHIDBB_STEREO is cleared, the mono data is stored:
1896 * 1st sample,
1897 * 2nd sample,
1898 * ...,
1899 * ahiac_BuffSamples:th sample.
1900 * Note that neither AHIACB_STEREO nor AHIACB_HIFI will be set if
1901 * you didn't report that you understand these flags when
1902 * AHI_AllocAudio() was called.
1904 * For AHI V2, the type of buffer is also available in ahiac_BuffType.
1905 * It is suggested that you use this value instead. ahiac_BuffType
1906 * can be one of AHIST_M16S, AHIST_S16S, AHIST_M32S and AHIST_S32S.
1908 * 4) Convert the buffer if needed and feed it to the audio hardware.
1909 * Note that you may have to clear CPU caches if you are using DMA
1910 * to play the buffer, and the buffer is not allocated in non-
1911 * cachable RAM (which is not a good idea anyway, for performace
1912 * reasons).
1914 * 5) [Call the ahiac_PostTimer function. A2 is assumed to point to
1915 * struct AHIAudioCtrlDrv. All registers are preserved. (V4)
1917 * Starting with V6, you can also call the post-timer Hook
1918 * (ahiac_PostTimerFunc) with the following parameters:
1919 * A0 - (struct Hook *) - The Hook itself
1920 * A2 - (struct AHIAudioCtrlDrv *)
1921 * A1 - Set to NULL.
1922 * The Hook is not guaranteed to preserve all registers. (V6)
1924 * This step, 5, is optional.]
1926 * 6) Wait until the whole buffer has been played, then repeat.
1928 * Use double buffering if possible!
1930 * You may DECREASE ahiac_BuffSamples slightly, for example to force an
1931 * even number of samples to be mixed. By doing this you will make
1932 * ahiac_PlayerFunc to be called at wrong frequency so be careful!
1933 * Even if ahiac_BuffSamples is defined ULONG, it will never be greater
1934 * than 65535.
1936 * ahiac_BuffSize is the largest size of the mixing buffer that will be
1937 * needed until AHIsub_Stop() is called.
1939 * ahiac_MaxBuffSamples is the maximum number of samples that will be
1940 * mixed (until AHIsub_Stop() is called). You can use this value if you
1941 * need to allocate DMA buffers.
1943 * ahiac_MinBuffSamples is the minimum number of samples that will be
1944 * mixed. Most drivers will ignore it.
1946 * If AHIsub_AllocAudio() returned with the AHISB_CANPOSTPROCESS bit set,
1947 * ahiac_BuffSize is large enough to hold two buffers. The mixing buffer
1948 * will be filled with the wet buffer first, immediately followed by the
1949 * dry buffer. I.e., ahiac_BuffSamples sample frames wet data, then
1950 * ahiac_BuffSamples sample frames dry data. The DSP fx should only be
1951 * applied to the wet buffer, and the two buffers should then be added
1952 * together. (V4)
1954 * - If AHIsub_AllocAudio() returned AHISF_MIXING, do as described above,
1955 * except calling ahiac_PlayerFunc. ahiac_PlayerFunc should be called
1956 * ahiac_PlayerFreq times per second, clocked by timers on your sound
1957 * card or by using 'timer.device' or 'realtime.library'. No other Amiga
1958 * resources may be used for timing (like direct CIA timers).
1959 * ahiac_MinBuffSamples and ahiac_MaxBuffSamples are undefined if
1960 * AHIsub_AllocAudio() returned AHISF_MIXING (AHISB_TIMING bit not set).
1962 * - If AHIsub_AllocAudio() returned with neither the AHISB_MIXING nor
1963 * the AHISB_TIMING bit set, then just start playback. Don't forget to
1964 * call ahiac_PlayerFunc ahiac_PlayerFreq times per second. Only your
1965 * own timing hardware, 'timer.device' or 'realtime.library' may be
1966 * used. Note that ahiac_MixerFunc, ahiac_BuffSamples,
1967 * ahiac_MinBuffSamples, ahiac_MaxBuffSamples and ahiac_BuffSize are
1968 * undefined. ahiac_MixFreq is the frequency the user wants to use for
1969 * recording, if you support that.
1971 * * Second, assume bit AHISB_RECORD in flags is set. This means that you
1972 * should start to sample. Create a interrupt or task that does the
1973 * following:
1975 * Allocate a buffer (you chose size, but try to keep it reasonable
1976 * small to avoid delays - it is suggested that RecordFunc is called
1977 * at least 4 times/second for the lowers sampling rate, and more often
1978 * for higher rates), and fill it with the sampled data. The buffer must
1979 * be long aligned, and it's size must be evenly divisible by four.
1980 * The format should always be AHIST_S16S (even with 8 bit mono samplers),
1981 * which means:
1982 * 1st sample left channel,
1983 * 1st sample right channel (same as prev. if mono),
1984 * 2nd sample left channel,
1985 * ... etc.
1986 * Each sample is a signed word (WORD). The sample rate should be equal
1987 * to the mixing rate.
1989 * Call the ahiac_SamplerFunc Hook with the following parameters:
1990 * A0 - (struct Hook *) - The Hook itself
1991 * A2 - (struct AHIAudioCtrlDrv *)
1992 * A1 - (struct AHIRecordMessage *)
1993 * The message should be filled as follows:
1994 * ahirm_Type - Set to AHIST_S16S.
1995 * ahirm_Buffer - A pointer to the filled buffer.
1996 * ahirm_Samples - How many sample frames stored.
1997 * You must not destroy the buffer until next time the Hook is called.
1999 * Repeat until AHIsub_Stop() is called.
2001 * * Note that both bits may be set when this function is called.
2003 * INPUTS
2004 * flags - See <libraries/ahi_sub.h>.
2005 * audioctrl - pointer to an AHIAudioCtrlDrv structure.
2007 * RESULT
2008 * Returns AHIE_OK if successful, else an error code as defined
2009 * in <devices/ahi.h>. AHIsub_Stop() will always be called, even
2010 * if this call failed.
2012 * NOTES
2013 * The driver must be able to handle multiple calls to this routine
2014 * without preceding calls to AHIsub_Stop().
2016 * SEE ALSO
2017 * AHIsub_Update(), AHIsub_Stop()
2019 *****************************************************************************
2024 AHIsub_Start:
2025 PRINTF 2,"AHIsub_Start()"
2027 pushm std
2029 move.l d0,d7
2030 lea custom,a4
2031 move.l ahiac_DriverData(a2),a3
2033 btst #AHISB_PLAY,d7
2034 beq .dont_play
2037 *** AHISB_PLAY
2039 moveq #AHISF_PLAY,d0
2040 call AHIsub_Stop ;Stop current playback if any.
2041 call AHIsub_Update ;fill variables
2043 move.l a6,a5
2044 move.l pb_SysLib(a5),a6
2046 btst #PB_DMA,p_Flags(a3)
2047 beq .no_dma
2048 bsr DMA_Start
2049 bra .exit
2050 .no_dma
2052 move.l ahiac_BuffSize(a2),d0
2053 add.l #EXTRABUFFSIZE,d0 ;Add space for 4 sample frames
2054 move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
2055 call AllocVec
2056 move.l d0,p_Mixbuffer(a3)
2057 beq .error_nomem
2059 move.l ahiac_MixFreq(a2),d0
2060 bsr.w calcperiod
2061 move.w d1,p_AudPer(a3)
2063 * The init*bit? routines allocates p_DMAbuffer, sets up
2064 * p_AudPtr, sets the volume, stores the correct interrupt routines in
2065 * p_PlayInt's and p_PlaySoftInt's IS_CODE.
2067 pea .1(pc)
2068 move.b p_Flags(a3),d0
2069 and.b #PF_STEREO|PF_14BIT,d0
2070 beq.w init8bitM
2071 cmp.b #PF_STEREO,d0
2072 beq.w init8bitS
2073 cmp.b #PF_14BIT,d0
2074 beq.w init14bitM
2075 bra.w init14bitS
2077 tst.l d0
2078 bne .exit
2080 * Create mixer task
2082 moveq #0,d0
2083 move.w p_MixTaskPri(a3),d0
2084 cmp.w #128,d0
2085 beq .nomixtask
2087 move.l sp,d2 ;Save sp
2088 move.l #TAG_DONE,-(sp)
2089 pea MixTask(pc)
2090 move.l #NP_Entry,-(sp)
2091 pea IDString(pc)
2092 move.l #NP_Name,-(sp)
2093 move.l d0,-(sp)
2094 move.l #NP_Priority,-(sp)
2095 move.l pb_SysLib(a5),a6
2096 call Forbid
2097 move.l sp,d1
2098 move.l pb_DosLib(a5),a6
2099 call CreateNewProc
2100 move.l d2,sp ;Restore sp
2101 move.l d0,p_MixTask(a3)
2102 beq .permit
2103 move.l d0,a0
2104 move.l a3,TC_Userdata(a0) ;Send struct as argument
2105 .permit
2106 move.l pb_SysLib(a5),a6
2107 call Permit
2109 ; If it worked, it worked. If not, softints will still be used.
2111 .nomixtask
2113 * Install play interrupt
2114 lea p_PlayInt(a3),a1
2115 moveq #INTB_AUD0,d0
2116 call SetIntVector
2118 or.w #INTF_SETCLR|INTF_AUD0,p_IRQMask(a3)
2120 call Disable
2121 tst.w p_DisableCount(a3)
2122 bne .dont_enable
2123 move.w #INTF_SETCLR|INTF_AUD0,INTENA(a4) ;enable
2124 .dont_enable
2125 move.w #INTF_SETCLR|INTF_AUD0,INTREQ(a4) ;start
2126 call Enable
2128 move.l a5,a6
2131 .dont_play
2132 btst #AHISB_RECORD,d7
2133 beq .dont_record
2135 *** AHISB_RECORD
2137 moveq #0,d0
2138 move.b p_Flags(a3),d0 ;Sanity check...
2139 and.b #PF_14BIT|PF_DMA,d0
2140 bne .error_unknown
2142 moveq #AHISF_RECORD,d0
2143 call AHIsub_Stop ;Stop current recording if any.
2145 move.l a6,a5
2146 move.l pb_SysLib(a5),a6
2148 move.l #RECORDSAMPLES*4,d0
2149 move.l #MEMF_PUBLIC,d1
2150 call AllocVec
2151 move.l d0,p_RecBuffer1(a3)
2152 beq .error_nomem
2154 move.l d0,p_RecFillPtr(a3)
2155 move.w #RECORDSAMPLES,p_RecFillCount(a3)
2157 move.l #RECORDSAMPLES*4,d0
2158 move.l #MEMF_PUBLIC,d1
2159 call AllocVec
2160 move.l d0,p_RecBuffer2(a3)
2161 beq .error_nomem
2163 move.l ahiac_MixFreq(a2),d0
2164 bsr.w calcperiod
2165 lsr.w #1,d1 ;Period/2 => Frequency·2
2166 move.w d1,AUD2PER(a4)
2167 move.w d1,AUD3PER(a4)
2168 move.w p_MonitorVolume(a3),d0
2169 move.w d0,AUD2VOL(a4)
2170 move.w d0,AUD3VOL(a4)
2172 * Install record interrupt
2173 move.w p_Input(a3),d0
2174 beq .parsampler
2175 cmp.w #1,d0
2176 beq .aurasampler
2177 cmp.w #2,d0
2178 beq .clarity
2179 bra .error_unknown
2181 .parsampler
2182 tst.b p_Parallel(a3) ;Parrallel port allocated?
2183 beq .error_unknown
2184 lea p_RecIntData(a3),a1
2185 move.l a1,IS_DATA+p_RecInt(a3)
2186 move.l #RecordInterrupt,IS_CODE+p_RecInt(a3)
2188 move.b #$ff,_ciab+ciaddrb ; Set parallel port to output
2190 bra .setrecint
2192 .clarity
2193 tst.b p_Parallel(a3) ;Parrallel port allocated?
2194 beq .error_unknown
2196 move.l pb_MiscResource(a5),a6
2197 move.l #MR_SERIALBITS,d0 ; allocate serial port control lines
2198 lea IDString(pc),a1
2199 jsr MR_ALLOCMISCRESOURCE(a6)
2200 move.l d0,p_SerBitsUser(a3)
2201 bne .error_unknown
2203 lea p_RecIntData(a3),a1
2204 move.l a1,IS_DATA+p_RecInt(a3)
2205 move.l #RecordInterruptClarity,IS_CODE+p_RecInt(a3)
2207 ; Set DTR, PRTBUSY and PRTRPOUT to outputs
2208 or.b #CIAF_COMDTR!CIAF_PRTRBUSY!CIAF_PRTRPOUT,_ciab+ciaddra
2209 move.b #$ff,_ciab+ciaddrb ; Set parallel port to output
2210 ; Reset Clarity
2211 move.b #CIAF_PRTRBUSY!CIAF_PRTRPOUT,_ciab+ciapra
2212 move.b #CIAF_PRTRPOUT,_ciab+ciapra
2213 move.b #CIAF_PRTRBUSY!CIAF_PRTRPOUT,_ciab+ciapra
2214 ; Clarity is now in stereo record mode
2216 bra .setrecint
2218 .aurasampler
2219 tst.l p_AuraAddress(a3) ;Aura sampler allocated?
2220 beq .error_unknown
2221 lea p_RecIntDataAura(a3),a1
2222 move.l a1,IS_DATA+p_RecInt(a3)
2223 move.l #RecordInterruptAura,IS_CODE+p_RecInt(a3)
2224 bra .setrecint
2226 .setrecint
2227 move.l pb_SysLib(a5),a6
2228 lea p_RecInt(a3),a1
2229 moveq #INTB_AUD3,d0
2230 call SetIntVector
2232 move.w #DMAF_AUD2|DMAF_AUD3,DMACON(a4) ;disable DMA
2233 or.w #INTF_SETCLR|INTF_AUD3,p_IRQMask(a3)
2234 move.w #INTF_SETCLR|INTF_AUD3,INTENA(a4) ;enable
2235 move.w #INTF_SETCLR|INTF_AUD3,INTREQ(a4) ;start
2237 .dont_record
2238 .return
2239 moveq #AHIE_OK,d0
2240 .exit
2241 popm std
2243 .error_nomem
2244 moveq #AHIE_NOMEM,d0
2245 bra.b .exit
2246 .error_unknown
2247 moveq #AHIE_UNKNOWN,d0
2248 bra.b .exit
2251 ;in:
2252 * a2 AudioCtrl
2253 * a3 paula
2254 * a4 custom
2255 * a5 paulaBase
2256 * a6 ExecBase
2257 init8bitM:
2258 PRINTF 2,"init8bitM()"
2259 move.l #AudioInterrupt2,IS_CODE+p_PlayInt(a3)
2260 move.l #SoftInt_8bitM,IS_CODE+p_PlaySoftInt(a3)
2261 IFEQ BETTERTIMING-1
2262 move.l #1,p_SampleFrameShift(a3) ;log2( sizeof( AHIST_M16S ) )
2263 ENDC
2264 move.b p_Flags(a3),d0
2265 btst #PB_HIFI,d0
2266 beq .nohifi
2267 move.l #SoftInt_8bitMH,IS_CODE+p_PlaySoftInt(a3)
2268 IFEQ BETTERTIMING-1
2269 move.l #2,p_SampleFrameShift(a3) ;log2( sizeof( AHIST_M32S ) )
2270 ENDC
2271 .nohifi
2273 move.l p_MinBufferLength(a3),d0
2274 add.l ahiac_MaxBuffSamples(a2),d0 ;Max. # of 8 bit samples
2275 addq.l #EXTRASAMPLES,d0
2276 addq.l #3,d0
2277 and.b #~3,d0 ;make it a multiple of 4
2278 move.l d0,d2 ;d2 = channel size
2280 lsl.l #1,d0 ;Double buffer
2281 move.l #MEMF_CHIP|MEMF_PUBLIC|MEMF_CLEAR,d1
2282 call AllocVec
2283 move.l d0,p_DMAbuffer(a3)
2284 beq .nomem
2286 move.l d0,p_AudPtr1A(a3)
2287 move.l d0,p_AudPtr2A(a3)
2288 add.l d2,d0
2289 move.l d0,p_AudPtr1B(a3)
2290 move.l d0,p_AudPtr2B(a3)
2292 ; move.w #64,AUD0VOL(a4)
2293 ; move.w #64,AUD1VOL(a4)
2295 moveq #0,d0
2297 .nomem
2298 moveq #AHIE_NOMEM,d0
2301 ;in:
2302 * a2 AudioCtrl
2303 * a3 paula
2304 * a5 paulaBase
2305 * a6 ExecBase
2306 init8bitS:
2307 PRINTF 2,"init8bitS()"
2308 move.l #AudioInterrupt2,IS_CODE+p_PlayInt(a3)
2309 move.l #SoftInt_8bitS,IS_CODE+p_PlaySoftInt(a3)
2310 IFEQ BETTERTIMING-1
2311 move.l #2,p_SampleFrameShift(a3) ;log2( sizeof( AHIST_S16S ) )
2312 ENDC
2313 move.b p_Flags(a3),d0
2314 btst #PB_HIFI,d0
2315 beq .nohifi
2316 move.l #SoftInt_8bitSH,IS_CODE+p_PlaySoftInt(a3)
2317 IFEQ BETTERTIMING-1
2318 move.l #3,p_SampleFrameShift(a3) ;log2( sizeof( AHIST_S32S ) )
2319 ENDC
2320 .nohifi
2322 move.l p_MinBufferLength(a3),d0
2323 add.l ahiac_MaxBuffSamples(a2),d0 ;Max. # of 8 bit samples
2324 addq.l #EXTRASAMPLES,d0
2325 addq.l #3,d0
2326 and.b #~3,d0 ;make it a multiple of 4
2327 move.l d0,d2 ;d2 = channel size
2329 lsl.l #2,d0 ;Double buffer + Stereo
2330 move.l #MEMF_CHIP|MEMF_PUBLIC|MEMF_CLEAR,d1
2331 call AllocVec
2332 move.l d0,p_DMAbuffer(a3)
2333 beq .nomem
2335 move.l d0,p_AudPtr1A(a3)
2336 add.l d2,d0
2337 move.l d0,p_AudPtr2A(a3)
2338 add.l d2,d0
2339 move.l d0,p_AudPtr1B(a3)
2340 add.l d2,d0
2341 move.l d0,p_AudPtr2B(a3)
2343 ; move.w #64,AUD0VOL(a4)
2344 ; move.w #64,AUD1VOL(a4)
2346 moveq #0,d0
2348 .nomem
2349 moveq #AHIE_NOMEM,d0
2352 ;in:
2353 * a2 AudioCtrl
2354 * a3 paula
2355 * a5 paulaBase
2356 * a6 ExecBase
2357 init14bitM:
2358 PRINTF 2,"init14bitM()"
2359 move.l #AudioInterrupt4,IS_CODE+p_PlayInt(a3)
2360 lea SoftInt_14bitM(pc),a0
2361 IFEQ BETTERTIMING-1
2362 move.l #1,p_SampleFrameShift(a3) ;log2( sizeof( AHIST_M16S ) )
2363 ENDC
2364 move.b p_Flags(a3),d0
2365 btst #PB_HIFI,d0
2366 beq .nohifi1
2367 lea SoftInt_14bitMH(pc),a0
2368 IFEQ BETTERTIMING-1
2369 move.l #2,p_SampleFrameShift(a3) ;log2( sizeof( AHIST_M32S ) )
2370 ENDC
2371 .nohifi1
2372 tst.l p_CalibrationTable(a3)
2373 beq.b .nocalib
2374 lea SoftInt_14CbitM(pc),a0
2375 move.b p_Flags(a3),d0
2376 btst #PB_HIFI,d0
2377 beq .nohifi2
2378 lea SoftInt_14CbitMH(pc),a0
2379 .nohifi2
2380 .nocalib
2381 move.l a0,IS_CODE+p_PlaySoftInt(a3)
2383 move.l p_MinBufferLength(a3),d0
2384 add.l ahiac_MaxBuffSamples(a2),d0 ;Max. # of 16 bit samples
2385 addq.l #EXTRASAMPLES,d0
2386 addq.l #3,d0
2387 and.b #~3,d0 ;make it a multiple of 4
2388 move.l d0,d2 ;d2 = channel size
2390 lsl.l #2,d0 ;Double buffer + 2×8 bit
2391 move.l #MEMF_CHIP|MEMF_PUBLIC|MEMF_CLEAR,d1
2392 call AllocVec
2393 move.l d0,p_DMAbuffer(a3)
2394 beq .nomem
2396 move.l d0,p_AudPtr1A(a3)
2397 move.l d0,p_AudPtr2A(a3)
2398 add.l d2,d0
2399 move.l d0,p_AudPtr4A(a3)
2400 move.l d0,p_AudPtr3A(a3)
2401 add.l d2,d0
2402 move.l d0,p_AudPtr1B(a3)
2403 move.l d0,p_AudPtr2B(a3)
2404 add.l d2,d0
2405 move.l d0,p_AudPtr4B(a3)
2406 move.l d0,p_AudPtr3B(a3)
2408 ; move.w #64,AUD0VOL(a4)
2409 ; move.w #64,AUD1VOL(a4)
2410 ; move.w #1,AUD2VOL(a4)
2411 ; move.w #1,AUD3VOL(a4)
2413 moveq #0,d0
2415 .nomem
2416 moveq #AHIE_NOMEM,d0
2419 ;in:
2420 * a2 AudioCtrl
2421 * a3 paula
2422 * a5 paulaBase
2423 * a6 ExecBase
2424 init14bitS:
2425 PRINTF 2,"init14bitS()"
2426 move.l #AudioInterrupt4,IS_CODE+p_PlayInt(a3)
2427 lea SoftInt_14bitS(pc),a0
2428 IFEQ BETTERTIMING-1
2429 move.l #2,p_SampleFrameShift(a3) ;log2( sizeof( AHIST_S16S ) )
2430 ENDC
2431 move.b p_Flags(a3),d0
2432 btst #PB_HIFI,d0
2433 beq .nohifi1
2434 lea SoftInt_14bitSH(pc),a0
2435 IFEQ BETTERTIMING-1
2436 move.l #3,p_SampleFrameShift(a3) ;log2( sizeof( AHIST_S32S ) )
2437 ENDC
2438 .nohifi1
2439 tst.l p_CalibrationTable(a3)
2440 beq.b .nocalib
2441 lea SoftInt_14CbitS(pc),a0
2442 move.b p_Flags(a3),d0
2443 btst #PB_HIFI,d0
2444 beq .nohifi2
2445 lea SoftInt_14CbitSH(pc),a0
2446 .nohifi2
2447 .nocalib
2448 move.l a0,IS_CODE+p_PlaySoftInt(a3)
2450 move.l p_MinBufferLength(a3),d0
2451 add.l ahiac_MaxBuffSamples(a2),d0 ;Max. # of 16 bit samples
2452 addq.l #EXTRASAMPLES,d0
2453 addq.l #3,d0
2454 and.b #~3,d0 ;make it a multiple of 4
2455 move.l d0,d2 ;d2 = channel size
2457 lsl.l #3,d0 ;Double buffer + 2×8 bit + Stereo
2458 move.l #MEMF_CHIP|MEMF_PUBLIC|MEMF_CLEAR,d1
2459 call AllocVec
2460 move.l d0,p_DMAbuffer(a3)
2461 beq .nomem
2463 move.l d0,p_AudPtr1A(a3)
2464 add.l d2,d0
2465 move.l d0,p_AudPtr2A(a3)
2466 add.l d2,d0
2467 move.l d0,p_AudPtr3A(a3)
2468 add.l d2,d0
2469 move.l d0,p_AudPtr4A(a3)
2470 add.l d2,d0
2471 move.l d0,p_AudPtr1B(a3)
2472 add.l d2,d0
2473 move.l d0,p_AudPtr2B(a3)
2474 add.l d2,d0
2475 move.l d0,p_AudPtr3B(a3)
2476 add.l d2,d0
2477 move.l d0,p_AudPtr4B(a3)
2479 ; move.w #64,AUD0VOL(a4)
2480 ; move.w #64,AUD1VOL(a4)
2481 ; move.w #1,AUD2VOL(a4)
2482 ; move.w #1,AUD3VOL(a4)
2484 moveq #0,d0
2486 .nomem
2487 moveq #AHIE_NOMEM,d0
2491 ****** [driver].audio/AHIsub_Update *****************************************
2493 * NAME
2494 * AHIsub_Update -- Update some variables
2496 * SYNOPSIS
2497 * AHIsub_Update( flags, audioctrl );
2498 * D0 A2
2500 * void AHIsub_Update(ULONG, struct AHIAudioCtrlDrv * );
2502 * IMPLEMENTATION
2503 * All you have to do is to reread some variables:
2505 * * Mixing & timing: ahiac_PlayerFunc, ahiac_MixerFunc, ahiac_SamplerFunc,
2506 * ahiac_BuffSamples (and perhaps ahiac_PlayerFreq if you use it).
2508 * * Mixing only: ahiac_PlayerFunc, ahiac_MixerFunc, ahiac_SamplerFunc and
2509 * ahiac_PlayerFreq.
2511 * * Nothing: ahiac_PlayerFunc, ahiac_SamplerFunc and ahiac_PlayerFreq.
2513 * INPUTS
2514 * flags - Currently no flags defined.
2515 * audioctrl - pointer to an AHIAudioCtrlDrv structure.
2517 * RESULT
2519 * NOTES
2520 * This call must be safe from interrupts.
2522 * SEE ALSO
2523 * AHIsub_Start()
2525 *****************************************************************************
2530 AHIsub_Update:
2531 PRINTF 2,"AHIsub_Update()"
2532 pushm std
2534 call AHIsub_Disable ;make sure we don't get an interrupt
2535 ;while updating our local variables
2536 move.l ahiac_DriverData(a2),a3
2538 move.l ahiac_PlayerFunc(a2),a0
2539 move.l a0,p_PlayerHook(a3)
2540 move.l h_Entry(a0),p_PlayerEntry(a3)
2542 btst #PB_DMA,p_Flags(a3)
2543 beq .no_dma
2544 bsr DMA_Update
2545 bra .exit
2547 .no_dma
2548 IFEQ BETTERTIMING-0
2549 move.l ahiac_BuffSamples(a2),d1
2550 and.b #~3,d1 ;make it a multiple of 4
2551 move.l d1,ahiac_BuffSamples(a2)
2552 move.l d1,d0
2553 lsr.l #2,d0
2554 subq.l #1,d0
2555 move.l d0,p_LoopTimes(a3) ;See softints. (Unrolled)
2556 ENDC
2558 PRINTF 4, "ahiac_BuffSamples is %ld", ahiac_BuffSamples(a2)
2560 move.l ahiac_MixerFunc(a2),a0
2561 move.l a0,p_MixHook(a3)
2562 move.l h_Entry(a0),p_MixEntry(a3)
2564 .exit
2565 call AHIsub_Enable
2566 ;moveq #0,d0 ; void function, no returncode needed
2567 popm std
2571 ****** [driver].audio/AHIsub_Stop *******************************************
2573 * NAME
2574 * AHIsub_Stop -- Stops playback.
2576 * SYNOPSIS
2577 * AHIsub_Stop( flags, audioctrl );
2578 * D0 A2
2580 * void AHIsub_Stop( ULONG, struct AHIAudioCtrlDrv * );
2582 * IMPLEMENTATION
2583 * Stop playback and/or recording, remove all resources allocated by
2584 * AHIsub_Start().
2586 * INPUTS
2587 * flags - See <libraries/ahi_sub.h>.
2588 * audioctrl - pointer to an AHIAudioCtrlDrv structure.
2590 * NOTES
2591 * It must be safe to call this routine even if AHIsub_Start() was never
2592 * called, failed or called more than once.
2594 * SEE ALSO
2595 * AHIsub_Start()
2597 *****************************************************************************
2601 AHIsub_Stop:
2602 PRINTF 2,"AHIsub_Stop()"
2603 pushm std
2605 lea custom,a4
2606 move.l a6,a5
2607 move.l pb_SysLib(a5),a6
2608 move.l ahiac_DriverData(a2),a3
2610 push d0
2611 btst #AHISB_PLAY,d0
2612 beq .dontplay
2615 *** AHISB_PLAY
2618 btst #PB_DMA,p_Flags(a3)
2619 beq .no_dma
2620 bsr DMA_Stop
2621 bra .playchecked
2622 .no_dma
2624 move.w #DMAF_AUDIO,DMACON(a4) ;disable audio DMA
2626 and.w #~INTF_AUD0,p_IRQMask(a3)
2627 move.w #INTF_AUD0,INTENA(a4)
2628 move.w #INTF_AUD0,INTREQ(a4) ;Clear any waiting interrupts
2629 move.l #Interrupt_Dummy,IS_CODE+p_PlayInt(a3)
2630 lea p_PlayInt(a3),a1
2631 moveq #INTB_AUD0,d0
2632 call SetIntVector
2634 moveq #0,d0
2635 move.w d0,AUD0VOL(a4)
2636 move.w d0,AUD1VOL(a4)
2637 move.w d0,AUD2VOL(a4)
2638 move.w d0,AUD3VOL(a4)
2640 * Remove mixer task
2641 tst.l p_MixTask(a3)
2642 beq .nomixtask
2643 suba.l a1,a1
2644 call FindTask
2645 move.l d0,p_ReplyTask(a3)
2646 moveq #0,d0
2647 move.l #SIGF_SINGLE,d1 ;Clear SINGLE signal
2648 call SetSignal
2649 move.l p_MixTask(a3),a1
2650 move.l #SIGBREAKF_CTRL_C,d0 ;Kill child
2651 call Signal
2652 move.l #SIGF_SINGLE,d0
2653 call Wait ;Wait until child is dead
2654 .nomixtask
2656 move.l p_DMAbuffer(a3),d0
2657 beq.b .nodmamem
2658 move.l d0,a1
2659 clr.l p_DMAbuffer(a3)
2660 call FreeVec
2661 .nodmamem
2662 move.l p_Mixbuffer(a3),d0
2663 beq.b .nomixmem
2664 move.l d0,a1
2665 clr.l p_Mixbuffer(a3)
2666 call FreeVec
2667 .nomixmem
2668 .playchecked
2670 .dontplay
2671 pop d0
2672 btst #AHISB_RECORD,d0
2673 beq .dontrecord
2676 *** AHISB_RECORD
2678 btst #PB_14BIT,p_Flags(a3) ;Sanity check...
2679 bne .dontrecord
2681 and.w #~INTF_AUD3,p_IRQMask(a3)
2682 move.w #INTF_AUD3,INTENA(a4)
2683 move.w #INTF_AUD3,INTREQ(a4) ;Clear any waiting interrupts
2685 move.l #Interrupt_Dummy,IS_CODE+p_RecInt(a3)
2686 lea p_RecInt(a3),a1
2687 moveq #INTB_AUD3,d0
2688 call SetIntVector
2690 move.w #0,AUD2VOL(a4)
2691 move.w #0,AUD3VOL(a4)
2693 move.l p_RecBuffer1(a3),d0
2694 beq.b .norecmem1
2695 move.l d0,a1
2696 clr.l p_RecBuffer1(a3)
2697 call FreeVec
2698 .norecmem1
2699 move.l p_RecBuffer2(a3),d0
2700 beq.b .norecmem2
2701 move.l d0,a1
2702 clr.l p_RecBuffer2(a3)
2703 call FreeVec
2704 .norecmem2
2705 .dontrecord
2706 .exit
2707 ;moveq #0,d0 ; void function, no returncode needed
2708 popm std
2712 ****** [driver].audio/AHIsub_GetAttr ****************************************
2714 * NAME
2715 * AHIsub_GetAttr -- Returns information about audio modes or driver
2717 * SYNOPSIS
2718 * AHIsub_GetAttr( attribute, argument, default, taglist, audioctrl );
2719 * D0 D0 D1 D2 A1 A2
2721 * LONG AHIsub_GetAttr( ULONG, LONG, LONG, struct TagItem *,
2722 * struct AHIAudioCtrlDrv * );
2724 * IMPLEMENTATION
2725 * Return the attribute based on a tag list and an AHIAudioCtrlDrv
2726 * structure, which are the same that will be passed to
2727 * AHIsub_AllocAudio() by 'ahi.device'. If the attribute is
2728 * unknown to you, return the default.
2730 * INPUTS
2731 * attribute - Is really a Tag and can be one of the following:
2733 * AHIDB_Bits - Return how many output bits the tag list will
2734 * result in.
2736 * AHIDB_MaxChannels - Return the maximum number of channels.
2738 * AHIDB_Frequencies - Return how many mixing/sampling frequencies
2739 * you support
2741 * AHIDB_Frequency - Return the argument:th frequency
2742 * Example: You support 3 frequencies; 32, 44.1 and 48 kHz.
2743 * If argument is 1, return 44100.
2745 * AHIDB_Index - Return the index which gives the frequency closest
2746 * to argument.
2747 * Example: You support 3 frequencies; 32, 44.1 and 48 kHz.
2748 * If argument is 40000, return 1 (=> 44100).
2750 * AHIDB_Author - Return pointer to name of driver author:
2751 * "Martin 'Leviticus' Blom"
2753 * AHIDB_Copyright - Return pointer to copyright notice, including
2754 * the '©' character: "© 1996 Martin Blom" or "Public Domain"
2756 * AHIDB_Version - Return pointer version string, normal Amiga
2757 * format: "paula 1.5 (18.2.96)\r\n"
2759 * AHIDB_Annotation - Return pointer to an annotation string, which
2760 * can be several lines.
2762 * AHIDB_Record - Are you a sampler, too? Return TRUE or FALSE.
2764 * AHIDB_FullDuplex - Return TRUE or FALSE.
2766 * AHIDB_Realtime - Return TRUE or FALSE.
2768 * AHIDB_MaxPlaySamples - Normally, return the default. See
2769 * AHIsub_AllocAudio(), section 2.
2771 * AHIDB_MaxRecordSamples - Return the size of the buffer you fill
2772 * when recording.
2774 * The following are associated with AHIsub_HardwareControl() and are
2775 * new for V2.
2777 * AHIDB_MinMonitorVolume
2778 * AHIDB_MaxMonitorVolume - Return the lower/upper limit for
2779 * AHIC_MonitorVolume. If unsupported but always 1.0, return
2780 * 1.0 for both.
2782 * AHIDB_MinInputGain
2783 * AHIDB_MaxInputGain - Return the lower/upper limit for
2784 * AHIC_InputGain. If unsupported but always 1.0, return 1.0 for
2785 * both.
2787 * AHIDB_MinOutputVolume
2788 * AHIDB_MaxOutputVolume - Return the lower/upper limit for
2789 * AHIC_OutputVolume.
2791 * AHIDB_Inputs - Return how many inputs you have.
2792 * AHIDB_Input - Return a short string describing the argument:th
2793 * input. Number 0 should be the default one. Example strings
2794 * can be "Line 1", "Mic", "Optical" or whatever.
2796 * AHIDB_Outputs - Return how many outputs you have.
2797 * AHIDB_Output - Return a short string describing the argument:th
2798 * output. Number 0 should be the default one. Example strings
2799 * can be "Line 1", "Headphone", "Optical" or whatever.
2801 * argument - extra info for some attributes.
2802 * default - What you should return for unknown attributes.
2803 * taglist - Pointer to a tag list that eventually will be fed to
2804 * AHIsub_AllocAudio(), or NULL.
2805 * audioctrl - Pointer to an AHIAudioCtrlDrv structure that eventually
2806 * will be fed to AHIsub_AllocAudio(), or NULL.
2808 * NOTES
2810 * SEE ALSO
2811 * AHIsub_AllocAudio(), AHIsub_HardwareControl(),
2812 * ahi.device/AHI_GetAudioAttrsA()
2814 *****************************************************************************
2818 AHIsub_GetAttr:
2819 PRINTF 2,"AHIsub_GetAttr()"
2820 pushm std
2821 move.l a1,a3
2822 move.l a6,a5
2823 move.l pb_UtilLib(a5),a6
2826 moveq #FALSE,d3 ; 14 bit flag
2827 moveq #FALSE,d4 ; DMA flag
2829 pushm d0-d1
2831 move.l a3,a0
2832 move.l a3,d0
2833 beq .notaglist
2835 move.l #AHIDB_Paula14Bit,d0
2836 move.l d3,d1
2837 call GetTagData
2838 move.l d0,d3
2840 move.l a3,a0
2841 move.l #AHIDB_PaulaDMA,d0
2842 move.l d4,d1
2843 call GetTagData
2844 move.l d0,d4
2846 .notaglist
2848 popm d0-d1
2850 and.l #~(AHI_TagBaseR),d0
2851 cmp.l #AHIDB_Data & ~(AHI_TagBaseR),d0
2852 bhi .default
2853 sub.w #100,d0
2854 lsl.w #1,d0
2855 move.w .jt(pc,d0.w),d0
2856 beq .default
2857 jsr .jt(pc,d0.w)
2859 .exit
2860 popm std
2863 .default
2864 move.l d2,d0
2865 bra .exit
2868 dc.w 0 ; AHIDB_AudioID
2869 dc.w 0 ; AHIDB_Driver
2870 dc.w 0 ; AHIDB_Flags
2871 dc.w ga_Volume-.jt ; AHIDB_Volume
2872 dc.w ga_Panning-.jt ; AHIDB_Panning
2873 dc.w ga_Stereo-.jt ; AHIDB_Stereo
2874 dc.w ga_HiFi-.jt ; AHIDB_HiFi
2875 dc.w ga_PingPong-.jt ; AHIDB_PingPong
2876 dc.w 0 ; AHIDB_MultTable
2877 dc.w 0 ; AHIDB_Name
2878 dc.w ga_Bits-.jt ; AHIDB_Bits
2879 dc.w ga_MaxChannels-.jt ; AHIDB_MaxChannels
2880 dc.w 0 ; AHIDB_MinMixFreq
2881 dc.w 0 ; AHIDB_MaxMixFreq
2882 dc.w ga_Record-.jt ; AHIDB_Record
2883 dc.w ga_Frequencies-.jt ; AHIDB_Frequencies
2884 dc.w 0 ; AHIDB_FrequencyArg
2885 dc.w ga_Frequency-.jt ; AHIDB_Frequency
2886 dc.w ga_Author-.jt ; AHIDB_Author
2887 dc.w ga_Copyright-.jt ; AHIDB_Copyright
2888 dc.w ga_Version-.jt ; AHIDB_Version
2889 dc.w ga_Annotation-.jt ; AHIDB_Annotation
2890 dc.w 0 ; AHIDB_BufferLen
2891 dc.w 0 ; AHIDB_IndexArg
2892 dc.w ga_Index-.jt ; AHIDB_Index
2893 dc.w ga_Realtime-.jt ; AHIDB_Realtime
2894 dc.w 0 ; AHIDB_MaxPlaySamples
2895 dc.w ga_MaxRecordSamples-.jt ; AHIDB_MaxRecordSample
2896 dc.w 0 ;
2897 dc.w ga_FullDuplex-.jt ; AHIDB_FullDuplex
2898 dc.w ga_MinMonitorVolume-.jt ; AHIDB_MinMonitorVolum
2899 dc.w ga_MaxMonitorVolume-.jt ; AHIDB_MaxMonitorVolum
2900 dc.w ga_MinInputGain-.jt ; AHIDB_MinInputGain
2901 dc.w ga_MaxInputGain-.jt ; AHIDB_MaxInputGain
2902 dc.w ga_MinOutputVolume-.jt ; AHIDB_MinOutputVolume
2903 dc.w ga_MaxOutputVolume-.jt ; AHIDB_MaxOutputVolume
2904 dc.w ga_Inputs-.jt ; AHIDB_Inputs
2905 dc.w 0 ; AHIDB_InputArg
2906 dc.w ga_Input-.jt ; AHIDB_Input
2907 dc.w ga_Outputs-.jt ; AHIDB_Outputs
2908 dc.w 0 ; AHIDB_OutputArg
2909 dc.w ga_Output-.jt ; AHIDB_Output
2910 dc.w 0 ; AHIDB_Data
2913 *** The tags AHIDB_Volume, AHIDB_Panning, AHIDB_Stereo and AHIDB_HiFi are
2914 *** parameters to the mixing routine when mixing, but attributes in DMA mode.
2916 ga_Volume:
2917 move.l d2,d0
2918 tst.l d4
2919 beq .exit
2920 moveq #TRUE,d0
2921 .exit
2924 ga_Panning:
2925 move.l d2,d0
2926 tst.l d4
2927 beq .exit
2928 moveq #FALSE,d0
2929 .exit
2932 ga_Stereo:
2933 move.l d2,d0
2934 tst.l d4
2935 beq .exit
2936 moveq #TRUE,d0
2937 .exit
2940 ga_HiFi:
2941 move.l d2,d0
2942 tst.l d4
2943 beq .exit
2944 moveq #TRUE,d0
2945 .exit
2948 ga_PingPong:
2949 move.l d2,d0
2950 tst.l d4
2951 beq .exit
2952 moveq #TRUE,d0
2953 .exit
2956 ga_Bits:
2957 moveq #14,d0
2958 tst.l d3
2959 bne .exit
2960 moveq #8,d0
2961 .exit
2964 ga_MaxChannels:
2965 moveq #4,d0
2966 tst.l d4
2967 bne .exit
2968 move.l d2,d0
2969 .exit
2972 ga_Record:
2973 moveq #FALSE,d0
2974 tst.l d3
2975 bne .exit
2976 tst.l d4
2977 bne .exit
2978 moveq #TRUE,d0
2979 .exit
2982 ga_Frequencies:
2983 moveq #1,d0
2984 tst.l d4
2985 bne .exit
2986 bsr checkvideo
2987 tst.l d0
2988 beq .1
2989 moveq #FREQUENCIES,d0
2990 .exit
2993 moveq #FREQUENCIES_OCS,d0
2996 ga_Frequency:
2997 tst.l d4
2998 beq .nodma
2999 move.l #PALFREQ,d2 ;PAL
3000 move.l pb_GfxLib(a5),a0
3001 move.w gb_DisplayFlags(a0),d0
3002 btst #REALLY_PALn,d0
3003 bne.b .1
3004 move.l #NTSCFREQ,d2 ;NTSC
3006 move.l d2,d0
3008 .nodma
3009 lsl.w #2,d1
3010 lea freqlist(pc),a0
3011 move.l (a0,d1.w),d2
3013 ; moveq #0,d0 ;Default
3014 ; lea fakefreqVar(pc),a0
3015 ; bsr GetVarInt
3016 ; tst.l d0
3017 ; bne .skipfrequpdate
3018 ; move.l d2,d0
3019 ; bsr calcperiod
3020 ; rts
3021 ;.skipfrequpdate
3022 move.l d2,d0
3025 ga_Author:
3026 lea .author(pc),a0
3027 move.l a0,d0
3029 .author dc.b "Martin 'Leviticus' Blom",0
3030 even
3032 ga_Copyright:
3033 lea .copyright(pc),a0
3034 move.l a0,d0
3036 .copyright dc.b "Public Domain",0
3037 even
3039 ga_Version:
3040 lea IDString(pc),a0
3041 move.l a0,d0
3044 ga_Annotation:
3045 lea .anno(pc),a0
3046 move.l a0,d0
3048 .anno dc.b "14 bit routines by Christian Buchner.",0
3049 even
3051 ga_Index:
3052 move.l d1,d0
3053 bsr findfreq
3054 move.l d1,d0
3058 ga_Realtime:
3059 moveq #TRUE,d0
3062 ga_MaxRecordSamples:
3063 move.l #RECORDSAMPLES,d0
3066 ga_FullDuplex:
3067 moveq #FALSE,d0
3068 tst.l d3
3069 bne .exit
3070 tst.l d4
3071 bne .exit
3072 moveq #TRUE,d0
3073 .exit
3077 ga_MinMonitorVolume:
3078 moveq #0,d0
3081 ga_MaxMonitorVolume:
3082 moveq #0,d0
3083 tst.l d3
3084 bne .exit
3085 tst.l d4
3086 bne .exit
3087 move.l #$10000,d0
3088 .exit
3091 ga_MinInputGain:
3092 move.l #$10000,d0
3095 ga_MaxInputGain:
3096 move.l #$10000,d0
3099 ga_MinOutputVolume:
3100 move.l #$10000,d0
3101 tst.l d3
3102 bne .exit
3103 tst.l d4
3104 bne .exit
3105 moveq #0,d0
3106 .exit
3109 ga_MaxOutputVolume:
3110 move.l #$10000,d0
3114 ga_Inputs:
3115 moveq #0,d0
3116 tst.l d3
3117 bne .exit
3118 tst.l d4
3119 bne .exit
3120 moveq #3,d0
3121 .exit
3124 ga_Input:
3125 lsl.l #2,d1
3126 move.l .inputs(pc,d1.w),d0
3128 .inputs dc.l .input0
3129 dc.l .input1
3130 dc.l .input2
3132 .input0 dc.b "Parallel port sampler",0
3133 .input1 dc.b "Aura sampler",0
3134 .input2 dc.b "Clarity sampler",0
3135 even
3137 ga_Outputs:
3138 moveq #1,d0
3141 ga_Output:
3142 lea .output(pc),a0
3143 move.l a0,d0
3145 .output dc.b "Line",0
3146 even
3149 ****** [driver].audio/AHIsub_HardwareControl ********************************
3151 * NAME
3152 * AHIsub_HardwareControl -- Modify sound card settings
3154 * SYNOPSIS
3155 * AHIsub_HardwareControl( attribute, argument, audioctrl );
3156 * D0 D0 D1 A2
3158 * LONG AHIsub_HardwareControl( ULONG, LONG, struct AHIAudioCtrlDrv * );
3160 * IMPLEMENTATION
3161 * Set or return the state of a particular hardware component. AHI uses
3162 * AHIsub_GetAttr() to supply the user with limits and what tags are
3163 * available.
3165 * INPUTS
3166 * attribute - Is really a Tag and can be one of the following:
3168 * AHIC_MonitorVolume - Set the input monitor volume to argument.
3169 * AHIC_MonitorVolume_Query - Return the current input monitor
3170 * volume (argument is ignored).
3172 * AHIC_InputGain - Set the input gain to argument. (V2)
3173 * AHIC_InputGain_Query (V2)
3175 * AHIC_OutputVolume - Set the output volume to argument. (V2)
3176 * AHIC_OutputVolume_Query (V2)
3178 * AHIC_Input - Use the argument:th input source (default is 0). (V2)
3179 * AHIC_Input_Query (V2)
3181 * AHIC_Output - Use the argument:th output destination (default
3182 * is 0). (V2)
3183 * AHIC_Output_Query (V2)
3185 * argument - What value attribute should be set to.
3186 * audioctrl - Pointer to an AHIAudioCtrlDrv structure.
3188 * RESULT
3189 * Return the state of selected attribute. If you were asked to set
3190 * something, return TRUE. If attribute is unknown to you or unsupported,
3191 * return FALSE.
3193 * NOTES
3194 * This call must be safe from interrupts.
3196 * SEE ALSO
3197 * ahi.device/AHI_ControlAudioA(), AHIsub_GetAttr()
3199 *****************************************************************************
3203 AHIsub_HardwareControl:
3204 PRINTF 2,"AHIsub_HardwareControl()"
3205 cmp.l #AHIC_MonitorVolume,d0
3206 bne.b .dontsetmonvol
3207 move.l ahiac_DriverData(a2),a1
3208 lsr.l #8,d1
3209 lsr.l #2,d1
3210 move.w d1,p_MonitorVolume(a1)
3211 bra.b .exit
3212 .dontsetmonvol
3213 cmp.l #AHIC_MonitorVolume_Query,d0
3214 bne.b .dontgetmonvol
3215 move.l ahiac_DriverData(a2),a1
3216 moveq #0,d0
3217 move.w p_MonitorVolume(a1),d0
3218 lsl.l #8,d0
3219 lsl.l #2,d0
3220 bra.b .quit
3221 .dontgetmonvol
3222 cmp.l #AHIC_OutputVolume,d0
3223 bne.b .dontsetoutvol
3224 move.l ahiac_DriverData(a2),a1
3225 lsr.l #8,d1
3226 lsr.l #2,d1
3227 move.w d1,p_OutputVolume(a1)
3228 bra.b .exit
3229 .dontsetoutvol
3230 cmp.l #AHIC_OutputVolume_Query,d0
3231 bne.b .dontgetoutvol
3232 move.l ahiac_DriverData(a2),a1
3233 moveq #0,d0
3234 move.w p_OutputVolume(a1),d0
3235 lsl.l #8,d0
3236 lsl.l #2,d0
3237 bra.b .quit
3238 .dontgetoutvol
3239 cmp.l #AHIC_Input,d0
3240 bne.b .dontsetinput
3241 move.l ahiac_DriverData(a2),a1
3242 move.w d1,p_Input(a1)
3243 bra.b .exit
3244 .dontsetinput
3245 cmp.l #AHIC_Input_Query,d0
3246 bne.b .dontgetinput
3247 move.l ahiac_DriverData(a2),a1
3248 moveq #0,d0
3249 move.w p_Input(a1),d0
3250 bra.b .quit
3251 .dontgetinput
3252 moveq #FALSE,d0
3253 .quit
3255 .exit
3256 moveq #TRUE,d0
3265 *******************************************************************************
3266 ***** Interrupt routines ******************************************************
3267 *******************************************************************************
3269 MixTask:
3270 move.l 4.w,a6
3271 suba.l a1,a1
3272 call FindTask
3273 move.l d0,a0
3274 move.l TC_Userdata(a0),a3
3275 move.l p_PaulaBase(a3),a5
3277 .loop
3278 move.l #SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D,d0
3279 call Wait
3281 btst #SIGBREAKB_CTRL_C,d0
3282 bne .quit
3284 btst #SIGBREAKB_CTRL_D,d0
3285 beq .loop
3287 pushm a3/a5-a6
3288 move.l p_PlaySoftInt+IS_CODE(a3),a5
3289 move.l p_PlaySoftInt+IS_DATA(a3),a1
3290 jsr (a5)
3291 popm a3/a5-a6
3293 bra .loop
3295 .quit
3296 call Forbid
3297 move.l p_ReplyTask(a3),d0
3298 move.l d0,a1
3299 beq .exit
3300 move.l #SIGF_SINGLE,d0
3301 call Signal
3303 .exit
3305 ; Multitasking will resume when we're dead
3309 Interrupt_Dummy:
3310 move.w #INTF_AUDIO,INTREQ(a0)
3311 SoftInt_Dummy:
3314 ;in:
3315 * d0 scratch
3316 * d1 INTENAR & INTREQR
3317 * a0 custom
3318 * a1 &(paula->p_RecIntData)
3319 * a5 &RecordInterrupt
3320 * a6 ExecBase
3321 RecordInterrupt:
3323 * This function will be executed up to 28000 times per second - that's once per
3324 * rasterline! It has to be as fast as possible.
3326 move.w #INTF_AUD2|INTF_AUD3,INTREQ(a0) ;Clear the interrupt flags
3327 moveq #0,d0
3328 move.b _ciaa+ciaprb,d0 ;read parallel port
3329 IFGE __CPU-68020
3330 move.l convtable(pc,d0.w*4),d0 ;1 unsigned byte -> 2 signed words
3331 ELSE
3332 add.w d0,d0
3333 add.w d0,d0
3334 move.l convtable(pc,d0.w),d0
3335 ENDC
3336 move.w d0,AUD2DAT(a0) ;left
3337 move.w d0,AUD3DAT(a0) ;right
3339 move.l (a1),a5 ;p_RecFillPtr
3340 move.l d0,(a5)+ ;store sample in buffer
3341 move.l a5,(a1)+ ;update pointer
3342 subq.w #1,(a1) ;p_ReqFillCount
3343 beq ri_Filled ;branch if buffer filled
3346 convtable
3347 CNT SET 0
3348 REPT 256
3349 dc.b CNT-128,CNT-128,CNT-128,CNT-128
3350 CNT SET CNT+1
3351 ENDR
3353 ;in:
3354 * d0 scratch
3355 * d1 INTENAR & INTREQR
3356 * a0 custom
3357 * a1 &(paula->p_RecIntData)
3358 * a5 &RecordInterrupt
3359 * a6 ExecBase
3360 RecordInterruptClarity:
3362 * This function will be executed up to 28000 times per second - that's once per
3363 * rasterline! It has to be as fast as possible.
3365 move.w #INTF_AUD2|INTF_AUD3,INTREQ(a0) ;Clear the interrupt flags
3367 lea _ciab+ciatahi,a5
3369 move.b _ciaa+ciaprb,d0 ;left lsb
3370 ror.l #8,d0 ;d0: L0xxxxxx
3371 tst.b (a5) ;3x700 kHz wait states
3372 tst.b (a5)
3373 tst.b (a5)
3375 move.b _ciaa+ciaprb,d0 ;left msb
3376 ror.l #8,d0 ;d0: L1L0xxxx
3377 tst.b (a5) ;3x700 kHz wait states
3378 tst.b (a5)
3379 tst.b (a5)
3381 move.b _ciaa+ciaprb,d0 ;right lsb
3382 lsl.w #8,d0 ;d0: L1L0R0xx
3383 tst.b (a5) ;3x700 kHz wait states
3384 tst.b (a5)
3385 tst.b (a5)
3387 move.b _ciaa+ciaprb,d0 ;right msb
3388 ror.w #8,d0 ;d0: L1L0R1R0
3390 move.l (a1),a5 ;p_RecFillPtr
3391 move.l d0,(a5)+ ;store sample in buffer
3392 move.l a5,(a1)+ ;update pointer
3394 move.w d0,d1
3395 lsr.w #8,d0
3396 move.b d0,d1
3398 move.w d1,AUD2DAT(a0) ;right
3399 move.w d1,AUD3DAT(a0) ;left
3401 subq.w #1,(a1) ;p_ReqFillCount
3402 beq ri_Filled ;branch if buffer filled
3405 ;in:
3406 * d0 scratch
3407 * d1 INTENAR & INTREQR
3408 * a0 custom
3409 * a1 &(paula->p_RecIntDataAura)
3410 * a5 &RecordInterrupt
3411 * a6 ExecBase
3412 RecordInterruptAura:
3414 * This function will be executed up to 28000 times per second - that's once per
3415 * rasterline! It has to be as fast as possible.
3417 move.w #INTF_AUD2|INTF_AUD3,INTREQ(a0) ;Clear the interrupt flags
3418 move.l (a1)+,a5
3419 move.l (a5),d0 ;read aura sampler
3420 eor.l #$80008000,d0
3421 move.l (a1),a5 ;p_RecFillPtr
3422 move.l d0,(a5)+ ;store sample in buffer
3423 move.l a5,(a1)+ ;update pointer
3425 move.w d0,d1
3426 lsr.w #8,d0
3427 move.b d0,d1
3429 move.w d1,AUD2DAT(a0) ;left
3430 move.w d1,AUD3DAT(a0) ;right
3432 subq.w #1,(a1) ;p_ReqFillCount
3433 beq ri_Filled ;branch if buffer filled
3436 *******************************************************************************
3438 ri_Filled:
3440 * This part is only executed every RECORDSAMPLES:th time... No need to hurry.
3442 move.l 8(a1),d0 ;p_RecBuffer2->
3443 move.l 4(a1),8(a1) ;p_RecBuffer1->p_RecBuffer2
3444 move.l d0,4(a1) ; ->p_RecBuffer1
3445 move.l d0,-4(a1) ;p_RecFillPtr
3446 move.w #RECORDSAMPLES,(a1) ;p_ReqFillCount
3447 move.l 12(a1),a1 ;p_RecSoftIntPtr
3448 jmp _LVOCause(a6)
3451 ;in:
3452 * d0 scratch
3453 * d1 scratch
3454 * a0 scratch
3455 * a1 struct paula *
3456 * a5 scratch
3457 RecordSoftInt:
3459 * This function is not executed many times per second and is therefore not
3460 * fully optimized... ;)
3461 push a2
3462 move.w p_MonitorVolume(a1),d0
3463 move.w d0,custom+AUD2VOL
3464 move.w d0,custom+AUD3VOL
3465 move.l p_RecBuffer2(a1),p_rmBuffer(a1)
3466 move.l p_AudioCtrl(a1),a2
3467 lea p_RecordMessage(a1),a1
3468 move.l ahiac_SamplerFunc(a2),a0
3469 move.l h_Entry(a0),a5
3470 jsr (a5)
3471 pop a2
3474 *******************************************************************************
3475 *******************************************************************************
3477 ;in:
3478 * d0 scratch
3479 * d1 INTENAR & INTREQR
3480 * a0 custom
3481 * a1 struct paula *
3482 * a5 &AudioInterrupt
3483 * a6 ExecBase
3485 AudioInterrupt2: ;Two hardware channels used
3486 ; move.l p_AudLenPer(a1),d0
3487 ; move.l d0,AUD0LEN(a0)
3488 ; move.l d0,AUD1LEN(a0)
3489 move.w p_AudPer(a1),d0
3490 move.w d0,AUD0PER(a0)
3491 move.w d0,AUD1PER(a0)
3492 move.w p_OutputVolume(a1),AUD0VOL(a0)
3493 move.w p_OutputVolume(a1),AUD1VOL(a0)
3495 move.l p_DoubleBufferOffset(a1),d0
3496 eor.w #4*4,d0
3497 move.l d0,p_DoubleBufferOffset(a1)
3499 lea p_AudPtrs(a1,d0.l),a5
3500 tst.b p_SwapChannels(a1)
3501 bne .swap
3502 move.l (a5)+,AUD0LC(a0)
3503 move.l (a5)+,AUD1LC(a0)
3504 bra .1
3505 .swap
3506 move.l (a5)+,AUD1LC(a0)
3507 move.l (a5)+,AUD0LC(a0)
3509 move.w #INTF_AUD0,INTREQ(a0) ;Clear the interrupt
3510 move.l p_MixTask(a1),d0
3511 bne .signal
3512 lea p_PlaySoftInt(a1),a1
3513 jmp _LVOCause(a6) ;start PlaySoftInt
3514 .signal
3515 move.l d0,a1
3516 move.l #SIGBREAKF_CTRL_D,d0
3517 jmp _LVOSignal(a6)
3520 AudioInterrupt4: ;Four hardware channels used
3521 ; move.l p_AudLenPer(a1),d0
3522 ; move.l d0,AUD0LEN(a0)
3523 ; move.l d0,AUD1LEN(a0)
3524 ; move.l d0,AUD2LEN(a0)
3525 ; move.l d0,AUD3LEN(a0)
3526 move.w p_AudPer(a1),d0
3527 move.w d0,AUD0PER(a0)
3528 move.w d0,AUD1PER(a0)
3529 move.w d0,AUD2PER(a0)
3530 move.w d0,AUD3PER(a0)
3531 move.w #64,AUD0VOL(a0)
3532 move.w #64,AUD1VOL(a0)
3533 move.w #1,AUD2VOL(a0)
3534 move.w #1,AUD3VOL(a0)
3536 move.l p_DoubleBufferOffset(a1),d0
3537 eor.w #4*4,d0
3538 move.l d0,p_DoubleBufferOffset(a1)
3540 lea p_AudPtrs(a1,d0.l),a5
3541 tst.b p_SwapChannels(a1)
3542 bne .swap
3543 move.l (a5)+,AUD0LC(a0)
3544 move.l (a5)+,AUD1LC(a0)
3545 move.l (a5)+,AUD2LC(a0)
3546 move.l (a5)+,AUD3LC(a0)
3547 bra .1
3548 .swap
3549 move.l (a5)+,AUD1LC(a0)
3550 move.l (a5)+,AUD0LC(a0)
3551 move.l (a5)+,AUD3LC(a0)
3552 move.l (a5)+,AUD2LC(a0)
3554 move.w #INTF_AUD0,INTREQ(a0) ;Clear the interrupt
3555 move.l p_MixTask(a1),d0
3556 bne .signal
3557 lea p_PlaySoftInt(a1),a1
3558 jmp _LVOCause(a6) ;start PlaySoftInt
3559 .signal
3560 move.l d0,a1
3561 move.l #SIGBREAKF_CTRL_D,d0
3562 jmp _LVOSignal(a6)
3566 *******************************************************************************
3568 ;in:
3569 * d0 scratch
3570 * d1 scratch
3571 * a0 scratch
3572 * a1 struct paula *
3573 * a5 scratch
3575 CONVERT_PRE MACRO
3576 pushm std
3577 move.l a1,a6
3578 move.l p_AudioCtrl(a6),a2
3579 move.l ahiac_PreTimer(a2),a0
3580 PRINTF 8,"Calling PreTimer: %08lx", a2
3581 jsr (a0)
3582 move.l d0,d7
3584 move.l p_DoubleBufferOffset(a6),d0
3585 lea p_AudPtrs(a6,d0.l),a0
3586 movem.l (a0)+,d2/d3/d4/d5 ;get all 4 buffer pointers
3588 IFEQ BETTERTIMING-1
3589 PRINTF 3,"Leftovers: %ld", p_LoopLeftovers(a6)
3590 ENDC
3592 moveq #0,d6
3593 .repeat
3594 movem.l p_PlayerHookRegs(a6),a0/a1/a3
3595 PRINTF 8,"Calling PlayerHook: %08lx, %08lx, %08lx", a0, a2, a1
3596 jsr (a3) ;call Player Hook
3597 tst.l d7
3598 beq .no_skip
3599 add.l ahiac_BuffSamples(a2),d6 ;Faked # of mixed samples
3600 bra .skip
3601 .no_skip
3603 movem.l p_MixHookRegs(a6),a0/a1/a3
3604 IFEQ BETTERTIMING-1
3605 move.l p_LoopLeftovers(a6),d0
3606 move.l p_SampleFrameShift(a6),d1
3607 lsl.l d1,d0
3608 PRINTF 3," adding %ld", d0
3609 add.l d0,a1 ;don't overwrite the leftovers
3610 ;(the mixbuffer is large enough,
3611 ;search for EXTRABUFFSIZE!)
3612 ENDC
3613 PRINTF 8,"Calling MixerHook: %08lx, %08lx, %08lx", a0, a2, a1
3614 jsr (a3) ;call Mixer Hook
3616 IFEQ BETTERTIMING-1
3617 move.l ahiac_BuffSamples(a2),d0
3618 add.l p_LoopLeftovers(a6),d0
3619 move.l d0,d1
3620 and.l #~3,d0
3621 sub.l d0,d1
3622 move.l d1,p_LoopLeftovers(a6)
3623 add.l d0,d6 ;Count actual number of played samples
3624 PRINTF 4," Playing %ld, %ld missing", d0, d1
3625 lsr.l #2,d0
3626 subq.l #1,d0
3627 move.l p_Mixbuffer(a6),a1 ;a1 was modified above, remember?
3628 ELSE
3629 move.l p_LoopTimes(a6),d0
3630 ENDC
3631 ENDM
3634 ; Conversion code here!
3636 ; d0 counter
3637 ; d1 scratch
3638 ; d2-d5 buffer pointers
3639 ; d6 (sample counter/4)
3640 ; d7 (pretimer flag)
3641 ; a0 scratch
3642 ; a1 source buffer (must be updated)
3643 ; a2 AudioCtrl
3644 ; a3-a5 scratch
3645 ; a6 struct paula *
3647 ; Conversion code here!
3650 CONVERT_POST MACRO
3652 IFEQ BETTERTIMING-1
3653 ; Transfer the leftovers to the beginning of the mixbuffer
3654 ; It's easy: just transfer p_LoopLeftovers samples from (a1) to
3655 ; (p_Mixbuffer).
3657 move.l p_Mixbuffer(a6),a0
3658 move.l p_LoopLeftovers(a6),d0
3659 PRINTF 3,"Tranfering %ld samples",d0
3660 move.l p_SampleFrameShift(a6),d1
3661 lsl.l d1,d0
3662 PRINTF 3,", that is %ld bytes",d0
3663 addq.l #3,d0
3664 lsr.l #2,d0
3665 beq .no_transfer
3666 PRINTF 4," or %ld iterations.",d0
3667 subq.l #1,d0
3668 .transfer
3669 move.l (a1)+,(a0)+
3670 dbf d0,.transfer
3671 .no_transfer
3672 ENDC
3674 .skip
3675 IFEQ BETTERTIMING-0
3676 add.l ahiac_BuffSamples(a2),d6
3677 ENDC
3678 cmp.l p_MinBufferLength(a6),d6
3679 blo .repeat
3680 move.l ahiac_PostTimer(a2),a0
3681 PRINTF 8,"Calling PostTimer: %08lx", a2
3682 jsr (a0)
3683 move.l d6,d0
3684 PRINTF 4,"I have played %ld samples", d0
3685 lea custom,a0
3686 popm std
3687 ENDM
3689 ; Exit code here
3690 ; d0 Samples in buffer
3691 ; a0 custom
3693 *******************************************************************************
3695 SoftInt_8bitM:
3697 CONVERT_PRE
3699 move.l d2,a0 ;get buffer ptr
3700 .loop
3701 move.b (a1),d1
3702 lsl.l #8,d1
3703 move.b 2(a1),d1
3704 lsl.l #8,d1
3705 move.b 4(a1),d1
3706 lsl.l #8,d1
3707 move.b 6(a1),d1
3708 move.l d1,(a0)+
3709 addq.w #8,a1
3710 dbf d0,.loop
3711 move.l a0,d2 ;save buffer ptr
3713 CONVERT_POST
3715 lsr.l #1,d0
3716 move.w d0,AUD0LEN(a0)
3717 move.w d0,AUD1LEN(a0)
3718 move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1,DMACON(a0)
3721 *******************************************************************************
3723 SoftInt_8bitMH:
3724 CONVERT_PRE
3726 move.l d2,a0 ;get buffer ptr
3727 .loop
3728 move.b (a1),d1
3729 lsl.l #8,d1
3730 move.b 4(a1),d1
3731 lsl.l #8,d1
3732 move.b 8(a1),d1
3733 lsl.l #8,d1
3734 move.b 12(a1),d1
3735 move.l d1,(a0)+
3736 add.w #16,a1
3737 dbf d0,.loop
3738 move.l a0,d2 ;save buffer ptr
3740 CONVERT_POST
3742 lsr.l #1,d0
3743 move.w d0,AUD0LEN(a0)
3744 move.w d0,AUD1LEN(a0)
3745 move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1,DMACON(a0)
3748 *******************************************************************************
3750 SoftInt_8bitS:
3751 CONVERT_PRE
3753 move.l d2,a0 ;get buffer ptr
3754 move.l d3,a3 ;get buffer ptr
3755 .loop
3757 ; Left
3758 move.b (a1),d1
3759 lsl.l #8,d1
3760 move.b 4(a1),d1
3761 lsl.l #8,d1
3762 move.b 8(a1),d1
3763 lsl.l #8,d1
3764 move.b 12(a1),d1
3765 move.l d1,(a3)+
3767 ; Right
3768 move.b 2(a1),d1
3769 lsl.l #8,d1
3770 move.b 6(a1),d1
3771 lsl.l #8,d1
3772 move.b 10(a1),d1
3773 lsl.l #8,d1
3774 move.b 14(a1),d1
3775 move.l d1,(a0)+
3777 add.w #16,a1
3778 dbf d0,.loop
3779 move.l a0,d2 ;save buffer ptr
3780 move.l a3,d3 ;save buffer ptr
3782 CONVERT_POST
3784 lsr.l #1,d0
3785 move.w d0,AUD0LEN(a0)
3786 move.w d0,AUD1LEN(a0)
3787 move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1,DMACON(a0)
3790 *******************************************************************************
3792 SoftInt_8bitSH:
3793 CONVERT_PRE
3795 move.l d2,a0 ;get buffer ptr
3796 move.l d3,a3 ;get buffer ptr
3797 .loop
3799 ; Left
3800 move.b (a1),d1
3801 lsl.l #8,d1
3802 move.b 8(a1),d1
3803 lsl.l #8,d1
3804 move.b 16(a1),d1
3805 lsl.l #8,d1
3806 move.b 24(a1),d1
3807 move.l d1,(a3)+
3809 ; Right
3810 move.b 4(a1),d1
3811 lsl.l #8,d1
3812 move.b 12(a1),d1
3813 lsl.l #8,d1
3814 move.b 20(a1),d1
3815 lsl.l #8,d1
3816 move.b 28(a1),d1
3817 move.l d1,(a0)+
3819 add.w #32,a1
3820 dbf d0,.loop
3821 move.l a0,d2 ;save buffer ptr
3822 move.l a3,d3 ;save buffer ptr
3824 CONVERT_POST
3826 lsr.l #1,d0
3827 move.w d0,AUD0LEN(a0)
3828 move.w d0,AUD1LEN(a0)
3829 move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1,DMACON(a0)
3832 *******************************************************************************
3834 SoftInt_14bitM:
3835 CONVERT_PRE
3837 move.l d2,a0 ;get buffer ptr
3838 move.l d5,a5 ;get buffer ptr
3839 .loop
3841 ; High
3842 move.b (a1),d1
3843 lsl.l #8,d1
3844 move.b 2(a1),d1
3845 lsl.l #8,d1
3846 move.b 4(a1),d1
3847 lsl.l #8,d1
3848 move.b 6(a1),d1
3849 move.l d1,(a0)+
3851 ; Low
3852 move.b 1(a1),d1
3853 lsr.b #2,d1
3854 lsl.l #8,d1
3855 move.b 3(a1),d1
3856 lsr.b #2,d1
3857 lsl.l #8,d1
3858 move.b 5(a1),d1
3859 lsr.b #2,d1
3860 lsl.l #8,d1
3861 move.b 7(a1),d1
3862 lsr.b #2,d1
3863 move.l d1,(a5)+
3865 addq.w #8,a1
3866 dbf d0,.loop
3867 move.l a0,d2 ;save buffer ptr
3868 move.l a5,d5 ;save buffer ptr
3870 CONVERT_POST
3872 lsr.l #1,d0
3873 move.w d0,AUD0LEN(a0)
3874 move.w d0,AUD1LEN(a0)
3875 move.w d0,AUD2LEN(a0)
3876 move.w d0,AUD3LEN(a0)
3877 move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3,DMACON(a0)
3880 *******************************************************************************
3883 SoftInt_14bitMH:
3884 CONVERT_PRE
3886 move.l d2,a0 ;get buffer ptr
3887 move.l d5,a5 ;get buffer ptr
3888 .loop
3890 ; High
3891 move.b (a1),d1
3892 lsl.l #8,d1
3893 move.b 4(a1),d1
3894 lsl.l #8,d1
3895 move.b 8(a1),d1
3896 lsl.l #8,d1
3897 move.b 12(a1),d1
3898 move.l d1,(a0)+
3900 ; Low
3901 move.b 1(a1),d1
3902 lsr.b #2,d1
3903 lsl.l #8,d1
3904 move.b 5(a1),d1
3905 lsr.b #2,d1
3906 lsl.l #8,d1
3907 move.b 9(a1),d1
3908 lsr.b #2,d1
3909 lsl.l #8,d1
3910 move.b 13(a1),d1
3911 lsr.b #2,d1
3912 move.l d1,(a5)+
3914 add.w #16,a1
3915 dbf d0,.loop
3916 move.l a0,d2 ;save buffer ptr
3917 move.l a5,d5 ;save buffer ptr
3919 CONVERT_POST
3921 lsr.l #1,d0
3922 move.w d0,AUD0LEN(a0)
3923 move.w d0,AUD1LEN(a0)
3924 move.w d0,AUD2LEN(a0)
3925 move.w d0,AUD3LEN(a0)
3926 move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3,DMACON(a0)
3929 *******************************************************************************
3931 SoftInt_14CbitM:
3932 CONVERT_PRE
3934 move.l d2,a0 ;get buffer ptr
3935 move.l d5,a5 ;get buffer ptr
3936 move.l p_CalibrationTable(a6),a3
3937 moveq #0,d3
3938 .loop
3940 IFGE __CPU-68020
3941 move.w (a1)+,d3
3942 move.w (a3,d3.l*2),d3
3943 ELSE
3944 moveq #0,d3
3945 move.w (a1)+,d3
3946 add.w d3,d3
3947 move.w (a3,d3.l),d3
3948 ENDC
3949 move.b d3,d1
3950 lsl.l #8,d1 ;xxxxAAxx
3951 move.w d3,d2
3952 lsl.l #8,d2 ;xxaaxxxx
3953 IFGE __CPU-68020
3954 move.w (a1)+,d3
3955 move.w (a3,d3.l*2),d3
3956 ELSE
3957 moveq #0,d3
3958 move.w (a1)+,d3
3959 add.w d3,d3
3960 move.w (a3,d3.l),d3
3961 ENDC
3962 move.b d3,d1
3963 lsl.l #8,d1 ;xxAABBxx
3964 move.w d3,d2
3965 lsl.l #8,d2 ;aabbxxxx
3966 IFGE __CPU-68020
3967 move.w (a1)+,d3
3968 move.w (a3,d3.l*2),d3
3969 ELSE
3970 moveq #0,d3
3971 move.w (a1)+,d3
3972 add.w d3,d3
3973 move.w (a3,d3.l),d3
3974 ENDC
3975 move.b d3,d1
3976 lsl.l #8,d1 ;AABBCCxx
3977 move.w d3,d2 ;aabbccxx
3979 IFGE __CPU-68020
3980 move.w (a1)+,d3
3981 move.w (a3,d3.l*2),d3
3982 ELSE
3983 moveq #0,d3
3984 move.w (a1)+,d3
3985 add.w d3,d3
3986 move.w (a3,d3.l),d3
3987 ENDC
3988 move.b d3,d1 ;AABBCCDD
3989 lsr.w #8,d3
3990 move.b d3,d2 ;aabbccdd
3992 move.l d1,(a5)+
3993 move.l d2,(a0)+
3995 dbf d0,.loop
3996 move.l a0,d2 ;save buffer ptr
3997 move.l a5,d5 ;save buffer ptr
3999 CONVERT_POST
4001 lsr.l #1,d0
4002 move.w d0,AUD0LEN(a0)
4003 move.w d0,AUD1LEN(a0)
4004 move.w d0,AUD2LEN(a0)
4005 move.w d0,AUD3LEN(a0)
4006 move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3,DMACON(a0)
4009 *******************************************************************************
4011 SoftInt_14CbitMH:
4012 CONVERT_PRE
4014 move.l d2,a0 ;get buffer ptr
4015 move.l d5,a5 ;get buffer ptr
4016 move.l p_CalibrationTable(a6),a3
4017 moveq #0,d3
4018 .loop
4020 IFGE __CPU-68020
4021 move.w (a1),d3
4022 move.w (a3,d3.l*2),d3
4023 ELSE
4024 moveq #0,d3
4025 move.w (a1),d3
4026 add.w d3,d3
4027 move.w (a3,d3.l),d3
4028 ENDC
4029 move.b d3,d1
4030 lsl.l #8,d1 ;xxxxAAxx
4031 move.w d3,d2
4032 lsl.l #8,d2 ;xxaaxxxx
4033 IFGE __CPU-68020
4034 move.w 4(a1),d3
4035 move.w (a3,d3.l*2),d3
4036 ELSE
4037 moveq #0,d3
4038 move.w 4(a1),d3
4039 add.w d3,d3
4040 move.w (a3,d3.l),d3
4041 ENDC
4042 move.b d3,d1
4043 lsl.l #8,d1 ;xxAABBxx
4044 move.w d3,d2
4045 lsl.l #8,d2 ;aabbxxxx
4046 IFGE __CPU-68020
4047 move.w 8(a1),d3
4048 move.w (a3,d3.l*2),d3
4049 ELSE
4050 moveq #0,d3
4051 move.w 8(a1),d3
4052 add.w d3,d3
4053 move.w (a3,d3.l),d3
4054 ENDC
4055 move.b d3,d1
4056 lsl.l #8,d1 ;AABBCCxx
4057 move.w d3,d2 ;aabbccxx
4059 IFGE __CPU-68020
4060 move.w 12(a1),d3
4061 move.w (a3,d3.l*2),d3
4062 ELSE
4063 moveq #0,d3
4064 move.w 12(a1),d3
4065 add.w d3,d3
4066 move.w (a3,d3.l),d3
4067 ENDC
4068 move.b d3,d1 ;AABBCCDD
4069 lsr.w #8,d3
4070 move.b d3,d2 ;aabbccdd
4072 move.l d1,(a5)+
4073 add.w #16,a1
4074 move.l d2,(a0)+
4076 dbf d0,.loop
4077 move.l a0,d2 ;save buffer ptr
4078 move.l a5,d5 ;save buffer ptr
4080 CONVERT_POST
4082 lsr.l #1,d0
4083 move.w d0,AUD0LEN(a0)
4084 move.w d0,AUD1LEN(a0)
4085 move.w d0,AUD2LEN(a0)
4086 move.w d0,AUD3LEN(a0)
4087 move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3,DMACON(a0)
4091 *******************************************************************************
4093 SoftInt_14bitS:
4094 CONVERT_PRE
4096 move.l d2,a0 ;get buffer ptr
4097 move.l d3,a3 ;get buffer ptr
4098 move.l d4,a4 ;get buffer ptr
4099 move.l d5,a5 ;get buffer ptr
4100 .loop
4102 ; Left High
4103 move.b (a1),d1
4104 lsl.l #8,d1
4105 move.b 4(a1),d1
4106 lsl.l #8,d1
4107 move.b 8(a1),d1
4108 lsl.l #8,d1
4109 move.b 12(a1),d1
4110 move.l d1,(a3)+
4112 ; Left Low
4113 move.b 1(a1),d1
4114 lsr.b #2,d1
4115 lsl.l #8,d1
4116 move.b 5(a1),d1
4117 lsr.b #2,d1
4118 lsl.l #8,d1
4119 move.b 9(a1),d1
4120 lsr.b #2,d1
4121 lsl.l #8,d1
4122 move.b 13(a1),d1
4123 lsr.b #2,d1
4124 move.l d1,(a4)+
4126 ; Right High
4127 move.b 2(a1),d1
4128 lsl.l #8,d1
4129 move.b 6(a1),d1
4130 lsl.l #8,d1
4131 move.b 10(a1),d1
4132 lsl.l #8,d1
4133 move.b 14(a1),d1
4134 move.l d1,(a0)+
4136 ; Right Low
4137 move.b 3(a1),d1
4138 lsr.b #2,d1
4139 lsl.l #8,d1
4140 move.b 7(a1),d1
4141 lsr.b #2,d1
4142 lsl.l #8,d1
4143 move.b 11(a1),d1
4144 lsr.b #2,d1
4145 lsl.l #8,d1
4146 move.b 15(a1),d1
4147 lsr.b #2,d1
4148 move.l d1,(a5)+
4150 add.w #16,a1
4151 dbf d0,.loop
4152 move.l a0,d2 ;save buffer ptr
4153 move.l a3,d3 ;save buffer ptr
4154 move.l a4,d4 ;save buffer ptr
4155 move.l a5,d5 ;save buffer ptr
4157 CONVERT_POST
4159 lsr.l #1,d0
4160 move.w d0,AUD0LEN(a0)
4161 move.w d0,AUD1LEN(a0)
4162 move.w d0,AUD2LEN(a0)
4163 move.w d0,AUD3LEN(a0)
4164 move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3,DMACON(a0)
4167 *******************************************************************************
4169 SoftInt_14bitSH:
4170 CONVERT_PRE
4172 move.l d2,a0 ;get buffer ptr
4173 move.l d3,a3 ;get buffer ptr
4174 move.l d4,a4 ;get buffer ptr
4175 move.l d5,a5 ;get buffer ptr
4176 .loop
4178 ; Left High
4179 move.b (a1),d1
4180 lsl.l #8,d1
4181 move.b 8(a1),d1
4182 lsl.l #8,d1
4183 move.b 16(a1),d1
4184 lsl.l #8,d1
4185 move.b 24(a1),d1
4186 move.l d1,(a3)+
4188 ; Left Low
4189 move.b 1(a1),d1
4190 lsr.b #2,d1
4191 lsl.l #8,d1
4192 move.b 9(a1),d1
4193 lsr.b #2,d1
4194 lsl.l #8,d1
4195 move.b 17(a1),d1
4196 lsr.b #2,d1
4197 lsl.l #8,d1
4198 move.b 25(a1),d1
4199 lsr.b #2,d1
4200 move.l d1,(a4)+
4202 ; Right High
4203 move.b 4(a1),d1
4204 lsl.l #8,d1
4205 move.b 12(a1),d1
4206 lsl.l #8,d1
4207 move.b 20(a1),d1
4208 lsl.l #8,d1
4209 move.b 28(a1),d1
4210 move.l d1,(a0)+
4212 ; Right Low
4213 move.b 5(a1),d1
4214 lsr.b #2,d1
4215 lsl.l #8,d1
4216 move.b 13(a1),d1
4217 lsr.b #2,d1
4218 lsl.l #8,d1
4219 move.b 21(a1),d1
4220 lsr.b #2,d1
4221 lsl.l #8,d1
4222 move.b 29(a1),d1
4223 lsr.b #2,d1
4224 move.l d1,(a5)+
4226 add.w #32,a1
4227 dbf d0,.loop
4228 move.l a0,d2 ;save buffer ptr
4229 move.l a3,d3 ;save buffer ptr
4230 move.l a4,d4 ;save buffer ptr
4231 move.l a5,d5 ;save buffer ptr
4233 CONVERT_POST
4235 lsr.l #1,d0
4236 move.w d0,AUD0LEN(a0)
4237 move.w d0,AUD1LEN(a0)
4238 move.w d0,AUD2LEN(a0)
4239 move.w d0,AUD3LEN(a0)
4240 move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3,DMACON(a0)
4244 *******************************************************************************
4246 SoftInt_14CbitS:
4247 CONVERT_PRE
4249 move.l d2,a0 ;get buffer ptr
4250 move.l d3,a3 ;get buffer ptr
4251 move.l d4,a4 ;get buffer ptr
4252 move.l d5,a5 ;get buffer ptr
4253 push a6
4254 move.l p_CalibrationTable(a6),a6
4255 moveq #0,d3
4256 .loop
4258 ; Left
4259 IFGE __CPU-68020
4260 move.w (a1),d3
4261 move.w (a6,d3.l*2),d3
4262 ELSE
4263 moveq #0,d3
4264 move.w (a1),d3
4265 add.w d3,d3
4266 move.w (a6,d3.l),d3
4267 ENDC
4268 move.b d3,d1
4269 lsl.l #8,d1 ;xxxxAAxx
4270 move.w d3,d2
4271 lsl.l #8,d2 ;xxaaxxxx
4272 IFGE __CPU-68020
4273 move.w 4(a1),d3
4274 move.w (a6,d3.l*2),d3
4275 ELSE
4276 moveq #0,d3
4277 move.w 4(a1),d3
4278 add.w d3,d3
4279 move.w (a6,d3.l),d3
4280 ENDC
4281 move.b d3,d1
4282 lsl.l #8,d1 ;xxAABBxx
4283 move.w d3,d2
4284 lsl.l #8,d2 ;aabbxxxx
4285 IFGE __CPU-68020
4286 move.w 8(a1),d3
4287 move.w (a6,d3.l*2),d3
4288 ELSE
4289 moveq #0,d3
4290 move.w 8(a1),d3
4291 add.w d3,d3
4292 move.w (a6,d3.l),d3
4293 ENDC
4294 move.b d3,d1
4295 lsl.l #8,d1 ;AABBCCxx
4296 move.w d3,d2 ;aabbccxx
4298 IFGE __CPU-68020
4299 move.w 12(a1),d3
4300 move.w (a6,d3.l*2),d3
4301 ELSE
4302 moveq #0,d3
4303 move.w 12(a1),d3
4304 add.w d3,d3
4305 move.w (a6,d3.l),d3
4306 ENDC
4307 move.b d3,d1 ;AABBCCDD
4308 lsr.w #8,d3
4309 move.b d3,d2 ;aabbccdd
4311 move.l d1,(a4)+
4312 move.l d2,(a3)+
4314 ; Right
4315 IFGE __CPU-68020
4316 move.w 2(a1),d3
4317 move.w (a6,d3.l*2),d3
4318 ELSE
4319 moveq #0,d3
4320 move.w 2(a1),d3
4321 add.w d3,d3
4322 move.w (a6,d3.l),d3
4323 ENDC
4324 move.b d3,d1
4325 lsl.l #8,d1 ;xxxxAAxx
4326 move.w d3,d2
4327 lsl.l #8,d2 ;xxaaxxxx
4328 IFGE __CPU-68020
4329 move.w 6(a1),d3
4330 move.w (a6,d3.l*2),d3
4331 ELSE
4332 moveq #0,d3
4333 move.w 6(a1),d3
4334 add.w d3,d3
4335 move.w (a6,d3.l),d3
4336 ENDC
4337 move.b d3,d1
4338 lsl.l #8,d1 ;xxAABBxx
4339 move.w d3,d2
4340 lsl.l #8,d2 ;aabbxxxx
4341 IFGE __CPU-68020
4342 move.w 10(a1),d3
4343 move.w (a6,d3.l*2),d3
4344 ELSE
4345 moveq #0,d3
4346 move.w 10(a1),d3
4347 add.w d3,d3
4348 move.w (a6,d3.l),d3
4349 ENDC
4350 move.b d3,d1
4351 lsl.l #8,d1 ;AABBCCxx
4352 move.w d3,d2 ;aabbccxx
4354 IFGE __CPU-68020
4355 move.w 14(a1),d3
4356 move.w (a6,d3.l*2),d3
4357 ELSE
4358 moveq #0,d3
4359 move.w 14(a1),d3
4360 add.w d3,d3
4361 move.w (a6,d3.l),d3
4362 ENDC
4363 move.b d3,d1 ;AABBCCDD
4364 lsr.w #8,d3
4365 move.b d3,d2 ;aabbccdd
4367 move.l d1,(a5)+
4368 add.w #16,a1
4369 move.l d2,(a0)+
4371 dbf d0,.loop
4372 pop a6
4373 move.l a0,d2 ;save buffer ptr
4374 move.l a3,d3 ;save buffer ptr
4375 move.l a4,d4 ;save buffer ptr
4376 move.l a5,d5 ;save buffer ptr
4378 CONVERT_POST
4380 lsr.l #1,d0
4381 move.w d0,AUD0LEN(a0)
4382 move.w d0,AUD1LEN(a0)
4383 move.w d0,AUD2LEN(a0)
4384 move.w d0,AUD3LEN(a0)
4385 move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3,DMACON(a0)
4389 *******************************************************************************
4391 SoftInt_14CbitSH:
4392 CONVERT_PRE
4394 move.l d2,a0 ;get buffer ptr
4395 move.l d3,a3 ;get buffer ptr
4396 move.l d4,a4 ;get buffer ptr
4397 move.l d5,a5 ;get buffer ptr
4398 push a6
4399 move.l p_CalibrationTable(a6),a6
4400 moveq #0,d3
4401 .loop
4403 ; Left
4404 IFGE __CPU-68020
4405 move.w (a1),d3
4406 move.w (a6,d3.l*2),d3
4407 ELSE
4408 moveq #0,d3
4409 move.w (a1),d3
4410 add.w d3,d3
4411 move.w (a6,d3.l),d3
4412 ENDC
4413 move.b d3,d1
4414 lsl.l #8,d1 ;xxxxAAxx
4415 move.w d3,d2
4416 lsl.l #8,d2 ;xxaaxxxx
4417 IFGE __CPU-68020
4418 move.w 8(a1),d3
4419 move.w (a6,d3.l*2),d3
4420 ELSE
4421 moveq #0,d3
4422 move.w 8(a1),d3
4423 add.w d3,d3
4424 move.w (a6,d3.l),d3
4425 ENDC
4426 move.b d3,d1
4427 lsl.l #8,d1 ;xxAABBxx
4428 move.w d3,d2
4429 lsl.l #8,d2 ;aabbxxxx
4430 IFGE __CPU-68020
4431 move.w 16(a1),d3
4432 move.w (a6,d3.l*2),d3
4433 ELSE
4434 moveq #0,d3
4435 move.w 16(a1),d3
4436 add.w d3,d3
4437 move.w (a6,d3.l),d3
4438 ENDC
4439 move.b d3,d1
4440 lsl.l #8,d1 ;AABBCCxx
4441 move.w d3,d2 ;aabbccxx
4443 IFGE __CPU-68020
4444 move.w 24(a1),d3
4445 move.w (a6,d3.l*2),d3
4446 ELSE
4447 moveq #0,d3
4448 move.w 24(a1),d3
4449 add.w d3,d3
4450 move.w (a6,d3.l),d3
4451 ENDC
4452 move.b d3,d1 ;AABBCCDD
4453 lsr.w #8,d3
4454 move.b d3,d2 ;aabbccdd
4456 move.l d1,(a4)+
4457 move.l d2,(a3)+
4459 ; Right
4460 IFGE __CPU-68020
4461 move.w 4(a1),d3
4462 move.w (a6,d3.l*2),d3
4463 ELSE
4464 moveq #0,d3
4465 move.w 4(a1),d3
4466 add.w d3,d3
4467 move.w (a6,d3.l),d3
4468 ENDC
4469 move.b d3,d1
4470 lsl.l #8,d1 ;xxxxAAxx
4471 move.w d3,d2
4472 lsl.l #8,d2 ;xxaaxxxx
4473 IFGE __CPU-68020
4474 move.w 12(a1),d3
4475 move.w (a6,d3.l*2),d3
4476 ELSE
4477 moveq #0,d3
4478 move.w 12(a1),d3
4479 add.w d3,d3
4480 move.w (a6,d3.l),d3
4481 ENDC
4482 move.b d3,d1
4483 lsl.l #8,d1 ;xxAABBxx
4484 move.w d3,d2
4485 lsl.l #8,d2 ;aabbxxxx
4486 IFGE __CPU-68020
4487 move.w 20(a1),d3
4488 move.w (a6,d3.l*2),d3
4489 ELSE
4490 moveq #0,d3
4491 move.w 20(a1),d3
4492 add.w d3,d3
4493 move.w (a6,d3.l),d3
4494 ENDC
4495 move.b d3,d1
4496 lsl.l #8,d1 ;AABBCCxx
4497 move.w d3,d2 ;aabbccxx
4499 IFGE __CPU-68020
4500 move.w 28(a1),d3
4501 move.w (a6,d3.l*2),d3
4502 ELSE
4503 moveq #0,d3
4504 move.w 28(a1),d3
4505 add.w d3,d3
4506 move.w (a6,d3.l),d3
4507 ENDC
4508 move.b d3,d1 ;AABBCCDD
4509 lsr.w #8,d3
4510 move.b d3,d2 ;aabbccdd
4512 move.l d1,(a5)+
4513 add.w #32,a1
4514 move.l d2,(a0)+
4516 dbf d0,.loop
4517 pop a6
4518 move.l a0,d2 ;save buffer ptr
4519 move.l a3,d3 ;save buffer ptr
4520 move.l a4,d4 ;save buffer ptr
4521 move.l a5,d5 ;save buffer ptr
4523 CONVERT_POST
4525 lsr.l #1,d0
4526 move.w d0,AUD0LEN(a0)
4527 move.w d0,AUD1LEN(a0)
4528 move.w d0,AUD2LEN(a0)
4529 move.w d0,AUD3LEN(a0)
4530 move.w #DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3,DMACON(a0)
4539 *******************************************************************************
4540 ***** DMA playback routines ***************************************************
4541 *******************************************************************************
4543 ;in:
4544 * a2 AudioCtrl
4545 * a3 paula
4546 * a4 custom
4547 * a5 paulaBase
4548 * a6 ExecBase
4549 ; out:
4550 * d0 AHIsub_Start return code
4552 DMA_Start:
4553 PRINTF 2,"DMA_Start()"
4555 * Allocate DMA buffers
4556 move.l #DMABUFFSAMPLES*8,d0 ; 4 channels, double buffers
4557 move.l #MEMF_CHIP|MEMF_PUBLIC|MEMF_CLEAR,d1
4558 call AllocVec
4559 move.l d0,p_DMAbuffer(a3)
4560 beq .nomem
4562 move.l #DMABUFFSAMPLES,d1
4563 move.l d0,p_AudPtr1A(a3)
4564 add.l d1,d0
4565 move.l d0,p_AudPtr1B(a3)
4566 add.l d1,d0
4567 move.l d0,p_AudPtr2A(a3)
4568 add.l d1,d0
4569 move.l d0,p_AudPtr2B(a3)
4570 add.l d1,d0
4571 move.l d0,p_AudPtr3A(a3)
4572 add.l d1,d0
4573 move.l d0,p_AudPtr3B(a3)
4574 add.l d1,d0
4575 move.l d0,p_AudPtr4A(a3)
4576 add.l d1,d0
4577 move.l d0,p_AudPtr4B(a3)
4579 * Set up audio hardware interrupts
4580 move.l #AudioInterruptDMA,IS_CODE+p_PlayInt(a3)
4581 move.l a3,IS_DATA+p_PlayInt(a3)
4583 lea p_PlayInt(a3),a1
4584 moveq #INTB_AUD0,d0
4585 call SetIntVector
4586 lea p_PlayInt(a3),a1
4587 moveq #INTB_AUD1,d0
4588 call SetIntVector
4589 lea p_PlayInt(a3),a1
4590 moveq #INTB_AUD2,d0
4591 call SetIntVector
4592 lea p_PlayInt(a3),a1
4593 moveq #INTB_AUD3,d0
4594 call SetIntVector
4596 * Use timer.device to clock the PlayerFunc() using a software interrupt/msg port
4598 lea p_TimerPort+MP_MSGLIST(a3),a0
4599 NEWLIST a0
4601 lea p_TimerPort(a3),a0
4602 move.b #NT_MSGPORT,LN_TYPE(a0)
4603 move.b #PA_SOFTINT,MP_FLAGS(a0)
4604 lea p_TimerInt(a3),a1
4605 move.l a1,MP_SIGTASK(a0)
4607 move.b #32,p_TimerInt+LN_PRI(a3) ; Highest priority to keep it steady
4608 lea PlayerFunc(pc),a0
4609 move.l a0,p_TimerInt+IS_CODE(a3)
4610 move.l a3,p_TimerInt+IS_DATA(a3)
4612 lea p_TimerPort(a3),a0
4613 moveq #IOTV_SIZE,d0
4614 call CreateIORequest
4615 move.l d0,p_TimerReq(a3)
4616 beq .notimer
4618 lea timerName(pc),a0
4619 moveq #UNIT_ECLOCK,d0
4620 move.l p_TimerReq(a3),a1
4621 moveq #0,d1
4622 call OpenDevice
4623 move.b d0,p_TimerDev(a3)
4624 bne .notimer
4626 move.l p_TimerReq(a3),a0
4627 move.l IO_DEVICE(a0),pb_TimerLib(a5)
4629 push a6
4630 move.l a5,a6
4631 bsr DMA_Update ;Calc p_EClock/p_EPeriod
4632 pop a6 ;and p_EAlarm
4634 ; Add p_EPeriod to the alarm time
4635 move.l p_EAlarm+EV_LO(a3),d0
4636 move.l p_EAlarm+EV_HI(a3),d1
4637 move.l p_EPeriod(a3),d2
4638 moveq #0,d3
4639 add.l d0,d2
4640 addx.l d1,d3
4641 move.l d2,p_EAlarm+EV_LO(a3)
4642 move.l d3,p_EAlarm+EV_HI(a3)
4644 clr.w p_TimerCommFlag(a3)
4646 move.l p_TimerReq(a3),a1
4647 move.w #TR_ADDREQUEST,IO_COMMAND(a1)
4648 move.l p_EPeriod(a3),IOTV_TIME+EV_LO(a1)
4649 clr.l IOTV_TIME+EV_HI(a1)
4650 bsr BeginIO
4652 call Disable
4653 or.w #INTF_SETCLR|INTF_AUDIO,p_IRQMask(a3)
4654 tst.w p_DisableCount(a3)
4655 bne .dont_enable
4656 move.w #INTF_SETCLR|INTF_AUDIO,INTENA(a4) ;enable all
4657 .dont_enable
4658 move.w #INTF_SETCLR|INTF_AUDIO,INTREQ(a4) ;start all
4659 call Enable
4661 moveq #AHIE_OK,d0
4662 .exit
4665 .notimer
4666 moveq #AHIE_UNKNOWN,d0
4667 bra .exit
4669 .nomem
4670 moveq #AHIE_NOMEM,d0
4671 bra .exit
4674 ;in:
4675 * a2 AudioCtrl
4676 * a3 paula
4677 * a6 paulaBase
4679 DMA_Update:
4680 PRINTF 2,"DMA_Update()"
4681 move.l pb_TimerLib(a6),d0
4682 beq .error
4683 push a6
4684 move.l d0,a6
4685 lea p_EAlarm(a3),a0
4686 call ReadEClock
4687 move.l d0,p_EClock(a3)
4688 pop a6
4690 lsl.l #8,d0
4691 move.l ahiac_PlayerFreq(a2),d1
4692 lsr.l #8,d1
4693 beq .error
4695 IFGE __CPU-68020
4696 divu.l d1,d0
4697 ELSE
4698 move.l pb_UtilLib(a6),a0
4699 jsr _LVOUDivMod32(a0)
4700 ENDIF
4701 move.l d0,p_EPeriod(a3)
4702 .exit
4705 .error
4706 move.l #709379/50,p_EPeriod(a3) ;Approx 50 Hz
4707 bra .exit
4710 ;in:
4711 * a2 AudioCtrl
4712 * a3 paula
4713 * a4 custom
4714 * a5 paulaBase
4715 * a6 ExecBase
4717 DMA_Stop:
4718 PRINTF 2,"DMA_Stop()"
4720 and.w #INTF_AUDIO,p_IRQMask(a3)
4721 move.w #INTF_AUDIO,INTENA(a4)
4722 move.w #DMAF_AUDIO,DMACON(a4) ;Disable DMA
4723 move.w #INTF_AUDIO,INTREQ(a4) ;Clear any waiting interrupts
4725 tst.b p_TimerDev(a3)
4726 bne .notimer
4727 st p_TimerDev(a3)
4729 * Ask timer softint to stop
4731 addq.w #1,p_TimerCommFlag(a3)
4732 .waittimer
4733 tst.w p_TimerCommFlag(a3)
4734 beq .closetimer
4735 move.l pb_DosLib(a5),a6
4736 moveq #1,d1
4737 call Delay
4738 bra .waittimer
4739 .closetimer
4741 clr.l pb_TimerLib(a5)
4743 move.l pb_SysLib(a5),a6
4744 move.l p_TimerReq(a3),a1
4745 call CloseDevice
4746 .notimer
4747 move.l p_TimerReq(a3),a0
4748 clr.l p_TimerReq(a3)
4749 call DeleteIORequest
4751 move.l #Interrupt_Dummy,IS_CODE+p_PlayInt(a3)
4753 lea p_PlayInt(a3),a1
4754 moveq #INTB_AUD0,d0
4755 call SetIntVector
4756 lea p_PlayInt(a3),a1
4757 moveq #INTB_AUD1,d0
4758 call SetIntVector
4759 lea p_PlayInt(a3),a1
4760 moveq #INTB_AUD2,d0
4761 call SetIntVector
4762 lea p_PlayInt(a3),a1
4763 moveq #INTB_AUD3,d0
4764 call SetIntVector
4766 move.l p_DMAbuffer(a3),a1
4767 clr.l p_DMAbuffer(a3)
4768 call FreeVec
4773 ****** [driver].audio/AHIsub_#? *********************************************
4775 * NAME
4776 * AHIsub_SetEffect -- Set effect.
4777 * AHIsub_SetFreq -- Set frequency.
4778 * AHIsub_SetSound -- Set sound.
4779 * AHIsub_SetVol -- Set volume and stereo panning.
4780 * AHIsub_LoadSound -- Prepare a sound for playback.
4781 * AHIsub_UnloadSound -- Discard a sound.
4783 * SYNOPSIS
4784 * See functions in 'ahi.device'.
4786 * IMPLEMENTATION
4787 * If AHIsub_AllocAudio() did not return with bit AHISB_MIXING set,
4788 * all user calls to these function will be routed to the driver.
4790 * If AHIsub_AllocAudio() did return with bit AHISB_MIXING set, the
4791 * calls will first be routed to the driver, and only handled by
4792 * 'ahi.device' if the driver returned AHIS_UNKNOWN. This way it is
4793 * possible to add effects that the sound card handles on its own, like
4794 * filter and echo effects.
4796 * For what each function does, see the autodocs for 'ahi.device'.
4798 * INPUTS
4799 * See functions in 'ahi.device'.
4801 * NOTES
4802 * See functions in 'ahi.device'.
4804 * SEE ALSO
4805 * ahi.device/AHI_SetEffect(), ahi.device/AHI_SetFreq(),
4806 * ahi.device/AHI_SetSound(), ahi.device/AHI_SetVol(),
4807 * ahi.device/AHI_LoadSound(), ahi.device/AHI_UnloadSound()
4810 *****************************************************************************
4815 *****************************************************************************
4816 * Panning is ignored, and negative volume is not supported.
4818 AHIsub_SetVol:
4819 push a3
4820 move.l ahiac_DriverData(a2),a3
4821 btst.b #PB_DMA,p_Flags(a3)
4822 beq AHIsub_NoDMA
4824 mulu.w #channel_SIZEOF,d0
4825 lea p_Channels(a3),a0
4826 add.l d0,a0
4827 asr.l #8,d1
4828 asr.w #2,d1
4829 bpl .plus
4830 neg.w d1
4831 .plus
4832 call AHIsub_Disable
4834 * Store volume and scale according to the master volume
4835 move.w d1,ch_NextVolumeNorm(a0)
4836 move.l p_MasterVolume(a3),d0
4837 cmp.l #$10000,d0
4838 blo .scale1
4839 move.w d1,d0
4840 bra .store1
4841 .scale1
4842 mulu.w d1,d0
4843 swap.w d0
4844 .store1
4845 move.w d0,ch_NextVolume(a0)
4847 btst #AHISB_IMM,d3
4848 beq .noimm
4849 move.w d1,ch_VolumeNorm(a0)
4850 move.l p_MasterVolume(a3),d0
4851 cmp.l #$10000,d0
4852 blo .scale2
4853 move.w d1,d0
4854 bra .store2
4855 .scale2
4856 mulu.w d1,d0
4857 swap.w d0
4858 .store2
4859 move.w d0,ch_Volume(a0)
4860 ; move.l ch_PerVol(a0),ch_AudPerVol(a0)
4861 move.l ch_RegBase(a0),a1
4862 move.w d0,AUDVOL(a1)
4863 .noimm
4865 call AHIsub_Enable
4867 moveq #0,d0 ; Return NULL!
4869 pop a3
4872 *****************************************************************************
4873 * If the frequency is higher than the audio DMA can handle, the samples will
4874 * be decimated before they are played. The frequency will only take effect
4875 * immediately if the decimate factor didn't change, or the new frequency
4876 * was zero. Otherwise, the frequency will change when the current DMA
4877 * block is finished.
4879 AHIsub_SetFreq:
4880 push a3
4881 move.l ahiac_DriverData(a2),a3
4882 btst.b #PB_DMA,p_Flags(a3)
4883 beq AHIsub_NoDMA
4885 PRINTF 2,"AHIsub_SetFreq()"
4886 push d3
4887 mulu.w #channel_SIZEOF,d0
4888 lea p_Channels(a3),a0
4889 add.l d0,a0
4891 cmp.l #AHI_MIXFREQ,d1
4892 bne .normal_freq
4893 move.l ahiac_MixFreq(a2),d1
4894 .normal_freq
4896 move.l #28800,d0
4897 tst.b p_ScreenIsDouble(a3)
4898 beq .1
4899 move.l #48000,d0
4901 moveq #0,d3 ; Decimate/scale (log)
4902 .loop
4903 cmp.l d0,d1
4904 bls .scaled
4905 addq.l #1,d3
4906 lsr.l #1,d1
4907 bra .loop
4908 .scaled
4910 tst.l d1
4911 bne .notnull
4912 moveq #0,d0 ;VVVeeerrryyyy ssslllooowww!!!
4913 moveq #0,d3
4914 bra .gotperiod
4915 .notnull
4917 move.l pb_AudioFreq(a6),d0
4919 IFGE __CPU-68020
4920 divu.l d1,d0
4921 ELSE
4922 move.l pb_UtilLib(a6),a1
4923 jsr _LVOUDivMod32(a1)
4924 ENDIF
4926 .gotperiod
4928 call AHIsub_Disable
4930 move.w d0,ch_NextPeriod(a0)
4931 move.w d3,ch_NextScale(a0)
4933 btst #AHISB_IMM,d2
4934 beq .noimm
4936 ; We must not change the frequency if the scale has changed! (Unless it's 0)
4937 tst.w d3
4938 beq .change
4939 cmp.w ch_Scale(a0),d3
4940 bne .nochange
4941 .change
4942 ; move.l ch_PerVol(a0),ch_AudPerVol(a0)
4943 move.l ch_RegBase(a0),a1
4944 move.w d0,AUDPER(a1)
4945 .nochange
4947 ; Force an interrupt if the channel was paused
4948 tst.w ch_Period(a0)
4949 bne .notzero
4950 tst.b ch_NoInt(a0)
4951 bne .noint
4952 lea custom,a1
4953 move.w ch_IntMask(a0),d1
4954 or.w #INTF_SETCLR,d1
4955 move.w d1,INTREQ(a1)
4956 .noint
4957 .notzero
4959 move.w d0,ch_Period(a0)
4960 move.w d3,ch_Scale(a0)
4962 .noimm
4964 call AHIsub_Enable
4966 moveq #0,d0 ; Return NULL!
4967 pop d3
4969 pop a3
4972 *****************************************************************************
4974 AHIsub_SetSound:
4975 push a3
4976 move.l ahiac_DriverData(a2),a3
4977 btst.b #PB_DMA,p_Flags(a3)
4978 beq AHIsub_NoDMA
4980 PRINTF 2,"AHIsub_SetSound()"
4981 pushm d2-d5
4983 mulu.w #channel_SIZEOF,d0
4984 lea p_Channels(a3),a0
4985 add.l d0,a0
4987 cmp.w #AHI_NOSOUND,d1
4988 bne .sound_ok
4989 moveq #0,d2
4990 moveq #0,d3
4991 moveq #AHIST_NOTYPE,d5
4992 bra .update_channel
4993 .sound_ok
4995 mulu.w #sound_SIZEOF,d1
4996 move.l p_Sounds(a3),a1
4997 add.l d1,a1
4999 tst.l d3
5000 bne .length_ok
5001 move.l so_Length(a1),d3
5002 .length_ok
5003 move.l so_Type(a1),d5
5005 .update_channel
5007 tst.l d3
5008 bpl .positive_length
5009 neg.l d3 ; Make positive
5010 or.l #AHIST_BW,d5 ; Mark type as backward-playing
5011 .positive_length
5013 ; PRINTF 0,"New sample! %08lx, %ld, %08lx", d2,d3,d5
5015 call AHIsub_Disable
5017 move.l so_Address(a1),ch_NextAddress(a0)
5018 move.l d2,ch_NextOffset(a0)
5019 move.l d3,ch_NextLength(a0)
5020 move.l d5,ch_NextType(a0)
5023 btst #AHISB_IMM,d4
5024 beq .noimm
5026 move.l so_Address(a1),ch_Address(a0)
5027 move.l d2,ch_Offset(a0)
5028 move.l d3,ch_Length(a0)
5029 move.l d5,ch_Type(a0)
5030 clr.l ch_Count(a0)
5031 st.b ch_EndOfSample(a0) ; Call SoundFunc()
5033 lea custom,a1
5035 ; Clear pending interrupt (if there was one)
5036 st.b ch_NoInt(a0)
5037 move.w ch_IntMask(a0),INTREQ(a1)
5039 ; Stop this channel
5040 move.w ch_DMAMask(a0),DMACON(a1)
5042 ; Wait for Agnus/Alice to understand
5043 push a6
5044 move.l pb_SysLib(a6),a6
5045 call Disable
5047 move.b VHPOSR(a1),d0
5048 .vert
5049 cmp.b VHPOSR(a1),d0
5050 beq .vert
5051 .hori
5052 cmp.b #20,VHPOSR+1(a1)
5053 blt .hori
5055 call Enable
5056 pop a6
5058 ; When the period reaches 0, Paula will invoke our interrupt routine!
5060 ; Now just make sure that we receive no more than 1 interrupt.
5061 move.l ch_RegBase(a0),a1
5062 move.w #1,AUDPER(a1)
5063 .noimm
5065 call AHIsub_Enable
5067 moveq #0,d0 ; Return NULL!
5068 popm d2-d5
5070 pop a3
5073 *****************************************************************************
5075 AHIsub_SetEffect:
5076 push a3
5077 move.l ahiac_DriverData(a2),a3
5078 btst.b #PB_DMA,p_Flags(a3)
5079 beq AHIsub_NoDMA
5081 PRINTF 2,"AHIsub_SetEffect()"
5082 move.l ahie_Effect(a0),d0
5083 cmp.l #AHIET_MASTERVOLUME,d0
5084 beq .mastervolume
5085 cmp.l #AHIET_CANCEL|AHIET_MASTERVOLUME,d0
5086 beq .mastervolume_off
5087 cmp.l #AHIET_CHANNELINFO,d0
5088 beq .channelinfo
5089 cmp.l #AHIET_CANCEL|AHIET_CHANNELINFO,d0
5090 beq .channelinfo_off
5092 moveq #AHIE_UNKNOWN,d0 ; Return error code!
5093 .exit
5094 pop a3
5097 .mastervolume
5098 move.l ahiemv_Volume(a0),d0
5099 .mastervolume_update
5100 move.l d0,p_MasterVolume(a3)
5102 lea p_Channels(a3),a0
5103 moveq #3,d1
5104 .mastervolume_loop
5105 move.l p_MasterVolume(a3),d0
5106 cmp.l #$10000,d0
5107 blo .mastervolume_scale1
5108 move.w ch_NextVolumeNorm(a0),d0
5109 bra .mastervolume_store1
5110 .mastervolume_scale1
5111 mulu.w ch_NextVolumeNorm(a0),d0
5112 swap.w d0
5113 .mastervolume_store1
5114 move.w d0,ch_NextVolume(a0)
5115 move.l p_MasterVolume(a3),d0
5116 cmp.l #$10000,d0
5117 blo .mastervolume_scale2
5118 move.w ch_VolumeNorm(a0),d0
5119 bra .mastervolume_store2
5120 .mastervolume_scale2
5121 mulu.w ch_VolumeNorm(a0),d0
5122 swap.w d0
5123 .mastervolume_store2
5124 move.w d0,ch_Volume(a0)
5125 ; move.l ch_PerVol(a0),ch_AudPerVol(a0)
5126 move.l ch_RegBase(a0),a1
5127 move.w d0,AUDVOL(a1)
5129 add.w #channel_SIZEOF,a0
5130 dbf d1,.mastervolume_loop
5132 moveq #AHIE_OK,d0
5133 bra .exit
5135 .mastervolume_off
5136 move.l #$10000,d0
5137 bra .mastervolume_update
5140 .channelinfo
5141 move.l a0,p_ChannelInfo(a3)
5142 moveq #AHIE_OK,d0
5143 bra .exit
5145 .channelinfo_off
5146 clr.l p_ChannelInfo(a3)
5147 moveq #AHIE_OK,d0
5148 bra .exit
5151 *****************************************************************************
5153 AHIsub_LoadSound:
5154 push a3
5155 move.l ahiac_DriverData(a2),a3
5156 btst.b #PB_DMA,p_Flags(a3)
5157 beq AHIsub_NoDMA
5159 PRINTF 2,"AHIsub_LoadSound()"
5160 cmp.l #AHIST_SAMPLE,d1
5161 beq .soundok
5162 cmp.l #AHIST_DYNAMICSAMPLE,d1
5163 bne .unknownsound
5164 .soundok
5165 mulu.w #sound_SIZEOF,d0
5166 move.l p_Sounds(a3),a1
5167 add.l d0,a1
5169 move.l ahisi_Type(a0),d0
5170 cmp.l #AHIST_M8S,d0
5171 beq .sampleok
5172 cmp.l #AHIST_M16S,d0
5173 beq .sampleok
5174 cmp.l #AHIST_S8S,d0
5175 beq .sampleok
5176 cmp.l #AHIST_S16S,d0
5177 bne .unknownsample
5178 .sampleok
5179 move.l d0,so_Type(a1)
5180 move.l ahisi_Address(a0),so_Address(a1)
5181 move.l ahisi_Length(a0),so_Length(a1)
5183 moveq #AHIE_OK,d0
5184 .exit
5186 pop a3
5189 .unknownsound
5190 moveq #AHIE_BADSOUNDTYPE,d0
5191 bra .exit
5192 .unknownsample
5193 moveq #AHIE_BADSAMPLETYPE,d0
5194 bra .exit
5196 *****************************************************************************
5198 AHIsub_UnloadSound:
5199 push a3
5200 move.l ahiac_DriverData(a2),a3
5201 btst.b #PB_DMA,p_Flags(a3)
5202 beq AHIsub_NoDMA
5204 PRINTF 2,"AHIsub_UnloadSound()"
5205 mulu.w #sound_SIZEOF,d0
5206 move.l p_Sounds(a3),a1
5207 add.l d0,a1
5208 move.l #AHIST_NOTYPE,so_Type(a1)
5209 clr.l so_Address(a1)
5210 clr.l so_Length(a1)
5212 moveq #0,d0 ; Return NULL!
5214 pop a3
5217 *****************************************************************************
5219 AHIsub_NoDMA:
5220 moveq #AHIS_UNKNOWN,d0 ; Return AHIS_UNKNOWN!
5221 pop a3
5224 *****************************************************************************
5226 ;in:
5227 * a1 struct paula *
5229 PlayerFunc:
5230 pushm std
5232 move.l a1,a3
5233 move.l p_AudioCtrl(a3),a2
5235 move.l p_PaulaBase(a3),a6
5236 move.l pb_SysLib(a6),a6
5237 lea p_TimerPort(a3),a0
5238 call GetMsg ; Remove message
5240 tst.w p_TimerCommFlag(a3)
5241 beq .normal
5243 clr.w p_TimerCommFlag(a3)
5244 bra .exit
5246 .normal
5247 ; Add p_EPeriod to the alarm time
5248 move.l p_EAlarm+EV_LO(a3),d0
5249 move.l p_EAlarm+EV_HI(a3),d1
5250 move.l p_EPeriod(a3),d2
5251 moveq #0,d3
5252 add.l d0,d2
5253 addx.l d1,d3
5254 move.l d2,p_EAlarm+EV_LO(a3)
5255 move.l d3,p_EAlarm+EV_HI(a3)
5257 ; Get current time
5258 push a6
5259 move.l p_PaulaBase(a3),a0
5260 move.l pb_TimerLib(a0),a6
5261 subq.l #8,sp
5262 move.l sp,a0
5263 call ReadEClock
5264 move.l EV_LO(sp),d0 ; Current time
5265 move.l EV_HI(sp),d1
5266 sub.l d0,d2 ; Calculate difference (Alarm - Current)
5267 subx.l d1,d3
5268 addq.l #8,sp
5269 pop a6
5271 tst.l d3
5272 bpl .positive
5273 moveq #1,d2
5274 moveq #0,d3 ; Rather small delay...
5275 .positive
5277 ; PRINTF 0,"Delay: %08ld%08ld",d3,d2
5278 move.l p_TimerReq(a3),a1
5279 move.w #TR_ADDREQUEST,IO_COMMAND(a1)
5280 move.l d2,IOTV_TIME+EV_LO(a1)
5281 move.l d3,IOTV_TIME+EV_HI(a1)
5282 bsr BeginIO
5284 move.l p_PaulaBase(a3),a6
5285 call AHIsub_Disable
5287 ; Handle the ChannelInfo effect
5289 move.l p_ChannelInfo(a3),d0
5290 beq .nochannelinfo
5291 move.l d0,a0
5292 lea ahieci_Offset(a0),a1
5293 move.w ahieci_Channels(a0),d0
5294 subq.w #1,d0
5295 bmi .nochannelinfo
5296 lea p_Channels(a3),a4
5297 .loop
5298 move.l ch_Offset(a4),(a1)+
5299 add.w #channel_SIZEOF,a4
5300 dbf d0,.loop
5302 move.l p_ChannelInfo(a3),a1
5303 move.l ahieci_Func(a1),d0
5304 beq .nochannelinfo
5305 move.l d0,a0
5306 move.l h_Entry(a0),a4
5307 jsr (a4)
5309 ; lea p_Channels(a3),a4
5310 ; PRINTF 0,"CI: %ld, %ld, %ld, %ld",ch_Offset(a4),ch_Offset+channel_SIZEOF(a4),ch_Offset+channel_SIZEOF*2(a4),ch_Offset+channel_SIZEOF*3(a4)
5311 .nochannelinfo
5313 ; Call the PlayerFunc()
5315 move.l ahiac_PlayerFunc(a2),d0
5316 move.l d0,a0
5317 beq .noplayerfunc
5318 sub.l a1,a1 ; IMPORTANT!
5319 move.l h_Entry(a0),a4
5320 PRINTF 8,"Calling PlayerFunc(%08lx,%08lx,%08lx)",a0,a2,a1
5321 jsr (a4)
5322 .noplayerfunc
5324 call AHIsub_Enable
5326 .exit
5327 moveq #0,d0
5328 popm std
5331 *****************************************************************************
5333 ;in:
5334 * d0 scratch
5335 * d1.w INTENAR & INTREQR
5336 * a0 custom
5337 * a1 struct paula *
5338 * a5 &AudioInterruptDMA
5339 * a6 ExecBase
5341 AudioInterruptDMA:
5342 pushm std
5344 PRINTF 3,"."
5345 PRINTF 6,"AudioInterruptDMA"
5347 move.l p_AudioCtrl(a1),a4
5348 lea p_Channels(a1),a5
5349 lea p_AudPtr1A(a1),a6
5350 move.w d1,d7
5352 move.w ch_IntMask(a5),d0
5353 and.w d7,d0
5354 beq .not0
5356 move.l ch_RegBase(a5),a0
5357 move.l ch_PerVol(a5),AUDPERVOL(a0)
5358 ; move.l ch_AudPerVol(a5),AUDPERVOL(a0)
5359 ; move.l ch_PerVol(a5),ch_AudPerVol(a5)
5361 bsr DMA_HandleInt
5363 move.w ch_IntMask(a5),custom+INTREQ ; Clear the interrupt
5364 move.l ch_RegBase(a5),a0
5365 move.l (a6),AUDLC(a0)
5366 move.w ch_DMALength(a5),AUDLEN(a0)
5368 clr.b ch_NoInt(a5)
5369 .not0
5371 add.w #channel_SIZEOF,a5
5372 addq.l #8,a6
5374 move.w ch_IntMask(a5),d0
5375 and.w d7,d0
5376 beq .not1
5378 move.l ch_RegBase(a5),a0
5379 move.l ch_PerVol(a5),AUDPERVOL(a0)
5380 ; move.l ch_AudPerVol(a5),AUDPERVOL(a0)
5381 ; move.l ch_PerVol(a5),ch_AudPerVol(a5)
5383 bsr DMA_HandleInt
5385 move.w ch_IntMask(a5),custom+INTREQ ; Clear the interrupt
5386 move.l ch_RegBase(a5),a0
5387 move.l (a6),AUDLC(a0)
5388 move.w ch_DMALength(a5),AUDLEN(a0)
5390 clr.b ch_NoInt(a5)
5391 .not1
5393 add.w #channel_SIZEOF,a5
5394 addq.l #8,a6
5396 move.w ch_IntMask(a5),d0
5397 and.w d7,d0
5398 beq .not2
5400 move.l ch_RegBase(a5),a0
5401 move.l ch_PerVol(a5),AUDPERVOL(a0)
5402 ; move.l ch_AudPerVol(a5),AUDPERVOL(a0)
5403 ; move.l ch_PerVol(a5),ch_AudPerVol(a5)
5405 bsr DMA_HandleInt
5407 move.w ch_IntMask(a5),custom+INTREQ ; Clear the interrupt
5408 move.l ch_RegBase(a5),a0
5409 move.l (a6),AUDLC(a0)
5410 move.w ch_DMALength(a5),AUDLEN(a0)
5412 clr.b ch_NoInt(a5)
5413 .not2
5415 add.w #channel_SIZEOF,a5
5416 addq.l #8,a6
5418 move.w ch_IntMask(a5),d0
5419 and.w d7,d0
5420 beq .not3
5422 move.l ch_RegBase(a5),a0
5423 move.l ch_PerVol(a5),AUDPERVOL(a0)
5424 ; move.l ch_AudPerVol(a5),AUDPERVOL(a0)
5425 ; move.l ch_PerVol(a5),ch_AudPerVol(a5)
5427 bsr DMA_HandleInt
5429 move.w ch_IntMask(a5),custom+INTREQ ; Clear the interrupt
5430 move.l ch_RegBase(a5),a0
5431 move.l (a6),AUDLC(a0)
5432 move.w ch_DMALength(a5),AUDLEN(a0)
5434 clr.b ch_NoInt(a5)
5435 .not3
5437 .exit
5438 lea custom,a0
5439 move.w #DMAF_SETCLR|DMAF_AUDIO,DMACON(a0) ; Enable DMA
5440 ; move.w #INTF_AUDIO,INTREQ(a0) ; Clear the interrupts
5442 popm std
5444 * d0-d6 scratch
5445 * a0-a3 scratch
5446 * a4 AHIAudioCtrlDrv
5447 * a5 struct channel *
5448 * a6 BYTE **buffer[2]
5449 DMA_HandleInt:
5451 * Check if the next set of parameters should be fetced
5453 cmp.l #AHIST_NOTYPE,ch_Type(a5)
5454 beq .check_eos
5455 tst.b ch_EndOfSample(a5) ; Already set?
5456 bne .check_eos
5457 move.l ch_Count(a5),d0
5458 beq .check_eos
5459 move.l ch_Length(a5),d1
5460 and.l #~1,d1 ; Force even
5461 cmp.l d1,d0
5462 blo .check_eos
5464 .load_next
5465 move.l ch_NextAddress(a5),ch_Address(a5)
5466 move.l ch_NextLength(a5),ch_Length(a5)
5467 move.l ch_NextType(a5),ch_Type(a5)
5468 move.l ch_NextPerVol(a5),ch_PerVol(a5)
5469 move.w ch_NextScale(a5),ch_Scale(a5)
5470 move.l ch_NextOffset(a5),ch_Offset(a5)
5471 clr.l ch_Count(a5)
5473 PRINTF 4,"New sound! %08lx, Length: %ld, Type: %08lx, PerVol: %08lx",ch_Address(a5),ch_Length(a5),ch_Type(a5),ch_PerVol(a5)
5475 ; Signal that SoundFunc() should be called
5476 st.b ch_EndOfSample(a5)
5479 * Check if SoundFunc() should be called
5480 .check_eos
5481 tst.b ch_EndOfSample(a5)
5482 beq .not_eos
5483 clr.b ch_EndOfSample(a5) ; Clear signal
5485 ; Call the SoundFunc()
5486 move.l ahiac_SoundFunc(a4),d0
5487 move.l d0,a0
5488 beq .nosoundfunc
5489 lea ch_SndMsg(a5),a1
5490 move.l a4,a2
5491 move.l h_Entry(a0),a3
5492 moveq #0,d0
5493 move.w ahism_Channel(a1),d0
5494 PRINTF 4,"Calling SoundFunc(%08lx,%08lx,%ld)",a0,a2,d0
5495 jsr (a3)
5496 .nosoundfunc
5497 .not_eos
5499 * Swap chipmem buffers
5500 move.l 4(a6),a1
5501 move.l (a6),4(a6)
5502 move.l a1,(a6)
5503 * Swap cleared indicators
5504 move.l ch_Cleared2(a5),d0
5505 move.l ch_Cleared(a5),ch_Cleared2(a5)
5506 move.l d0,ch_Cleared(a5)
5508 move.l ch_Address(a5),a2
5509 moveq #0,d2
5510 move.w ch_Scale(a5),d2
5512 move.l ch_Length(a5),d0
5513 move.l ch_Count(a5),d1
5515 * Calculate the number of samples to transfer (this is source samples, which is
5516 * a multiple of the destination samples if ch_Scale != 0.
5518 sub.l d1,d0
5519 ble .endofsample ; <= 0 ?
5520 tst.w ch_Period(a5)
5521 bne .normallength
5522 .endofsample
5523 * We have either already reached the end of the sample, or it's paused.
5524 * Set the length to DMABUFFSAMPLES and scale to 0. (I.e., clear the whole
5525 * chipmem buffer.) Do NOT increase ch_Offset/ch_Count!
5526 move.l #DMABUFFSAMPLES,d0
5527 moveq #0,d2
5528 bra .set_dmalength
5529 .normallength
5531 ; samples = max(samples, DMABUFFSAMPLES*(2^scale))
5532 move.l #DMABUFFSAMPLES,d3
5533 lsl.l d2,d3
5534 cmp.l d3,d0
5535 blo .1
5536 move.l d3,d0
5538 add.l d0,ch_Count(a5)
5540 * Get current ch_Offset
5541 move.l ch_Offset(a5),d1
5543 * Update the ch_Offset
5544 move.l ch_Type(a5),d3
5545 and.l #AHIST_BW,d3
5546 beq .2
5547 sub.l d0,ch_Offset(a5)
5548 skipl
5550 add.l d0,ch_Offset(a5)
5552 .set_dmalength
5553 lsr.l d2,d0 ; Calc. destination samples
5554 move.l d0,d3
5555 lsr.l #1,d3 ; # of words, round to lower
5556 move.w d3,ch_DMALength(a5)
5558 move.l d2,d3 ;Convert ²log scale...
5559 moveq #0,d2
5560 bset d3,d2 ;...to linear
5562 move.l ch_Type(a5),d3
5564 * If the period is 0, this sample is paused => clear the buffer
5565 * If type == AHIST_NOTYPE, clear the buffer
5566 tst.w ch_Period(a5)
5567 beq .clearsample
5568 cmp.l #AHIST_NOTYPE,d3
5569 bne .istype
5571 .clearsample
5573 * Alright, we should play silence. But before the dma buffer is filled with
5574 * zeroes, check if we already have cleared it. In that case, there is no need
5575 * to do that again (chipmem accesses are expensive!).
5576 cmp.l ch_Cleared(a5),d0
5577 bls .filled ; Skip it!
5578 move.l d0,ch_Cleared(a5)
5579 lea ClearSample(pc),a3
5580 bra .fill
5581 .istype
5583 * It was a normal sample. Figure out which transfer routine to use etc.
5584 clr.l ch_Cleared(a5) ; Mark buffer as un-cleared
5585 move.l d3,d4
5586 and.l #AHIST_BW,d4
5587 beq .forwardsample
5588 neg.l d2
5589 .forwardsample
5590 and.l #~AHIST_BW,d3 ; Mask fwd/bwd bit
5591 cmp.l #AHIST_S16S,d3
5592 bhi .error ; Sanity check!
5593 lsl.l #2,d3
5594 move.l jmpt(pc,d3.l),a3
5595 .fill
5596 jsr (a3)
5597 .filled
5598 .exit
5601 * This should never happen...
5602 .error
5603 PRINTF 2,"Illegal type! %08lx",d3
5606 jmpt:
5607 dc.l CopySampleM8S
5608 dc.l CopySampleM16S
5609 dc.l CopySampleS8S
5610 dc.l CopySampleS16S
5612 ;in:
5613 * d0 Samples to copy
5614 * d1 Source offset
5615 * d2 Decimate/Scale (not log, but linear, can be negative)
5616 * a1 Destination
5617 * a2 Source
5618 * a5 Channel
5620 ClearSample:
5621 PRINTF 6,"ClearSample %08lx, %ld, %ld",a1,d0,d1
5622 addq.l #3,d0
5623 lsr.l #2,d0 ;Unrolled
5624 subq.l #1,d0
5625 bmi .exit
5626 .loop
5627 clr.l (a1)+
5628 dbf d0,.loop
5629 .exit
5633 CopySampleM8S:
5634 PRINTF 6,"CopySampleM8S %08lx, %ld, %ld",a1,d0,d1
5635 addq.l #3,d0
5636 lsr.l #2,d0 ;Unrolled
5637 subq.l #1,d0
5638 bmi CopySampleExit
5639 add.l d1,a2
5640 cmp.w #0,a2
5641 bne CopySample
5642 bra CopySampleError
5644 CopySampleM16S:
5645 PRINTF 6,"CopySampleM16S %08lx, %ld, %ld",a1,d0,d1
5646 lsl.l #1,d1 ; 16 bits/sample
5647 lsl.l #1,d2 ; 16 bits/sample
5648 addq.l #3,d0
5649 lsr.l #2,d0 ;Unrolled
5650 subq.l #1,d0
5651 bmi CopySampleExit
5652 add.l d1,a2
5653 cmp.w #0,a2
5654 bne CopySample
5655 bra CopySampleError
5657 CopySampleS8S:
5658 PRINTF 6,"CopySampleS8S %08lx, %ld, %ld",a1,d0,d1
5659 lsl.l #1,d1 ; 16 bits/sample frame
5660 lsl.l #1,d2 ; 16 bits/sample frame
5661 addq.l #3,d0
5662 lsr.l #2,d0 ;Unrolled
5663 subq.l #1,d0
5664 bmi CopySampleExit
5665 add.l d1,a2
5666 cmp.w #0,a2
5667 beq CopySampleError
5668 add.w ch_Stereo(a5),a2
5669 bra CopySample
5671 CopySampleS16S:
5672 PRINTF 6,"CopySampleS16S %08lx, %ld, %ld",a1,d0,d1
5673 lsl.l #2,d1 ; 32 bits/sample frame
5674 lsl.l #2,d2 ; 32 bits/sample frame
5675 addq.l #3,d0
5676 lsr.l #2,d0 ;Unrolled
5677 subq.l #1,d0
5678 bmi CopySampleExit
5679 add.l d1,a2
5680 cmp.w #0,a2
5681 beq CopySampleError
5682 add.w ch_Stereo(a5),a2
5683 add.w ch_Stereo(a5),a2
5684 bra CopySample
5686 CopySampleExit:
5689 CopySampleError
5690 PRINTF 2,"CopySampleError"
5691 bra CopySampleExit
5693 * Collect 4 samples and write a full longword to the chipmem buffer
5694 CopySample:
5695 .loop
5696 move.b (a2),d3
5697 add.l d2,a2
5698 lsl.l #8,d3
5699 move.b (a2),d3
5700 add.l d2,a2
5701 lsl.l #8,d3
5702 move.b (a2),d3
5703 add.l d2,a2
5704 lsl.l #8,d3
5705 move.b (a2),d3
5706 add.l d2,a2
5707 move.l d3,(a1)+
5708 dbf d0,.loop
5710 EndCode: