home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Best of Mecomp Multimedia 1
/
Mecomp-CD.iso
/
amiga
/
player
/
ahi
/
developer
/
drivers
/
toccata
/
toccata.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-01
|
11KB
|
439 lines
#include <exec/exec.h>
#include <devices/ahi.h>
#include <libraries/ahi_sub.h>
#include <libraries/toccata.h>
#include <dos/dos.h>
#include <proto/exec.h>
#include <proto/utility.h>
#include <proto/ahi_sub.h>
#include <clib/toccata_protos.h>
#include <pragmas/toccata_pragmas.h>
#include "toccata.h"
#define EQ ==
#define dd ((struct toccata *) AudioCtrl->ahiac_DriverData)
#define PLAYBUFFERSIZE 128*4 // in samples
#define PLAYIRQSIZE 1<<9 // 5=32, 6=64, ... 9=512
#define RECBUFFERSIZE 128*50 // in samples
extern char __far _LibID[];
extern char __far _LibName[];
extern void __asm RecordFunc(void);
extern void __asm PlayFuncMono(void);
extern void __asm PlayFuncStereo(void);
struct Library *UtilityBase=NULL;
struct Library *AHIsubBase=NULL;
struct ToccataBase *ToccataBase=NULL;
#define INPUTS 5
const static STRPTR Inputs[] =
{ "Line",
"Aux1",
"Mic",
"Mic as Line",
"Mixer"
};
const static ULONG inputmap[] =
{ TINPUT_Line,
TINPUT_Aux1,
TINPUT_Mic,
TINPUT_Mic,
TINPUT_Mix
};
const static ULONG micgainmap[] =
{ FALSE,
FALSE,
FALSE,
TRUE,
FALSE
};
int __saveds __asm __UserLibInit (register __a6 struct Library *libbase)
{
AHIsubBase=libbase;
if(!(UtilityBase=OpenLibrary("utility.library",37)))
{
Alert(AN_Unknown|AG_OpenLib|AO_UtilityLib);
return 1;
}
if(!(ToccataBase=(struct ToccataBase *)OpenLibrary("toccata.library",TOCCATA_LIB_VERSION)))
{
Alert(AN_Unknown|AG_OpenLib|AO_Unknown);
return 1;
}
return 0;
}
void __saveds __asm __UserLibCleanup (register __a6 struct Library *libbase)
{
if(UtilityBase) { CloseLibrary(UtilityBase); UtilityBase=NULL; }
if(ToccataBase) { CloseLibrary((struct Library *)ToccataBase); ToccataBase=NULL; }
}
ULONG __asm __saveds intAHIsub_AllocAudio(
register __a1 struct TagItem *tagList,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
if(AudioCtrl->ahiac_DriverData=AllocVec(sizeof(struct toccata),MEMF_PUBLIC|MEMF_ANY|MEMF_CLEAR))
{
dd->t_AHIsubBase=AHIsubBase;
dd->t_TocSamples=PLAYBUFFERSIZE;
/*
** This one is just to keep the $#£@$£#"% T_RawPlayback() happy.
** Thank you so very much, MacroSystem, for documenting that TT_ErrorTask and
** TT_ErrorMask must be specified for T_RawPlayback() but not T_Capture().
** After all, spending four days trying to figure out how to get T_RawPlayback()
** work is exactly my idea of fun. Or maybe not.
** Funny it should have to take a disassembly of 'toccata.library' to figure out
** how to use it.
*/
dd->t_ErrorTask=FindTask(NULL);
dd->t_ErrorSignal=AllocSignal(-1);
if(dd->t_ErrorSignal != -1)
{
AudioCtrl->ahiac_MixFreq=T_FindFrequency(AudioCtrl->ahiac_MixFreq);
if(ToccataBase->tb_HardInfo) // Check if hardware is present...
{
T_SaveSettings(0); // Save state
T_Stop(TSF_DONTSAVECACHE);
T_SetPartTags( // Reset
PAT_InputVolumeLeft,0,
PAT_InputVolumeRight,0,
PAT_OutputVolumeLeft,0,
PAT_OutputVolumeRight,0,
PAT_LoopbackVolume,-64,
PAT_Input,TINPUT_Line,
PAT_Mode,TMODE_LINEAR_16_S,
PAT_Frequency,ToccataBase->tb_HardInfo->hi_MaxFrequency,
TAG_DONE);
return AHISF_KNOWSTEREO|AHISF_CANRECORD|AHISF_MIXING|AHISF_TIMING;
}
}
}
return AHISF_ERROR;
}
void __asm __saveds intAHIsub_FreeAudio(
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
if(AudioCtrl->ahiac_DriverData)
{
FreeSignal(dd->t_ErrorSignal);
FreeVec(AudioCtrl->ahiac_DriverData);
AudioCtrl->ahiac_DriverData=NULL;
T_LoadSettings(0); // Restore state
}
}
ULONG __asm __saveds intAHIsub_Start(
register __d0 ULONG Flags,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
AHIsub_Stop(AHISF_PLAY|AHISF_RECORD,AudioCtrl); // Only half duplex!
if(Flags & AHISF_PLAY)
{
ULONG toccata_mode;
ULONG toccata_size;
if(!(dd->t_PlaySoftInt=AllocVec(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_ANY|MEMF_CLEAR)))
return AHIE_NOMEM;
switch(AudioCtrl->ahiac_BuffType)
{
case AHIST_M16S:
dd->t_PlaySoftInt->is_Code=(void (* )())PlayFuncMono;
toccata_mode=TMODE_LINEAR_16;
toccata_size=dd->t_TocSamples<<1;
break;
case AHIST_S16S:
dd->t_PlaySoftInt->is_Code=(void (* )())PlayFuncStereo;
toccata_mode=TMODE_LINEAR_16_S;
toccata_size=dd->t_TocSamples<<2;
break;
default:
return AHIE_BADSAMPLETYPE;
}
if(!(dd->t_SampBuffer1=AllocVec(toccata_size,MEMF_PUBLIC|MEMF_ANY)))
return AHIE_NOMEM;
if(!(dd->t_SampBuffer2=AllocVec(toccata_size,MEMF_PUBLIC|MEMF_ANY)))
return AHIE_NOMEM;
if(!(dd->t_MixBuffer=AllocVec(AudioCtrl->ahiac_BuffSize,MEMF_PUBLIC|MEMF_ANY)))
return AHIE_NOMEM;
dd->t_PlaySoftInt->is_Node.ln_Type=NT_INTERRUPT;
dd->t_PlaySoftInt->is_Node.ln_Name=_LibName;
dd->t_PlaySoftInt->is_Data=AudioCtrl;
if(!T_RawPlaybackTags(
TT_ErrorTask, dd->t_ErrorTask,
TT_ErrorMask, (1L << dd->t_ErrorSignal),
TT_Mode, toccata_mode,
TT_Frequency, AudioCtrl->ahiac_MixFreq,
TT_RawBuffer1, dd->t_SampBuffer1,
TT_RawBuffer2, dd->t_SampBuffer2,
TT_BufferSize, toccata_size,
TT_RawIrqSize, PLAYIRQSIZE,
TT_RawInt, dd->t_PlaySoftInt,
TAG_DONE))
{
T_Stop(TSF_DONTSAVECACHE);
return AHIE_UNKNOWN;
}
}
if(Flags & AHISF_RECORD)
{
if(!(dd->t_RecBuffer=AllocVec(RECBUFFERSIZE<<2,MEMF_PUBLIC|MEMF_ANY)))
return AHIE_NOMEM;
if(!(dd->t_RecMessage=AllocVec(sizeof(struct AHIRecordMessage),MEMF_PUBLIC|MEMF_ANY|MEMF_CLEAR)))
return AHIE_NOMEM;
dd->t_RecMessage->ahirm_Type=AHIST_S16S;
dd->t_RecMessage->ahirm_Buffer=dd->t_RecBuffer;
if(!T_CaptureTags(
TT_BufferSize,RECBUFFERSIZE<<2,
TT_Save, RecordFunc,
TT_CBParamA1, AudioCtrl,
TT_Mode, TMODE_LINEAR_16_S,
TT_Frequency, AudioCtrl->ahiac_MixFreq,
TT_Flags, TTF_READYRETURN,
TAG_DONE))
{
T_Stop(TSF_DONTSAVECACHE);
return AHIE_UNKNOWN;
}
}
return AHIE_OK;
}
/*
void __asm __saveds __interrupt intAHIsub_Update(
register __d0 ULONG Flags,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
}
*/
void __asm __saveds intAHIsub_Stop(
register __d0 ULONG Flags,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
if(Flags & AHISF_PLAY)
{
T_Stop(TSF_DONTSAVECACHE);
FreeVec(dd->t_MixBuffer);
dd->t_MixBuffer=NULL;
FreeVec(dd->t_SampBuffer1);
dd->t_SampBuffer1=NULL;
FreeVec(dd->t_SampBuffer2);
dd->t_SampBuffer2=NULL;
FreeVec(dd->t_PlaySoftInt);
dd->t_PlaySoftInt=NULL;
}
if(Flags & AHISF_RECORD)
{
T_Stop(TSF_DONTSAVECACHE);
FreeVec(dd->t_RecBuffer);
dd->t_RecBuffer=NULL;
}
}
LONG __asm __saveds intAHIsub_GetAttr(
register __d0 ULONG Attribute,
register __d1 LONG Argument,
register __d2 LONG Default,
register __a1 struct TagItem *tagList,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl)
{
switch(Attribute)
{
case AHIDB_Bits:
return 16;
case AHIDB_Frequencies:
{
ULONG freq=NULL;
LONG freqs=0;
while(freq=T_NextFrequency(freq))
freqs++;
return freqs;
}
case AHIDB_Frequency: // Index->Frequency
{
ULONG freq=NULL;
LONG i;
for(i=0; i<=Argument ; i++)
freq=T_NextFrequency(freq);
return (LONG) freq;
}
case AHIDB_Index: // Frequency->Index
{
ULONG freq=NULL,realfreq=T_FindFrequency(Argument);
LONG index=0;
while((freq=T_NextFrequency(freq)) != realfreq)
index++;
return index;
}
case AHIDB_Author:
return (LONG) "Martin 'Leviticus' Blom";
case AHIDB_Copyright:
return (LONG) "Public Domain";
case AHIDB_Version:
return (LONG) _LibID;
case AHIDB_Annotation:
return (LONG) "Based on code by Pauli Porkka, Peter Kunath and Frank Riffel.";
case AHIDB_Record:
return TRUE;
case AHIDB_FullDuplex:
return FALSE;
case AHIDB_Realtime:
return TRUE;
case AHIDB_MaxPlaySamples:
return Default+PLAYBUFFERSIZE;
case AHIDB_MaxRecordSamples:
return RECBUFFERSIZE;
case AHIDB_MinMonitorVolume:
return 0x00000;
case AHIDB_MaxMonitorVolume:
return 0x10000;
case AHIDB_MinInputGain:
return 0x10000;
case AHIDB_MaxInputGain:
return 0xd55d0; // 13.335<<16 == +22.5 dB
case AHIDB_MinOutputVolume:
return 0x00000;
case AHIDB_MaxOutputVolume:
return 0x10000;
case AHIDB_Inputs:
return INPUTS;
case AHIDB_Input:
{
return (LONG) Inputs[Argument];
}
case AHIDB_Outputs:
return 1;
case AHIDB_Output:
return (LONG) "Line"; // We have only one output!
default:
return Default;
}
}
const static LONG negboundaries[] =
{
65536,55141,46395,39037,32845,27636,23253,19565,16461,13850,11654,9805,8250,
6941,5840,4914,4135,3479,2927,2463,2072,1743,1467,1234,1038,873,735,618,520,
438,368,310,260,219,184,155,130,110,92,77,65,55,46,39,32,27,23,19,16,13,11,9,
8,6,5,4,4,3,2,2,2,1,1,1,0
};
LONG fixed2negdbvalue( LONG volume)
{
LONG i=0;
while(volume >= negboundaries[i])
i++;
return(-i);
}
const static LONG posboundaries[] =
{
65536,77889,92572,110022,130761,155410,184705,219522,260903,
310084,368536,438005,520570,618699,735326,873936
};
LONG fixed2posdbvalue( LONG volume)
{
LONG i=0;
while((volume >= posboundaries[i+1]) && i<15)
i++;
return(i);
}
LONG __asm __saveds __interrupt intAHIsub_HardwareControl(
register __d0 ULONG attribute,
register __d1 LONG argument,
register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
{
LONG rc=TRUE;
if(ToccataBase->tb_HardInfo) // Check if hardware is present...
{
switch (attribute)
{
case AHIC_MonitorVolume:
T_SetPartTags(PAT_LoopbackVolume, fixed2negdbvalue(argument), TAG_DONE);
break;
case AHIC_MonitorVolume_Query:
T_GetPartTags(PAT_LoopbackVolume, &rc, TAG_DONE);
rc=negboundaries[-rc];
break;
case AHIC_InputGain:
T_SetPartTags(PAT_InputVolumeLeft, fixed2posdbvalue(argument),
PAT_InputVolumeRight, fixed2posdbvalue(argument), TAG_DONE);
break;
case AHIC_InputGain_Query:
T_GetPartTags(PAT_InputVolumeLeft, &rc, TAG_DONE);
rc=negboundaries[rc];
break;
case AHIC_OutputVolume:
T_SetPartTags(PAT_OutputVolumeLeft, fixed2negdbvalue(argument),
PAT_OutputVolumeRight, fixed2negdbvalue(argument), TAG_DONE);
break;
case AHIC_OutputVolume_Query:
T_GetPartTags(PAT_OutputVolumeLeft, &rc, TAG_DONE);
rc=negboundaries[-rc];
break;
case AHIC_Input:
dd->t_Input=argument;
T_SetPartTags(PAT_Input, inputmap[argument],
PAT_MicGain, micgainmap[argument], TAG_DONE);
break;
case AHIC_Input_Query:
rc=dd->t_Input;
break;
case AHIC_Output_Query:
rc=0; // There is only one output
break;
default:
rc=FALSE;
break;
}
}
else
rc=FALSE;
return rc;
}