2 AHI - Hardware independent audio subsystem
3 Copyright (C) 2017 The AROS Dev Team
4 Copyright (C) 1996-2005 Martin Blom <martin@blom.org>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with this library; if not, write to the
18 Free Software Foundation, Inc., 59 Temple Place - Suite 330, Cambridge,
24 #include <exec/alerts.h>
25 #include <exec/errors.h>
26 #include <exec/tasks.h>
28 #include <exec/devices.h>
29 #include <exec/memory.h>
31 #include <dos/dostags.h>
32 #include <libraries/iffparse.h>
33 #include <prefs/prefhdr.h>
35 #include <clib/alib_protos.h>
36 #include <proto/exec.h>
37 #include <proto/dos.h>
38 #include <proto/iffparse.h>
40 #define __NOGLOBALIFACE__
41 #include <proto/ahi.h>
43 #undef __NOGLOBALIFACE__
44 #include <proto/ahi_sub.h>
51 #include "devcommands.h"
63 ** Message passed to the Unit Process at
70 struct AHIDevUnit
*Unit
;
75 AHIDevUnit
*InitUnit( ULONG
, struct AHIBase
* );
78 ExpungeUnit( struct AHIDevUnit
*, struct AHIBase
* );
81 PlayerFunc( struct Hook
* hook
,
82 struct AHIAudioCtrl
* actrl
,
87 RecordFunc( struct Hook
* hook
,
88 struct AHIAudioCtrl
* actrl
,
89 struct AHIRecordMessage
* recmsg
);
93 SoundFunc( struct Hook
* hook
,
94 struct AHIAudioCtrl
* actrl
,
95 struct AHISoundMessage
* sndmsg
);
99 ChannelInfoFunc( struct Hook
* hook
,
100 struct AHIAudioCtrl
* actrl
,
101 struct AHIEffChannelInfo
* cimsg
);
104 /***** ahi.device/--background-- *******************************************
108 * The 'ahi.device' was first created because the lack of standards
109 * when it comes to sound cards on the Amiga. Another reason was to
110 * make it easier to write multi-channel music programs.
112 * This device is by no means the final and perfect solution. But
113 * hopefully, it can evolve into something useful until AT brings you
114 * The Real Thing (TM).
118 * Please see the document "AHI Developer's Guide" for more
124 * Each supported sound card is controlled by a library-based audio
125 * driver. For a 'dumb' sound card, a new driver could be written in
126 * a few hours. For a 'smart' sound card, it is possible to utilize an
127 * on-board DSP, for example, to maximize performance and sound quality.
128 * For sound cards with own DSP but little or no memory, it is possible
129 * to use the main CPU to mix channels and do the post-processing
130 * with the DSP. Drivers are available for most popular sound cards,
131 * as well as an 8SVX (mono) and AIFF/AIFC (mono & stereo) sample render
134 * * Fast, powerful mixing routines (yeah, right... haha)
136 * The device's mixing routines mix 8- or 16-bit signed samples,
137 * both mono, stereo and 7.1, located in Fast-RAM and outputs
138 * 16-bit mono or stereo (with stereo panning if desired) data,
139 * using any number of channels (as long as 'any' means less than
140 * 128). Tables can be used speed the mixing up (especially when
141 * using 8-bit samples). The samples can have any length
142 * (including odd) and can have any number of loops. There are
143 * also so-called HiFi mixing routines that can be used, that use
144 * linear interpolation and gives 32 bit output.
146 * * Support for non-realtime mixing
148 * By providing a timing feature, it is possible to create high-
149 * quality output even if the processing power is lacking, by saving
150 * the output to disk, for example as an IFF AIFF or 8SXV file.
154 * Uses ID codes, much like Screenmode IDs, to select the many
155 * parameters that can be set. The functions to access the audio
156 * database are not too different from those in 'graphics.library'.
157 * The device also features a requester to get an ID code from the
160 * * Both high- and low-level protocol
162 * By acting both like a device and a library, AHI gives the programmer
163 * a choice between full control and simplicity. The device API allows
164 * several programs to use the audio hardware at the same time, and
165 * the AUDIO: dos-device driver makes playing and recording sound very
166 * simple for both the programmer and user.
168 * * Future Compatible
170 * When AmigaOS gets device-independent audio worth it's name, it should
171 * not be too difficult to write a driver for AHI, allowing applications
172 * using 'ahi.device' to automatically use the new OS interface. At
173 * least I hope it wont.
176 ****************************************************************************
181 /******************************************************************************
182 ** DevOpen ********************************************************************
183 ******************************************************************************/
185 /****** ahi.device/OpenDevice **********************************************
188 * OpenDevice -- Open the device
191 * error = OpenDevice(AHINAME, unit, ioRequest, flags)
194 * BYTE OpenDevice(STRPTR, ULONG, struct AHIRequest *, ULONG);
197 * This is an exec call. Exec will search for the ahi.device, and
198 * if found, will pass this call on to the device.
201 * AHINAME - pointer to the string "ahi.device".
202 * unit - Either AHI_DEFAULT_UNIT (0), AHI_NO_UNIT (255) or any other
203 * unit the user has requested, for example with a UNIT tooltype.
204 * AHI_NO_UNIT should be used when you're using the low-level
206 * ioRequest - a pointer to a struct AHIRequest, initialized by
207 * exec.library/CreateIORequest(). ahir_Version *must* be preset
208 * to the version you need!
209 * flags - There is only one flag defined, AHIDF_NOMODESCAN, which
210 * asks ahi.device not to build the audio mode database if not
211 * already initialized. It should not be used by applications
212 * without good reasons (AddAudioModes uses this flag).
215 * error - Same as io_Error.
216 * io_Error - If the call succeeded, io_Error will be 0, else
217 * an error code as defined in <exec/errors.h> and
219 * io_Device - A pointer to the device base, which can be used
220 * to call the functions the device provides.
229 * CloseDevice(), exec.library/OpenDevice(), <exec/errors.h>,
232 ****************************************************************************
236 // This function is called by the system each time a unit is opened with
237 // exec.library/OpenDevice().
240 _DevOpen ( struct AHIRequest
* ioreq
,
243 struct AHIBase
* AHIBase
)
247 struct AHIDevUnit
*iounit
=NULL
;
249 ahibug("[AHI:Device] %s()\n", __func__
);
251 if(AHIBase
->ahib_DebugLevel
>= AHI_DEBUG_LOW
)
253 KPrintF("OpenDevice(%ld, 0x%p, %ld)", unit
, (IPTR
)ioreq
, flags
);
256 // Check if size includes the ahir_Version field
258 if(ioreq
->ahir_Std
.io_Message
.mn_Length
< (sizeof(struct IOStdReq
) + 2))
260 Req( "Bad parameters to OpenDevice()." );
261 ioreq
->ahir_Std
.io_Error
=IOERR_OPENFAIL
;
262 return IOERR_OPENFAIL
;
267 if((unit
!= AHI_NO_UNIT
) && (ioreq
->ahir_Version
>= 4))
269 if(ioreq
->ahir_Std
.io_Message
.mn_Length
< sizeof(struct AHIRequest
))
271 Req( "Bad parameters to OpenDevice()." );
272 ioreq
->ahir_Std
.io_Error
=IOERR_OPENFAIL
;
273 return IOERR_OPENFAIL
;
277 /* KPrintF( "Tagging %08lx on task %08lx\n", ioreq, FindTask(0)); */
278 ioreq
->ahir_Private
[1] = (IPTR
) ioreq
;
282 AHIBase
->ahib_Library
.lib_OpenCnt
++;
284 ObtainSemaphore(&AHIBase
->ahib_Lock
);
286 if( ! (flags
& AHIDF_NOMODESCAN
))
288 // Load database if not already loaded
290 if(AHI_NextAudioID(AHI_INVALID_ID
) == (IPTR
) AHI_INVALID_ID
)
292 AHI_LoadModeFile("DEVS:AudioModes");
294 // Be quiet here. - Piru
297 APTR
*windowptr
= &((struct Process
*) FindTask(NULL
))->pr_WindowPtr
;
298 APTR oldwindowptr
= *windowptr
;
299 *windowptr
= (APTR
) -1;
301 AHI_LoadModeFile("MOSSYS:DEVS/AudioModes");
303 *windowptr
= oldwindowptr
;
306 // Load Void driver if no real hardware was found
308 if(AHI_NextAudioID(AHI_INVALID_ID
) == (IPTR
) AHI_INVALID_ID
)
310 AHI_LoadModeFile("SYS:Storage/AudioModes/VOID");
315 if( ioreq
->ahir_Version
> AHIBase
->ahib_Library
.lib_Version
)
321 iounit
=InitUnit(unit
,AHIBase
);
325 else if(unit
== AHI_NO_UNIT
)
326 InitUnit(unit
,AHIBase
);
331 ioreq
->ahir_Std
.io_Unit
=(struct Unit
*) iounit
;
332 if(iounit
) // Is NULL for AHI_NO_UNIT
333 iounit
->Unit
.unit_OpenCnt
++;
334 AHIBase
->ahib_Library
.lib_OpenCnt
++;
335 AHIBase
->ahib_Library
.lib_Flags
&=~LIBF_DELEXP
;
340 ioreq
->ahir_Std
.io_Error
=IOERR_OPENFAIL
;
341 ioreq
->ahir_Std
.io_Device
=(struct Device
*) -1;
342 ioreq
->ahir_Std
.io_Unit
=(struct Unit
*) -1;
345 ReleaseSemaphore(&AHIBase
->ahib_Lock
);
347 AHIBase
->ahib_Library
.lib_OpenCnt
--;
349 if(AHIBase
->ahib_DebugLevel
>= AHI_DEBUG_LOW
)
351 KPrintF("=>%ld\n",rc
);
358 /******************************************************************************
359 ** DevClose *******************************************************************
360 ******************************************************************************/
362 /****** ahi.device/CloseDevice *********************************************
365 * CloseDevice -- Close the device
368 * CloseDevice(ioRequest)
371 * void CloseDevice(struct IORequest *);
374 * This is an exec call that closes the device. Every OpenDevice()
375 * must be matched with a call to CloseDevice().
377 * The user must ensure that all outstanding IO Requests have been
378 * returned before closing the device.
381 * ioRequest - a pointer to the same struct AHIRequest that was used
382 * to open the device.
393 * OpenDevice(), exec.library/CloseDevice()
395 ****************************************************************************
399 // This function is called by the system each time a unit is closed with
400 // exec.library/CloseDevice().
403 _DevClose ( struct AHIRequest
* ioreq
,
404 struct AHIBase
* AHIBase
)
406 struct AHIDevUnit
*iounit
;
409 ahibug("[AHI:Device] %s()\n", __func__
);
411 if(AHIBase
->ahib_DebugLevel
>= AHI_DEBUG_LOW
)
413 KPrintF("CloseDevice(0x%P)\n", (IPTR
)ioreq
);
415 if( ioreq
->ahir_Private
[1] != (IPTR
) ioreq
)
417 KPrintF( "Warning: Expected I/O request 0x%P.\n",
418 ioreq
->ahir_Private
[1] );
422 ObtainSemaphore(&AHIBase
->ahib_Lock
);
424 iounit
= (struct AHIDevUnit
*) ioreq
->ahir_Std
.io_Unit
;
425 ioreq
->ahir_Std
.io_Device
= (struct Device
*) -1;
426 ioreq
->ahir_Std
.io_Unit
= (struct Unit
*) -1;
430 iounit
->Unit
.unit_OpenCnt
--;
431 if(!iounit
->Unit
.unit_OpenCnt
)
432 ExpungeUnit(iounit
,AHIBase
);
435 AHIBase
->ahib_Library
.lib_OpenCnt
--;
437 ReleaseSemaphore(&AHIBase
->ahib_Lock
);
439 if(!AHIBase
->ahib_Library
.lib_OpenCnt
)
441 if(AHIBase
->ahib_Library
.lib_Flags
& LIBF_DELEXP
)
442 seglist
=_DevExpunge(AHIBase
);
448 /******************************************************************************
449 ** InitUnit *******************************************************************
450 ******************************************************************************/
452 // This function is called by DevOpen() to initialize a unit
454 static struct AHIDevUnit
*
455 InitUnit ( ULONG unit
,
456 struct AHIBase
*AHIBase
)
458 struct AHIDevUnit
*iounit
;
460 ahibug("[AHI:Device] %s()\n", __func__
);
462 if( unit
== AHI_NO_UNIT
)
464 ReadConfig(NULL
,AHIBase
);
467 else if(!AHIBase
->ahib_DevUnits
[unit
])
469 if((iounit
= AllocVec(sizeof(struct AHIDevUnit
), MEMF_CLEAR
|MEMF_PUBLIC
)))
471 NewList(&iounit
->Unit
.unit_MsgPort
.mp_MsgList
);
473 iounit
->Unit
.unit_MsgPort
.mp_Node
.ln_Type
= NT_MSGPORT
;
474 iounit
->Unit
.unit_MsgPort
.mp_Flags
= PA_IGNORE
;
475 iounit
->Unit
.unit_MsgPort
.mp_Node
.ln_Name
= AHINAME
" Unit";
476 iounit
->UnitNum
= unit
;
477 AHIInitSemaphore(&iounit
->Lock
);
478 NewList((struct List
*)&iounit
->ReadList
);
479 NewList((struct List
*)&iounit
->PlayingList
);
480 NewList((struct List
*)&iounit
->SilentList
);
481 NewList((struct List
*)&iounit
->WaitingList
);
482 NewList((struct List
*)&iounit
->RequestQueue
);
484 if(ReadConfig(iounit
,AHIBase
))
486 if((iounit
->Voices
= AllocVec(
487 sizeof(struct Voice
)*iounit
->Channels
,MEMF_PUBLIC
|MEMF_CLEAR
)))
490 struct Voice
*v
= iounit
->Voices
;
491 struct MsgPort
*replyport
;
493 // Mark all channels as free
494 for(i
= 0 ; i
< iounit
->Channels
; i
++)
496 v
->NextOffset
= FREE
;
500 replyport
= CreateMsgPort();
502 if( replyport
!= NULL
)
504 struct StartupMessage sm
=
507 { NULL
, NULL
, NT_UNKNOWN
, 0, NULL
},
508 replyport
, sizeof(struct StartupMessage
),
513 iounit
->Process
= CreateNewProcTags( NP_Entry
, (IPTR
) &m68k_DevProc
,
514 NP_Name
, (IPTR
) AHINAME
" Unit Process",
515 NP_Priority
, AHI_PRI
,
518 if( iounit
->Process
!= NULL
)
521 PutMsg( &iounit
->Process
->pr_MsgPort
,
527 DeleteMsgPort(replyport
);
535 AHIBase
->ahib_DevUnits
[unit
] = iounit
;
539 return AHIBase
->ahib_DevUnits
[unit
];
543 /******************************************************************************
544 ** ExpungeUnit ****************************************************************
545 ******************************************************************************/
547 // This function is called by DevClose() to remove a unit.
550 ExpungeUnit ( struct AHIDevUnit
*iounit
,
551 struct AHIBase
*AHIBase
)
553 struct Task
*unittask
;
556 ahibug("[AHI:Device] %s()\n", __func__
);
558 signal
= AllocSignal(-1);
562 signal
= SIGB_SINGLE
;
563 SetSignal(0, SIGF_SINGLE
);
566 unittask
= (struct Task
*) iounit
->Process
;
567 iounit
->Process
= (struct Process
*) FindTask(NULL
);
568 iounit
->SyncSignal
= signal
;
569 Signal(unittask
,SIGBREAKF_CTRL_F
);
571 AHIBase
->ahib_DevUnits
[iounit
->UnitNum
]=NULL
;
572 FreeVec(iounit
->Voices
);
575 if(signal
!= SIGB_SINGLE
)
582 /******************************************************************************
583 ** ReadConfig *****************************************************************
584 ******************************************************************************/
586 // This functions loads the users settings for AHI.
589 ReadConfig ( struct AHIDevUnit
*iounit
,
590 struct AHIBase
*AHIBase
)
592 struct IFFHandle
*iff
;
593 struct StoredProperty
*ahig
;
594 struct CollectionItem
*ci
;
597 ahibug("[AHI:Device] %s()\n", __func__
);
601 /* Internal defaults for device unit */
602 iounit
->AudioMode
= AHI_INVALID_ID
; // See at the end of the function!
603 iounit
->Frequency
= 44100;
604 iounit
->Channels
= 4;
605 iounit
->MonitorVolume
= ~0;
606 iounit
->InputGain
= ~0;
607 iounit
->OutputVolume
= ~0;
613 /* Internal defaults for low-level mode */
614 AHIBase
->ahib_AudioMode
= AHI_INVALID_ID
;
615 AHIBase
->ahib_Frequency
= 44100;
616 AHIBase
->ahib_MonitorVolume
= 0x00000;
617 AHIBase
->ahib_InputGain
= 0x10000;
618 AHIBase
->ahib_OutputVolume
= 0x10000;
619 AHIBase
->ahib_Input
= 0;
620 AHIBase
->ahib_Output
= 0;
625 iff
->iff_Stream
=(IPTR
) Open("ENV:Sys/ahi.prefs", MODE_OLDFILE
);
629 if(!OpenIFF(iff
,IFFF_READ
))
631 if(!(PropChunk(iff
,ID_PREF
,ID_PRHD
)
632 || PropChunk(iff
,ID_PREF
,ID_AHIG
)
633 || CollectionChunk(iff
,ID_PREF
,ID_AHIU
)
634 || StopOnExit(iff
,ID_PREF
,ID_FORM
)))
636 if(ParseIFF(iff
,IFFPARSE_SCAN
) == IFFERR_EOC
)
638 ahig
=FindProp(iff
,ID_PREF
,ID_AHIG
);
642 struct AHIGlobalPrefs
*globalprefs
;
645 globalprefs
= (struct AHIGlobalPrefs
*)ahig
->sp_Data
;
647 debug_level
= globalprefs
->ahigp_DebugLevel
;
648 EndianSwap( sizeof (UWORD
), &debug_level
);
649 AHIBase
->ahib_DebugLevel
= debug_level
;
651 AHIBase
->ahib_Flags
= 0;
653 /* Not used in version 5:
655 * if(globalprefs->ahigp_DisableSurround)
656 * AHIBase->ahib_Flags |= AHIBF_NOSURROUND;
658 * if(globalprefs->ahigp_DisableEcho)
659 * AHIBase->ahib_Flags |= AHIBF_NOECHO;
661 * if(globalprefs->ahigp_FastEcho)
662 * AHIBase->ahib_Flags |= AHIBF_FASTECHO;
666 if( (ULONG
) ahig
->sp_Size
> offsetof( struct AHIGlobalPrefs
,
669 AHIBase
->ahib_MaxCPU
= globalprefs
->ahigp_MaxCPU
;
670 EndianSwap( sizeof (Fixed
), &AHIBase
->ahib_MaxCPU
);
674 AHIBase
->ahib_MaxCPU
= 0x10000 * 90 / 100;
677 /* In version 5: Clipping is always used
679 * if( (ULONG) ahig->sp_Size > offsetof( struct AHIGlobalPrefs,
680 * ahigp_ClipMasterVolume) )
682 * if(globalprefs->ahigp_ClipMasterVolume)
683 * AHIBase->ahib_Flags |= AHIBF_CLIPPING;
687 if( (ULONG
) ahig
->sp_Size
> offsetof( struct AHIGlobalPrefs
,
688 ahigp_AntiClickTime
) )
690 AHIBase
->ahib_AntiClickTime
= globalprefs
->ahigp_AntiClickTime
;
691 EndianSwap( sizeof (Fixed
), &AHIBase
->ahib_AntiClickTime
);
695 AHIBase
->ahib_AntiClickTime
= 0;
698 if( (ULONG
) ahig
->sp_Size
> offsetof( struct AHIGlobalPrefs
,
701 AHIBase
->ahib_ScaleMode
= globalprefs
->ahigp_ScaleMode
;
702 EndianSwap( sizeof (UWORD
), &AHIBase
->ahib_ScaleMode
);
706 AHIBase
->ahib_ScaleMode
= AHI_SCALE_FIXED_0_DB
;
709 ci
=FindCollection(iff
,ID_PREF
,ID_AHIU
);
712 struct AHIUnitPrefs
*unitprefs
;
714 unitprefs
= (struct AHIUnitPrefs
*)ci
->ci_Data
;
718 if(unitprefs
->ahiup_Unit
== iounit
->UnitNum
)
720 iounit
->AudioMode
= unitprefs
->ahiup_AudioMode
;
721 iounit
->Frequency
= unitprefs
->ahiup_Frequency
;
722 iounit
->Channels
= unitprefs
->ahiup_Channels
;
723 iounit
->MonitorVolume
= unitprefs
->ahiup_MonitorVolume
;
724 iounit
->InputGain
= unitprefs
->ahiup_InputGain
;
725 iounit
->OutputVolume
= unitprefs
->ahiup_OutputVolume
;
726 iounit
->Input
= unitprefs
->ahiup_Input
;
727 iounit
->Output
= unitprefs
->ahiup_Output
;
729 EndianSwap( sizeof (ULONG
), &iounit
->AudioMode
);
730 EndianSwap( sizeof (ULONG
), &iounit
->Frequency
);
731 EndianSwap( sizeof (UWORD
), &iounit
->Channels
);
732 EndianSwap( sizeof (Fixed
), &iounit
->MonitorVolume
);
733 EndianSwap( sizeof (Fixed
), &iounit
->InputGain
);
734 EndianSwap( sizeof (Fixed
), &iounit
->OutputVolume
);
735 EndianSwap( sizeof (ULONG
), &iounit
->Input
);
736 EndianSwap( sizeof (ULONG
), &iounit
->Output
);
741 if(unitprefs
->ahiup_Unit
== AHI_NO_UNIT
)
743 AHIBase
->ahib_AudioMode
= unitprefs
->ahiup_AudioMode
;
744 AHIBase
->ahib_Frequency
= unitprefs
->ahiup_Frequency
;
745 AHIBase
->ahib_MonitorVolume
= unitprefs
->ahiup_MonitorVolume
;
746 AHIBase
->ahib_InputGain
= unitprefs
->ahiup_InputGain
;
747 AHIBase
->ahib_OutputVolume
= unitprefs
->ahiup_OutputVolume
;
748 AHIBase
->ahib_Input
= unitprefs
->ahiup_Input
;
749 AHIBase
->ahib_Output
= unitprefs
->ahiup_Output
;
751 EndianSwap( sizeof (ULONG
), &AHIBase
->ahib_AudioMode
);
752 EndianSwap( sizeof (ULONG
), &AHIBase
->ahib_Frequency
);
753 EndianSwap( sizeof (Fixed
), &AHIBase
->ahib_MonitorVolume
);
754 EndianSwap( sizeof (Fixed
), &AHIBase
->ahib_InputGain
);
755 EndianSwap( sizeof (Fixed
), &AHIBase
->ahib_OutputVolume
);
756 EndianSwap( sizeof (ULONG
), &AHIBase
->ahib_Input
);
757 EndianSwap( sizeof (ULONG
), &AHIBase
->ahib_Output
);
767 Close((BPTR
) iff
->iff_Stream
);
772 // Avoids calling AHI_BestAudioID if not neccessary (faster startup time,
773 // since doesn't open all sub libraries.
776 mode
= &iounit
->AudioMode
;
778 mode
= &AHIBase
->ahib_AudioMode
;
779 if(mode
[0] == (IPTR
) AHI_INVALID_ID
)
780 { static const Tag tags
[] = { AHIDB_Realtime
,TRUE
,TAG_DONE
};
781 mode
[0] = AHI_BestAudioIDA((struct TagItem
*)tags
);
788 /******************************************************************************
789 ** AllocHardware **************************************************************
790 ******************************************************************************/
792 // Allocates the audio hardware
795 AllocHardware ( struct AHIDevUnit
*iounit
,
796 struct AHIBase
*AHIBase
)
799 ULONG fullduplex
= FALSE
;
800 ULONG stereo
= FALSE
;
801 ULONG panning
= FALSE
;
803 ahibug("[AHI:Device] %s()\n", __func__
);
805 /* Allocate the hardware */
806 iounit
->AudioCtrl
= AHI_AllocAudio(
807 AHIA_AudioID
, (IPTR
)iounit
->AudioMode
,
808 AHIA_MixFreq
, (IPTR
)iounit
->Frequency
,
809 AHIA_Channels
, (IPTR
)iounit
->Channels
,
810 AHIA_Sounds
, MAXSOUNDS
,
811 AHIA_PlayerFunc
, (IPTR
)&iounit
->PlayerHook
,
812 AHIA_RecordFunc
, (IPTR
)&iounit
->RecordHook
,
813 AHIA_SoundFunc
, (IPTR
)&iounit
->SoundHook
,
816 if(iounit
->AudioCtrl
!= NULL
)
819 AHI_GetAudioAttrs(AHI_INVALID_ID
,iounit
->AudioCtrl
,
820 AHIDB_FullDuplex
, (IPTR
)&fullduplex
,
821 AHIDB_Stereo
, (IPTR
)&stereo
,
822 AHIDB_Panning
, (IPTR
)&panning
,
824 iounit
->FullDuplex
= fullduplex
;
825 iounit
->PseudoStereo
= stereo
&& !panning
;
827 /* Set hardware properties */
828 AHI_ControlAudio(iounit
->AudioCtrl
,
829 (iounit
->MonitorVolume
== ~0 ? TAG_IGNORE
: AHIC_MonitorVolume
),
830 iounit
->MonitorVolume
,
832 (iounit
->InputGain
== ~0 ? TAG_IGNORE
: AHIC_InputGain
),
835 (iounit
->OutputVolume
== ~0 ? TAG_IGNORE
: AHIC_OutputVolume
),
836 iounit
->OutputVolume
,
838 (iounit
->Input
== ~0 ? TAG_IGNORE
: AHIC_Input
),
841 (iounit
->Output
== ~0 ? TAG_IGNORE
: AHIC_Output
),
846 iounit
->ChannelInfoStruct
->ahie_Effect
= AHIET_CHANNELINFO
;
847 iounit
->ChannelInfoStruct
->ahieci_Func
= &iounit
->ChannelInfoHook
;
848 iounit
->ChannelInfoStruct
->ahieci_Channels
= iounit
->Channels
;
849 if(!AHI_SetEffect(iounit
->ChannelInfoStruct
, iounit
->AudioCtrl
))
858 /******************************************************************************
859 ** FreeHardware ***************************************************************
860 ******************************************************************************/
862 // Take a wild guess!
865 FreeHardware ( struct AHIDevUnit
*iounit
,
866 struct AHIBase
*AHIBase
)
868 ahibug("[AHI:Device] %s()\n", __func__
);
870 if(iounit
->AudioCtrl
)
872 if(iounit
->ChannelInfoStruct
)
874 iounit
->ChannelInfoStruct
->ahie_Effect
= (AHIET_CANCEL
| AHIET_CHANNELINFO
);
875 AHI_SetEffect(iounit
->ChannelInfoStruct
, iounit
->AudioCtrl
);
877 AHI_FreeAudio(iounit
->AudioCtrl
);
878 iounit
->AudioCtrl
= NULL
;
879 iounit
->IsRecording
= FALSE
;
880 iounit
->IsPlaying
= FALSE
;
881 iounit
->ValidRecord
= FALSE
;
886 /******************************************************************************
887 ** DevProc ********************************************************************
888 ******************************************************************************/
893 struct Process
*proc
;
894 struct StartupMessage
*sm
;
895 struct AHIDevUnit
*iounit
;
898 ahibug("[AHI:Device] %s()\n", __func__
);
900 proc
= (struct Process
*)FindTask(NULL
);
901 WaitPort(&proc
->pr_MsgPort
);
902 sm
= (struct StartupMessage
*)GetMsg(&proc
->pr_MsgPort
);
905 iounit
->Process
= NULL
;
907 iounit
->PlayerHook
.h_Entry
= (HOOKFUNC
) HookEntry
;
908 iounit
->PlayerHook
.h_SubEntry
= (HOOKFUNC
) PlayerFunc
;
909 iounit
->PlayerHook
.h_Data
= iounit
;
911 iounit
->RecordHook
.h_Entry
= (HOOKFUNC
) HookEntry
;
912 iounit
->RecordHook
.h_SubEntry
= (HOOKFUNC
) RecordFunc
;
913 iounit
->RecordHook
.h_Data
= iounit
;
915 iounit
->SoundHook
.h_Entry
= (HOOKFUNC
) HookEntry
;
916 iounit
->SoundHook
.h_SubEntry
= (HOOKFUNC
) SoundFunc
;
917 iounit
->SoundHook
.h_Data
= iounit
;
919 iounit
->ChannelInfoHook
.h_Entry
= (HOOKFUNC
) HookEntry
;
920 iounit
->ChannelInfoHook
.h_SubEntry
= (HOOKFUNC
) ChannelInfoFunc
;
921 iounit
->ChannelInfoHook
.h_Data
= iounit
;
923 iounit
->ChannelInfoStruct
= AllocVec(
924 sizeof(struct AHIEffChannelInfo
) + (iounit
->Channels
* sizeof(ULONG
)),
925 MEMF_PUBLIC
| MEMF_CLEAR
);
929 signalbit
= AllocSignal(-1);
930 iounit
->PlaySignal
= AllocSignal(-1);
931 iounit
->RecordSignal
= AllocSignal(-1);
932 iounit
->SampleSignal
= AllocSignal(-1);
935 && (iounit
->PlaySignal
!= -1)
936 && (iounit
->RecordSignal
!= -1)
937 && (iounit
->SampleSignal
!= -1)
938 && (iounit
->ChannelInfoStruct
!= NULL
)
941 /* Set up our Unit's MsgPort. */
942 iounit
->Unit
.unit_MsgPort
.mp_SigBit
= signalbit
;
943 iounit
->Unit
.unit_MsgPort
.mp_SigTask
= (struct Task
*)proc
;
944 iounit
->Unit
.unit_MsgPort
.mp_Flags
= PA_SIGNAL
;
946 /* Allocate the hardware */
947 if(AllocHardware(iounit
, AHIBase
))
950 /* Set iounit->Process to pointer to our unit process.
951 This will let the Unit init code know that were
953 iounit
->Process
= proc
;
957 /* Reply to our startup message */
962 ULONG waitmask
,signals
;
964 waitmask
= (1L << signalbit
)
965 | SIGBREAKF_CTRL_E
// Dummy signal to wake up task
966 | SIGBREAKF_CTRL_F
// Quit signal
967 | (1L << iounit
->PlaySignal
)
968 | (1L << iounit
->RecordSignal
)
969 | (1L << iounit
->SampleSignal
);
973 signals
= Wait(waitmask
);
975 /* Have we been signaled to shut down? */
976 if(signals
& SIGBREAKF_CTRL_F
)
979 if(signals
& (1L << iounit
->SampleSignal
))
981 RethinkPlayers(iounit
,AHIBase
);
984 if(signals
& (1L << signalbit
))
986 struct AHIRequest
*ioreq
;
988 while((ioreq
= (struct AHIRequest
*) GetMsg(&iounit
->Unit
.unit_MsgPort
)))
990 PerformIO(ioreq
,AHIBase
);
994 if(signals
& (1L << iounit
->PlaySignal
))
996 AHIObtainSemaphore(&iounit
->Lock
);
998 UpdateSilentPlayers(iounit
,AHIBase
);
1000 AHIReleaseSemaphore(&iounit
->Lock
);
1003 if(signals
& (1L << iounit
->RecordSignal
))
1005 iounit
->ValidRecord
= TRUE
;
1006 FeedReaders(iounit
,AHIBase
);
1011 FreeHardware(iounit
, AHIBase
);
1012 FreeSignal(iounit
->SampleSignal
);
1013 iounit
->SampleSignal
= -1;
1014 FreeSignal(iounit
->RecordSignal
);
1015 iounit
->RecordSignal
= -1;
1016 FreeSignal(iounit
->PlaySignal
);
1017 iounit
->PlaySignal
= -1;
1018 FreeVec(iounit
->ChannelInfoStruct
);
1023 Signal((struct Task
*) iounit
->Process
, 1UL << iounit
->SyncSignal
);
1025 FreeSignal(signalbit
);
1029 /******************************************************************************
1030 ** PlayerFunc *****************************************************************
1031 ******************************************************************************/
1034 PlayerFunc( struct Hook
* hook
,
1035 struct AHIAudioCtrl
* actrl
,
1038 struct AHIDevUnit
*iounit
= (struct AHIDevUnit
*) hook
->h_Data
;
1040 if(AHIAttemptSemaphore(&iounit
->Lock
))
1042 UpdateSilentPlayers(iounit
,AHIBase
);
1043 AHIReleaseSemaphore(&iounit
->Lock
);
1046 { // Do it later instead
1047 Signal((struct Task
*) iounit
->Master
, (1L << iounit
->PlaySignal
));
1054 /******************************************************************************
1055 ** RecordFunc *****************************************************************
1056 ******************************************************************************/
1059 RecordFunc( struct Hook
* hook
,
1060 struct AHIAudioCtrl
* actrl
,
1061 struct AHIRecordMessage
* recmsg
)
1063 struct AHIDevUnit
*iounit
;
1065 if(recmsg
->ahirm_Type
== AHIST_S16S
)
1067 iounit
= (struct AHIDevUnit
*) hook
->h_Data
;
1068 iounit
->RecordBuffer
= recmsg
->ahirm_Buffer
;
1069 iounit
->RecordSize
= recmsg
->ahirm_Length
<<2;
1070 Signal((struct Task
*) iounit
->Master
, (1L << iounit
->RecordSignal
));
1076 /******************************************************************************
1077 ** SoundFunc ******************************************************************
1078 ******************************************************************************/
1081 SoundFunc( struct Hook
* hook
,
1082 struct AHIAudioCtrl
* actrl
,
1083 struct AHISoundMessage
* sndmsg
)
1085 struct AHIDevUnit
* iounit
;
1086 struct Voice
* voice
;
1087 struct AHIRequest
* playreq
;
1089 iounit
= (struct AHIDevUnit
*) hook
->h_Data
;
1090 voice
= &iounit
->Voices
[(WORD
)sndmsg
->ahism_Channel
];
1092 Disable(); // Not needed?
1094 playreq
= voice
->PlayingRequest
;
1096 if( playreq
!= NULL
)
1098 playreq
->ahir_Std
.io_Command
= AHICMD_WRITTEN
;
1103 voice
->PlayingRequest
= voice
->QueuedRequest
;
1104 voice
->Flags
|= VF_STARTED
;
1105 voice
->QueuedRequest
= NULL
;
1107 switch(voice
->NextOffset
)
1113 /* A AHI_NOSOUND is done, channel is silent */
1114 voice
->NextOffset
= FREE
;
1118 /* A normal sound is done and playing, no other sound is queued */
1119 AHI_SetSound(sndmsg
->ahism_Channel
,AHI_NOSOUND
,0,0,actrl
,AHISF_NONE
);
1120 voice
->NextOffset
= MUTE
;
1124 /* A normal sound is done, and another is waiting */
1125 AHI_SetSound(sndmsg
->ahism_Channel
,
1130 AHI_SetFreq(sndmsg
->ahism_Channel
,
1131 voice
->NextFrequency
,
1133 AHI_SetVol(sndmsg
->ahism_Channel
,
1137 voice
->QueuedRequest
= voice
->NextRequest
;
1138 voice
->NextRequest
= NULL
;
1139 voice
->NextOffset
= PLAY
;
1143 Signal((struct Task
*) iounit
->Master
, (1L << iounit
->SampleSignal
));
1147 /******************************************************************************
1148 ** ChannelInfoFunc ************************************************************
1149 ******************************************************************************/
1151 // This hook keeps updating the io_Actual field of each playing requests
1154 ChannelInfoFunc( struct Hook
* hook
,
1155 struct AHIAudioCtrl
* actrl
,
1156 struct AHIEffChannelInfo
* cimsg
)
1158 struct AHIDevUnit
*iounit
= (struct AHIDevUnit
*) hook
->h_Data
;
1159 struct Voice
*voice
;
1160 ULONG
*offsets
= (ULONG
*) &cimsg
->ahieci_Offset
;
1163 Disable(); // Not needed?
1165 voice
= iounit
->Voices
;
1167 for(i
= 0; i
< iounit
->Channels
; i
++)
1169 struct AHIRequest
* playreq
;
1171 playreq
= voice
->PlayingRequest
;
1173 if( playreq
!= NULL
)
1175 playreq
->ahir_Std
.io_Actual
= *offsets
;