grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / devs / AHI / Device / mixer.c
blobbdadb904363e96c308a1c6c6c1c01120005661f1
1 /*
2 AHI - Hardware independent audio subsystem
3 Copyright (C) 1996-2005 Martin Blom <martin@blom.org>
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.
21 #include <config.h>
23 #include <string.h>
24 #include <stddef.h>
26 #include <dos/dos.h>
27 #include <dos/dostags.h>
28 #include <exec/memory.h>
30 #include <proto/dos.h>
31 #include <proto/exec.h>
32 #include <proto/utility.h>
33 #define __NOLIBBASE__
34 #define __NOGLOBALIFACE__
35 #include <proto/ahi.h>
36 #undef __NOLIBBASE__
37 #undef __NOGLOBALIFACE__
39 #include "ahi_def.h"
41 #include "addroutines.h"
42 #include "debug.h"
43 #include "dsp.h"
44 #include "header.h"
45 #include "misc.h"
46 #include "mixer.h"
47 #include "sound.h"
49 #if defined( ENABLE_WARPUP )
50 # include "warpup.h"
51 #endif
53 #define min(a,b) (((a)<(b))?(a):(b))
54 #define max(a,b) (((a)>(b))?(a):(b))
56 /******************************************************************************
57 ** Prototypes *****************************************************************
58 ******************************************************************************/
60 void
61 CallSoundHook( struct AHIPrivAudioCtrl *audioctrl,
62 void* arg )
64 switch( MixBackend )
66 case MB_NATIVE:
67 CallHookPkt( audioctrl->ac.ahiac_SoundFunc,
68 audioctrl,
69 arg );
70 break;
72 #if defined( ENABLE_WARPUP )
73 case MB_WARPUP:
74 WarpUpCallSoundHook( audioctrl, arg );
75 break;
76 #endif
81 void
82 MixerFunc( struct Hook* hook,
83 struct AHIPrivAudioCtrl* audioctrl,
84 void* dst )
86 switch( MixBackend )
88 case MB_NATIVE:
89 Mix( hook, audioctrl, dst );
90 DoMasterVolume( dst, audioctrl );
91 DoOutputBuffer( dst, audioctrl );
92 DoChannelInfo( audioctrl );
93 break;
95 #if defined( ENABLE_WARPUP )
96 case MB_WARPUP:
97 WarpUpCallMixer( audioctrl, dst );
98 DoOutputBuffer( dst, audioctrl );
99 DoChannelInfo( audioctrl );
100 break;
101 #endif
106 /******************************************************************************
107 ** InitMixroutine *************************************************************
108 ******************************************************************************/
110 // This function is used to initialize the mixer routine (called from
111 // AHI_AllocAudio()).
113 BOOL
114 InitMixroutine( struct AHIPrivAudioCtrl *audioctrl )
116 BOOL rc = FALSE;
118 // Allocate and initialize the AHIChannelData structures
119 // This structure could be accessed from from interrupts!
121 ULONG data_flags = MEMF_ANY;
123 switch( MixBackend )
125 case MB_NATIVE:
126 data_flags = MEMF_PUBLIC | MEMF_CLEAR;
127 break;
129 #if defined( ENABLE_WARPUP )
130 case MB_WARPUP:
131 // Non-cached from both the PPC and m68k side
132 data_flags = MEMF_PUBLIC | MEMF_CLEAR | MEMF_CHIP;
133 break;
134 #endif
137 audioctrl->ahiac_ChannelDatas = AHIAllocVec(
138 audioctrl->ac.ahiac_Channels * sizeof( struct AHIChannelData ),
139 data_flags );
141 // Allocate and initialize the AHISoundData structures
142 // This structure could be accessed from from interrupts!
144 audioctrl->ahiac_SoundDatas = AHIAllocVec(
145 audioctrl->ac.ahiac_Sounds * sizeof( struct AHISoundData ),
146 data_flags );
148 // Now link the list and fill in the channel number for each structure.
150 if( audioctrl->ahiac_ChannelDatas != NULL
151 && audioctrl->ahiac_SoundDatas != NULL )
153 struct AHIChannelData *cd;
154 struct AHISoundData *sd;
155 int i;
157 cd = audioctrl->ahiac_ChannelDatas;
159 audioctrl->ahiac_WetList = cd;
160 audioctrl->ahiac_DryList = NULL;
162 for(i = 0; i < audioctrl->ac.ahiac_Channels - 1; i++)
164 // Set Channel No
165 cd->cd_ChannelNo = i;
167 // Set link to next channel
168 cd->cd_Succ = cd + 1;
169 cd++;
172 // Set the last No
173 cd->cd_ChannelNo = i;
175 // Clear the last link;
176 cd->cd_Succ = NULL;
179 sd = audioctrl->ahiac_SoundDatas;
181 for( i = 0; i < audioctrl->ac.ahiac_Sounds; i++)
183 sd->sd_Type = AHIST_NOTYPE;
184 sd++;
189 switch( MixBackend )
191 case MB_NATIVE:
192 rc = TRUE;
193 break;
195 #if defined( ENABLE_WARPUP )
196 case MB_WARPUP:
197 rc = WarpUpInit( audioctrl );
198 break;
199 #endif
202 return rc;
206 /******************************************************************************
207 ** CleanUpMixroutine **********************************************************
208 ******************************************************************************/
210 // This function is used to clean up after the mixer routine (called from
211 // AHI_FreeAudio()).
213 void
214 CleanUpMixroutine( struct AHIPrivAudioCtrl *audioctrl )
216 switch( MixBackend )
218 case MB_NATIVE:
219 break;
221 #if defined( ENABLE_WARPUP )
222 case MB_WARPUP:
223 WarpUpCleanUp( audioctrl );
224 break;
225 #endif
228 AHIFreeVec( audioctrl->ahiac_SoundDatas );
229 audioctrl->ahiac_SoundDatas = NULL;
231 AHIFreeVec( audioctrl->ahiac_ChannelDatas );
232 audioctrl->ahiac_ChannelDatas = NULL;
236 /******************************************************************************
237 ** SelectAddRoutine ***********************************************************
238 ******************************************************************************/
240 // This routine gets called each time there is reason to believe that a new
241 // add-routine should be used (new sound selected, volume changed,
242 // mastervolume changed)
244 // Based on VolumeLeft, VolumeRight and SampleType, fill in ScaleLeft,
245 // ScaleRight and AddRoutine.
247 void
248 SelectAddRoutine ( Fixed VolumeLeft,
249 Fixed VolumeRight,
250 ULONG SampleType,
251 struct AHIPrivAudioCtrl *audioctrl,
252 LONG *ScaleLeft,
253 LONG *ScaleRight,
254 ADDFUNC **AddRoutine )
257 // This version only cares about the sample format and does not use any
258 // optimized add-routines.
260 // Scale the volume
262 VolumeLeft = VolumeLeft * (audioctrl->ahiac_MasterVolume >> 8) /
263 (audioctrl->ahiac_Channels2 << 8);
265 VolumeRight = VolumeRight * (audioctrl->ahiac_MasterVolume >> 8) /
266 (audioctrl->ahiac_Channels2 << 8);
268 // First, select HiFi or LoFi...
270 if( audioctrl->ac.ahiac_Flags & AHIACF_HIFI )
273 // Then, check the output format...
275 switch(audioctrl->ac.ahiac_BuffType)
278 case AHIST_M32S:
280 // ...and then the source format.
282 switch(SampleType)
284 case AHIST_M8S:
285 case AHIST_BW|AHIST_M8S:
286 *ScaleLeft = VolumeLeft + VolumeRight;
287 *ScaleRight = 0;
288 if(SampleType & AHIST_BW)
289 *AddRoutine = AddByteMonoBPtr;
290 else
291 *AddRoutine = AddByteMonoPtr;
292 break;
294 case AHIST_S8S:
295 case AHIST_BW|AHIST_S8S:
296 *ScaleLeft = VolumeLeft;
297 *ScaleRight = VolumeRight;
298 if(SampleType & AHIST_BW)
299 *AddRoutine = AddBytesMonoBPtr;
300 else
301 *AddRoutine = AddBytesMonoPtr;
302 break;
304 case AHIST_M16S:
305 case AHIST_BW|AHIST_M16S:
306 *ScaleLeft = VolumeLeft + VolumeRight;
307 *ScaleRight = 0;
308 if(SampleType & AHIST_BW)
309 *AddRoutine = AddWordMonoBPtr;
310 else
311 *AddRoutine = AddWordMonoPtr;
312 break;
314 case AHIST_S16S:
315 case AHIST_BW|AHIST_S16S:
316 *ScaleLeft = VolumeLeft;
317 *ScaleRight = VolumeRight;
318 if(SampleType & AHIST_BW)
319 *AddRoutine = AddWordsMonoBPtr;
320 else
321 *AddRoutine = AddWordsMonoPtr;
322 break;
324 case AHIST_M32S:
325 case AHIST_BW|AHIST_M32S:
326 *ScaleLeft = VolumeLeft + VolumeRight;
327 *ScaleRight = 0;
328 if(SampleType & AHIST_BW)
329 *AddRoutine = AddLongMonoBPtr;
330 else
331 *AddRoutine = AddLongMonoPtr;
332 break;
334 case AHIST_S32S:
335 case AHIST_BW|AHIST_S32S:
336 *ScaleLeft = VolumeLeft;
337 *ScaleRight = VolumeRight;
338 if(SampleType & AHIST_BW)
339 *AddRoutine = AddLongsMonoBPtr;
340 else
341 *AddRoutine = AddLongsMonoPtr;
342 break;
344 case AHIST_L7_1:
345 case AHIST_BW|AHIST_L7_1:
346 *ScaleLeft = VolumeLeft;
347 *ScaleRight = VolumeRight;
348 if(SampleType & AHIST_BW)
349 *AddRoutine = Add71MonoBPtr;
350 else
351 *AddRoutine = Add71MonoPtr;
352 break;
354 default:
355 *ScaleLeft = 0;
356 *ScaleRight = 0;
357 *AddRoutine = NULL;
358 break;
360 break;
362 case AHIST_S32S:
364 // ...and then the source format.
366 switch(SampleType)
368 case AHIST_M8S:
369 case AHIST_BW|AHIST_M8S:
370 *ScaleLeft = VolumeLeft;
371 *ScaleRight = VolumeRight;
372 if(SampleType & AHIST_BW)
373 *AddRoutine = AddByteStereoBPtr;
374 else
375 *AddRoutine = AddByteStereoPtr;
376 break;
378 case AHIST_S8S:
379 case AHIST_BW|AHIST_S8S:
380 *ScaleLeft = VolumeLeft;
381 *ScaleRight = VolumeRight;
382 if(SampleType & AHIST_BW)
383 *AddRoutine = AddBytesStereoBPtr;
384 else
385 *AddRoutine = AddBytesStereoPtr;
386 break;
388 case AHIST_M16S:
389 case AHIST_BW|AHIST_M16S:
390 *ScaleLeft = VolumeLeft;
391 *ScaleRight = VolumeRight;
392 if(SampleType & AHIST_BW)
393 *AddRoutine = AddWordStereoBPtr;
394 else
395 *AddRoutine = AddWordStereoPtr;
396 break;
398 case AHIST_S16S:
399 case AHIST_BW|AHIST_S16S:
400 *ScaleLeft = VolumeLeft;
401 *ScaleRight = VolumeRight;
402 if(SampleType & AHIST_BW)
403 *AddRoutine = AddWordsStereoBPtr;
404 else
405 *AddRoutine = AddWordsStereoPtr;
406 break;
408 case AHIST_M32S:
409 case AHIST_BW|AHIST_M32S:
410 *ScaleLeft = VolumeLeft;
411 *ScaleRight = VolumeRight;
412 if(SampleType & AHIST_BW)
413 *AddRoutine = AddLongStereoBPtr;
414 else
415 *AddRoutine = AddLongStereoPtr;
416 break;
418 case AHIST_S32S:
419 case AHIST_BW|AHIST_S32S:
420 *ScaleLeft = VolumeLeft;
421 *ScaleRight = VolumeRight;
422 if(SampleType & AHIST_BW)
423 *AddRoutine = AddLongsStereoBPtr;
424 else
425 *AddRoutine = AddLongsStereoPtr;
426 break;
428 case AHIST_L7_1:
429 case AHIST_BW|AHIST_L7_1:
430 *ScaleLeft = VolumeLeft;
431 *ScaleRight = VolumeRight;
432 if(SampleType & AHIST_BW)
433 *AddRoutine = Add71StereoBPtr;
434 else
435 *AddRoutine = Add71StereoPtr;
436 break;
438 default:
439 *ScaleLeft = 0;
440 *ScaleRight = 0;
441 *AddRoutine = NULL;
442 break;
444 break;
446 case AHIST_L7_1:
448 // ...and then the source format.
450 switch(SampleType)
452 case AHIST_M8S:
453 case AHIST_BW|AHIST_M8S:
454 *ScaleLeft = VolumeLeft;
455 *ScaleRight = VolumeRight;
456 if(SampleType & AHIST_BW)
457 *AddRoutine = AddByte71BPtr;
458 else
459 *AddRoutine = AddByte71Ptr;
460 break;
462 case AHIST_S8S:
463 case AHIST_BW|AHIST_S8S:
464 *ScaleLeft = VolumeLeft;
465 *ScaleRight = VolumeRight;
466 if(SampleType & AHIST_BW)
467 *AddRoutine = AddBytes71BPtr;
468 else
469 *AddRoutine = AddBytes71Ptr;
470 break;
472 case AHIST_M16S:
473 case AHIST_BW|AHIST_M16S:
474 *ScaleLeft = VolumeLeft;
475 *ScaleRight = VolumeRight;
476 if(SampleType & AHIST_BW)
477 *AddRoutine = AddWord71BPtr;
478 else
479 *AddRoutine = AddWord71Ptr;
480 break;
482 case AHIST_S16S:
483 case AHIST_BW|AHIST_S16S:
484 *ScaleLeft = VolumeLeft;
485 *ScaleRight = VolumeRight;
486 if(SampleType & AHIST_BW)
487 *AddRoutine = AddWords71BPtr;
488 else
489 *AddRoutine = AddWords71Ptr;
490 break;
492 case AHIST_M32S:
493 case AHIST_BW|AHIST_M32S:
494 *ScaleLeft = VolumeLeft;
495 *ScaleRight = VolumeRight;
496 if(SampleType & AHIST_BW)
497 *AddRoutine = AddLong71BPtr;
498 else
499 *AddRoutine = AddLong71Ptr;
500 break;
502 case AHIST_S32S:
503 case AHIST_BW|AHIST_S32S:
504 *ScaleLeft = VolumeLeft;
505 *ScaleRight = VolumeRight;
506 if(SampleType & AHIST_BW)
507 *AddRoutine = AddLongs71BPtr;
508 else
509 *AddRoutine = AddLongs71Ptr;
510 break;
512 case AHIST_L7_1:
513 case AHIST_BW|AHIST_L7_1:
514 *ScaleLeft = VolumeLeft;
515 *ScaleRight = VolumeRight;
516 if(SampleType & AHIST_BW)
517 *AddRoutine = Add7171BPtr;
518 else
519 *AddRoutine = Add7171Ptr;
520 break;
522 default:
523 *ScaleLeft = 0;
524 *ScaleRight = 0;
525 *AddRoutine = NULL;
526 break;
528 break;
530 default:
531 *ScaleLeft = 0;
532 *ScaleRight = 0;
533 *AddRoutine = NULL;
534 break;
537 else
540 // Then, check the output format...
542 switch(audioctrl->ac.ahiac_BuffType)
545 case AHIST_M16S:
547 // ...and then the source format.
549 switch(SampleType)
551 case AHIST_M8S:
552 case AHIST_BW|AHIST_M8S:
553 *ScaleLeft = VolumeLeft + VolumeRight;
554 *ScaleRight = 0;
555 if(SampleType & AHIST_BW)
556 *AddRoutine = AddLofiByteMonoBPtr;
557 else
558 *AddRoutine = AddLofiByteMonoPtr;
559 break;
561 case AHIST_S8S:
562 case AHIST_BW|AHIST_S8S:
563 *ScaleLeft = VolumeLeft;
564 *ScaleRight = VolumeRight;
565 if(SampleType & AHIST_BW)
566 *AddRoutine = AddLofiBytesMonoBPtr;
567 else
568 *AddRoutine = AddLofiBytesMonoPtr;
569 break;
571 case AHIST_M16S:
572 case AHIST_BW|AHIST_M16S:
573 *ScaleLeft = VolumeLeft + VolumeRight;
574 *ScaleRight = 0;
575 if(SampleType & AHIST_BW)
576 *AddRoutine = AddLofiWordMonoBPtr;
577 else
578 *AddRoutine = AddLofiWordMonoPtr;
579 break;
581 case AHIST_S16S:
582 case AHIST_BW|AHIST_S16S:
583 *ScaleLeft = VolumeLeft;
584 *ScaleRight = VolumeRight;
585 if(SampleType & AHIST_BW)
586 *AddRoutine = AddLofiWordsMonoBPtr;
587 else
588 *AddRoutine = AddLofiWordsMonoPtr;
589 break;
591 case AHIST_M32S:
592 case AHIST_BW|AHIST_M32S:
593 *ScaleLeft = VolumeLeft + VolumeRight;
594 *ScaleRight = 0;
595 if(SampleType & AHIST_BW)
596 *AddRoutine = AddLofiLongMonoBPtr;
597 else
598 *AddRoutine = AddLofiLongMonoPtr;
599 break;
601 case AHIST_S32S:
602 case AHIST_BW|AHIST_S32S:
603 *ScaleLeft = VolumeLeft;
604 *ScaleRight = VolumeRight;
605 if(SampleType & AHIST_BW)
606 *AddRoutine = AddLofiLongsMonoBPtr;
607 else
608 *AddRoutine = AddLofiLongsMonoPtr;
609 break;
611 default:
612 *ScaleLeft = 0;
613 *ScaleRight = 0;
614 *AddRoutine = NULL;
615 break;
617 break;
619 case AHIST_S16S:
621 // ...and then the source format.
623 switch(SampleType)
625 case AHIST_M8S:
626 case AHIST_BW|AHIST_M8S:
627 *ScaleLeft = VolumeLeft;
628 *ScaleRight = VolumeRight;
629 if(SampleType & AHIST_BW)
630 *AddRoutine = AddLofiByteStereoBPtr;
631 else
632 *AddRoutine = AddLofiByteStereoPtr;
633 break;
635 case AHIST_S8S:
636 case AHIST_BW|AHIST_S8S:
637 *ScaleLeft = VolumeLeft;
638 *ScaleRight = VolumeRight;
639 if(SampleType & AHIST_BW)
640 *AddRoutine = AddLofiBytesStereoBPtr;
641 else
642 *AddRoutine = AddLofiBytesStereoPtr;
643 break;
645 case AHIST_M16S:
646 case AHIST_BW|AHIST_M16S:
647 *ScaleLeft = VolumeLeft;
648 *ScaleRight = VolumeRight;
649 if(SampleType & AHIST_BW)
650 *AddRoutine = AddLofiWordStereoBPtr;
651 else
652 *AddRoutine = AddLofiWordStereoPtr;
653 break;
655 case AHIST_S16S:
656 case AHIST_BW|AHIST_S16S:
657 *ScaleLeft = VolumeLeft;
658 *ScaleRight = VolumeRight;
659 if(SampleType & AHIST_BW)
660 *AddRoutine = AddLofiWordsStereoBPtr;
661 else
662 *AddRoutine = AddLofiWordsStereoPtr;
663 break;
665 case AHIST_M32S:
666 case AHIST_BW|AHIST_M32S:
667 *ScaleLeft = VolumeLeft;
668 *ScaleRight = VolumeRight;
669 if(SampleType & AHIST_BW)
670 *AddRoutine = AddLofiLongStereoBPtr;
671 else
672 *AddRoutine = AddLofiLongStereoPtr;
673 break;
675 case AHIST_S32S:
676 case AHIST_BW|AHIST_S32S:
677 *ScaleLeft = VolumeLeft;
678 *ScaleRight = VolumeRight;
679 if(SampleType & AHIST_BW)
680 *AddRoutine = AddLofiLongsStereoBPtr;
681 else
682 *AddRoutine = AddLofiLongsStereoPtr;
683 break;
685 default:
686 *ScaleLeft = 0;
687 *ScaleRight = 0;
688 *AddRoutine = NULL;
689 break;
691 break;
693 default:
694 *ScaleLeft = 0;
695 *ScaleRight = 0;
696 *AddRoutine = NULL;
697 break;
703 /******************************************************************************
704 ** Mix ************************************************************************
705 ******************************************************************************/
707 // This is the function that the driver calls each time it want more data
708 // to play.
710 void
711 Mix( struct Hook* unused_Hook,
712 struct AHIPrivAudioCtrl* audioctrl,
713 void* dst )
715 struct AHIChannelData *cd;
716 void *dstptr;
717 LONG samplesleft;
719 /* Clear the buffer */
721 memset( dst, 0, audioctrl->ahiac_BuffSizeNow );
722 /* Mix the samples */
724 audioctrl->ahiac_WetOrDry = AHIEDM_WET;
726 cd = audioctrl->ahiac_WetList;
728 while(TRUE)
730 while(cd != NULL) // .nextchannel
732 samplesleft = audioctrl->ac.ahiac_BuffSamples;
733 dstptr = dst;
735 while(TRUE) // .contchannel
737 LONG samples;
738 LONG processed;
740 /* Call Sound Hook */
742 if(cd->cd_EOS)
744 cd->cd_EOS = FALSE;
745 if(audioctrl->ac.ahiac_SoundFunc != NULL)
747 CallSoundHook( audioctrl, &cd->cd_ChannelNo );
751 processed = 0;
753 if( cd->cd_AntiClickCount > 0 && cd->cd_FreqOK && cd->cd_SoundOK )
755 // Sound is ok and we're looking for a zero-crossing.
757 LONG try_samples;
759 samples = min( samplesleft, cd->cd_Samples );
760 try_samples = min( samples, cd->cd_AntiClickCount );
762 if( try_samples > 0 )
764 cd->cd_TempStartPointL = cd->cd_StartPointL;
765 cd->cd_TempStartPointR = cd->cd_StartPointR;
766 cd->cd_TempStartPointRL = cd->cd_StartPointRL;
767 cd->cd_TempStartPointRR = cd->cd_StartPointRR;
768 cd->cd_TempStartPointSL = cd->cd_StartPointSL;
769 cd->cd_TempStartPointSR = cd->cd_StartPointSR;
770 cd->cd_TempStartPointC = cd->cd_StartPointC;
771 cd->cd_TempStartPointLFE = cd->cd_StartPointLFE;
773 processed = ((ADDFUNC *) cd->cd_AddRoutine)( try_samples,
774 cd->cd_ScaleLeft,
775 cd->cd_ScaleRight,
776 &cd->cd_TempStartPointL,
777 &cd->cd_TempStartPointR,
778 cd->cd_DataStart,
779 &dstptr,
780 cd->cd_FirstOffsetI,
781 cd->cd_Add,
782 &cd->cd_Offset,
783 TRUE );
785 cd->cd_Samples -= processed;
786 samplesleft -= processed;
788 else
790 processed = 0;
793 if( processed != try_samples || // Found zero-crossing
794 try_samples <= cd->cd_AntiClickCount ) // End-of-sound or
795 // max delay reached
797 // We either found a zero-crossing, looked as far as
798 // we were allowed to or reached the end of sound.
800 // To be perfect, the we should not run this code if the
801 // end-of-sound was reached. Instead, since cd_Samples is zero
802 // and the second cd_AddRoutine call below will have no effect,
803 // we should just go onand the cd_Next#? variables will be copied
804 // instead. However, that requires two sets of delay variables:
805 // The one we have now and one delayed set of "next" variables.
806 // I might do that another time, but not today...
808 // Now start the delayed sound.
810 if( cd->cd_VolDelayed )
812 cd->cd_VolDelayed = FALSE;
813 cd->cd_VolumeLeft = cd->cd_DelayedVolumeLeft;
814 cd->cd_VolumeRight = cd->cd_DelayedVolumeRight;
815 cd->cd_ScaleLeft = cd->cd_DelayedScaleLeft;
816 cd->cd_ScaleRight = cd->cd_DelayedScaleRight;
817 cd->cd_AddRoutine = cd->cd_DelayedAddRoutine;
820 if( cd->cd_FreqDelayed )
822 cd->cd_FreqDelayed = FALSE;
823 cd->cd_FreqOK = cd->cd_DelayedFreqOK;
824 cd->cd_Add = cd->cd_DelayedAdd;
826 // Since we have advanced, cd_Samples must be recalculated!
827 cd->cd_Samples = CalcSamples( cd->cd_Add,
828 cd->cd_Type,
829 cd->cd_LastOffset,
830 cd->cd_Offset );
833 if( cd->cd_SoundDelayed )
835 cd->cd_SoundDelayed = FALSE;
837 cd->cd_SoundOK = cd->cd_DelayedSoundOK;
839 cd->cd_StartPointL = 0;
840 cd->cd_StartPointR = 0;
842 cd->cd_Offset = cd->cd_DelayedOffset;
843 cd->cd_FirstOffsetI = cd->cd_DelayedFirstOffsetI;
844 cd->cd_LastOffset = cd->cd_DelayedLastOffset;
845 cd->cd_DataStart = cd->cd_DelayedDataStart;
847 cd->cd_Type = cd->cd_DelayedType;
848 cd->cd_AddRoutine = cd->cd_DelayedAddRoutine;
850 cd->cd_Samples = cd->cd_DelayedSamples;
852 cd->cd_ScaleLeft = cd->cd_DelayedScaleLeft;
853 cd->cd_ScaleRight = cd->cd_DelayedScaleRight;
854 cd->cd_AddRoutine = cd->cd_DelayedAddRoutine;
858 if( cd->cd_VolDelayed || cd->cd_FreqDelayed || cd->cd_SoundDelayed )
860 cd->cd_AntiClickCount -= processed;
862 else
864 cd->cd_AntiClickCount = 0;
868 if( cd->cd_FreqOK && cd->cd_SoundOK )
870 // Sound is still ok, let's rock'n roll.
872 samples = min( samplesleft, cd->cd_Samples );
874 if( samples > 0 )
876 cd->cd_TempStartPointL = cd->cd_StartPointL;
877 cd->cd_TempStartPointR = cd->cd_StartPointR;
878 cd->cd_TempStartPointRL = cd->cd_StartPointRL;
879 cd->cd_TempStartPointRR = cd->cd_StartPointRR;
880 cd->cd_TempStartPointSL = cd->cd_StartPointSL;
881 cd->cd_TempStartPointSR = cd->cd_StartPointSR;
882 cd->cd_TempStartPointC = cd->cd_StartPointC;
883 cd->cd_TempStartPointLFE = cd->cd_StartPointLFE;
885 processed = ((ADDFUNC *) cd->cd_AddRoutine)( samples,
886 cd->cd_ScaleLeft,
887 cd->cd_ScaleRight,
888 &cd->cd_TempStartPointL,
889 &cd->cd_TempStartPointR,
890 cd->cd_DataStart,
891 &dstptr,
892 cd->cd_FirstOffsetI,
893 cd->cd_Add,
894 &cd->cd_Offset,
895 FALSE );
896 cd->cd_Samples -= processed;
897 samplesleft -= processed;
900 if( cd->cd_Samples == 0 )
902 /* Linear interpol. stuff */
904 ULONG lo = (ULONG) (cd->cd_LastOffset >> 32);
906 switch( cd->cd_Type ) {
908 case AHIST_M8S:
909 cd->cd_StartPointL = ((BYTE*) cd->cd_DataStart)[ lo ] << 8;
910 break;
912 case AHIST_S8S:
913 cd->cd_StartPointL = ((BYTE*) cd->cd_DataStart)[ lo*2+0 ] << 8;
914 cd->cd_StartPointR = ((BYTE*) cd->cd_DataStart)[ lo*2+1 ] << 8;
915 break;
917 case AHIST_M16S:
918 cd->cd_StartPointL = ((WORD*) cd->cd_DataStart)[ lo ];
919 break;
921 case AHIST_S16S:
922 cd->cd_StartPointL = ((WORD*) cd->cd_DataStart)[ lo*2+0 ];
923 cd->cd_StartPointR = ((WORD*) cd->cd_DataStart)[ lo*2+1 ];
924 break;
926 case AHIST_M32S:
927 cd->cd_StartPointL = ((LONG*) cd->cd_DataStart)[ lo ] >> 16;
928 break;
930 case AHIST_S32S:
931 cd->cd_StartPointL = ((LONG*) cd->cd_DataStart)[ lo*2+0 ] >> 16;
932 cd->cd_StartPointR = ((LONG*) cd->cd_DataStart)[ lo*2+1 ] >> 16;
933 break;
936 // This old code is totally fucked up ... Why didn't anybody
937 // complain?!
938 // cd->cd_StartPointL = cd->cd_TempStartPointL;
939 // cd->cd_StartPointR = cd->cd_TempStartPointR;
941 /* KPrintF( "cd->cd_StartPointL=%08lx, cd->cd_StartPointR=%08lx\n", */
942 /* cd->cd_StartPointL, cd->cd_StartPointR ); */
944 ** Offset always points OUTSIDE the sample after this
945 ** call. Ie, if we read a sample at offset (Offset.I)
946 ** now, it does not belong to the sample just played.
947 ** This is true for both backward and forward mixing.
950 /* KPrintF( "cd->cd_Add=0x%08lx:%08lx\n", */
951 /* (ULONG) (cd->cd_Add >> 32), (ULONG) cd->cd_Add ); */
952 /* KPrintF( "cd->cd_Offset=0x%08lx:%08lx, " */
953 /* "cd->cd_LastOffset=0x%08lx:%08lx," */
954 /* "cd->cd_FirstOffset=%08lx\n", */
955 /* (ULONG) (cd->cd_Offset >> 32), (ULONG) cd->cd_Offset, */
956 /* (ULONG) (cd->cd_LastOffset >> 32), (ULONG) cd->cd_LastOffset, */
957 /* cd->cd_FirstOffsetI ); */
959 /* What we do now is to calculate how much futher we have
960 advanced. */
962 cd->cd_Offset -= cd->cd_LastOffset + 1;
964 /* KPrintF( "cd->cd_Offset=0x%08lx:%08lx, " */
965 /* "cd->cd_LastOffset=0x%08lx:%08lx," */
966 /* "cd->cd_FirstOffset=%08lx\n", */
967 /* (ULONG) (cd->cd_Offset >> 32), (ULONG) cd->cd_Offset, */
968 /* (ULONG) (cd->cd_LastOffset >> 32), (ULONG) cd->cd_LastOffset, */
969 /* cd->cd_FirstOffsetI ); */
972 ** Offset should now be added to the NEXT Offset. Offset
973 ** is positive of the sample was mixed forwards, and
974 ** negative if the sample was mixed backwards. There is
975 ** one catch, however. If the direction is about to
976 ** change now, Offset should instead be SUBTRACTED.
977 ** Let's check:
980 if( (cd->cd_Type ^ cd->cd_NextType) & AHIST_BW )
982 cd->cd_Offset = -cd->cd_Offset;
985 cd->cd_Offset += cd->cd_NextOffset;
987 // cd->cd_FirstOffsetI = cd->cd_Offset >> 32;
988 cd->cd_FirstOffsetI = cd->cd_NextOffset >> 32;
990 /* KPrintF( "cd->cd_Offset=0x%08lx:%08lx, " */
991 /* "cd->cd_LastOffset=0x%08lx:%08lx," */
992 /* "cd->cd_FirstOffset=%08lx\n", */
993 /* (ULONG) (cd->cd_Offset >> 32), (ULONG) cd->cd_Offset, */
994 /* (ULONG) (cd->cd_LastOffset >> 32), (ULONG) cd->cd_LastOffset, */
995 /* cd->cd_FirstOffsetI ); */
997 ** But what if the next sample is so short that we just
998 ** passed it!? Here is the nice part. CalcSamples
999 ** checks this, and sets cd_Samples to 0 in that case.
1000 ** And the add routines doesn't do anything when asked to
1001 ** mix 0 samples. Assume we have passed a sample with 4
1002 ** samples, and the next one is only 3. CalcSamples
1003 ** returns 0. The (ADDFUNC) call above does not do
1004 ** anything at all, OffsetI is still 4. Now we subtract
1005 ** LastOffsetI, which is 3. Result: We have passed the
1006 ** sample with 1. And guess what? That's in range.
1009 /* Now, let's copy the rest of the cd_Next#? stuff... */
1011 cd->cd_FreqOK = cd->cd_NextFreqOK;
1012 cd->cd_SoundOK = cd->cd_NextSoundOK;
1013 cd->cd_Add = cd->cd_NextAdd;
1014 cd->cd_DataStart = cd->cd_NextDataStart;
1015 cd->cd_LastOffset = cd->cd_NextLastOffset;
1016 cd->cd_ScaleLeft = cd->cd_NextScaleLeft;
1017 cd->cd_ScaleRight = cd->cd_NextScaleRight;
1018 cd->cd_AddRoutine = cd->cd_NextAddRoutine;
1019 cd->cd_VolumeLeft = cd->cd_NextVolumeLeft;
1020 cd->cd_VolumeRight = cd->cd_NextVolumeRight;
1021 cd->cd_Type = cd->cd_NextType;
1023 cd->cd_Samples = CalcSamples( cd->cd_Add,
1024 cd->cd_Type,
1025 cd->cd_LastOffset,
1026 cd->cd_Offset );
1028 /* Also update all cd_Delayed#? stuff */
1030 if( !cd->cd_VolDelayed )
1032 cd->cd_DelayedVolumeLeft = cd->cd_NextVolumeLeft;
1033 cd->cd_DelayedVolumeRight = cd->cd_NextVolumeRight;
1036 if( !cd->cd_FreqDelayed )
1038 cd->cd_DelayedFreqOK = cd->cd_NextFreqOK;
1039 cd->cd_DelayedAdd = cd->cd_NextAdd;
1042 if( !cd->cd_SoundDelayed )
1044 cd->cd_DelayedSoundOK = cd->cd_NextSoundOK;
1045 cd->cd_DelayedOffset = cd->cd_NextOffset;
1046 cd->cd_DelayedFirstOffsetI = cd->cd_FirstOffsetI; // See above
1047 cd->cd_DelayedLastOffset = cd->cd_NextLastOffset;
1048 cd->cd_DelayedType = cd->cd_NextType;
1049 cd->cd_DelayedDataStart = cd->cd_NextDataStart;
1052 if( !cd->cd_VolDelayed && !cd->cd_SoundDelayed )
1054 cd->cd_DelayedScaleLeft = cd->cd_NextScaleLeft;
1055 cd->cd_DelayedScaleRight = cd->cd_NextScaleRight;
1056 cd->cd_DelayedAddRoutine = cd->cd_NextAddRoutine;
1059 if( !cd->cd_FreqDelayed && !cd->cd_SoundDelayed )
1061 cd->cd_DelayedSamples = cd->cd_Samples;
1064 cd->cd_EOS = TRUE; // signal End-Of-Sample
1065 continue; // .contchannel (same channel, new sound)
1067 } // FreqOK && SoundOK
1068 break; // .contchannel
1070 } // while(TRUE)
1072 cd = cd->cd_Succ;
1073 } // while(cd)
1075 if(audioctrl->ahiac_WetOrDry == AHIEDM_WET)
1077 audioctrl->ahiac_WetOrDry = AHIEDM_DRY;
1079 /*** AHIET_DSPECHO ***/
1080 if(audioctrl->ahiac_EffDSPEchoStruct != NULL)
1082 audioctrl->ahiac_EffDSPEchoStruct->ahiecho_Code(
1083 audioctrl->ahiac_EffDSPEchoStruct, dst, audioctrl);
1086 cd = audioctrl->ahiac_DryList;
1088 if(audioctrl->ac.ahiac_Flags & AHIACF_POSTPROC)
1090 /*** AHIET_MASTERVOLUME ***/
1092 DoMasterVolume(dst, audioctrl);
1095 ** When AHIACB_POSTPROC is set, the dry data shall be placed
1096 ** immediate after the wet data. This is done by modifying the
1097 ** dst pointer
1100 dst = (char *) dst + audioctrl->ac.ahiac_BuffSamples *
1101 _AHI_SampleFrameSize( audioctrl->ac.ahiac_BuffType, AHIBase );
1104 continue; /* while(TRUE) */
1106 else
1108 break; /* while(TRUE) */
1110 } // while(TRUE)
1112 return;
1116 /******************************************************************************
1117 ** DoMasterVolume *************************************************************
1118 ******************************************************************************/
1121 ** This function would be better if it was written in assembler,
1122 ** since overflow could then be detected. Instead we reduce the
1123 ** number of bits to 20 and then scale and compare.
1126 void
1127 DoMasterVolume( void *buffer,
1128 struct AHIPrivAudioCtrl *audioctrl )
1130 int cnt;
1131 LONG vol;
1132 LONG sample;
1134 cnt = audioctrl->ac.ahiac_BuffSamples;
1136 switch(audioctrl->ac.ahiac_BuffType)
1139 case AHIST_M16S:
1140 case AHIST_M32S:
1141 break;
1143 case AHIST_S16S:
1144 case AHIST_S32S:
1145 cnt *= 2;
1146 break;
1148 case AHIST_L7_1:
1149 cnt *= 8;
1150 break;
1152 default:
1153 return; // Panic
1156 if( audioctrl->ac.ahiac_BuffType == AHIST_M32S
1157 || audioctrl->ac.ahiac_BuffType == AHIST_S32S
1158 || audioctrl->ac.ahiac_BuffType == AHIST_L7_1 )
1160 LONG *dst = buffer;
1162 vol = audioctrl->ahiac_SetMasterVolume >> 8;
1164 while(cnt > 0)
1166 cnt--;
1168 sample = (*dst >> 12) * vol;
1170 if(sample > (LONG) 0x07ffffff)
1171 sample = 0x07ffffff;
1172 else if(sample < (LONG) 0xf8000000)
1173 sample = 0xf8000000;
1175 *dst++ = sample << 4;
1178 else
1180 WORD *dst = buffer;
1182 vol = audioctrl->ahiac_SetMasterVolume >> 4;
1184 while(cnt > 0)
1186 cnt--;
1188 sample = *dst * vol;
1190 if(sample > (LONG) 0x07ffffff)
1191 sample = 0x07ffffff;
1192 else if(sample < (LONG) 0xf8000000)
1193 sample = 0xf8000000;
1195 *dst++ = sample >> 12;
1202 /******************************************************************************
1203 ** DoOutputBuffer *************************************************************
1204 ******************************************************************************/
1206 void
1207 DoOutputBuffer( void *buffer,
1208 struct AHIPrivAudioCtrl *audioctrl )
1210 struct AHIEffOutputBuffer *ob;
1212 ob = audioctrl->ahiac_EffOutputBufferStruct;
1214 if(ob != NULL)
1216 ob->ahieob_Buffer = buffer;
1217 ob->ahieob_Length = audioctrl->ac.ahiac_BuffSamples;
1218 ob->ahieob_Type = audioctrl->ac.ahiac_BuffType;
1220 CallHookPkt( ob->ahieob_Func,
1221 audioctrl,
1222 ob);
1227 /******************************************************************************
1228 ** DoChannelInfo **************************************************************
1229 ******************************************************************************/
1231 void
1232 DoChannelInfo( struct AHIPrivAudioCtrl *audioctrl )
1234 struct AHIEffChannelInfo *ci;
1235 struct AHIChannelData *cd;
1236 ULONG *offsets;
1238 ci = audioctrl->ahiac_EffChannelInfoStruct;
1240 if(ci != NULL)
1242 int i;
1244 cd = audioctrl->ahiac_ChannelDatas;
1245 offsets = ci->ahieci_Offset;
1247 for(i = ci->ahieci_Channels; i > 0; i--)
1249 *offsets++ = cd->cd_Offset >> 32;
1250 cd++;
1253 CallHookPkt( ci->ahieci_Func,
1254 audioctrl,
1255 ci );
1260 /******************************************************************************
1261 ** CalcSamples ****************************************************************
1262 ******************************************************************************/
1264 LONG
1265 CalcSamples ( Fixed64 Add,
1266 ULONG Type,
1267 Fixed64 LastOffset,
1268 Fixed64 Offset )
1271 Fixed64 len;
1273 if( Type & AHIST_BW )
1275 len = Offset - LastOffset;
1277 else
1279 len = LastOffset - Offset;
1282 if(len < 0 || Add == 0) return 0; // Error!
1284 return (LONG) ( len / Add ) + 1;