4 #include <devices/ahi.h>
5 #include <libraries/ahi_sub.h>
6 #include <libraries/toccata.h>
9 #include <dos/dostags.h>
11 #include <proto/exec.h>
12 #include <proto/dos.h>
13 #include <proto/intuition.h>
14 #include <proto/utility.h>
15 #include <proto/ahi_sub.h>
16 #include <clib/toccata_protos.h>
17 #include <pragmas/toccata_pragmas.h>
23 extern void KPrintF(char *fmt
,...);
25 #define dd ((struct toccata *) AudioCtrl->ahiac_DriverData)
27 //#define PLAYBUFFERSIZE 512 // Size in bytes
28 //#define RECBUFFERSIZE 512*32 // in bytes
30 extern char __far _LibID
[];
31 extern char __far _LibName
[];
33 extern void __asm
SlaveProcessEntry(void);
34 extern void __asm
CallPlayFunc(void);
35 extern void __asm
RecordFunc(void);
36 extern void __asm
PlayFuncMono(void);
37 extern void __asm
PlayFuncStereo(void);
38 extern void __asm
PlayFuncMono32(void);
39 extern void __asm
PlayFuncStereo32(void);
40 extern void __asm
MixFunc(void);
42 struct Library
*UtilityBase
= NULL
;
43 struct Library
*AHIsubBase
= NULL
;
44 struct ToccataBase
*ToccataBase
= NULL
;
45 struct DosLibrary
*DOSBase
= NULL
;
51 LONG PLAYBUFFERSIZE
= 512;
52 LONG RECBUFFERSIZE
= 512*32;
55 LONG
fixed2negdbvalue( LONG volume
);
56 LONG
fixed2posdbvalue( LONG volume
);
57 BOOL
StartPlaying(struct AHIAudioCtrlDrv
*AudioCtrl
, struct Process
*me
);
58 BOOL
StartRecording(struct AHIAudioCtrlDrv
*AudioCtrl
, struct Process
*me
);
61 PreTimer_proto(register __a2
struct AHIAudioCtrlDrv
* actrl
);
64 PostTimer_proto(register __a2
struct AHIAudioCtrlDrv
* actrl
);
66 const static STRPTR Inputs
[] =
75 const static ULONG inputmap
[] =
84 const static ULONG micgainmap
[] =
94 int __saveds __asm
__UserLibInit (register __a6
struct Library
*libbase
)
100 if(!(DOSBase
= (struct DosLibrary
*)OpenLibrary("dos.library",37)))
102 Alert(AN_Unknown
|AG_OpenLib
|AO_DOSLib
);
106 if(!(UtilityBase
= OpenLibrary("utility.library",37)))
108 Alert(AN_Unknown
|AG_OpenLib
|AO_UtilityLib
);
113 ** "toccata..library" is a modified version of "toccata.library" which calls
114 ** TT_RawInt in a real hardware interrupt instead of a software interrupt.
115 ** The author wishes to remain anonymous, but his hack suits my purposes well.
118 ToccataBase
= (struct ToccataBase
*)OpenLibrary("toccata..library",12);
120 if(ToccataBase
== NULL
)
122 ToccataBase
= (struct ToccataBase
*)OpenLibrary("toccata.library",12);
125 if(ToccataBase
== NULL
)
127 struct IntuitionBase
*IntuitionBase
= (struct IntuitionBase
*)
128 OpenLibrary("intuition.library", 37);
129 struct EasyStruct req
= { sizeof (struct EasyStruct
),
130 0, _LibName
, "Cannot open 'toccata.library' v12", "OK"};
133 EasyRequest( NULL
, &req
, NULL
, NULL
);
134 CloseLibrary((struct Library
*) IntuitionBase
);
138 Alert(AN_Unknown
|AG_OpenLib
|AO_Unknown
);
140 // NOTE! Don't fail if Toccata.library couldn't be opened!
144 /* Check for DraCoMotion */
147 ToccataBase
->tb_HardInfo
&&
148 (ToccataBase
->tb_HardInfo
->hi_Flags
& HIF_DMOTION
))
157 if(GetVar("ENV:AHItoccataNoTask", prefs
, sizeof prefs
, NULL
) != -1)
165 if(GetVar("ENV:AHItoccataIrqSize", prefs
, sizeof prefs
, NULL
) != -1)
167 if(StrToLong(prefs
, &IrqSize
) != -1)
169 IrqSize
= max(IrqSize
, 32);
170 IrqSize
= min(IrqSize
, 512);
185 if(GetVar("ENV:AHItoccataPlayBufferSize", prefs
, sizeof prefs
, NULL
) != -1)
187 if(StrToLong(prefs
, &PLAYBUFFERSIZE
) != -1)
189 PLAYBUFFERSIZE
= max(PLAYBUFFERSIZE
, 512);
190 PLAYBUFFERSIZE
= min(PLAYBUFFERSIZE
, 512*32);
191 PLAYBUFFERSIZE
= PLAYBUFFERSIZE
& 0xfffffe00;
195 if(GetVar("ENV:AHItoccataRecordBufferSize", prefs
, sizeof prefs
, NULL
) != -1)
197 if(StrToLong(prefs
, &RECBUFFERSIZE
) != -1)
199 RECBUFFERSIZE
= max(RECBUFFERSIZE
, 512);
200 RECBUFFERSIZE
= min(RECBUFFERSIZE
, 512*32);
201 RECBUFFERSIZE
= RECBUFFERSIZE
& 0xfffffe00;
208 void __saveds __asm
__UserLibCleanup (register __a6
struct Library
*libbase
)
210 if(DOSBase
) { CloseLibrary((struct Library
*)DOSBase
); DOSBase
= NULL
; }
211 if(UtilityBase
) { CloseLibrary(UtilityBase
); UtilityBase
= NULL
; }
212 if(ToccataBase
) { CloseLibrary((struct Library
*)ToccataBase
); ToccataBase
= NULL
; }
215 ULONG __asm __saveds
intAHIsub_AllocAudio(
216 register __a1
struct TagItem
*tagList
,
217 register __a2
struct AHIAudioCtrlDrv
*AudioCtrl
)
219 if((ToccataBase
== NULL
) ||
220 (ToccataBase
->tb_HardInfo
== NULL
))
225 // Make sure only there is only one user!
236 if(AudioCtrl
->ahiac_DriverData
= AllocVec(sizeof(struct toccata
),MEMF_PUBLIC
|MEMF_ANY
|MEMF_CLEAR
))
238 dd
->t_AHIsubBase
= AHIsubBase
;
239 dd
->t_NoTask
= NoTask
;
240 dd
->t_SlaveSignal
= -1;
241 dd
->t_PlaySignal
= -1;
242 dd
->t_RecordSignal
= -1;
243 dd
->t_MixSignal
= -1;
245 dd
->t_MasterTask
= FindTask(NULL
);
246 dd
->t_MasterSignal
= AllocSignal(-1);
247 if(dd
->t_MasterSignal
!= -1)
249 AudioCtrl
->ahiac_MixFreq
= T_FindFrequency(AudioCtrl
->ahiac_MixFreq
);
252 if(dd
->t_SlaveProcess
= CreateNewProcTags(
253 NP_Entry
,&SlaveProcessEntry
,
258 dd
->t_SlaveProcess
->pr_Task
.tc_UserData
= AudioCtrl
;
262 if(dd
->t_SlaveProcess
)
264 Wait(1L << dd
->t_MasterSignal
); // Wait for slave to come alive
265 if(dd
->t_SlaveProcess
!= NULL
) // Is slave alive or dead?
267 dd
->t_Flags
|= TF_IAMTHEOWNER
;
269 return AHISF_KNOWSTEREO
|AHISF_KNOWHIFI
|AHISF_CANRECORD
|
270 AHISF_MIXING
|AHISF_TIMING
;
280 void __asm __saveds
intAHIsub_FreeAudio(
281 register __a2
struct AHIAudioCtrlDrv
*AudioCtrl
)
283 if(AudioCtrl
->ahiac_DriverData
)
285 if(dd
->t_SlaveProcess
)
287 if(dd
->t_SlaveSignal
!= -1)
289 Signal((struct Task
*)dd
->t_SlaveProcess
,1L<<dd
->t_SlaveSignal
); // Kill him!
291 Wait(1L<<dd
->t_MasterSignal
); // Wait for slave to die
294 if(dd
->t_Flags
& TF_IAMTHEOWNER
)
299 FreeSignal(dd
->t_MasterSignal
);
300 FreeVec(AudioCtrl
->ahiac_DriverData
);
301 AudioCtrl
->ahiac_DriverData
= NULL
;
307 ULONG __asm __saveds
intAHIsub_Start(
308 register __d0 ULONG Flags
,
309 register __a2
struct AHIAudioCtrlDrv
*AudioCtrl
)
312 AHIsub_Stop(AHISF_PLAY
|AHISF_RECORD
,AudioCtrl
); // Only half duplex!
314 if(Flags
& AHISF_PLAY
)
317 if(!(dd
->t_PlaySoftInt
= AllocVec(sizeof(struct Interrupt
),MEMF_PUBLIC
|MEMF_ANY
|MEMF_CLEAR
)))
320 if(!(dd
->t_MixSoftInt
= AllocVec(sizeof(struct Interrupt
),MEMF_PUBLIC
|MEMF_ANY
|MEMF_CLEAR
)))
323 switch(AudioCtrl
->ahiac_BuffType
)
326 dd
->t_PlaySoftInt
->is_Code
= (void (* )())PlayFuncMono
;
327 dd
->t_Mode
= TMODE_LINEAR_16
;
328 dd
->t_TocSamples
= PLAYBUFFERSIZE
>>1; // Toc. buffer is 16 bit mono
331 dd
->t_PlaySoftInt
->is_Code
= (void (* )())PlayFuncStereo
;
332 dd
->t_Mode
= TMODE_LINEAR_16_S
;
333 dd
->t_TocSamples
= PLAYBUFFERSIZE
>>2; // Toc. buffer is 16 bit stereo
336 dd
->t_PlaySoftInt
->is_Code
= (void (* )())PlayFuncMono32
;
337 dd
->t_Mode
= TMODE_LINEAR_16
;
338 dd
->t_TocSamples
= PLAYBUFFERSIZE
>>1; // Toc. buffer is 16 bit mono
341 dd
->t_PlaySoftInt
->is_Code
= (void (* )())PlayFuncStereo32
;
342 dd
->t_Mode
= TMODE_LINEAR_16_S
;
343 dd
->t_TocSamples
= PLAYBUFFERSIZE
>>2; // Toc. buffer is 16 bit stereo
346 return AHIE_BADSAMPLETYPE
;
349 if(!(dd
->t_SampBuffer1
= AllocVec(PLAYBUFFERSIZE
,
350 MEMF_PUBLIC
|MEMF_CLEAR
|MEMF_ANY
)))
352 if(!(dd
->t_SampBuffer2
= AllocVec(PLAYBUFFERSIZE
,
353 MEMF_PUBLIC
|MEMF_CLEAR
|MEMF_ANY
)))
356 if(!(dd
->t_MixBuffer1
= AllocVec(AudioCtrl
->ahiac_BuffSize
,
357 MEMF_PUBLIC
|MEMF_CLEAR
|MEMF_ANY
)))
359 if(!(dd
->t_MixBuffer2
= AllocVec(AudioCtrl
->ahiac_BuffSize
,
360 MEMF_PUBLIC
|MEMF_CLEAR
|MEMF_ANY
)))
362 if(!(dd
->t_MixBuffer3
= AllocVec(AudioCtrl
->ahiac_BuffSize
,
363 MEMF_PUBLIC
|MEMF_CLEAR
|MEMF_ANY
)))
366 dd
->t_PlaySoftInt
->is_Node
.ln_Type
= NT_INTERRUPT
;
367 dd
->t_PlaySoftInt
->is_Node
.ln_Name
= _LibName
;
368 dd
->t_PlaySoftInt
->is_Data
= AudioCtrl
;
370 dd
->t_MixSoftInt
->is_Code
= (void (* )())MixFunc
;
371 dd
->t_MixSoftInt
->is_Node
.ln_Type
= NT_INTERRUPT
;
372 dd
->t_MixSoftInt
->is_Node
.ln_Name
= _LibName
;
373 dd
->t_MixSoftInt
->is_Data
= AudioCtrl
;
375 Signal((struct Task
*)dd
->t_SlaveProcess
,1L<<dd
->t_PlaySignal
);
378 if(Flags
& AHISF_RECORD
)
380 if(!(dd
->t_RecBuffer
= AllocVec(RECBUFFERSIZE
,MEMF_PUBLIC
|MEMF_ANY
)))
382 if(!(dd
->t_RecMessage
= AllocVec(sizeof(struct AHIRecordMessage
),MEMF_PUBLIC
|MEMF_ANY
|MEMF_CLEAR
)))
385 dd
->t_RecMessage
->ahirm_Type
= AHIST_S16S
;
386 dd
->t_RecMessage
->ahirm_Buffer
= dd
->t_RecBuffer
;
388 Signal((struct Task
*)dd
->t_SlaveProcess
,1L<<dd
->t_RecordSignal
);
395 void __asm __saveds __interrupt intAHIsub_Update(
396 register __d0 ULONG Flags,
397 register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
402 void __asm __saveds
intAHIsub_Stop(
403 register __d0 ULONG Flags
,
404 register __a2
struct AHIAudioCtrlDrv
*AudioCtrl
)
406 if(Flags
& AHISF_PLAY
)
408 T_Stop(TSF_DONTSAVECACHE
);
409 dd
->t_Flags
&= ~TF_ISPLAYING
;
412 T_SetPartTags(PAT_LoopbackVolume
, -64, TAG_DONE
);
414 FreeVec(dd
->t_MixBuffer1
); dd
->t_MixBuffer1
= NULL
;
415 FreeVec(dd
->t_MixBuffer2
); dd
->t_MixBuffer2
= NULL
;
416 FreeVec(dd
->t_MixBuffer3
); dd
->t_MixBuffer3
= NULL
;
417 FreeVec(dd
->t_SampBuffer1
); dd
->t_SampBuffer1
= NULL
;
418 FreeVec(dd
->t_SampBuffer2
); dd
->t_SampBuffer2
= NULL
;
419 FreeVec(dd
->t_MixSoftInt
); dd
->t_MixSoftInt
= NULL
;
420 FreeVec(dd
->t_PlaySoftInt
); dd
->t_PlaySoftInt
= NULL
;
423 if(Flags
& AHISF_RECORD
)
425 T_Stop(TSF_DONTSAVECACHE
);
426 dd
->t_Flags
&= ~TF_ISRECORDING
;
429 T_SetPartTags(PAT_LoopbackVolume
, -64, TAG_DONE
);
431 FreeVec(dd
->t_RecBuffer
);
432 dd
->t_RecBuffer
= NULL
;
438 IPTR __asm __saveds
intAHIsub_GetAttr(
439 register __d0 ULONG Attribute
,
440 register __d1 LONG Argument
,
441 register __d2 IPTR Default
,
442 register __a1
struct TagItem
*tagList
,
443 register __a2
struct AHIAudioCtrlDrv
*AudioCtrl
)
445 if(ToccataBase
== NULL
)
454 case AHIDB_Frequencies
:
458 while(freq
= T_NextFrequency(freq
))
462 case AHIDB_Frequency
: // Index->Frequency
466 for(i
= 0; i
<=Argument
; i
++)
467 freq
= T_NextFrequency(freq
);
470 case AHIDB_Index
: // Frequency->Index
472 ULONG freq
= NULL
,realfreq
= T_FindFrequency(Argument
);
474 while((freq
= T_NextFrequency(freq
)) != realfreq
)
479 return (IPTR
) "Martin 'Leviticus' Blom";
480 case AHIDB_Copyright
:
481 return (IPTR
) "Public Domain";
483 return (IPTR
) _LibID
;
484 case AHIDB_Annotation
:
485 return (IPTR
) "Based on code by Pauli Porkka, Peter Kunath and Frank Riffel.";
488 case AHIDB_FullDuplex
:
492 case AHIDB_MaxPlaySamples
:
493 // FIXME: PLAYBUFFERSIZE should actually be converted to samples here.
494 // However, it's no disaster, since AHIDB_MaxPlaySamples will just be
495 // overy pessimistic.
496 return Default
+PLAYBUFFERSIZE
;
497 case AHIDB_MaxRecordSamples
:
498 return RECBUFFERSIZE
>>2;
499 case AHIDB_MinMonitorVolume
:
501 case AHIDB_MaxMonitorVolume
:
502 if(ToccataBase
->tb_HardInfo
!= NULL
&&
503 ToccataBase
->tb_HardInfo
->hi_Flags
& HIF_1845
)
505 return 0x0000; // Workaround for bug in AD1845
511 case AHIDB_MinInputGain
:
513 case AHIDB_MaxInputGain
:
514 return 0xd55d0; // 13.335<<16 == +22.5 dB
515 case AHIDB_MinOutputVolume
:
517 case AHIDB_MaxOutputVolume
:
522 return (IPTR
) Inputs
[Argument
];
526 return (IPTR
) "Line"; // We have only one output!
532 const static LONG negboundaries
[] =
534 65536,55141,46395,39037,32845,27636,23253,19565,16461,13850,11654,9805,8250,
535 6941,5840,4914,4135,3479,2927,2463,2072,1743,1467,1234,1038,873,735,618,520,
536 438,368,310,260,219,184,155,130,110,92,77,65,55,46,39,32,27,23,19,16,13,11,9,
537 8,6,5,4,4,3,2,2,2,1,1,1,0
540 LONG
fixed2negdbvalue( LONG volume
)
544 while(volume
< negboundaries
[i
])
549 const static LONG posboundaries
[] =
551 65536,77889,92572,110022,130761,155410,184705,219522,260903,
552 310084,368536,438005,520570,618699,735326,873936
555 LONG
fixed2posdbvalue( LONG volume
)
559 while((volume
>= posboundaries
[i
+1]) && i
<=14)
564 LONG __asm __saveds __interrupt
intAHIsub_HardwareControl(
565 register __d0 ULONG attribute
,
566 register __d1 LONG argument
,
567 register __a2
struct AHIAudioCtrlDrv
*AudioCtrl
)
571 if(ToccataBase
&& ToccataBase
->tb_HardInfo
) // Check if hardware is present...
575 case AHIC_MonitorVolume
:
576 if((ToccataBase
->tb_HardInfo
->hi_Flags
& HIF_1845
) == 0)
578 dd
->t_Loopback
= argument
;
579 if(dd
->t_Flags
& TF_ISRECORDING
)
581 T_SetPartTags(PAT_LoopbackVolume
, fixed2negdbvalue(argument
), TAG_DONE
);
585 case AHIC_MonitorVolume_Query
:
586 if(dd
->t_Flags
& TF_ISRECORDING
)
588 T_GetPartTags(PAT_LoopbackVolume
, &rc
, TAG_DONE
);
589 rc
= negboundaries
[-rc
];
597 T_SetPartTags(PAT_InputVolumeLeft
, fixed2posdbvalue(argument
),
598 PAT_InputVolumeRight
, fixed2posdbvalue(argument
), TAG_DONE
);
600 case AHIC_InputGain_Query
:
601 T_GetPartTags(PAT_InputVolumeLeft
, &rc
, TAG_DONE
);
602 rc
= negboundaries
[rc
];
604 case AHIC_OutputVolume
:
605 T_SetPartTags(PAT_OutputVolumeLeft
, fixed2negdbvalue(argument
),
606 PAT_OutputVolumeRight
, fixed2negdbvalue(argument
), TAG_DONE
);
608 case AHIC_OutputVolume_Query
:
609 T_GetPartTags(PAT_OutputVolumeLeft
, &rc
, TAG_DONE
);
610 rc
= negboundaries
[-rc
];
613 dd
->t_Input
= argument
;
614 T_SetPartTags(PAT_Input
, inputmap
[argument
],
615 PAT_MicGain
, micgainmap
[argument
], TAG_DONE
);
617 case AHIC_Input_Query
:
620 case AHIC_Output_Query
:
621 rc
= 0; // There is only one output
635 // SlaveProcessEntry() sets up a2 and a6. __saveds fixes a5
636 void __asm __saveds
SlaveProcess(register __a2
struct AHIAudioCtrlDrv
*AudioCtrl
)
638 struct Process
*me
= (struct Process
*) FindTask(NULL
);
640 T_SaveSettings(0); // Save state
642 T_Stop(TSF_DONTSAVECACHE
);
643 dd
->t_Flags
&= ~(TF_ISPLAYING
| TF_ISRECORDING
);
645 T_SetPartTags( // Reset
646 PAT_InputVolumeLeft
, 0,
647 PAT_InputVolumeRight
, 0,
648 PAT_OutputVolumeLeft
, 0,
649 PAT_OutputVolumeRight
, 0,
650 PAT_LoopbackVolume
, -64,
651 PAT_Input
, TINPUT_Line
,
652 // PAT_Mode, TMODE_LINEAR_16_S,
653 // PAT_Frequency, AudioCtrl->ahiac_MixFreq,
656 dd
->t_SlaveSignal
= AllocSignal(-1);
657 dd
->t_PlaySignal
= AllocSignal(-1);
658 dd
->t_RecordSignal
= AllocSignal(-1);
659 dd
->t_MixSignal
= AllocSignal(-1);
661 if( (dd
->t_SlaveSignal
!= -1) &&
662 (dd
->t_PlaySignal
!= -1) &&
663 (dd
->t_RecordSignal
!= -1) &&
664 (dd
->t_MixSignal
!= -1))
666 // Tell Master we're alive
667 Signal(dd
->t_MasterTask
, 1L << dd
->t_MasterSignal
);
673 signalset
= Wait((1L << dd
->t_SlaveSignal
)
674 | (1L << dd
->t_PlaySignal
)
675 | (1L << dd
->t_RecordSignal
)
676 | (1L << dd
->t_MixSignal
));
678 if(signalset
& (1L << dd
->t_SlaveSignal
))
684 if(signalset
& (1L << dd
->t_PlaySignal
))
686 StartPlaying(AudioCtrl
, me
);
689 if(signalset
& (1L << dd
->t_RecordSignal
))
691 StartRecording(AudioCtrl
, me
);
694 if(signalset
& (1L << dd
->t_MixSignal
))
696 PreTimer_proto
* pretimer
= (PreTimer_proto
*) AudioCtrl
->ahiac_PreTimer
;
697 PostTimer_proto
* posttimer
= (PostTimer_proto
*) AudioCtrl
->ahiac_PostTimer
;
700 pretimer_rc
= pretimer(AudioCtrl
);
702 CallHookPkt(AudioCtrl
->ahiac_PlayerFunc
, AudioCtrl
, NULL
);
705 CallHookPkt(AudioCtrl
->ahiac_MixerFunc
, AudioCtrl
, dd
->t_MixBuffer3
);
708 posttimer(AudioCtrl
);
713 T_Stop(TSF_DONTSAVECACHE
);
714 dd
->t_Flags
&= ~(TF_ISPLAYING
| TF_ISRECORDING
);
716 T_LoadSettings(0); // Restore state
719 FreeSignal(dd
->t_SlaveSignal
); dd
->t_SlaveSignal
= -1;
720 FreeSignal(dd
->t_PlaySignal
); dd
->t_PlaySignal
= -1;
721 FreeSignal(dd
->t_RecordSignal
); dd
->t_RecordSignal
= -1;
722 FreeSignal(dd
->t_MixSignal
); dd
->t_MixSignal
= -1;
724 // Tell the Master we're dying
725 dd
->t_SlaveProcess
= NULL
;
726 Signal((struct Task
*)dd
->t_MasterTask
, 1L << dd
->t_MasterSignal
);
728 // Multitaking will resume when we are dead.
732 BOOL
StartPlaying(struct AHIAudioCtrlDrv
*AudioCtrl
, struct Process
*me
)
737 T_SetPartTags(PAT_LoopbackVolume
, -64, TAG_DONE
);
739 playing
= T_RawPlaybackTags(
741 TT_ErrorMask
, (1L << dd
->t_PlaySignal
),
742 TT_RawInt
, dd
->t_PlaySoftInt
,
744 TT_Frequency
, AudioCtrl
->ahiac_MixFreq
,
745 TT_RawBuffer1
, dd
->t_SampBuffer1
,
746 TT_RawBuffer2
, dd
->t_SampBuffer2
,
747 TT_BufferSize
, PLAYBUFFERSIZE
,
748 TT_RawIrqSize
, IrqSize
,
753 dd
->t_Flags
|= TF_ISPLAYING
;
759 BOOL
StartRecording(struct AHIAudioCtrlDrv
*AudioCtrl
, struct Process
*me
)
763 if(ToccataBase
->tb_HardInfo
->hi_Flags
& HIF_1845
)
765 // Disable Loopback (workaround for bug in AD1845)
766 T_SetPartTags(PAT_LoopbackVolume
, -64, TAG_DONE
);
771 T_SetPartTags(PAT_LoopbackVolume
, fixed2negdbvalue(dd
->t_Loopback
), TAG_DONE
);
774 recording
= T_CaptureTags(
776 TT_ErrorMask
, (1L << dd
->t_RecordSignal
),
778 TT_CBParamA1
, AudioCtrl
,
779 TT_Mode
, TMODE_LINEAR_16_S
,
780 TT_Frequency
, AudioCtrl
->ahiac_MixFreq
,
781 TT_BufferSize
, RECBUFFERSIZE
,
782 TT_Flags
, TTF_READYRETURN
,
787 dd
->t_Flags
|= TF_ISRECORDING
;