TABLE OF CONTENTS 0001 [driver].audio/--background-- 0002 [driver].audio/AHIsub_#? 0003 [driver].audio/AHIsub_AllocAudio 0004 [driver].audio/AHIsub_Disable 0005 [driver].audio/AHIsub_Enable 0006 [driver].audio/AHIsub_FreeAudio 0007 [driver].audio/AHIsub_GetAttr 0008 [driver].audio/AHIsub_HardwareControl 0009 [driver].audio/AHIsub_Start 0010 [driver].audio/AHIsub_Stop 0011 [driver].audio/AHIsub_Update [driver].audio/--background-- OVERVIEW DRIVER VERSIONS The lowest supported driver version is 2. If you use any feature introduced in later versions of AHI, you should set the driver version to the same version as the features were introduced with. Example: You use PreTimer() and PostTimer(), and since these calls were added in V4 of ahi.device, your driver's version should be 4, too. AUDIO ID NUMBERS Just some notes about selecting ID numbers for different modes: It is up to the driver programmer to chose which modes should be available to the user. Take care when selecting. The upper word is the hardware ID, and can only be allocated by Martin Blom . The lower word is free, but in order to allow enhancements, please only use bit 0 to 3 for modes! If your driver supports multiple sound cards, use bit 12-15 to select card (first one is 0). If your sound card has multiple AD/DA converters, you can use bit 8-11 to select them (the first should be 0). Set the remaining bits to zero. Use AHI:Developer/Support/ScanAudioModes to have a look at the modes currently available. Use AHI:Developer/Support/sift to make sure your mode descriptor file is a legal IFF file. I do reserve the right to change the rules if I find them incorrect! [driver].audio/AHIsub_#? NAME AHIsub_SetEffect -- Set effect. AHIsub_SetFreq -- Set frequency. AHIsub_SetSound -- Set sound. AHIsub_SetVol -- Set volume and stereo panning. AHIsub_LoadSound -- Prepare a sound for playback. AHIsub_UnloadSound -- Discard a sound. SYNOPSIS See functions in 'ahi.device'. IMPLEMENTATION If AHIsub_AllocAudio() did not return with bit AHISB_MIXING set, all user calls to these function will be routed to the driver. If AHIsub_AllocAudio() did return with bit AHISB_MIXING set, the calls will first be routed to the driver, and only handled by 'ahi.device' if the driver returned AHIS_UNKNOWN. This way it is possible to add effects that the sound card handles on its own, like filter and echo effects. For what each function does, see the autodocs for 'ahi.device'. INPUTS See functions in 'ahi.device'. NOTES See functions in 'ahi.device'. SEE ALSO ahi.device/AHI_SetEffect(), ahi.device/AHI_SetFreq(), ahi.device/AHI_SetSound(), ahi.device/AHI_SetVol(), ahi.device/AHI_LoadSound(), ahi.device/AHI_UnloadSound() [driver].audio/AHIsub_AllocAudio NAME AHIsub_AllocAudio -- Allocates and initializes the audio hardware. SYNOPSIS result = AHIsub_AllocAudio( tags, audioctrl); D0 A1 A2 ULONG AHIsub_AllocAudio( struct TagItem *, struct AHIAudioCtrlDrv * ); IMPLEMENTATION Allocate and initialize the audio hardware. Decide if and how you wish to use the mixing routines provided by 'ahi.device', by looking in the AHIAudioCtrlDrv structure and parsing the tag list for tags you support. 1) Use mixing routines with timing: You will need to be able to play any number of samples from about 80 up to 65535 with low overhead. · Update AudioCtrl->ahiac_MixFreq to nearest value that your hardware supports. · Return AHISF_MIXING|AHISF_TIMING. 2) Use mixing routines without timing: If the hardware can't play samples with any length, use this alternative and provide timing yourself. The buffer must take less than about 20 ms to play, preferable less than 10! · Update AudioCtrl->ahiac_MixFreq to nearest value that your hardware supports. · Store the number of samples to mix each pass in AudioCtrl->ahiac_BuffSamples. · Return AHISF_MIXING Alternatively, you can use the first method and call the mixing hook several times in a row to fill up a buffer. In that case, AHIsub_GetAttr(AHIDB_MaxPlaySamples) should return the size of the buffer plus AudioCtrl->ahiac_MaxBuffSamples. If the buffer is so large that it takes more than (approx.) 10 ms to play it for high sample frequencies, AHIsub_GetAttr(AHIDB_Realtime) should return FALSE. 3) Don't use mixing routines: If your hardware can handle everything without using the CPU to mix the channels, you tell 'ahi.device' this by not setting either the AHISB_MIXING or the AHISB_TIMING bit. If you can handle stereo output from the mixing routines, also set bit AHISB_KNOWSTEREO. If you can handle hifi (32 bit) output from the mixing routines, set bit AHISB_KNOWHIFI. If this driver can be used to record samples, set bit AHISB_CANRECORD, too (regardless if you use the mixing routines in AHI or not). If the sound card has hardware to do DSP effects, you can set the AHISB_CANPOSTPROCESS bit. The output from the mixing routines will then be two separate buffers, one wet and one dry. You should then apply the Fx on the wet buffer, and post-mix the two buffers before you send the samples to the DAC. (V4) INPUTS tags - pointer to a taglist. audioctrl - pointer to an AHIAudioCtrlDrv structure. TAGS The tags are from the audio database (AHIDB_#? in ), NOT the tag list the user called ahi.device/AHI_AllocAudio() with. RESULT Flags, defined in . EXAMPLE NOTES You don't have to clean up on failure, AHIsub_FreeAudio() will always be called. BUGS SEE ALSO AHIsub_FreeAudio(), AHIsub_Start() [driver].audio/AHIsub_Disable NAME AHIsub_Disable -- Temporary turn off audio interrupt/task SYNOPSIS AHIsub_Disable( audioctrl ); A2 void AHIsub_Disable( struct AHIAudioCtrlDrv * ); IMPLEMENTATION If you are lazy, then call exec.library/Disable(). If you are smart, only disable your own interrupt or task. INPUTS audioctrl - pointer to an AHIAudioCtrlDrv structure. NOTES This call should be guaranteed to preserve all registers. This call nests. SEE ALSO AHIsub_Enable(), exec.library/Disable() [driver].audio/AHIsub_Enable NAME AHIsub_Enable -- Turn on audio interrupt/task SYNOPSIS AHIsub_Enable( audioctrl ); A2 void AHIsub_Enable( struct AHIAudioCtrlDrv * ); IMPLEMENTATION If you are lazy, then call exec.library/Enable(). If you are smart, only enable your own interrupt or task. INPUTS audioctrl - pointer to an AHIAudioCtrlDrv structure. NOTES This call should be guaranteed to preserve all registers. This call nests. SEE ALSO AHIsub_Disable(), exec.library/Enable() [driver].audio/AHIsub_FreeAudio NAME AHIsub_FreeAudio -- Deallocates the audio hardware. SYNOPSIS AHIsub_FreeAudio( audioctrl ); A2 void AHIsub_FreeAudio( struct AHIAudioCtrlDrv * ); IMPLEMENTATION Deallocate the audio hardware and other resources allocated in AHIsub_AllocAudio(). AHIsub_Stop() will always be called by 'ahi.device' before this call is made. INPUTS audioctrl - pointer to an AHIAudioCtrlDrv structure. NOTES It must be safe to call this routine even if AHIsub_AllocAudio() was never called, failed or called more than once. SEE ALSO AHIsub_AllocAudio() [driver].audio/AHIsub_GetAttr NAME AHIsub_GetAttr -- Returns information about audio modes or driver SYNOPSIS AHIsub_GetAttr( attribute, argument, default, taglist, audioctrl ); D0 D0 D1 D2 A1 A2 LONG AHIsub_GetAttr( ULONG, LONG, LONG, struct TagItem *, struct AHIAudioCtrlDrv * ); IMPLEMENTATION Return the attribute based on a tag list and an AHIAudioCtrlDrv structure, which are the same that will be passed to AHIsub_AllocAudio() by 'ahi.device'. If the attribute is unknown to you, return the default. INPUTS attribute - Is really a Tag and can be one of the following: AHIDB_Bits - Return how many output bits the tag list will result in. AHIDB_MaxChannels - Return the resulting number of channels. AHIDB_Frequencies - Return how many mixing/sampling frequencies you support AHIDB_Frequency - Return the argument:th frequency Example: You support 3 frequencies 32, 44.1 and 48 kHz. If argument is 1, return 44100. AHIDB_Index - Return the index which gives the frequency closest to argument. Example: You support 3 frequencies 32, 44.1 and 48 kHz. If argument is 40000, return 1 (=> 44100). AHIDB_Author - Return pointer to name of driver author: "Martin 'Leviticus' Blom" AHIDB_Copyright - Return pointer to copyright notice, including the '©' character: "© 1996 Martin Blom" or "Public Domain" AHIDB_Version - Return pointer version string, normal Amiga format: "paula 1.5 (18.2.96)\r\n" AHIDB_Annotation - Return pointer to an annotation string, which can be several lines. AHIDB_Record - Are you a sampler, too? Return TRUE or FALSE. AHIDB_FullDuplex - Return TRUE or FALSE. AHIDB_Realtime - Return TRUE or FALSE. AHIDB_MaxPlaySamples - Normally, return the default. See AHIsub_AllocAudio(), section 2. AHIDB_MaxRecordSamples - Return the size of the buffer you fill when recording. The following are associated with AHIsub_HardwareControl() and are new for V2. AHIDB_MinMonitorVolume AHIDB_MaxMonitorVolume - Return the lower/upper limit for AHIC_MonitorVolume. If unsupported but always 1.0, return 1.0 for both. AHIDB_MinInputGain AHIDB_MaxInputGain - Return the lower/upper limit for AHIC_InputGain. If unsupported but always 1.0, return 1.0 for both. AHIDB_MinOutputVolume AHIDB_MaxOutputVolume - Return the lower/upper limit for AHIC_OutputVolume. AHIDB_Inputs - Return how many inputs you have. AHIDB_Input - Return a short string describing the argument:th input. Number 0 should be the default one. Example strings can be "Line 1", "Mic", "Optical" or whatever. AHIDB_Outputs - Return how many outputs you have. AHIDB_Output - Return a short string describing the argument:th output. Number 0 should be the default one. Example strings can be "Line 1", "Headphone", "Optical" or whatever. argument - extra info for some attributes. default - What you should return for unknown attributes. taglist - Pointer to a tag list that eventually will be fed to AHIsub_AllocAudio(), or NULL. audioctrl - Pointer to an AHIAudioCtrlDrv structure that eventually will be fed to AHIsub_AllocAudio(), or NULL. NOTES SEE ALSO AHIsub_AllocAudio(), AHIsub_HardwareControl(), ahi.device/AHI_GetAudioAttrsA() [driver].audio/AHIsub_HardwareControl NAME AHIsub_HardwareControl -- Modify sound card settings SYNOPSIS AHIsub_HardwareControl( attribute, argument, audioctrl ); D0 D0 D1 A2 LONG AHIsub_HardwareControl( ULONG, LONG, struct AHIAudioCtrlDrv * ); IMPLEMENTATION Set or return the state of a particular hardware component. AHI uses AHIsub_GetAttr() to supply the user with limits and what tags are available. INPUTS attribute - Is really a Tag and can be one of the following: AHIC_MonitorVolume - Set the input monitor volume to argument. AHIC_MonitorVolume_Query - Return the current input monitor volume (argument is ignored). AHIC_InputGain - Set the input gain to argument. (V2) AHIC_InputGain_Query (V2) AHIC_OutputVolume - Set the output volume to argument. (V2) AHIC_OutputVolume_Query (V2) AHIC_Input - Use the argument:th input source (default is 0). (V2) AHIC_Input_Query (V2) AHIC_Output - Use the argument:th output destination (default is 0). (V2) AHIC_Output_Query (V2) argument - What value attribute should be set to. audioctrl - Pointer to an AHIAudioCtrlDrv structure. RESULT Return the state of selected attribute. If you were asked to set something, return TRUE. If attribute is unknown to you or unsupported, return FALSE. NOTES This call must be safe from interrupts. SEE ALSO ahi.device/AHI_ControlAudioA(), AHIsub_GetAttr() [driver].audio/AHIsub_Start NAME AHIsub_Start -- Starts playback or recording SYNOPSIS error = AHIsub_Start( flags, audioctrl ); D0 D0 A2 ULONG AHIsub_Start(ULONG, struct AHIAudioCtrlDrv * ); IMPLEMENTATION What to do depends what you returned in AHIsub_AllocAudio(). * First, assume bit AHISB_PLAY in flags is set. This means that you should begin playback. - AHIsub_AllocAudio() returned AHISF_MIXING|AHISF_TIMING: A) Allocate a mixing buffer of ahiac_BuffSize bytes. The buffer must be long aligned! B) Create/start an interrupt or task that will do 1-6 over and over again until AHIsub_Stop() is called. Note that it is not a good idea to do the actual mixing and conversion in a real hardware interrupt. Signal a task or create a Software Interrupt to do the number crunching. 1) Call the user Hook ahiac_PlayerFunc with the following parameters: A0 - (struct Hook *) A2 - (struct AHIAudioCtrlDrv *) A1 - Set to NULL. 2) [Call the ahiac_PreTimer function. If it returns TRUE (Z will be cleared so you don't have to test d0), skip step 3 and 4. This is used to avoid overloading the CPU. This step is optional. A2 is assumed to point to struct AHIAudioCtrlDrv. All registers except d0 are preserved. (V4)] 3) Call the mixing Hook (ahiac_MixerFunc) with the following parameters: A0 - (struct Hook *) - The Hook itself A2 - (struct AHIAudioCtrlDrv *) A1 - (WORD *[]) - The mixing buffer. Note that ahiac_MixerFunc preserves ALL registers. The user Hook ahiac_SoundFunc will be called by the mixing routine when a sample have been processed, so you don't have to worry about that. How the buffer will be filled is indicated by ahiac_Flags. It is always filled with signed 16-bit (32 bit if AHIACB_HIFI in in ahiac_Flags is set) words, even if playback is 8 bit. If AHIDBB_STEREO is set (in ahiac_Flags), data for left and right channel are interleaved: 1st sample left channel, 1st sample right channel, 2nd sample left channel, ..., ahiac_BuffSamples:th sample left channel, ahiac_BuffSamples:th sample right channel. If AHIDBB_STEREO is cleared, the mono data is stored: 1st sample, 2nd sample, ..., ahiac_BuffSamples:th sample. Note that neither AHIACB_STEREO nor AHIACB_HIFI will be set if you didn't report that you understand these flags when AHI_AllocAudio() was called. For AHI V2, the type of buffer is also available in ahiac_BuffType. It is suggested that you use this value instead. ahiac_BuffType can be one of AHIST_M16S, AHIST_S16S, AHIST_M32S and AHIST_S32S. 4) Convert the buffer if needed and feed it to the audio hardware. Note that you may have to clear CPU caches if you are using DMA to play the buffer, and the buffer is not allocated in non- cachable RAM. 5) [Call the ahiac_PostTimer function. A2 is assumed to point to struct AHIAudioCtrlDrv. All registers are preserved. (V4)] 6) Wait until the whole buffer has been played, then repeat. Use double buffering if possible! You may DECREASE ahiac_BuffSamples slightly, for example to force an even number of samples to be mixed. By doing this you will make ahiac_PlayerFunc to be called at wrong frequency so be careful! Even if ahiac_BuffSamples is defined ULONG, it will never be greater than 65535. ahiac_BuffSize is the largest size of the mixing buffer that will be needed until AHIsub_Stop() is called. ahiac_MaxBuffSamples is the maximum number of samples that will be mixed (until AHIsub_Stop() is called). You can use this value if you need to allocate DMA buffers. ahiac_MinBuffSamples is the minimum number of samples that will be mixed. Most drivers will ignore it. If AHIsub_AllocAudio() returned with the AHISB_CANPOSTPROCESS bit set, ahiac_BuffSize is large enough to hold two buffers. The mixing buffer will be filled with the wet buffer first, immediately followed by the dry buffer. I.e., ahiac_BuffSamples sample frames wet data, then ahiac_BuffSamples sample frames dry data. The DSP fx should only be applied to the wet buffer, and the two buffers should then be added together. (V4) - If AHIsub_AllocAudio() returned AHISF_MIXING, do as described above, except calling ahiac_PlayerFunc. ahiac_PlayerFunc should be called ahiac_PlayerFreq times per second, clocked by timers on your sound card or by using 'realtime.library'. No other Amiga resources may be used for timing (like direct CIA timers). ahiac_MinBuffSamples and ahiac_MaxBuffSamples are undefined if AHIsub_AllocAudio() returned AHISF_MIXING (AHISB_TIMING bit not set). - If AHIsub_AllocAudio() returned with neither the AHISB_MIXING nor the AHISB_TIMING bit set, then just start playback. Don't forget to call ahiac_PlayerFunc ahiac_PlayerFreq times per second. Only your own timing hardware or 'realtime.library' may be used. Note that ahiac_MixerFunc, ahiac_BuffSamples, ahiac_MinBuffSamples, ahiac_MaxBuffSamples and ahiac_BuffSize are undefined. ahiac_MixFreq is the frequency the user wants to use for recording, if you support that. * Second, assume bit AHISB_RECORD in flags is set. This means that you should start to sample. Create a interrupt or task that does the following: Allocate a buffer (you chose size, but try to keep it reasonable small to avoid delays - it is suggested that RecordFunc is called at least 4 times/second for the lowers sampling rate, and more often for higher rates), and fill it with the sampled data. The buffer must be long aligned, and it's size must be evenly divisible by four. The format should always be AHIST_S16S (even with 8 bit mono samplers), which means: 1st sample left channel, 1st sample right channel (same as prev. if mono), 2nd sample left channel, ... etc. Each sample is a signed word (WORD). The sample rate should be equal to the mixing rate. Call the ahiac_SamplerFunc Hook with the following parameters: A0 - (struct Hook *) - The Hook itself A2 - (struct AHIAudioCtrlDrv *) A1 - (struct AHIRecordMessage *) The message should be filled as follows: ahirm_Type - Set to AHIST_S16S. ahirm_Buffer - A pointer to the filled buffer. ahirm_Samples - How many sample frames stored. You must not destroy the buffer until next time the Hook is called. Repeat until AHIsub_Stop() is called. * Note that both bits may be set when this function is called. INPUTS flags - See . audioctrl - pointer to an AHIAudioCtrlDrv structure. RESULT Returns AHIE_OK if successful, else an error code as defined in . AHIsub_Stop() will always be called, even if this call failed. NOTES The driver must be able to handle multiple calls to this routine without preceding calls to AHIsub_Stop(). SEE ALSO AHIsub_Update(), AHIsub_Stop() [driver].audio/AHIsub_Stop NAME AHIsub_Stop -- Stops playback. SYNOPSIS AHIsub_Stop( flags, audioctrl ); D0 A2 void AHIsub_Stop( ULONG, struct AHIAudioCtrlDrv * ); IMPLEMENTATION Stop playback and/or recording, remove all resources allocated by AHIsub_Start(). INPUTS flags - See . audioctrl - pointer to an AHIAudioCtrlDrv structure. NOTES It must be safe to call this routine even if AHIsub_Start() was never called, failed or called more than once. SEE ALSO AHIsub_Start() [driver].audio/AHIsub_Update NAME AHIsub_Update -- Update some variables SYNOPSIS AHIsub_Update( flags, audioctrl ); D0 A2 void AHIsub_Update(ULONG, struct AHIAudioCtrlDrv * ); IMPLEMENTATION All you have to do is to update some variables: Mixing & timing: ahiac_PlayerFunc, ahiac_MixerFunc, ahiac_SamplerFunc, ahiac_BuffSamples (and perhaps ahiac_PlayerFreq if you use it). Mixing only: ahiac_PlayerFunc, ahiac_MixerFunc, ahiac_SamplerFunc and ahiac_PlayerFreq. Nothing: ahiac_PlayerFunc, ahiac_SamplerFunc and ahiac_PlayerFreq. INPUTS flags - Currently no flags defined. audioctrl - pointer to an AHIAudioCtrlDrv structure. RESULT NOTES This call must be safe from interrupts. SEE ALSO AHIsub_Start()