Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / devs / AHI / Drivers / Toccata / toccata.c
blob7df0af96a48b4bf1a93b156f6bbc7cc6dce076b4
2 #include <exec/exec.h>
4 #include <devices/ahi.h>
5 #include <libraries/ahi_sub.h>
6 #include <libraries/toccata.h>
8 #include <dos/dos.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>
19 #include <math.h>
21 #include "toccata.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;
47 LONG INPUTS = 5;
48 BOOL In_Use = FALSE;
49 BOOL NoTask = FALSE;
50 LONG IrqSize = 512;
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);
60 typedef BOOL __asm
61 PreTimer_proto(register __a2 struct AHIAudioCtrlDrv* actrl);
63 typedef void __asm
64 PostTimer_proto(register __a2 struct AHIAudioCtrlDrv* actrl);
66 const static STRPTR Inputs[] =
68 "Line",
69 "Aux1",
70 "Mic",
71 "Mic +20 dB",
72 "Mixer"
75 const static ULONG inputmap[] =
77 TINPUT_Line,
78 TINPUT_Aux1,
79 TINPUT_Mic,
80 TINPUT_Mic,
81 TINPUT_Mix
84 const static ULONG micgainmap[] =
86 FALSE,
87 FALSE,
88 FALSE,
89 TRUE,
90 FALSE
94 int __saveds __asm __UserLibInit (register __a6 struct Library *libbase)
96 char prefs[10]="0";
98 AHIsubBase = libbase;
100 if(!(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",37)))
102 Alert(AN_Unknown|AG_OpenLib|AO_DOSLib);
103 return 1;
106 if(!(UtilityBase = OpenLibrary("utility.library",37)))
108 Alert(AN_Unknown|AG_OpenLib|AO_UtilityLib);
109 return 1;
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"};
132 if(IntuitionBase) {
133 EasyRequest( NULL, &req, NULL, NULL );
134 CloseLibrary((struct Library *) IntuitionBase);
136 else
138 Alert(AN_Unknown|AG_OpenLib|AO_Unknown);
140 // NOTE! Don't fail if Toccata.library couldn't be opened!
144 /* Check for DraCoMotion */
146 if(ToccataBase &&
147 ToccataBase->tb_HardInfo &&
148 (ToccataBase->tb_HardInfo->hi_Flags & HIF_DMOTION))
150 INPUTS = 1;
152 else
154 INPUTS = 5;
157 if(GetVar("ENV:AHItoccataNoTask", prefs, sizeof prefs, NULL ) != -1)
159 if(prefs[0] == '1')
161 NoTask = TRUE;
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);
171 switch(IrqSize) {
172 case 32:
173 case 64:
174 case 128:
175 case 256:
176 case 512:
177 break;
178 default:
179 IrqSize = 512;
180 break;
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;
205 return 0;
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))
222 return AHISF_ERROR;
225 // Make sure only there is only one user!
227 Forbid();
228 if(In_Use)
230 Permit();
231 return AHISF_ERROR;
233 In_Use = TRUE;
234 Permit();
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);
251 Forbid();
252 if(dd->t_SlaveProcess = CreateNewProcTags(
253 NP_Entry,&SlaveProcessEntry,
254 NP_Name,_LibName,
255 NP_Priority,127,
256 TAG_DONE))
258 dd->t_SlaveProcess->pr_Task.tc_UserData = AudioCtrl;
260 Permit();
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;
276 In_Use = FALSE;
277 return AHISF_ERROR;
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)
296 In_Use = FALSE;
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)))
318 return AHIE_NOMEM;
320 if(!(dd->t_MixSoftInt = AllocVec(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_ANY|MEMF_CLEAR)))
321 return AHIE_NOMEM;
323 switch(AudioCtrl->ahiac_BuffType)
325 case AHIST_M16S:
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
329 break;
330 case AHIST_S16S:
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
334 break;
335 case AHIST_M32S:
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
339 break;
340 case AHIST_S32S:
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
344 break;
345 default:
346 return AHIE_BADSAMPLETYPE;
349 if(!(dd->t_SampBuffer1 = AllocVec(PLAYBUFFERSIZE,
350 MEMF_PUBLIC|MEMF_CLEAR|MEMF_ANY)))
351 return AHIE_NOMEM;
352 if(!(dd->t_SampBuffer2 = AllocVec(PLAYBUFFERSIZE,
353 MEMF_PUBLIC|MEMF_CLEAR|MEMF_ANY)))
354 return AHIE_NOMEM;
356 if(!(dd->t_MixBuffer1 = AllocVec(AudioCtrl->ahiac_BuffSize,
357 MEMF_PUBLIC|MEMF_CLEAR|MEMF_ANY)))
358 return AHIE_NOMEM;
359 if(!(dd->t_MixBuffer2 = AllocVec(AudioCtrl->ahiac_BuffSize,
360 MEMF_PUBLIC|MEMF_CLEAR|MEMF_ANY)))
361 return AHIE_NOMEM;
362 if(!(dd->t_MixBuffer3 = AllocVec(AudioCtrl->ahiac_BuffSize,
363 MEMF_PUBLIC|MEMF_CLEAR|MEMF_ANY)))
364 return AHIE_NOMEM;
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)))
381 return AHIE_NOMEM;
382 if(!(dd->t_RecMessage = AllocVec(sizeof(struct AHIRecordMessage),MEMF_PUBLIC|MEMF_ANY|MEMF_CLEAR)))
383 return AHIE_NOMEM;
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);
391 return AHIE_OK;
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;
411 // Disable Loopback
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;
428 // Disable Loopback
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)
447 return Default;
450 switch(Attribute)
452 case AHIDB_Bits:
453 return 16;
454 case AHIDB_Frequencies:
456 ULONG freq = NULL;
457 LONG freqs = 0;
458 while(freq = T_NextFrequency(freq))
459 freqs++;
460 return freqs;
462 case AHIDB_Frequency: // Index->Frequency
464 ULONG freq = NULL;
465 LONG i;
466 for(i = 0; i<=Argument ; i++)
467 freq = T_NextFrequency(freq);
468 return (LONG) freq;
470 case AHIDB_Index: // Frequency->Index
472 ULONG freq = NULL,realfreq = T_FindFrequency(Argument);
473 LONG index = 0;
474 while((freq = T_NextFrequency(freq)) != realfreq)
475 index++;
476 return index;
478 case AHIDB_Author:
479 return (IPTR) "Martin 'Leviticus' Blom";
480 case AHIDB_Copyright:
481 return (IPTR) "Public Domain";
482 case AHIDB_Version:
483 return (IPTR) _LibID;
484 case AHIDB_Annotation:
485 return (IPTR) "Based on code by Pauli Porkka, Peter Kunath and Frank Riffel.";
486 case AHIDB_Record:
487 return TRUE;
488 case AHIDB_FullDuplex:
489 return FALSE;
490 case AHIDB_Realtime:
491 return TRUE;
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:
500 return 0x00000;
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
507 else
509 return 0x10000;
511 case AHIDB_MinInputGain:
512 return 0x10000;
513 case AHIDB_MaxInputGain:
514 return 0xd55d0; // 13.335<<16 == +22.5 dB
515 case AHIDB_MinOutputVolume:
516 return 0x00000;
517 case AHIDB_MaxOutputVolume:
518 return 0x10000;
519 case AHIDB_Inputs:
520 return INPUTS;
521 case AHIDB_Input:
522 return (IPTR) Inputs[Argument];
523 case AHIDB_Outputs:
524 return 1;
525 case AHIDB_Output:
526 return (IPTR) "Line"; // We have only one output!
527 default:
528 return Default;
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)
542 LONG i = 0;
544 while(volume < negboundaries[i])
545 i++;
546 return(-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)
557 LONG i = 0;
559 while((volume >= posboundaries[i+1]) && i<=14)
560 i++;
561 return(i);
564 LONG __asm __saveds __interrupt intAHIsub_HardwareControl(
565 register __d0 ULONG attribute,
566 register __d1 LONG argument,
567 register __a2 struct AHIAudioCtrlDrv *AudioCtrl )
569 LONG rc = TRUE;
571 if(ToccataBase && ToccataBase->tb_HardInfo) // Check if hardware is present...
573 switch (attribute)
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);
584 break;
585 case AHIC_MonitorVolume_Query:
586 if(dd->t_Flags & TF_ISRECORDING)
588 T_GetPartTags(PAT_LoopbackVolume, &rc, TAG_DONE);
589 rc = negboundaries[-rc];
591 else
593 rc = dd->t_Loopback;
595 break;
596 case AHIC_InputGain:
597 T_SetPartTags(PAT_InputVolumeLeft, fixed2posdbvalue(argument),
598 PAT_InputVolumeRight, fixed2posdbvalue(argument), TAG_DONE);
599 break;
600 case AHIC_InputGain_Query:
601 T_GetPartTags(PAT_InputVolumeLeft, &rc, TAG_DONE);
602 rc = negboundaries[rc];
603 break;
604 case AHIC_OutputVolume:
605 T_SetPartTags(PAT_OutputVolumeLeft, fixed2negdbvalue(argument),
606 PAT_OutputVolumeRight, fixed2negdbvalue(argument), TAG_DONE);
607 break;
608 case AHIC_OutputVolume_Query:
609 T_GetPartTags(PAT_OutputVolumeLeft, &rc, TAG_DONE);
610 rc = negboundaries[-rc];
611 break;
612 case AHIC_Input:
613 dd->t_Input = argument;
614 T_SetPartTags(PAT_Input, inputmap[argument],
615 PAT_MicGain, micgainmap[argument], TAG_DONE);
616 break;
617 case AHIC_Input_Query:
618 rc = dd->t_Input;
619 break;
620 case AHIC_Output_Query:
621 rc = 0; // There is only one output
622 break;
623 default:
624 rc = FALSE;
625 break;
628 else
630 rc = FALSE;
632 return rc;
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,
654 TAG_DONE);
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);
669 for(;;)
671 ULONG signalset;
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))
680 // Quit
681 break;
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;
698 BOOL pretimer_rc;
700 pretimer_rc = pretimer(AudioCtrl);
702 CallHookPkt(AudioCtrl->ahiac_PlayerFunc, AudioCtrl, NULL);
704 if(! pretimer_rc ) {
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
718 Forbid();
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)
734 BOOL playing;
736 // Disable Loopback
737 T_SetPartTags(PAT_LoopbackVolume, -64, TAG_DONE);
739 playing = T_RawPlaybackTags(
740 TT_ErrorTask, me,
741 TT_ErrorMask, (1L << dd->t_PlaySignal),
742 TT_RawInt, dd->t_PlaySoftInt,
743 TT_Mode, dd->t_Mode,
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,
749 TAG_DONE);
751 if(playing)
753 dd->t_Flags |= TF_ISPLAYING;
756 return playing;
759 BOOL StartRecording(struct AHIAudioCtrlDrv *AudioCtrl, struct Process *me)
761 BOOL recording;
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);
768 else
770 // Enable Loopback
771 T_SetPartTags(PAT_LoopbackVolume, fixed2negdbvalue(dd->t_Loopback), TAG_DONE);
774 recording = T_CaptureTags(
775 TT_ErrorTask, me,
776 TT_ErrorMask, (1L << dd->t_RecordSignal),
777 TT_Save, RecordFunc,
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,
783 TAG_DONE);
785 if(recording)
787 dd->t_Flags |= TF_ISRECORDING;
790 return recording;