home *** CD-ROM | disk | FTP | other *** search
- /* $Id: audioctrl.c,v 4.33 1999/09/12 10:40:08 lcs Exp $ */
-
- /*
- AHI - Hardware independent audio subsystem
- Copyright (C) 1996-1999 Martin Blom <martin@blom.org>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330, Cambridge,
- MA 02139, USA.
- */
-
- #include <config.h>
- #include <CompilerSpecific.h>
-
- #include <exec/memory.h>
- #include <powerup/ppclib/memory.h>
- #include <exec/alerts.h>
- #include <utility/utility.h>
- #include <utility/tagitem.h>
-
- #include <proto/exec.h>
- #include <proto/utility.h>
- #include <clib/ahi_protos.h>
- #include <pragmas/ahi_pragmas.h>
- #include <proto/ahi_sub.h>
- #include <strings.h>
-
- #include "ahi_def.h"
- #include "audioctrl.h"
- #include "mixer.h"
- #include "asmfuncs.h"
- #include "database.h"
- #include "debug.h"
- #include "misc.h"
- #include "header.h"
-
-
- // Makes 'in' fit the given bounds.
-
- #define inbounds(in,min,max) \
- ( (in > max) ? max : ( (in < min) ? min : in ) )
-
-
- /******************************************************************************
- ** RecalcBuff *****************************************************************
- ******************************************************************************/
-
- // Calculates how many samples to mix each mixer pass. The result it
- // both returned and stored in ahiac_BuffSamples.
- // ahiac_BuffSizeNow will also be updated (For mixing routine)
-
- static ULONG
- RecalcBuff ( Fixed freq, struct AHIPrivAudioCtrl *audioctrl )
- {
- int length;
-
- // If ULONG, convert to Fixed
- // if(freq < 65536) freq <<= 16;
-
- // Sanity check
- if(freq == 0) return 0;
-
- audioctrl->ac.ahiac_BuffSamples = (audioctrl->ac.ahiac_MixFreq << 8) /
- (freq >> 8);
-
- // ahiac_BuffSamples *must* fit a WORD according to the driver autodocs!
- if(audioctrl->ac.ahiac_BuffSamples > 65535)
- {
- audioctrl->ac.ahiac_BuffSamples = 65535;
- }
-
- // Now, calculate the required mixing buffer size.
-
- length = audioctrl->ac.ahiac_BuffSamples *
- AHI_SampleFrameSize(audioctrl->ac.ahiac_BuffType);
-
- if(audioctrl->ac.ahiac_Flags & AHIACF_POSTPROC)
- {
- length <<= 1; // 2 buffers
- }
-
- // Pad to even 8 and add some more (because of an old Mungwall hit, but I
- // think that bug was fixed a long, long time ago..?)
-
- length = ((length + 7) & (~7) ) + 80;
-
- audioctrl->ahiac_BuffSizeNow = length;
-
- return audioctrl->ac.ahiac_BuffSamples;
-
- }
-
-
- /******************************************************************************
- ** CreateAudioCtrl & UpdateAudioCtrl ******************************************
- ******************************************************************************/
-
- #define DEFPLAYERFREQ (50<<16)
-
- static ULONG
- DummyHook( void )
- {
- return 0;
- }
-
-
- static struct Hook DefPlayerHook =
- {
- {0, 0},
- DummyHook,
- 0,
- 0
- };
-
-
- static struct TagItem boolmap[] =
- {
- { AHIDB_Volume, AHIACF_VOL },
- { AHIDB_Panning, AHIACF_PAN },
- { AHIDB_Stereo, AHIACF_STEREO },
- { AHIDB_HiFi, AHIACF_HIFI },
- { AHIDB_PingPong, AHIACF_PINGPONG },
- { AHIDB_Record, AHIACF_RECORD },
- { AHIDB_MultTable, AHIACF_MULTTAB },
- { TAG_DONE, NULL }
- };
-
-
- struct AHIPrivAudioCtrl *
- CreateAudioCtrl(struct TagItem *tags)
- {
- struct AHIPrivAudioCtrl *audioctrl;
- struct AHI_AudioDatabase *audiodb;
- struct TagItem *dbtags;
- BOOL error=TRUE;
-
- audioctrl = AHIAllocVec( sizeof( struct AHIPrivAudioCtrl ),
- MEMF_PUBLIC | MEMF_CLEAR |
- MEMF_NOCACHESYNCPPC | MEMF_NOCACHESYNCM68K );
-
- if( audioctrl != NULL )
- {
- audioctrl->ac.ahiac_AudioCtrl.ahiac_UserData =
- (APTR)GetTagData(AHIA_UserData,NULL,tags);
- audioctrl->ahiac_AudioID =
- GetTagData(AHIA_AudioID,AHI_DEFAULT_ID,tags);
- audioctrl->ac.ahiac_MixFreq =
- GetTagData(AHIA_MixFreq,AHI_DEFAULT_FREQ,tags);
- audioctrl->ac.ahiac_Channels =
- GetTagData(AHIA_Channels,0,tags);
- audioctrl->ac.ahiac_Sounds =
- GetTagData(AHIA_Sounds,0,tags);
- audioctrl->ac.ahiac_SoundFunc =
- (struct Hook *)GetTagData(AHIA_SoundFunc,NULL,tags);
- audioctrl->ahiac_RecordFunc =
- (struct Hook *)GetTagData(AHIA_RecordFunc,NULL,tags);
- audioctrl->ac.ahiac_PlayerFunc =
- (struct Hook *)GetTagData(AHIA_PlayerFunc,NULL,tags);
- audioctrl->ac.ahiac_PlayerFreq =
- GetTagData(AHIA_PlayerFreq,0,tags);
- audioctrl->ac.ahiac_MinPlayerFreq =
- GetTagData(AHIA_MinPlayerFreq,0,tags);
- audioctrl->ac.ahiac_MaxPlayerFreq =
- GetTagData(AHIA_MaxPlayerFreq,0,tags);
- audioctrl->ac.ahiac_AntiClickSamples =
- GetTagData(AHIA_AntiClickSamples,~0,tags);
-
- audioctrl->ahiac_MasterVolume=0x00010000;
- audioctrl->ahiac_SetMasterVolume=0x00010000;
- audioctrl->ahiac_EchoMasterVolume=0x00010000;
-
- if(audioctrl->ahiac_AudioID == AHI_DEFAULT_ID)
- audioctrl->ahiac_AudioID = AHIBase->ahib_AudioMode;
-
- if(audioctrl->ac.ahiac_MixFreq == AHI_DEFAULT_FREQ)
- audioctrl->ac.ahiac_MixFreq = AHIBase->ahib_Frequency;
-
- if(audioctrl->ac.ahiac_PlayerFunc == NULL)
- audioctrl->ac.ahiac_PlayerFunc=&DefPlayerHook;
-
- if(audioctrl->ac.ahiac_PlayerFreq == 0)
- audioctrl->ac.ahiac_PlayerFreq = DEFPLAYERFREQ;
- if(audioctrl->ac.ahiac_MinPlayerFreq == 0)
- audioctrl->ac.ahiac_MinPlayerFreq = DEFPLAYERFREQ;
- if(audioctrl->ac.ahiac_MaxPlayerFreq == 0)
- audioctrl->ac.ahiac_MaxPlayerFreq = DEFPLAYERFREQ;
-
- if(audioctrl->ac.ahiac_PlayerFreq < 65536)
- audioctrl->ac.ahiac_PlayerFreq <<= 16;
- if(audioctrl->ac.ahiac_MinPlayerFreq < 65536)
- audioctrl->ac.ahiac_MinPlayerFreq <<= 16;
- if(audioctrl->ac.ahiac_MaxPlayerFreq < 65536)
- audioctrl->ac.ahiac_MaxPlayerFreq <<= 16;
-
- if(audioctrl->ac.ahiac_AntiClickSamples == ~0UL)
- audioctrl->ac.ahiac_AntiClickSamples =
- ( AHIBase->ahib_AntiClickTime * audioctrl->ac.ahiac_MixFreq ) >> 16;
-
- if((audiodb=LockDatabase()))
- {
- if((dbtags=GetDBTagList(audiodb,audioctrl->ahiac_AudioID)))
- {
- audioctrl->ac.ahiac_Flags=PackBoolTags(GetTagData(AHIDB_Flags,NULL,dbtags),dbtags,boolmap);
- #ifdef HAVE_CLIPPING
- if(AHIBase->ahib_Flags & AHIBF_CLIPPING)
- {
- audioctrl->ac.ahiac_Flags |= AHIACF_CLIPPING;
- }
- #endif
- strcpy( audioctrl->ahiac_DriverName,
- "DEVS:AHI/" );
- strcat( audioctrl->ahiac_DriverName,
- (char *) GetTagData( AHIDB_Driver, (ULONG) "", dbtags ) );
- strcat( audioctrl->ahiac_DriverName,
- ".audio" );
-
- error=FALSE;
- }
- UnlockDatabase(audiodb);
- }
- }
-
- if(error)
- {
- AHIFreeVec(audioctrl);
- return NULL;
- }
- else
- return audioctrl;
- }
-
- static void
- UpdateAudioCtrl(struct AHIPrivAudioCtrl *audioctrl)
- {
- ULONG temp;
-
- temp=audioctrl->ac.ahiac_MinPlayerFreq;
- if(temp>=65536)
- temp >>=16;
- if(temp)
- audioctrl->ac.ahiac_MaxBuffSamples=audioctrl->ac.ahiac_MixFreq/temp;
- else
- audioctrl->ac.ahiac_MaxBuffSamples=AHIBase->ahib_Frequency/audioctrl->ac.ahiac_PlayerFreq;
-
- temp=audioctrl->ac.ahiac_MaxPlayerFreq;
- if(temp>=65536)
- temp = (temp + 65535) >> 16;
- if(temp)
- audioctrl->ac.ahiac_MinBuffSamples=audioctrl->ac.ahiac_MixFreq/temp;
- else
- audioctrl->ac.ahiac_MinBuffSamples=AHIBase->ahib_Frequency/audioctrl->ac.ahiac_PlayerFreq;
- }
-
-
-
- /******************************************************************************
- ** Sampler ********************************************************************
- ******************************************************************************/
-
- static void ASMCALL INTERRUPT
- Sampler ( REG(a0, struct Hook *hook),
- REG(a2, struct AHIPrivAudioCtrl *actrl),
- REG(a1, struct AHIRecordMessage *recmsg) )
- {
- if(actrl->ahiac_RecordFunc)
- {
- CallHookPkt(actrl->ahiac_RecordFunc, actrl, recmsg);
- }
- }
-
- /******************************************************************************
- ** AHI_AllocAudioA ************************************************************
- ******************************************************************************/
-
- /****** ahi.device/AHI_AllocAudioA ******************************************
- *
- * NAME
- * AHI_AllocAudioA -- allocates and initializes the audio hardware
- * AHI_AllocAudio -- varargs stub for AHI_AllocAudioA()
- *
- * SYNOPSIS
- * audioctrl = AHI_AllocAudioA( tags );
- * D0 A1
- *
- * struct AHIAudioCtrl *AHI_AllocAudioA( struct TagItem * );
- *
- * audioctrl = AHI_AllocAudio( tag1, ... );
- *
- * struct AHIAudioCtrl *AHI_AllocAudio( Tag, ... );
- *
- * FUNCTION
- * Allocates and initializes the audio hardware, selects the best
- * mixing routine (if necessary) according to the supplied tags.
- * To start playing you first need to call AHI_ControlAudioA().
- *
- * INPUTS
- * tags - A pointer to a tag list.
- *
- * TAGS
- *
- * AHIA_AudioID (ULONG) - The audio mode to use. Default is
- * AHI_DEFAULT_ID. (AHI_DEFAULT_ID is the ID the user has selected
- * in the preferences program. It's a good value to use the first
- * time she starts your application.)
- *
- * AHIA_MixFreq (ULONG) - Desired mixing frequency. The actual
- * mixing rate may or may not be exactly what you asked for.
- * Default is AHI_DEFAULT_FREQ. (AHI_DEFAULT_FREQ is the user's
- * prefered frequency.)
- *
- * AHIA_Channels (UWORD) - Number of channel to use. The actual
- * number of channels used will be equal or grater than the
- * requested. If too many channels were requested, this function
- * will fail. This tag must be supplied.
- *
- * AHIA_Sounds (UWORD) - Number of sounds to use. This tag must be
- * supplied.
- *
- * AHIA_SoundFunc (struct Hook *) - A function to call each time
- * when a sound has been started. The function receives the
- * following parameters:
- * A0 - (struct Hook *)
- * A2 - (struct AHIAudioCtrl *)
- * A1 - (struct AHISoundMessage *)
- * The hook may be called from an interrupt, so normal interrupt
- * restrictions apply.
- *
- * The called function should follow normal register conventions,
- * which means that d2-d7 and a2-a6 must be preserved.
- *
- * Default is NULL.
- *
- * AHIA_PlayerFunc (struct Hook *) - A function to be called at regular
- * intervals. By using this hook there is no need for music players
- * to use other timing, such as VBLANK or CIA timers. But the real
- * reason it's present is that it makes it possible to do non-
- * realtime mixing to disk.
- *
- * Using this interrupt source is currently the only supported way
- * to ensure that no mixing occurs between calls to AHI_SetVol(),
- * AHI_SetFreq() or AHI_SetSound().
- *
- * If the sound playback is done without mixing, 'realtime.library'
- * is used to provide timing. The function receives the following
- * parameters:
- * A0 - (struct Hook *)
- * A2 - (struct AHIAudioCtrl *)
- * A1 - Undefined.
- * Do not assume A1 contains any particular value!
- * The hook may be called from an interrupt, so normal interrupt
- * restrictions apply.
- *
- * The called function should follow normal register conventions,
- * which means that d2-d7 and a2-a6 must be preserved.
- *
- * Default is NULL.
- *
- * AHIA_PlayerFreq (Fixed) - If non-zero, enables timing and specifies
- * how many times per second PlayerFunc will be called. This must
- * be specified if AHIA_PlayerFunc is! Do not use any extreme
- * frequencies. The result of MixFreq/PlayerFreq must fit an UWORD,
- * ie it must be less or equal to 65535. It is also suggested that
- * you keep the result over 80. For normal use this should not be a
- * problem. Note that the data type is Fixed, not integer. 50 Hz is
- * 50<<16.
- *
- * Default is a reasonable value. Don't depend on it.
- *
- * AHIA_MinPlayerFreq (Fixed) - The minimum frequency (AHIA_PlayerFreq)
- * you will use. You MUST supply this if you are using the device's
- * interrupt feature!
- *
- * AHIA_MaxPlayerFreq (Fixed) - The maximum frequency (AHIA_PlayerFreq)
- * you will use. You MUST supply this if you are using the device's
- * interrupt feature!
- *
- * AHIA_RecordFunc (struct Hook *) - This function will be called
- * regularly when sampling is turned on (see AHI_ControlAudioA())
- * with the following parameters:
- * A0 - (struct Hook *)
- * A2 - (struct AHIAudioCtrl *)
- * A1 - (struct AHIRecordMessage *)
- * The message (AHIRecordMessage) is filled as follows:
- * ahirm_Buffer - Pointer to the samples. The buffer is valid
- * until next time the Hook is called.
- * ahirm_Length - Number of sample FRAMES in buffer.
- * To get the size in bytes, multiply by 4 if ahiim_Type is
- * AHIST_S16S.
- * ahirm_Type - Always AHIST_S16S at the moment, but you *must*
- * check this, since it may change in the future!
- * The hook may be called from an interrupt, so normal interrupt
- * restrictions apply. Signal a process if you wish to save the
- * buffer to disk. The called function should follow normal register
- * conventions, which means that d2-d7 and a2-a6 must be preserved.
- *
- * NOTE: The function MUST return NULL (in d0). This was previously
- * not documented. Now you know.
- *
- * Default is NULL.
- *
- * AHIA_UserData (APTR) - Can be used to initialize the ahiac_UserData
- * field. Default is 0.
- *
- * RESULT
- * A pointer to an AHIAudioCtrl structure or NULL if an error occured.
- *
- * EXAMPLE
- *
- * NOTES
- * SoundFunc will be called in the same manner as Paula interrupts
- * occur; when the device has updated its internal variables and can
- * accept new commands.
- *
- * BUGS
- *
- * SEE ALSO
- * AHI_FreeAudio(), AHI_ControlAudioA()
- *
- ****************************************************************************
- *
- */
-
- struct AHIAudioCtrl * ASMCALL
- AllocAudioA( REG(a1, struct TagItem *tags),
- REG(a6, struct AHIBase *AHIBase) )
- {
- struct AHIPrivAudioCtrl* audioctrl;
- struct Library *AHIsubBase;
- struct AHI_AudioDatabase *audiodb;
- struct TagItem *dbtags;
-
- if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW)
- {
- Debug_AllocAudioA(tags);
- }
-
- audioctrl = CreateAudioCtrl( tags );
- if(!audioctrl)
- goto error;
-
- AHIBase->ahib_AudioCtrl=audioctrl; // Save latest (for KillAudio)
-
- if(!audioctrl->ac.ahiac_Channels || !audioctrl->ac.ahiac_Sounds)
- goto error;
-
- audioctrl->ahiac_SubAllocRC = AHISF_ERROR;
- audioctrl->ahiac_SubLib=
- AHIsubBase = OpenLibrary(audioctrl->ahiac_DriverName,DriverVersion);
-
- if(!AHIsubBase)
- goto error;
-
- // Never allow drivers that are newer than ahi.device.
- if(AHIsubBase->lib_Version > Version)
- goto error;
-
- audiodb=LockDatabase();
- if(!audiodb)
- goto error;
-
- dbtags=GetDBTagList(audiodb,audioctrl->ahiac_AudioID);
- if(dbtags)
- audioctrl->ahiac_SubAllocRC=AHIsub_AllocAudio(dbtags,(struct AHIAudioCtrlDrv *)audioctrl);
-
- UnlockDatabase(audiodb);
-
- if(!dbtags)
- goto error;
-
- UpdateAudioCtrl(audioctrl);
-
- if(audioctrl->ahiac_SubAllocRC & AHISF_ERROR)
- goto error;
-
- // Mixing
- if(!(audioctrl->ahiac_SubAllocRC & AHISF_MIXING))
- audioctrl->ac.ahiac_Flags |= AHIACF_NOMIXING;
-
- // Timing
- if(!(audioctrl->ahiac_SubAllocRC & AHISF_TIMING))
- audioctrl->ac.ahiac_Flags |= AHIACF_NOTIMING;
-
- // Stereo
- if(!(audioctrl->ahiac_SubAllocRC & AHISF_KNOWSTEREO))
- audioctrl->ac.ahiac_Flags &= ~AHIACF_STEREO;
-
- // HiFi
- #ifdef HAVE_HIFI
- if(!(audioctrl->ahiac_SubAllocRC & AHISF_KNOWHIFI))
- audioctrl->ac.ahiac_Flags &= ~AHIACF_HIFI;
- #else
- // If plain 68k, unconditionally clear the HIFI bit
- audioctrl->ac.ahiac_Flags &= ~AHIACF_HIFI;
- #endif
-
- // Post-processing
- if(audioctrl->ahiac_SubAllocRC & AHISF_CANPOSTPROCESS)
- audioctrl->ac.ahiac_Flags |= AHIACF_POSTPROC;
-
- if(!(audioctrl->ac.ahiac_Flags & AHIACF_NOMIXING))
- {
- switch(audioctrl->ac.ahiac_Flags & (AHIACF_STEREO | AHIACF_HIFI))
- {
- case NULL:
- audioctrl->ac.ahiac_BuffType=AHIST_M16S;
- break;
- case AHIACF_STEREO:
- audioctrl->ac.ahiac_BuffType=AHIST_S16S;
- break;
- case AHIACF_HIFI:
- audioctrl->ac.ahiac_Flags |= AHIACF_CLIPPING;
- audioctrl->ac.ahiac_BuffType=AHIST_M32S;
- break;
- case (AHIACF_STEREO | AHIACF_HIFI):
- audioctrl->ac.ahiac_Flags |= AHIACF_CLIPPING;
- audioctrl->ac.ahiac_BuffType=AHIST_S32S;
- break;
- default:
- Alert(AT_Recovery|AG_BadParm);
- goto error;
- }
-
- /* Max channels/2 channels per hardware channel if stereo w/o pan */
- if((audioctrl->ac.ahiac_Flags & (AHIACF_STEREO | AHIACF_PAN)) == AHIACF_STEREO)
- audioctrl->ahiac_Channels2=(audioctrl->ac.ahiac_Channels+1)/2;
- else
- audioctrl->ahiac_Channels2=audioctrl->ac.ahiac_Channels;
- /*
- KPrintF("Mode: 0x%08lx, channels: %ld (%ld), flags: 0x%08lx\n",
- audioctrl->ac.ahiac_BuffType, audioctrl->ac.ahiac_Channels,
- audioctrl->ahiac_Channels2, audioctrl->ac.ahiac_Flags);
- */
-
- if(!(audioctrl->ac.ahiac_Flags & AHIACF_NOTIMING))
- {
- RecalcBuff(audioctrl->ac.ahiac_MinPlayerFreq,audioctrl);
- audioctrl->ac.ahiac_BuffSize=audioctrl->ahiac_BuffSizeNow;
- RecalcBuff(audioctrl->ac.ahiac_PlayerFreq,audioctrl);
- }
- else // No timing
- {
- ULONG size;
-
- size=audioctrl->ac.ahiac_BuffSamples*\
- AHI_SampleFrameSize(audioctrl->ac.ahiac_BuffType)*\
- (audioctrl->ac.ahiac_Flags & AHIACF_POSTPROC ? 2 : 1);
-
- size +=7;
- size &= ~7; // byte align
-
- audioctrl->ahiac_BuffSizeNow=size;
- }
-
- audioctrl->ac.ahiac_MixerFunc=AllocVec(sizeof(struct Hook),MEMF_PUBLIC|MEMF_CLEAR);
- if(!audioctrl->ac.ahiac_MixerFunc)
- goto error;
-
-
- audioctrl->ac.ahiac_MixerFunc->h_Entry = (HOOKFUNC) Mix;
-
- if((AHIBase->ahib_MaxCPU >= 0x10000) || (AHIBase->ahib_MaxCPU <= 0x0))
- {
- audioctrl->ac.ahiac_PreTimer = (BOOL (*)(void)) DummyPreTimer;
- audioctrl->ac.ahiac_PostTimer = (void (*)(void)) DummyPostTimer;
- }
- else
- {
- audioctrl->ahiac_MaxCPU = AHIBase->ahib_MaxCPU >> 8;
- audioctrl->ac.ahiac_PreTimer = (BOOL (*)(void)) PreTimer;
- audioctrl->ac.ahiac_PostTimer = (void (*)(void)) PostTimer;
- }
-
- if( !InitMixroutine( audioctrl ) ) goto error;
- }
-
- audioctrl->ac.ahiac_SamplerFunc = AllocVec(sizeof(struct Hook),
- MEMF_PUBLIC|MEMF_CLEAR);
- if(!audioctrl->ac.ahiac_SamplerFunc)
- goto error;
- audioctrl->ac.ahiac_SamplerFunc->h_Entry = (HOOKFUNC) Sampler;
-
- /* Set default hardware properties, only if AHI_DEFAULT_ID was used!*/
- if(GetTagData(AHIA_AudioID, AHI_DEFAULT_ID, tags) == AHI_DEFAULT_ID)
- {
- AHI_ControlAudio((struct AHIAudioCtrl *)audioctrl,
- AHIC_MonitorVolume, AHIBase->ahib_MonitorVolume,
- AHIC_InputGain, AHIBase->ahib_InputGain,
- AHIC_OutputVolume, AHIBase->ahib_OutputVolume,
- AHIC_Input, AHIBase->ahib_Input,
- AHIC_Output, AHIBase->ahib_Output,
- TAG_DONE);
- }
-
- exit:
- if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW)
- {
- KPrintF("=>0x%08lx\n",audioctrl);
- }
- return (struct AHIAudioCtrl *) audioctrl;
-
-
- error:
- AHI_FreeAudio((struct AHIAudioCtrl *)audioctrl);
- audioctrl=NULL;
- goto exit;
- }
-
-
- /******************************************************************************
- ** AHI_FreeAudio **************************************************************
- ******************************************************************************/
-
- /****** ahi.device/AHI_FreeAudio *******************************************
- *
- * NAME
- * AHI_FreeAudio -- deallocates the audio hardware
- *
- * SYNOPSIS
- * AHI_FreeAudio( audioctrl );
- * A2
- *
- * void AHI_FreeAudio( struct AHIAudioCtrl * );
- *
- * FUNCTION
- * Deallocates the AHIAudioCtrl structure and any other resources
- * allocated by AHI_AllocAudioA(). After this call it must not be used
- * by any other functions anymore. AHI_UnloadSound() is automatically
- * called for every sound.
- *
- * INPUTS
- * audioctrl - A pointer to an AHIAudioCtrl structure obtained from
- * AHI_AllocAudioA(). If NULL, this function does nothing.
- *
- * EXAMPLE
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * AHI_AllocAudioA(), AHI_UnloadSound()
- *
- ****************************************************************************
- *
- */
-
- ULONG ASMCALL
- FreeAudio( REG(a2, struct AHIPrivAudioCtrl *audioctrl),
- REG(a6, struct AHIBase *AHIBase) )
- {
- struct Library *AHIsubBase;
- int i;
-
- if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW)
- {
- Debug_FreeAudio(audioctrl);
- }
-
- if(audioctrl)
- {
- if((AHIsubBase=audioctrl->ahiac_SubLib))
- {
- if(!(audioctrl->ahiac_SubAllocRC & AHISF_ERROR))
- {
- AHIsub_Stop(AHISF_PLAY|AHISF_RECORD,(struct AHIAudioCtrlDrv *)audioctrl);
-
- for(i=audioctrl->ac.ahiac_Sounds-1;i>=0;i--)
- {
- AHI_UnloadSound(i,(struct AHIAudioCtrl *)audioctrl);
- }
- }
- AHIsub_FreeAudio((struct AHIAudioCtrlDrv *) audioctrl);
- CloseLibrary(AHIsubBase);
- }
-
- if(!(audioctrl->ac.ahiac_Flags & AHIACF_NOMIXING))
- {
- CleanUpMixroutine( audioctrl );
- }
-
- FreeVec( audioctrl->ahiac_MasterVolumeTable );
- FreeVec( audioctrl->ahiac_MultTableS );
- FreeVec( audioctrl->ahiac_MultTableU );
- FreeVec( audioctrl->ac.ahiac_SamplerFunc );
- FreeVec( audioctrl->ac.ahiac_MixerFunc );
-
- AHIFreeVec( audioctrl );
- }
- return NULL;
- }
-
-
- /******************************************************************************
- ** AHI_KillAudio **************************************************************
- ******************************************************************************/
-
- /****i* ahi.device/AHI_KillAudio *******************************************
- *
- * NAME
- * AHI_KillAudio -- clean up
- *
- * SYNOPSIS
- * AHI_KillAudio();
- *
- * void AHI_KillAudio( void );
- *
- * FUNCTION
- * 'ahi.device' keeps track of most of what the user does. This call is
- * used to clean up as much as possible. It must never, ever, be used
- * in an application. It is included for development use only, and can
- * be used to avoid rebooting the computer if your program has allocated
- * the audio hardware and crashed. This call can lead to a system crash,
- * so don't use it if you don't have to.
- *
- * INPUTS
- *
- * RESULT
- * This function returns nothing. In fact, it may never return.
- *
- * EXAMPLE
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * AHI_FreeAudio()
- *
- ****************************************************************************
- *
- */
-
- ULONG ASMCALL
- KillAudio( REG(a6, struct AHIBase *AHIBase) )
- {
- UWORD i;
-
- if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW)
- {
- Debug_KillAudio();
- }
-
- for(i=0xffff;i != 0; i--)
- {
- *((UWORD *) 0xdff102)=i;
- }
-
- AHI_FreeAudio(AHIBase->ahib_AudioCtrl);
- AHIBase->ahib_AudioCtrl=NULL;
- return NULL;
- }
-
-
- /******************************************************************************
- ** AHI_ControlAudioA **********************************************************
- ******************************************************************************/
-
- /****** ahi.device/AHI_ControlAudioA ***************************************
- *
- * NAME
- * AHI_ControlAudioA -- change audio attributes
- * AHI_ControlAudio -- varargs stub for AHI_ControlAudioA()
- *
- * SYNOPSIS
- * error = AHI_ControlAudioA( audioctrl, tags );
- * D0 A2 A1
- *
- * ULONG AHI_ControlAudioA( struct AHIAudioCtrl *, struct TagItem * );
- *
- * error = AHI_ControlAudio( AudioCtrl, tag1, ...);
- *
- * ULONG AHI_ControlAudio( struct AHIAudioCtrl *, Tag, ... );
- *
- * FUNCTION
- * This function should be used to change attributes for a given
- * AHIAudioCtrl structure. It is also used to start and stop playback,
- * and to control special hardware found on some sound cards.
- *
- * INPUTS
- * audioctrl - A pointer to an AHIAudioCtrl structure.
- * tags - A pointer to a tag list.
- *
- * TAGS
- * AHIC_Play (BOOL) - Starts (TRUE) and stops (FALSE) playback and
- * PlayerFunc. NOTE: If the audio hardware cannot play at the same
- * time as recording samples, the recording will be stopped.
- *
- * AHIC_Record (BOOL) - Starts (TRUE) and stops (FALSE) sampling and
- * RecordFunc. NOTE: If the audio hardware cannot record at the same
- * time as playing samples, the playback will be stopped.
- *
- * AHIC_MonitorVolume (Fixed) - Sets the input monitor volume, i.e. how
- * much of the input signal is mixed with the output signal while
- * recording. Use AHI_GetAudioAttrsA() to find the available range.
- *
- * AHIC_MonitorVolume_Query (Fixed *) - Get the current input monitor
- * volume. ti_Data is a pointer to a Fixed variable, where the result
- * will be stored.
- *
- * AHIC_MixFreq_Query (ULONG *) - Get the current mixing frequency.
- * ti_Data is a pointer to an ULONG variable, where the result will
- * be stored.
- *
- * AHIC_InputGain (Fixed) - Set the input gain. Use AHI_GetAudioAttrsA()
- * to find the available range. (V2)
- *
- * AHIC_InputGain_Query (Fixed *) - Get current input gain. (V2)
- *
- * AHIC_OutputVolume (Fixed) - Set the output volume. Use
- * AHI_GetAudioAttrsA() to find the available range. (V2)
- *
- * AHIC_OutputVolume_Query (Fixed *) - Get current output volume. (V2)
- *
- * AHIC_Input (ULONG) - Select input source. See AHI_GetAudioAttrsA().
- * (V2)
- *
- * AHIC_Input_Query (ULONG *) - Get current input source. (V2)
- *
- * AHIC_Output (ULONG) - Select destination for output. See
- * AHI_GetAudioAttrsA(). (V2)
- *
- * AHIC_Output_Query (ULONG *) - Get destination for output. (V2)
- *
- * The following tags are also recognized by AHI_ControlAudioA(). See
- * AHI_AllocAudioA() for what they do. They may be used from interrupts.
- *
- * AHIA_SoundFunc (struct Hook *)
- * AHIA_PlayerFunc (struct Hook *)
- * AHIA_PlayerFreq (Fixed)
- * AHIA_RecordFunc (struct Hook *)
- * AHIA_UserData (APTR)
- *
- * Note that AHIA_PlayerFreq must never be outside the limits specified
- * with AHIA_MinPlayerFreq and AHIA_MaxPlayerFreq! Also note that the
- * timing feature is designed to be used for music. When you change the
- * frequency, be reasonable. Using 50 Hz one moment and 5 the other is
- * to ask for trouble.
- *
- * RESULT
- * An error code, defined in <devices/ahi.h>.
- *
- * EXAMPLE
- *
- * NOTES
- * The AHIC_Play and AHIC_Record tags *must not* be used from
- * interrupts.
- *
- * BUGS
- *
- * SEE ALSO
- * AHI_AllocAudioA(), AHI_GetAudioAttrsA(), <devices/ahi.h>
- *
- ****************************************************************************
- *
- */
-
- ULONG ASMCALL
- ControlAudioA( REG(a2, struct AHIPrivAudioCtrl *audioctrl),
- REG(a1, struct TagItem *tags),
- REG(a6, struct AHIBase *AHIBase) )
- {
- ULONG *ptr, playflags=NULL, stopflags=NULL, rc=AHIE_OK;
- UBYTE update=FALSE;
- struct TagItem *tag,*tstate=tags;
- struct Library *AHIsubBase=audioctrl->ahiac_SubLib;
-
- if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW)
- {
- Debug_ControlAudioA(audioctrl,tags);
- }
-
- while((tag=NextTagItem(&tstate)))
- {
- ptr=(ULONG *)tag->ti_Data; // For ..._Query tags
- switch(tag->ti_Tag)
- {
- case AHIA_SoundFunc:
- audioctrl->ac.ahiac_SoundFunc=(struct Hook *) tag->ti_Data;
- update=TRUE;
- break;
- case AHIA_RecordFunc:
- audioctrl->ahiac_RecordFunc=(struct Hook *) tag->ti_Data;
- update=TRUE;
- break;
- case AHIA_PlayerFunc:
- audioctrl->ac.ahiac_PlayerFunc=(struct Hook *) tag->ti_Data;
- update=TRUE;
- break;
- case AHIA_PlayerFreq:
- audioctrl->ac.ahiac_PlayerFreq=tag->ti_Data;
-
- if(audioctrl->ac.ahiac_PlayerFreq < 65536)
- audioctrl->ac.ahiac_PlayerFreq <<= 16;
-
- if(!(audioctrl->ac.ahiac_Flags & AHIACF_NOTIMING)) // Dont call unless timing is used.
- RecalcBuff(audioctrl->ac.ahiac_PlayerFreq,audioctrl);
- update=TRUE;
- break;
- case AHIA_UserData:
- audioctrl->ac.ahiac_AudioCtrl.ahiac_UserData=(void *)tag->ti_Data;
- break;
- case AHIC_Play:
- if(tag->ti_Data)
- {
- playflags |= AHISF_PLAY;
- stopflags &= ~AHISF_PLAY;
- }
- else
- {
- playflags &= ~AHISF_PLAY;
- stopflags |= AHISF_PLAY;
- }
- update=FALSE;
- break;
- case AHIC_Record:
- if(tag->ti_Data)
- {
- playflags |= AHISF_RECORD;
- stopflags &= ~AHISF_RECORD;
- }
- else
- {
- playflags &= ~AHISF_RECORD;
- stopflags |= AHISF_RECORD;
- }
- update=FALSE;
- break;
- case AHIC_MixFreq_Query:
- *ptr=audioctrl->ac.ahiac_MixFreq;
- break;
- case AHIC_MonitorVolume:
- case AHIC_InputGain:
- case AHIC_OutputVolume:
- case AHIC_Input:
- case AHIC_Output:
- AHIsub_HardwareControl(tag->ti_Tag, tag->ti_Data, (struct AHIAudioCtrlDrv *)audioctrl);
- break;
- case AHIC_MonitorVolume_Query:
- case AHIC_InputGain_Query:
- case AHIC_OutputVolume_Query:
- case AHIC_Input_Query:
- case AHIC_Output_Query:
- *ptr=AHIsub_HardwareControl(tag->ti_Tag, NULL, (struct AHIAudioCtrlDrv *)audioctrl);
- break;
- }
- }
-
- // Let's act!
- if(update)
- {
- AHIsub_Update(NULL,(struct AHIAudioCtrlDrv *)audioctrl);
- }
-
- if(playflags)
- {
- rc=AHIsub_Start(playflags,(struct AHIAudioCtrlDrv *)audioctrl);
- }
-
- if(stopflags)
- {
- AHIsub_Stop(stopflags,(struct AHIAudioCtrlDrv *)audioctrl);
- }
-
- if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_LOW)
- {
- KPrintF("=>%ld\n",rc);
- }
-
- return rc;
- }
-