Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / devs / AHI / Toccata / slaveproc.c
blobaceff5657c1010107608f8c3641109198aed25c2
1 /*
2 toccata.library - AHI-based Toccata emulation library
3 Copyright (C) 1997-2005 Martin Blom <martin@blom.org> and Teemu Suikki.
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330, Cambridge,
18 MA 02139, USA.
22 #include <devices/ahi.h>
23 #include <dos/dos.h>
24 #include <dos/dostags.h>
25 #include <exec/exec.h>
26 #include <libraries/iffparse.h>
27 #include <libraries/maud.h>
29 #include <proto/ahi.h>
30 #include <proto/dos.h>
31 #include <proto/exec.h>
32 #include <proto/iffparse.h>
33 #include <proto/utility.h>
34 #include <clib/toccata_protos.h>
35 #include <pragmas/toccata_pragmas.h>
37 #include <math.h>
38 #include <limits.h>
39 #include <string.h>
40 #include <stdio.h>
42 #include "toccata.h"
44 //#define DEBUG
46 #ifdef DEBUG
47 BPTR dfh;
48 #define DBG(text) {Forbid();FPuts(dfh,text);Flush(dfh);Permit();}
49 #define DVAL(text,val) {Forbid();VFPrintf(dfh,(STRPTR)text,&val);Flush(dfh);Permit();}
50 #else
51 #define DBG(text)
52 #define DVAL(text,val)
53 #endif
55 /* Prototypes */
57 static ASM ULONG SoundFunc(REG(a0) struct Hook *hook,
58 REG(a2) struct AHIAudioCtrl *audioctrl,
59 REG(a1) struct AHISoundMessage *msg);
60 static ASM ULONG RecordFunc(REG(a0) struct Hook *hook,
61 REG(a2) struct AHIAudioCtrl *audioctrl,
62 REG(a1) struct AHIRecordMessage *msg);
64 ASM LONG ReadMAUD(REG(a0) UBYTE *buffer, REG(d0) ULONG length, REG(a1) ULONG unused);
66 static BOOL AllocAudio(void);
67 static void FreeAudio(void);
68 static BOOL TuneAudio(void);
69 static BOOL ControlAudio(void);
71 static void Pause(ULONG pause);
72 static void Stop(ULONG flags);
73 static BOOL RawPlayback(struct TagItem *tags);
74 static BOOL Playback(struct TagItem *tags);
77 struct Process *IOProcess = NULL;
78 BOOL IOInitialized = FALSE;
82 /* Some flags */
84 BOOL SlaveInitialized = FALSE;
85 BOOL AudioInitialized = FALSE;
86 BOOL Playing = FALSE;
87 BOOL Recording = FALSE;
88 BOOL Leveling = FALSE;
89 BOOL Pausing = FALSE;
90 BOOL Sound0Loaded = FALSE;
91 BOOL Sound1Loaded = FALSE;
92 LONG SoundFlag = 0;
93 BOOL FirstBuf = FALSE;
95 /* RawPlayback variables */
97 struct Task *ErrorTask, *RawTask, *SigTask;
98 ULONG ErrorMask, RawMask, SigMask;
99 struct Interrupt *RawInt;
100 BYTE *RawBuffer1, *RawBuffer2;
101 ULONG RawBufferSize, RawIrqSize=512;
102 ULONG *ByteCount;
103 ULONG ByteSkip;
105 ULONG RawBufferLength; /* RawBufferSize / samplesize */
106 LONG NextBufferOK;
107 LONG ByteSkipCounter;
109 /* Playback variables */
111 struct Task *EndTask;
112 ULONG EndMask;
113 struct Window *Window;
114 BYTE IoPri;
115 ULONG BufferSize;
116 ASM LONG (*Load)(REG(a0) UBYTE *, REG(d0) ULONG, REG(a1) ULONG);
117 ULONG LoadParam;
118 STRPTR FileName;
119 LONG Length;
120 BOOL SmartPlay;
121 UWORD PreBlocks;
122 UWORD PlayBlocks;
123 ULONG Flags;
125 struct IFFHandle *iff;
126 BOOL iffopened;
127 BYTE *Buffer1, *Buffer2;
128 UWORD BuffersLoaded;
129 struct List BufferList;
130 WORD BufferFlag;
132 struct Buffer {
133 struct Node Node;
134 LONG Size;
135 BYTE *Buffer;
138 /* Audio stuff */
140 struct AHIAudioCtrl *audioctrl = NULL;
142 Fixed MinMonVol, MaxMonVol, MinOutVol, MaxOutVol, MinGain, MaxGain;
144 struct Hook SoundHook = {
145 NULL, NULL, (ULONG (*)()) HookLoad, SoundFunc, NULL
148 struct Hook RecordHook = {
149 NULL, NULL, (ULONG (*)()) HookLoad, RecordFunc, NULL
152 /* dB<->Fixed conversion */
154 const Fixed negboundaries[] = {
155 65536,55141,46395,39037,32845,27636,23253,19565,16461,13850,11654,9805,8250,
156 6941,5840,4914,4135,3479,2927,2463,2072,1743,1467,1234,1038,873,735,618,520,
157 438,368,310,260,219,184,155,130,110,92,77,65,55,46,39,32,27,23,19,16,13,11,9,
158 8,6,5,4,4,3,2,2,2,1,1,1,0
161 const Fixed posboundaries[] = {
162 65536,77889,92572,110022,130761,155410,184705,219522,260903,
163 310084,368536,438005,520570,618699,735326,873936
169 * SoundFunc(): Called when a sample has just started
172 static ASM ULONG SoundFunc(REG(a0) struct Hook *hook,
173 REG(a2) struct AHIAudioCtrl *audioctrl,
174 REG(a1) struct AHISoundMessage *msg) {
176 if(SoundFlag == 0) {
177 SoundFlag = 1;
179 else {
180 SoundFlag = 0;
183 if (!FirstBuf) {
184 if(!NextBufferOK && (ErrorTask != NULL)) {
185 Signal(ErrorTask, ErrorMask);
186 if(IOProcess != NULL) {
187 Signal((struct Task *) IOProcess, SIGBREAKF_CTRL_E);
189 else {
190 Signal((struct Task *) SlaveProcess, SIGBREAKF_CTRL_E);
194 if(RawInt != NULL) {
195 Cause(RawInt);
197 else if(RawTask != NULL) {
198 NextBufferOK=FALSE;
199 Signal(RawTask, RawMask);
201 } else FirstBuf=FALSE;
203 AHI_SetSound(0, SoundFlag, 0,RawBufferLength, audioctrl,0);
205 if(ByteCount != NULL) {
206 *ByteCount += RawBufferSize;
210 if(SigTask != NULL) {
211 ByteSkipCounter -= RawBufferSize;
212 if(ByteSkipCounter <= 0) {
213 ByteSkipCounter += ByteSkip;
214 Signal(SigTask, SigMask);
218 return 0;
223 * RecordFunc(): Called when a new block of recorded data is available
226 static ASM ULONG RecordFunc(REG(a0) struct Hook *hook,
227 REG(a2) struct AHIAudioCtrl *audioctrl,
228 REG(a1) struct AHIRecordMessage *msg) {
230 return 0;
235 * SlaveTask(): The slave process
236 * CTRL_C terminates, CTRL_E stops playing/recording (error signal)
239 void ASM SlaveTask(void) {
240 struct MsgPort *AHImp = NULL;
241 struct AHIRequest *AHIio = NULL;
242 BYTE AHIDevice = -1;
243 struct Process *me;
244 ToccataBase->tb_HardInfo = NULL;
246 #ifdef DEBUG
247 dfh=Open("con:10/300/400/300/Output",MODE_OLDFILE);
248 DBG("Slave started!\n");
249 #endif
251 me = (struct Process *) FindTask(NULL);
253 if(AHImp=CreateMsgPort()) {
254 if(AHIio=(struct AHIRequest *)CreateIORequest(AHImp,sizeof(struct AHIRequest))) {
255 AHIio->ahir_Version = 4;
256 AHIDevice = OpenDevice(AHINAME, AHI_NO_UNIT, (struct IORequest *)AHIio, NULL);
260 if(AHIDevice == 0) {
261 AHIBase = (struct Library *) AHIio->ahir_Std.io_Device;
263 fillhardinfo();
265 SlaveInitialized = TRUE;
267 while(TRUE) {
268 ULONG signals;
269 struct slavemessage *msg;
271 signals = Wait((1L << me->pr_MsgPort.mp_SigBit) |
272 SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_E);
274 if(signals & SIGBREAKF_CTRL_C) {
275 break;
278 if(signals & SIGBREAKF_CTRL_E) {
279 Stop(0);
282 if(signals & (1L << me->pr_MsgPort.mp_SigBit)) {
283 while(msg = (struct slavemessage *) GetMsg(&me->pr_MsgPort)) {
284 DVAL("gotmessage! %ld: ",msg->ID);
285 DVAL("0x%08lx\n",msg->Data);
286 switch(msg->ID) {
287 case MSG_MODE:
288 FreeAudio();
289 AllocAudio();
290 break;
291 case MSG_HWPROP:
292 TuneAudio();
293 break;
294 case MSG_RAWPLAY:
295 msg->Data = (APTR) RawPlayback(msg->Data);
296 break;
297 case MSG_PLAY:
298 msg->Data = (APTR) Playback(msg->Data);
299 break;
300 case MSG_RECORD:
301 DBG("record\n");
302 break;
303 case MSG_STOP:
304 Stop(*((ULONG *) msg->Data));
305 break;
306 case MSG_PAUSE:
307 Pause(*((ULONG *) msg->Data));
308 break;
309 case MSG_LEVELON:
310 DBG("levelon\n");
311 break;
312 case MSG_LEVELOFF:
313 DBG("leveloff\n");
314 break;
315 default:
316 DBG("unknown\n");
317 break;
319 ReplyMsg((struct Message *) msg);
322 } /* while */
325 SlaveInitialized = FALSE;
327 Stop(0);
328 FreeAudio();
330 AHIBase = NULL;
331 if(!AHIDevice) {
332 CloseDevice((struct IORequest *)AHIio);
334 DeleteIORequest((struct IORequest *)AHIio);
335 DeleteMsgPort(AHImp);
336 DBG("(slave closed down)\n");
338 #ifdef DEBUG
339 Close(dfh);
340 dfh=NULL;
341 #endif
343 Forbid();
344 SlaveProcess = NULL;
349 * IOTask(): The play/record process
350 * CTRL_C terminates, CTRL_D rawsignal, CTRL_E error signal
353 void ASM IOTask(void) {
354 struct Process *me;
355 BOOL rc = FALSE;
357 me = (struct Process *) FindTask(NULL);
359 BuffersLoaded = 0;
360 NewList(&BufferList);
362 iff = NULL;
363 iffopened = FALSE;
366 /* Open MAUD file for reading */
368 if(FileName != NULL) {
369 iff = AllocIFF();
370 if(iff) {
371 iff->iff_Stream = Open(FileName, MODE_OLDFILE);
372 if(iff->iff_Stream) {
373 InitIFFasDOS(iff);
374 if(!OpenIFF(iff, IFFF_READ)) {
375 iffopened = TRUE;
376 if(!StopChunk(iff, ID_MAUD, ID_MDAT)) {
377 while(TRUE) {
378 LONG error = ParseIFF(iff,IFFPARSE_SCAN);
379 struct ContextNode *cn;
381 if(error == IFFERR_EOC) continue;
382 if(error) break;
384 cn = CurrentChunk(iff);
386 if(cn && (cn->cn_Type == ID_MAUD) && (cn->cn_ID == ID_MDAT)) {
387 rc = TRUE;
388 break;
390 } /* while */
396 else rc = TRUE; /* Not an error! */
399 /* Fill the two play buffers with data */
401 memset(Buffer1, 0, BufferSize);
402 Load(Buffer1, BufferSize, LoadParam);
404 memset(Buffer2, 0, BufferSize);
405 Load(Buffer2, BufferSize, LoadParam);
407 BufferFlag = 0;
409 /* Now prefill some more */
411 if(rc) {
412 while(BuffersLoaded < (PreBlocks - 2)) {
413 struct Buffer *buffer;
415 buffer = (struct Buffer *) AllocVec(sizeof (struct Buffer), MEMF_CLEAR);
416 if(buffer == NULL) {
417 break;
420 buffer->Buffer = AllocVec(BufferSize, MEMF_PUBLIC | MEMF_CLEAR);
421 if(buffer->Buffer) {
422 buffer->Size = Load(buffer->Buffer, BufferSize, LoadParam);
423 AddTail(&BufferList, (struct Node *) buffer);
424 BuffersLoaded++;
426 else {
427 FreeVec(buffer);
428 break;
432 IOInitialized = TRUE;
434 DBG("iotask initialized\n");
437 while(rc) {
438 ULONG signals;
440 signals = SetSignal(0,0);
442 if(signals & SIGBREAKF_CTRL_C) {
443 DBG("iotask got break\n");
444 break;
447 if(SIGBREAKF_CTRL_D) {
448 struct Buffer *buffer;
449 LONG size = 0;
451 DBG("iotask swapped buffer!\n");
453 buffer = (struct Buffer *) RemHead(&BufferList);
454 if(buffer) {
455 BuffersLoaded--;
456 size = buffer->Size;
457 memcpy((BufferFlag == 0 ? Buffer1 : Buffer2) , buffer->Buffer,
458 buffer->Size);
461 /* Clear the rest of the block */
462 if((BufferSize - size) > 0) {
463 memset((BufferFlag == 0 ? Buffer1 : Buffer2) + size, 0,
464 BufferSize - size);
467 if(BufferFlag == 0) {
468 BufferFlag = 1;
470 else {
471 BufferFlag = 0;
474 RawReply();
478 if(SIGBREAKF_CTRL_E) {
479 DBG("iotask got error\n");
480 if(!SmartPlay) {
481 /* Ask him to stop and kill us */
482 Signal((struct Task *) SlaveProcess, SIGBREAKF_CTRL_E);
487 /* If there are no signals pending, lets load some data! */
489 while((signals & ((1L << me->pr_MsgPort.mp_SigBit) |
490 SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E)) == 0) {
492 if(BuffersLoaded < PlayBlocks) {
493 struct Buffer *buffer;
495 buffer = AllocVec(sizeof (struct Buffer), MEMF_CLEAR);
496 if(buffer == NULL) {
497 break;
500 buffer->Buffer = AllocVec(BufferSize, MEMF_PUBLIC | MEMF_CLEAR);
501 if(buffer->Buffer) {
502 buffer->Size = Load(buffer->Buffer, BufferSize, LoadParam);
503 AddTail(&BufferList, (struct Node *) buffer);
504 BuffersLoaded++;
506 else {
507 FreeVec(buffer);
508 break;
511 else {
512 /* Wait */
513 signals = Wait((1L << me->pr_MsgPort.mp_SigBit) |
514 SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E);
523 DBG("iotask terminating\n");
525 if(iff) {
527 if(iffopened) {
528 CloseIFF(iff);
531 if(iff->iff_Stream) {
532 Close(iff->iff_Stream);
535 FreeIFF(iff);
538 iff = NULL;
541 /* Free buffers if any left */
543 struct Buffer *buffer;
545 while(buffer = (struct Buffer *) RemHead(&BufferList)) {
546 FreeVec(buffer->Buffer);
547 FreeVec(buffer);
551 FreeVec(Buffer1);
552 Buffer1 = NULL;
553 FreeVec(Buffer2);
554 Buffer2 = NULL;
556 Forbid();
557 IOProcess = NULL;
562 * ReadMAUD(): Used as callback function when playing
565 ASM LONG ReadMAUD(REG(a0) UBYTE *buffer, REG(d0) ULONG length,
566 REG(a1) ULONG unused) {
568 return ReadChunkBytes(iff, buffer, length);
572 * AllocAudio(): Allocate the audio hardware
575 static BOOL AllocAudio(void) {
577 DBG("(AllocAudio())...\n");
579 /* Set up for HookFunc */
580 SoundHook.h_Data = ToccataBase;
581 RecordHook.h_Data = ToccataBase;
583 MinMonVol = MaxMonVol = 0;
584 MinOutVol = MaxOutVol = 0x10000;
585 MinGain = MaxGain = 0x10000;
587 audioctrl = AHI_AllocAudio(
588 AHIA_AudioID, (tprefs.Mode & TMODEF_STEREO ?
589 tprefs.StereoMode : tprefs.MonoMode),
590 AHIA_MixFreq, tprefs.Frequency,
591 AHIA_Channels, 1,
592 AHIA_Sounds, 2,
593 AHIA_SoundFunc, &SoundHook,
595 AHIA_PlayerFreq, (tprefs.Frequency / 512) << 16,
596 AHIA_MinPlayerFreq, (tprefs.Frequency / 512) << 16,
597 AHIA_MaxPlayerFreq, (tprefs.Frequency / 512) << 16,
598 AHIA_RecordFunc, &RecordHook,
599 TAG_DONE);
601 if(audioctrl != NULL) {
602 AHI_GetAudioAttrs(AHI_INVALID_ID, audioctrl,
603 AHIDB_MinMonitorVolume, &MinMonVol,
604 AHIDB_MaxMonitorVolume, &MaxMonVol,
605 AHIDB_MinOutputVolume, &MinOutVol,
606 AHIDB_MaxOutputVolume, &MaxOutVol,
607 AHIDB_MinInputGain, &MinGain,
608 AHIDB_MaxInputGain, &MaxGain,
609 TAG_DONE);
611 fillhardinfo();
612 TuneAudio();
614 AudioInitialized = TRUE;
615 DBG("ok!\n");
616 return TRUE;
618 DBG("Nope!\n");
619 return FALSE;
624 * FreeAudio(): Release the audio hardware
627 static void FreeAudio(void) {
629 DBG("(FreeAudio())...\n");
631 Playing = FALSE;
632 Recording = FALSE;
634 ControlAudio();
636 if(audioctrl != NULL) {
637 AHI_FreeAudio(audioctrl);
640 audioctrl = NULL;
641 AudioInitialized = FALSE;
646 * TuneAudio(): Change (hardware) properties of the allocated audio mode
649 static BOOL TuneAudio() {
650 Fixed MonVol, OutVol, Gain;
651 ULONG Input;
652 BOOL rc = FALSE;
654 DBG("(TuneAudio())\n");
656 if(audioctrl != NULL) {
658 MonVol = negboundaries[tprefs.LoopbackVolume];
659 OutVol = negboundaries[tprefs.OutputVolumeLeft];
660 Gain = posboundaries[tprefs.InputVolumeLeft];
662 MonVol = min( max(MonVol, MinMonVol), MaxMonVol);
663 OutVol = min( max(OutVol, MinOutVol), MaxOutVol);
664 Gain = min( max(Gain, MinGain), MaxGain);
666 switch(tprefs.Input) {
668 case TINPUT_Line:
669 Input = tprefs.LineInput;
670 break;
672 case TINPUT_Aux1:
673 Input = tprefs.Aux1Input;
674 break;
676 case TINPUT_Mic:
677 if(tprefs.MicGain) {
678 Input = tprefs.MicGainInput;
680 else {
681 Input = tprefs.MicInput;
683 break;
685 case TINPUT_Mix:
686 Input = tprefs.MixInput;
687 break;
690 rc = AHI_ControlAudio(audioctrl,
691 AHIC_MonitorVolume, MonVol,
692 AHIC_OutputVolume, OutVol,
693 AHIC_InputGain, Gain,
694 AHIC_Input, Input,
695 TAG_DONE);
696 rc = (rc == AHIE_OK ? TRUE : FALSE);
699 return rc;
704 * ControlAudio(): Start/Stop/Pause playing and recording
707 static BOOL ControlAudio(void) {
708 BOOL rc;
710 DBG("(ControlAudio())\n");
712 if(audioctrl) {
713 rc = AHI_ControlAudio(audioctrl,
714 AHIC_Play, (Playing && !Pausing),
715 AHIC_Record, (Recording && !Pausing),
716 AHIA_PlayerFreq, (tprefs.Frequency / 512),
717 TAG_DONE);
720 rc = (rc == AHIE_OK ? TRUE : FALSE);
721 return rc;
726 * Pause(): Take care of the T_Pause() function
729 static void Pause(ULONG pause) {
731 DVAL("(Pause %ld)\n", pause);
732 Pausing = pause;
733 ControlAudio();
738 * Stop(): Take care of the T_Stop() function
741 static void Stop(ULONG flags) {
743 DVAL("Stop(%lx)...\n", flags);
745 Playing = FALSE;
746 Recording = FALSE;
748 ControlAudio();
750 if(Sound0Loaded) {
751 AHI_UnloadSound(0, audioctrl);
754 if(Sound1Loaded) {
755 AHI_UnloadSound(1, audioctrl);
758 Sound0Loaded = Sound1Loaded = FALSE;
760 /* Fill defaults */
762 ErrorTask =
763 RawTask =
764 SigTask = NULL;
765 RawInt = NULL;
766 RawBuffer1 =
767 RawBuffer2 = NULL;
768 RawBufferSize = 32768;
769 RawIrqSize = 512;
770 ByteCount = NULL;
771 ByteSkip =
772 ByteSkipCounter = 2048;
774 if(IOProcess) {
775 Signal((struct Task *)IOProcess, SIGBREAKF_CTRL_C);
776 while(IOProcess) {
777 Delay(1);
781 if((flags & TSF_DONTSAVECACHE) == 0) {
782 /* Save cache here... */
785 /* Check if a record/play file is open, and close them if so */
786 DBG("ok\n");
791 * RawPlayback(): Take care of the T_RawPlayback() function
794 static BOOL RawPlayback(struct TagItem *tags) {
795 BOOL rc = TRUE;
796 BOOL newmode = FALSE;
797 struct TagItem *tstate;
798 struct TagItem *tag;
800 DBG("RawPlayback()...\n");
802 /* Is this correct?? */
804 if(Playing || Recording) {
805 return FALSE;
808 /* Check arguments */
810 tstate = tags;
812 while (tag = NextTagItem(&tstate)) {
813 DVAL("%ld ", tag->ti_Tag - TT_Min);
814 DVAL("0x%08lx,\n", tag->ti_Data);
815 switch (tag->ti_Tag) {
817 case TT_IrqPri:
818 break;
820 case TT_Mode:
821 if(tag->ti_Data != tprefs.Mode) {
822 tprefs.Mode = tag->ti_Data;
823 newmode = TRUE;
825 break;
827 case TT_Frequency:
828 if(tag->ti_Data != tprefs.Frequency) {
829 tprefs.Frequency = tag->ti_Data;
830 newmode = TRUE;
832 break;
834 case TT_ErrorTask:
835 ErrorTask = (struct Task *) tag->ti_Data;
836 break;
838 case TT_ErrorMask:
839 ErrorMask = tag->ti_Data;
840 break;
842 case TT_RawTask:
843 RawTask = (struct Task *) tag->ti_Data;
844 break;
846 case TT_RawMask:
847 RawMask = tag->ti_Data;
848 break;
850 case TT_RawReply:
852 ULONG *p = (ULONG *) tag->ti_Data;
854 *p = GetRawReply(ToccataBase);
855 DVAL("Rawreply is 0x%08lx\n", *p);
856 break;
859 case TT_RawInt:
860 RawInt = (struct Interrupt *) tag->ti_Data;
861 break;
863 case TT_RawBuffer1:
864 RawBuffer1 = (BYTE *) tag->ti_Data;
865 break;
867 case TT_RawBuffer2:
868 RawBuffer2 = (BYTE *) tag->ti_Data;
869 break;
871 case TT_BufferSize:
872 RawBufferSize = tag->ti_Data;
873 break;
875 case TT_RawIrqSize:
876 RawIrqSize = tag->ti_Data;
877 break;
879 case TT_ByteCount:
880 ByteCount = (ULONG *) tag->ti_Data;
881 break;
883 case TT_ByteSkip:
884 ByteSkip = tag->ti_Data;
885 break;
887 case TT_SigTask:
888 SigTask = (struct Task *) tag->ti_Data;
889 break;
891 case TT_SigMask:
892 SigMask = tag->ti_Data;
893 break;
895 } /* switch */
896 } /* while */
898 DVAL("<<%ld\n", rc);
900 if((ErrorTask == NULL) ||
901 ((RawTask == NULL) && (RawInt == NULL)) ||
902 (RawBuffer1 == NULL) ||
903 (RawBuffer2 == NULL)) {
905 rc = FALSE;
908 DVAL("<<%ld\n", rc);
909 if(rc && (newmode || !AudioInitialized)) {
910 FreeAudio();
911 rc = AllocAudio();
914 DVAL("<<%ld\n", rc);
916 if(rc) {
917 ULONG sampletype = AHIST_NOTYPE;
918 struct AHISampleInfo s0, s1;
920 switch(tprefs.Mode) {
921 case TMODE_LINEAR_8:
922 sampletype = AHIST_M8S;
923 break;
924 case TMODE_LINEAR_16:
925 sampletype = AHIST_M16S;
926 break;
927 case TMODE_ALAW:
928 case TMODE_ULAW:
929 case TMODE_RAW_16:
930 rc = FALSE;
931 break;
932 case TMODE_LINEAR_8_S:
933 sampletype = AHIST_S8S;
934 break;
935 case TMODE_LINEAR_16_S:
936 sampletype = AHIST_S16S;
937 break;
938 case TMODE_ALAW_S:
939 case TMODE_ULAW_S:
940 case TMODE_RAW_16_S:
941 rc = FALSE;
942 break;
943 default:
944 rc = FALSE;
947 DVAL("<<%ld\n", rc);
948 if(sampletype != AHIST_NOTYPE) {
950 s0.ahisi_Type =
951 s1.ahisi_Type = sampletype;
952 s0.ahisi_Address = RawBuffer1;
953 s1.ahisi_Address = RawBuffer2;
954 s0.ahisi_Length =
955 s1.ahisi_Length = RawBufferSize / AHI_SampleFrameSize(sampletype);
957 if(AHI_LoadSound(0, AHIST_DYNAMICSAMPLE, &s0, audioctrl) == AHIE_OK) {
958 Sound0Loaded = TRUE;
961 if(AHI_LoadSound(1, AHIST_DYNAMICSAMPLE, &s1, audioctrl) == AHIE_OK) {
962 Sound1Loaded = TRUE;
965 if(!(Sound0Loaded && Sound1Loaded)) {
966 rc = FALSE;
969 RawBufferLength = RawBufferSize / AHI_SampleFrameSize(sampletype);
974 DVAL("<<%ld\n", rc);
975 if(rc) {
976 Playing = TRUE;
977 SoundFlag = 0;
978 NextBufferOK = TRUE;
979 FirstBuf = TRUE;
981 ControlAudio();
982 AHI_Play(audioctrl,
983 AHIP_BeginChannel, 0,
984 AHIP_Freq, tprefs.Frequency,
985 AHIP_Vol, 0x10000,
986 AHIP_Pan, 0x8000,
987 AHIP_Sound, 0,
988 AHIP_Offset, 0,
989 AHIP_Length, RawBufferLength,
990 AHIP_EndChannel, NULL,
991 TAG_DONE);
994 DVAL("ok %ld\n", rc);
995 return rc;
999 static BOOL Playback(struct TagItem *tags) {
1000 BOOL rc = TRUE;
1001 struct TagItem *tstate;
1002 struct TagItem *tag;
1004 DBG("Playback()...\n");
1006 Stop(0);
1008 /* Fill defaults */
1010 EndTask = NULL;
1011 EndMask = 0;
1012 Window = NULL;
1013 IoPri = tprefs.PlaybackIoPri;
1014 BufferSize = tprefs.PlaybackBlockSize;
1015 Load = NULL;
1016 LoadParam = 0;
1017 FileName = NULL;
1018 Length = LONG_MAX;
1019 SmartPlay = FALSE;
1020 PreBlocks = tprefs.PlaybackStartBlocks;
1021 PlayBlocks = tprefs.PlaybackBlocks;
1022 Flags = NULL;
1024 Buffer1 = Buffer2 = NULL;
1026 /* Check arguments */
1028 FileName = (STRPTR) GetTagData(TT_FileName, NULL, tags);
1030 if(FileName != NULL) {
1031 struct IFFHandle *iff;
1032 struct StoredProperty *sp;
1033 BOOL gotheader = FALSE;
1035 Load = ReadMAUD;
1037 iff = AllocIFF();
1039 if(iff) {
1041 iff->iff_Stream = Open(FileName, MODE_OLDFILE);
1043 if(iff->iff_Stream) {
1045 InitIFFasDOS(iff);
1047 if(!OpenIFF(iff, IFFF_READ)) {
1049 if(!(PropChunk(iff, ID_MAUD, ID_MHDR)
1050 || StopOnExit(iff,ID_MAUD, ID_FORM))) {
1052 while(ParseIFF(iff,IFFPARSE_SCAN) == IFFERR_EOC) {
1054 sp = FindProp(iff, ID_MAUD, ID_MHDR);
1056 if(sp) {
1057 struct MaudHeader *mhdr = (struct MaudHeader *) sp->sp_Data;
1059 gotheader = TRUE;
1061 Length = mhdr->mhdr_Samples * mhdr->mhdr_SampleSizeU / 8;
1063 tprefs.Frequency = mhdr->mhdr_RateSource / mhdr->mhdr_RateDevide;
1065 switch(mhdr->mhdr_Compression) {
1067 case MCOMP_NONE:
1068 if(mhdr->mhdr_SampleSizeU == 8) {
1069 tprefs.Mode = TMODE_LINEAR_8;
1071 else if(mhdr->mhdr_SampleSizeU == 16) {
1072 tprefs.Mode = TMODE_LINEAR_16;
1074 else rc = FALSE;
1075 break;
1077 case MCOMP_ALAW:
1078 tprefs.Mode = TMODE_ALAW;
1079 break;
1081 case MCOMP_ULAW:
1082 tprefs.Mode = TMODE_ULAW;
1083 break;
1084 } /* swicth */
1086 if(mhdr->mhdr_ChannelInfo == MCI_STEREO) {
1087 tprefs.Mode |= TMODEF_STEREO;
1089 else if(mhdr->mhdr_ChannelInfo != MCI_MONO) {
1090 rc = FALSE;
1093 FreeAudio();
1094 AllocAudio();
1095 break; /* We have what we want, no need to loop futher */
1099 CloseIFF(iff);
1101 Close(iff->iff_Stream);
1103 FreeIFF(iff);
1106 if(!gotheader) {
1107 rc = FALSE;
1111 tstate = tags;
1113 while (rc && (tag = NextTagItem(&tstate))) {
1114 //kprintf("%ld, 0x%08lx,\n", tag->ti_Tag - TT_Min, tag->ti_Data);
1115 switch (tag->ti_Tag) {
1117 case TT_Window:
1118 Window = (struct Window *) tag->ti_Data;
1119 break;
1121 case TT_IoPri:
1122 IoPri = tag->ti_Data;
1123 break;
1125 case TT_IrqPri:
1126 break;
1128 case TT_BufferSize:
1129 BufferSize = tag->ti_Data;
1130 break;
1132 case TT_Load:
1133 Load = (ASM LONG (*)(REG(a0) UBYTE *, REG(d0) ULONG, REG(a1) ULONG)) tag->ti_Data;
1134 break;
1136 case TT_CBParamA1:
1137 LoadParam = tag->ti_Data;
1138 break;
1140 case TT_Mode:
1141 case TT_Frequency:
1142 break;
1144 /* Already handled above!
1145 case TT_FileName:
1146 FileName = (STRPTR) tag->ti_Data;
1147 break;
1150 case TT_Length:
1151 Length = tag->ti_Data;
1152 break;
1154 case TT_ErrorTask:
1155 case TT_ErrorMask:
1156 break;
1158 case TT_SmartPlay:
1159 SmartPlay = tag->ti_Data;
1160 break;
1162 case TT_PreBlocks:
1163 PreBlocks = tag->ti_Data;
1164 break;
1166 case TT_PlayBlocks:
1167 PlayBlocks = tag->ti_Data;
1168 break;
1170 case TT_Flags:
1171 Flags = tag->ti_Data;
1172 break;
1174 case TT_EndTask:
1175 EndTask = (struct Task *) tag->ti_Data;
1177 case TT_EndMask:
1178 EndMask = tag->ti_Data;
1179 break;
1181 case TT_MSList:
1182 case TT_StartOffset:
1183 case TT_FieldsPerSecond:
1184 rc = FALSE;
1185 break;
1187 /* RawPlayback takes care of these */
1188 case TT_ByteCount:
1189 case TT_ByteSkip:
1190 case TT_SigTask:
1191 case TT_SigMask:
1192 break;
1194 } /* switch */
1195 } /* while */
1197 if((Load == 0) && (FileName == NULL)) {
1198 rc = FALSE;
1201 if(rc) {
1202 IOProcess = CreateNewProcTags(
1203 NP_Entry, IOTaskEntry,
1204 NP_Name, _LibName,
1205 NP_Priority, IoPri,
1206 NP_WindowPtr, Window,
1207 TAG_DONE);
1209 if(IOProcess == NULL) {
1210 rc = FALSE;
1214 if(rc) {
1215 struct TagItem rawtags[] = {
1216 TT_RawTask, 0, /* IOProcess */
1217 TT_RawMask, SIGBREAKF_CTRL_D,
1218 TT_RawBuffer1, 0, /* Buffer1 */
1219 TT_RawBuffer2, 0, /* Buffer2 */
1220 TT_BufferSize, 0, /* BufferSize */
1221 TT_ErrorTask, 0, /* IOProcess -- Can be overridded by users errortask */
1222 TT_ErrorMask, SIGBREAKF_CTRL_E,
1223 TAG_MORE, 0, /* tags */
1224 TAG_DONE
1227 Buffer1 = AllocVec(BufferSize, MEMF_PUBLIC);
1228 Buffer2 = AllocVec(BufferSize, MEMF_PUBLIC);
1230 rawtags[0].ti_Data = (ULONG) IOProcess;
1231 rawtags[2].ti_Data = (ULONG) Buffer1;
1232 rawtags[3].ti_Data = (ULONG) Buffer2;
1233 rawtags[4].ti_Data = (ULONG) BufferSize;
1234 rawtags[5].ti_Data = (ULONG) IOProcess;
1235 rawtags[7].ti_Data = (ULONG) tags;
1237 /* Make sure all buffers are preloaded */
1238 while((IOProcess != NULL) && !IOInitialized) {
1239 Delay(1);
1242 if(IOProcess == NULL) {
1243 rc = FALSE;
1246 if(rc) {
1247 rc = RawPlayback((struct TagItem *) &rawtags);
1253 return rc;