revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / AHI / Device / mixer.c
blob542933d4c85e642dfa7d5ad29e4a21388f2981df
1 /*
2 AHI - Hardware independent audio subsystem
3 Copyright (C) 2017 The AROS Dev Team
4 Copyright (C) 1996-2005 Martin Blom <martin@blom.org>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with this library; if not, write to the
18 Free Software Foundation, Inc., 59 Temple Place - Suite 330, Cambridge,
19 MA 02139, USA.
22 #include <config.h>
24 #include <string.h>
25 #include <stddef.h>
27 #include <dos/dos.h>
28 #include <dos/dostags.h>
29 #include <exec/memory.h>
31 #include <proto/dos.h>
32 #include <proto/exec.h>
33 #include <proto/utility.h>
34 #define __NOLIBBASE__
35 #define __NOGLOBALIFACE__
36 #include <proto/ahi.h>
37 #undef __NOLIBBASE__
38 #undef __NOGLOBALIFACE__
40 #include "ahi_def.h"
42 #include "addroutines.h"
43 #include "debug.h"
44 #include "dsp.h"
45 #include "header.h"
46 #include "misc.h"
47 #include "mixer.h"
48 #include "sound.h"
50 #if defined( ENABLE_WARPUP )
51 # include "warpup.h"
52 #endif
54 #define min(a,b) (((a)<(b))?(a):(b))
55 #define max(a,b) (((a)>(b))?(a):(b))
57 /******************************************************************************
58 ** Prototypes *****************************************************************
59 ******************************************************************************/
61 void
62 CallSoundHook( struct AHIPrivAudioCtrl *audioctrl,
63 void* arg )
65 switch( MixBackend )
67 case MB_NATIVE:
68 CallHookPkt( audioctrl->ac.ahiac_SoundFunc,
69 audioctrl,
70 arg );
71 break;
73 #if defined( ENABLE_WARPUP )
74 case MB_WARPUP:
75 WarpUpCallSoundHook( audioctrl, arg );
76 break;
77 #endif
82 void
83 MixerFunc( struct Hook* hook,
84 struct AHIPrivAudioCtrl* audioctrl,
85 void* dst )
87 switch( MixBackend )
89 case MB_NATIVE:
90 Mix( hook, audioctrl, dst );
91 DoMasterVolume( dst, audioctrl );
92 DoOutputBuffer( dst, audioctrl );
93 DoChannelInfo( audioctrl );
94 break;
96 #if defined( ENABLE_WARPUP )
97 case MB_WARPUP:
98 WarpUpCallMixer( audioctrl, dst );
99 DoOutputBuffer( dst, audioctrl );
100 DoChannelInfo( audioctrl );
101 break;
102 #endif
107 /******************************************************************************
108 ** InitMixroutine *************************************************************
109 ******************************************************************************/
111 // This function is used to initialize the mixer routine (called from
112 // AHI_AllocAudio()).
114 BOOL
115 InitMixroutine( struct AHIPrivAudioCtrl *audioctrl )
117 BOOL rc = FALSE;
119 // Allocate and initialize the AHIChannelData structures
120 // This structure could be accessed from from interrupts!
122 ULONG data_flags = MEMF_ANY;
124 switch( MixBackend )
126 case MB_NATIVE:
127 data_flags = MEMF_PUBLIC | MEMF_CLEAR;
128 break;
130 #if defined( ENABLE_WARPUP )
131 case MB_WARPUP:
132 // Non-cached from both the PPC and m68k side
133 data_flags = MEMF_PUBLIC | MEMF_CLEAR | MEMF_CHIP;
134 break;
135 #endif
138 audioctrl->ahiac_ChannelDatas = AHIAllocVec(
139 audioctrl->ac.ahiac_Channels * sizeof( struct AHIChannelData ),
140 data_flags );
142 // Allocate and initialize the AHISoundData structures
143 // This structure could be accessed from from interrupts!
145 audioctrl->ahiac_SoundDatas = AHIAllocVec(
146 audioctrl->ac.ahiac_Sounds * sizeof( struct AHISoundData ),
147 data_flags );
149 // Now link the list and fill in the channel number for each structure.
151 if( audioctrl->ahiac_ChannelDatas != NULL
152 && audioctrl->ahiac_SoundDatas != NULL )
154 struct AHIChannelData *cd;
155 struct AHISoundData *sd;
156 int i;
158 cd = audioctrl->ahiac_ChannelDatas;
160 audioctrl->ahiac_WetList = cd;
161 audioctrl->ahiac_DryList = NULL;
163 for(i = 0; i < audioctrl->ac.ahiac_Channels - 1; i++)
165 // Set Channel No
166 cd->cd_ChannelNo = i;
168 // Set link to next channel
169 cd->cd_Succ = cd + 1;
170 cd++;
173 // Set the last No
174 cd->cd_ChannelNo = i;
176 // Clear the last link;
177 cd->cd_Succ = NULL;
180 sd = audioctrl->ahiac_SoundDatas;
182 for( i = 0; i < audioctrl->ac.ahiac_Sounds; i++)
184 sd->sd_Type = AHIST_NOTYPE;
185 sd++;
190 switch( MixBackend )
192 case MB_NATIVE:
193 rc = TRUE;
194 break;
196 #if defined( ENABLE_WARPUP )
197 case MB_WARPUP:
198 rc = WarpUpInit( audioctrl );
199 break;
200 #endif
203 return rc;
207 /******************************************************************************
208 ** CleanUpMixroutine **********************************************************
209 ******************************************************************************/
211 // This function is used to clean up after the mixer routine (called from
212 // AHI_FreeAudio()).
214 void
215 CleanUpMixroutine( struct AHIPrivAudioCtrl *audioctrl )
217 switch( MixBackend )
219 case MB_NATIVE:
220 break;
222 #if defined( ENABLE_WARPUP )
223 case MB_WARPUP:
224 WarpUpCleanUp( audioctrl );
225 break;
226 #endif
229 AHIFreeVec( audioctrl->ahiac_SoundDatas );
230 audioctrl->ahiac_SoundDatas = NULL;
232 AHIFreeVec( audioctrl->ahiac_ChannelDatas );
233 audioctrl->ahiac_ChannelDatas = NULL;
237 /******************************************************************************
238 ** SelectAddRoutine ***********************************************************
239 ******************************************************************************/
241 // This routine gets called each time there is reason to believe that a new
242 // add-routine should be used (new sound selected, volume changed,
243 // mastervolume changed)
245 // Based on VolumeLeft, VolumeRight and SampleType, fill in ScaleLeft,
246 // ScaleRight and AddRoutine.
248 void
249 SelectAddRoutine ( Fixed VolumeLeft,
250 Fixed VolumeRight,
251 ULONG SampleType,
252 struct AHIPrivAudioCtrl *audioctrl,
253 LONG *ScaleLeft,
254 LONG *ScaleRight,
255 ADDFUNC **AddRoutine )
258 // This version only cares about the sample format and does not use any
259 // optimized add-routines.
261 // Scale the volume
263 VolumeLeft = VolumeLeft * (audioctrl->ahiac_MasterVolume >> 8) /
264 (audioctrl->ahiac_Channels2 << 8);
266 VolumeRight = VolumeRight * (audioctrl->ahiac_MasterVolume >> 8) /
267 (audioctrl->ahiac_Channels2 << 8);
269 // First, select HiFi or LoFi...
271 if( audioctrl->ac.ahiac_Flags & AHIACF_HIFI )
274 // Then, check the output format...
276 switch(audioctrl->ac.ahiac_BuffType)
279 case AHIST_M32S:
281 // ...and then the source format.
283 switch(SampleType)
285 case AHIST_M8S:
286 case AHIST_BW|AHIST_M8S:
287 *ScaleLeft = VolumeLeft + VolumeRight;
288 *ScaleRight = 0;
289 if(SampleType & AHIST_BW)
290 *AddRoutine = AddByteMonoBPtr;
291 else
292 *AddRoutine = AddByteMonoPtr;
293 break;
295 case AHIST_S8S:
296 case AHIST_BW|AHIST_S8S:
297 *ScaleLeft = VolumeLeft;
298 *ScaleRight = VolumeRight;
299 if(SampleType & AHIST_BW)
300 *AddRoutine = AddBytesMonoBPtr;
301 else
302 *AddRoutine = AddBytesMonoPtr;
303 break;
305 case AHIST_M16S:
306 case AHIST_BW|AHIST_M16S:
307 *ScaleLeft = VolumeLeft + VolumeRight;
308 *ScaleRight = 0;
309 if(SampleType & AHIST_BW)
310 *AddRoutine = AddWordMonoBPtr;
311 else
312 *AddRoutine = AddWordMonoPtr;
313 break;
315 case AHIST_S16S:
316 case AHIST_BW|AHIST_S16S:
317 *ScaleLeft = VolumeLeft;
318 *ScaleRight = VolumeRight;
319 if(SampleType & AHIST_BW)
320 *AddRoutine = AddWordsMonoBPtr;
321 else
322 *AddRoutine = AddWordsMonoPtr;
323 break;
325 case AHIST_M32S:
326 case AHIST_BW|AHIST_M32S:
327 *ScaleLeft = VolumeLeft + VolumeRight;
328 *ScaleRight = 0;
329 if(SampleType & AHIST_BW)
330 *AddRoutine = AddLongMonoBPtr;
331 else
332 *AddRoutine = AddLongMonoPtr;
333 break;
335 case AHIST_S32S:
336 case AHIST_BW|AHIST_S32S:
337 *ScaleLeft = VolumeLeft;
338 *ScaleRight = VolumeRight;
339 if(SampleType & AHIST_BW)
340 *AddRoutine = AddLongsMonoBPtr;
341 else
342 *AddRoutine = AddLongsMonoPtr;
343 break;
345 case AHIST_L7_1:
346 case AHIST_BW|AHIST_L7_1:
347 *ScaleLeft = VolumeLeft;
348 *ScaleRight = VolumeRight;
349 if(SampleType & AHIST_BW)
350 *AddRoutine = Add71MonoBPtr;
351 else
352 *AddRoutine = Add71MonoPtr;
353 break;
355 default:
356 *ScaleLeft = 0;
357 *ScaleRight = 0;
358 *AddRoutine = NULL;
359 break;
361 break;
363 case AHIST_S32S:
365 // ...and then the source format.
367 switch(SampleType)
369 case AHIST_M8S:
370 case AHIST_BW|AHIST_M8S:
371 *ScaleLeft = VolumeLeft;
372 *ScaleRight = VolumeRight;
373 if(SampleType & AHIST_BW)
374 *AddRoutine = AddByteStereoBPtr;
375 else
376 *AddRoutine = AddByteStereoPtr;
377 break;
379 case AHIST_S8S:
380 case AHIST_BW|AHIST_S8S:
381 *ScaleLeft = VolumeLeft;
382 *ScaleRight = VolumeRight;
383 if(SampleType & AHIST_BW)
384 *AddRoutine = AddBytesStereoBPtr;
385 else
386 *AddRoutine = AddBytesStereoPtr;
387 break;
389 case AHIST_M16S:
390 case AHIST_BW|AHIST_M16S:
391 *ScaleLeft = VolumeLeft;
392 *ScaleRight = VolumeRight;
393 if(SampleType & AHIST_BW)
394 *AddRoutine = AddWordStereoBPtr;
395 else
396 *AddRoutine = AddWordStereoPtr;
397 break;
399 case AHIST_S16S:
400 case AHIST_BW|AHIST_S16S:
401 *ScaleLeft = VolumeLeft;
402 *ScaleRight = VolumeRight;
403 if(SampleType & AHIST_BW)
404 *AddRoutine = AddWordsStereoBPtr;
405 else
406 *AddRoutine = AddWordsStereoPtr;
407 break;
409 case AHIST_M32S:
410 case AHIST_BW|AHIST_M32S:
411 *ScaleLeft = VolumeLeft;
412 *ScaleRight = VolumeRight;
413 if(SampleType & AHIST_BW)
414 *AddRoutine = AddLongStereoBPtr;
415 else
416 *AddRoutine = AddLongStereoPtr;
417 break;
419 case AHIST_S32S:
420 case AHIST_BW|AHIST_S32S:
421 *ScaleLeft = VolumeLeft;
422 *ScaleRight = VolumeRight;
423 if(SampleType & AHIST_BW)
424 *AddRoutine = AddLongsStereoBPtr;
425 else
426 *AddRoutine = AddLongsStereoPtr;
427 break;
429 case AHIST_L7_1:
430 case AHIST_BW|AHIST_L7_1:
431 *ScaleLeft = VolumeLeft;
432 *ScaleRight = VolumeRight;
433 if(SampleType & AHIST_BW)
434 *AddRoutine = Add71StereoBPtr;
435 else
436 *AddRoutine = Add71StereoPtr;
437 break;
439 default:
440 *ScaleLeft = 0;
441 *ScaleRight = 0;
442 *AddRoutine = NULL;
443 break;
445 break;
447 case AHIST_L7_1:
449 // ...and then the source format.
451 switch(SampleType)
453 case AHIST_M8S:
454 case AHIST_BW|AHIST_M8S:
455 *ScaleLeft = VolumeLeft;
456 *ScaleRight = VolumeRight;
457 if(SampleType & AHIST_BW)
458 *AddRoutine = AddByte71BPtr;
459 else
460 *AddRoutine = AddByte71Ptr;
461 break;
463 case AHIST_S8S:
464 case AHIST_BW|AHIST_S8S:
465 *ScaleLeft = VolumeLeft;
466 *ScaleRight = VolumeRight;
467 if(SampleType & AHIST_BW)
468 *AddRoutine = AddBytes71BPtr;
469 else
470 *AddRoutine = AddBytes71Ptr;
471 break;
473 case AHIST_M16S:
474 case AHIST_BW|AHIST_M16S:
475 *ScaleLeft = VolumeLeft;
476 *ScaleRight = VolumeRight;
477 if(SampleType & AHIST_BW)
478 *AddRoutine = AddWord71BPtr;
479 else
480 *AddRoutine = AddWord71Ptr;
481 break;
483 case AHIST_S16S:
484 case AHIST_BW|AHIST_S16S:
485 *ScaleLeft = VolumeLeft;
486 *ScaleRight = VolumeRight;
487 if(SampleType & AHIST_BW)
488 *AddRoutine = AddWords71BPtr;
489 else
490 *AddRoutine = AddWords71Ptr;
491 break;
493 case AHIST_M32S:
494 case AHIST_BW|AHIST_M32S:
495 *ScaleLeft = VolumeLeft;
496 *ScaleRight = VolumeRight;
497 if(SampleType & AHIST_BW)
498 *AddRoutine = AddLong71BPtr;
499 else
500 *AddRoutine = AddLong71Ptr;
501 break;
503 case AHIST_S32S:
504 case AHIST_BW|AHIST_S32S:
505 *ScaleLeft = VolumeLeft;
506 *ScaleRight = VolumeRight;
507 if(SampleType & AHIST_BW)
508 *AddRoutine = AddLongs71BPtr;
509 else
510 *AddRoutine = AddLongs71Ptr;
511 break;
513 case AHIST_L7_1:
514 case AHIST_BW|AHIST_L7_1:
515 *ScaleLeft = VolumeLeft;
516 *ScaleRight = VolumeRight;
517 if(SampleType & AHIST_BW)
518 *AddRoutine = Add7171BPtr;
519 else
520 *AddRoutine = Add7171Ptr;
521 break;
523 default:
524 *ScaleLeft = 0;
525 *ScaleRight = 0;
526 *AddRoutine = NULL;
527 break;
529 break;
531 default:
532 *ScaleLeft = 0;
533 *ScaleRight = 0;
534 *AddRoutine = NULL;
535 break;
538 else
541 // Then, check the output format...
543 switch(audioctrl->ac.ahiac_BuffType)
546 case AHIST_M16S:
548 // ...and then the source format.
550 switch(SampleType)
552 case AHIST_M8S:
553 case AHIST_BW|AHIST_M8S:
554 *ScaleLeft = VolumeLeft + VolumeRight;
555 *ScaleRight = 0;
556 if(SampleType & AHIST_BW)
557 *AddRoutine = AddLofiByteMonoBPtr;
558 else
559 *AddRoutine = AddLofiByteMonoPtr;
560 break;
562 case AHIST_S8S:
563 case AHIST_BW|AHIST_S8S:
564 *ScaleLeft = VolumeLeft;
565 *ScaleRight = VolumeRight;
566 if(SampleType & AHIST_BW)
567 *AddRoutine = AddLofiBytesMonoBPtr;
568 else
569 *AddRoutine = AddLofiBytesMonoPtr;
570 break;
572 case AHIST_M16S:
573 case AHIST_BW|AHIST_M16S:
574 *ScaleLeft = VolumeLeft + VolumeRight;
575 *ScaleRight = 0;
576 if(SampleType & AHIST_BW)
577 *AddRoutine = AddLofiWordMonoBPtr;
578 else
579 *AddRoutine = AddLofiWordMonoPtr;
580 break;
582 case AHIST_S16S:
583 case AHIST_BW|AHIST_S16S:
584 *ScaleLeft = VolumeLeft;
585 *ScaleRight = VolumeRight;
586 if(SampleType & AHIST_BW)
587 *AddRoutine = AddLofiWordsMonoBPtr;
588 else
589 *AddRoutine = AddLofiWordsMonoPtr;
590 break;
592 case AHIST_M32S:
593 case AHIST_BW|AHIST_M32S:
594 *ScaleLeft = VolumeLeft + VolumeRight;
595 *ScaleRight = 0;
596 if(SampleType & AHIST_BW)
597 *AddRoutine = AddLofiLongMonoBPtr;
598 else
599 *AddRoutine = AddLofiLongMonoPtr;
600 break;
602 case AHIST_S32S:
603 case AHIST_BW|AHIST_S32S:
604 *ScaleLeft = VolumeLeft;
605 *ScaleRight = VolumeRight;
606 if(SampleType & AHIST_BW)
607 *AddRoutine = AddLofiLongsMonoBPtr;
608 else
609 *AddRoutine = AddLofiLongsMonoPtr;
610 break;
612 default:
613 *ScaleLeft = 0;
614 *ScaleRight = 0;
615 *AddRoutine = NULL;
616 break;
618 break;
620 case AHIST_S16S:
622 // ...and then the source format.
624 switch(SampleType)
626 case AHIST_M8S:
627 case AHIST_BW|AHIST_M8S:
628 *ScaleLeft = VolumeLeft;
629 *ScaleRight = VolumeRight;
630 if(SampleType & AHIST_BW)
631 *AddRoutine = AddLofiByteStereoBPtr;
632 else
633 *AddRoutine = AddLofiByteStereoPtr;
634 break;
636 case AHIST_S8S:
637 case AHIST_BW|AHIST_S8S:
638 *ScaleLeft = VolumeLeft;
639 *ScaleRight = VolumeRight;
640 if(SampleType & AHIST_BW)
641 *AddRoutine = AddLofiBytesStereoBPtr;
642 else
643 *AddRoutine = AddLofiBytesStereoPtr;
644 break;
646 case AHIST_M16S:
647 case AHIST_BW|AHIST_M16S:
648 *ScaleLeft = VolumeLeft;
649 *ScaleRight = VolumeRight;
650 if(SampleType & AHIST_BW)
651 *AddRoutine = AddLofiWordStereoBPtr;
652 else
653 *AddRoutine = AddLofiWordStereoPtr;
654 break;
656 case AHIST_S16S:
657 case AHIST_BW|AHIST_S16S:
658 *ScaleLeft = VolumeLeft;
659 *ScaleRight = VolumeRight;
660 if(SampleType & AHIST_BW)
661 *AddRoutine = AddLofiWordsStereoBPtr;
662 else
663 *AddRoutine = AddLofiWordsStereoPtr;
664 break;
666 case AHIST_M32S:
667 case AHIST_BW|AHIST_M32S:
668 *ScaleLeft = VolumeLeft;
669 *ScaleRight = VolumeRight;
670 if(SampleType & AHIST_BW)
671 *AddRoutine = AddLofiLongStereoBPtr;
672 else
673 *AddRoutine = AddLofiLongStereoPtr;
674 break;
676 case AHIST_S32S:
677 case AHIST_BW|AHIST_S32S:
678 *ScaleLeft = VolumeLeft;
679 *ScaleRight = VolumeRight;
680 if(SampleType & AHIST_BW)
681 *AddRoutine = AddLofiLongsStereoBPtr;
682 else
683 *AddRoutine = AddLofiLongsStereoPtr;
684 break;
686 default:
687 *ScaleLeft = 0;
688 *ScaleRight = 0;
689 *AddRoutine = NULL;
690 break;
692 break;
694 default:
695 *ScaleLeft = 0;
696 *ScaleRight = 0;
697 *AddRoutine = NULL;
698 break;
704 /******************************************************************************
705 ** Mix ************************************************************************
706 ******************************************************************************/
708 // This is the function that the driver calls each time it want more data
709 // to play.
711 void
712 Mix( struct Hook* unused_Hook,
713 struct AHIPrivAudioCtrl* audioctrl,
714 void* dst )
716 struct AHIChannelData *cd;
717 void *dstptr;
718 LONG samplesleft;
720 /* Clear the buffer */
722 memset( dst, 0, audioctrl->ahiac_BuffSizeNow );
723 /* Mix the samples */
725 audioctrl->ahiac_WetOrDry = AHIEDM_WET;
727 cd = audioctrl->ahiac_WetList;
729 while(TRUE)
731 while(cd != NULL) // .nextchannel
733 samplesleft = audioctrl->ac.ahiac_BuffSamples;
734 dstptr = dst;
736 while(TRUE) // .contchannel
738 LONG samples;
739 LONG processed;
741 /* Call Sound Hook */
743 if(cd->cd_EOS)
745 cd->cd_EOS = FALSE;
746 if(audioctrl->ac.ahiac_SoundFunc != NULL)
748 CallSoundHook( audioctrl, &cd->cd_ChannelNo );
752 processed = 0;
754 if( cd->cd_AntiClickCount > 0 && cd->cd_FreqOK && cd->cd_SoundOK )
756 // Sound is ok and we're looking for a zero-crossing.
758 LONG try_samples;
760 samples = min( samplesleft, cd->cd_Samples );
761 try_samples = min( samples, cd->cd_AntiClickCount );
763 if( try_samples > 0 )
765 cd->cd_TempStartPointL = cd->cd_StartPointL;
766 cd->cd_TempStartPointR = cd->cd_StartPointR;
767 cd->cd_TempStartPointRL = cd->cd_StartPointRL;
768 cd->cd_TempStartPointRR = cd->cd_StartPointRR;
769 cd->cd_TempStartPointSL = cd->cd_StartPointSL;
770 cd->cd_TempStartPointSR = cd->cd_StartPointSR;
771 cd->cd_TempStartPointC = cd->cd_StartPointC;
772 cd->cd_TempStartPointLFE = cd->cd_StartPointLFE;
774 processed = ((ADDFUNC *) cd->cd_AddRoutine)( try_samples,
775 cd->cd_ScaleLeft,
776 cd->cd_ScaleRight,
777 &cd->cd_TempStartPointL,
778 &cd->cd_TempStartPointR,
779 cd->cd_DataStart,
780 &dstptr,
781 cd->cd_FirstOffsetI,
782 cd->cd_Add,
783 &cd->cd_Offset,
784 TRUE );
786 cd->cd_Samples -= processed;
787 samplesleft -= processed;
789 else
791 processed = 0;
794 if( processed != try_samples || // Found zero-crossing
795 try_samples <= cd->cd_AntiClickCount ) // End-of-sound or
796 // max delay reached
798 // We either found a zero-crossing, looked as far as
799 // we were allowed to or reached the end of sound.
801 // To be perfect, the we should not run this code if the
802 // end-of-sound was reached. Instead, since cd_Samples is zero
803 // and the second cd_AddRoutine call below will have no effect,
804 // we should just go onand the cd_Next#? variables will be copied
805 // instead. However, that requires two sets of delay variables:
806 // The one we have now and one delayed set of "next" variables.
807 // I might do that another time, but not today...
809 // Now start the delayed sound.
811 if( cd->cd_VolDelayed )
813 cd->cd_VolDelayed = FALSE;
814 cd->cd_VolumeLeft = cd->cd_DelayedVolumeLeft;
815 cd->cd_VolumeRight = cd->cd_DelayedVolumeRight;
816 cd->cd_ScaleLeft = cd->cd_DelayedScaleLeft;
817 cd->cd_ScaleRight = cd->cd_DelayedScaleRight;
818 cd->cd_AddRoutine = cd->cd_DelayedAddRoutine;
821 if( cd->cd_FreqDelayed )
823 cd->cd_FreqDelayed = FALSE;
824 cd->cd_FreqOK = cd->cd_DelayedFreqOK;
825 cd->cd_Add = cd->cd_DelayedAdd;
827 // Since we have advanced, cd_Samples must be recalculated!
828 cd->cd_Samples = CalcSamples( cd->cd_Add,
829 cd->cd_Type,
830 cd->cd_LastOffset,
831 cd->cd_Offset );
834 if( cd->cd_SoundDelayed )
836 cd->cd_SoundDelayed = FALSE;
838 cd->cd_SoundOK = cd->cd_DelayedSoundOK;
840 cd->cd_StartPointL = 0;
841 cd->cd_StartPointR = 0;
843 cd->cd_Offset = cd->cd_DelayedOffset;
844 cd->cd_FirstOffsetI = cd->cd_DelayedFirstOffsetI;
845 cd->cd_LastOffset = cd->cd_DelayedLastOffset;
846 cd->cd_DataStart = cd->cd_DelayedDataStart;
848 cd->cd_Type = cd->cd_DelayedType;
849 cd->cd_AddRoutine = cd->cd_DelayedAddRoutine;
851 cd->cd_Samples = cd->cd_DelayedSamples;
853 cd->cd_ScaleLeft = cd->cd_DelayedScaleLeft;
854 cd->cd_ScaleRight = cd->cd_DelayedScaleRight;
855 cd->cd_AddRoutine = cd->cd_DelayedAddRoutine;
859 if( cd->cd_VolDelayed || cd->cd_FreqDelayed || cd->cd_SoundDelayed )
861 cd->cd_AntiClickCount -= processed;
863 else
865 cd->cd_AntiClickCount = 0;
869 if( cd->cd_FreqOK && cd->cd_SoundOK )
871 // Sound is still ok, let's rock'n roll.
873 samples = min( samplesleft, cd->cd_Samples );
875 if( samples > 0 )
877 cd->cd_TempStartPointL = cd->cd_StartPointL;
878 cd->cd_TempStartPointR = cd->cd_StartPointR;
879 cd->cd_TempStartPointRL = cd->cd_StartPointRL;
880 cd->cd_TempStartPointRR = cd->cd_StartPointRR;
881 cd->cd_TempStartPointSL = cd->cd_StartPointSL;
882 cd->cd_TempStartPointSR = cd->cd_StartPointSR;
883 cd->cd_TempStartPointC = cd->cd_StartPointC;
884 cd->cd_TempStartPointLFE = cd->cd_StartPointLFE;
886 processed = ((ADDFUNC *) cd->cd_AddRoutine)( samples,
887 cd->cd_ScaleLeft,
888 cd->cd_ScaleRight,
889 &cd->cd_TempStartPointL,
890 &cd->cd_TempStartPointR,
891 cd->cd_DataStart,
892 &dstptr,
893 cd->cd_FirstOffsetI,
894 cd->cd_Add,
895 &cd->cd_Offset,
896 FALSE );
897 cd->cd_Samples -= processed;
898 samplesleft -= processed;
901 if( cd->cd_Samples == 0 )
903 /* Linear interpol. stuff */
905 ULONG lo = (ULONG) (cd->cd_LastOffset >> 32);
907 switch( cd->cd_Type ) {
909 case AHIST_M8S:
910 cd->cd_StartPointL = ((BYTE*) cd->cd_DataStart)[ lo ] << 8;
911 break;
913 case AHIST_S8S:
914 cd->cd_StartPointL = ((BYTE*) cd->cd_DataStart)[ lo*2+0 ] << 8;
915 cd->cd_StartPointR = ((BYTE*) cd->cd_DataStart)[ lo*2+1 ] << 8;
916 break;
918 case AHIST_M16S:
919 cd->cd_StartPointL = ((WORD*) cd->cd_DataStart)[ lo ];
920 break;
922 case AHIST_S16S:
923 cd->cd_StartPointL = ((WORD*) cd->cd_DataStart)[ lo*2+0 ];
924 cd->cd_StartPointR = ((WORD*) cd->cd_DataStart)[ lo*2+1 ];
925 break;
927 case AHIST_M32S:
928 cd->cd_StartPointL = ((LONG*) cd->cd_DataStart)[ lo ] >> 16;
929 break;
931 case AHIST_S32S:
932 cd->cd_StartPointL = ((LONG*) cd->cd_DataStart)[ lo*2+0 ] >> 16;
933 cd->cd_StartPointR = ((LONG*) cd->cd_DataStart)[ lo*2+1 ] >> 16;
934 break;
937 // This old code is totally fucked up ... Why didn't anybody
938 // complain?!
939 // cd->cd_StartPointL = cd->cd_TempStartPointL;
940 // cd->cd_StartPointR = cd->cd_TempStartPointR;
942 /* KPrintF( "cd->cd_StartPointL=%08lx, cd->cd_StartPointR=%08lx\n", */
943 /* cd->cd_StartPointL, cd->cd_StartPointR ); */
945 ** Offset always points OUTSIDE the sample after this
946 ** call. Ie, if we read a sample at offset (Offset.I)
947 ** now, it does not belong to the sample just played.
948 ** This is true for both backward and forward mixing.
951 /* KPrintF( "cd->cd_Add=0x%08lx:%08lx\n", */
952 /* (IPTR) (cd->cd_Add >> 32), (IPTR) cd->cd_Add ); */
953 /* KPrintF( "cd->cd_Offset=0x%08lx:%08lx, " */
954 /* "cd->cd_LastOffset=0x%08lx:%08lx," */
955 /* "cd->cd_FirstOffset=%08lx\n", */
956 /* (IPTR) (cd->cd_Offset >> 32), (IPTR) cd->cd_Offset, */
957 /* (IPTR) (cd->cd_LastOffset >> 32), (IPTR) cd->cd_LastOffset, */
958 /* cd->cd_FirstOffsetI ); */
960 /* What we do now is to calculate how much futher we have
961 advanced. */
963 cd->cd_Offset -= cd->cd_LastOffset + 1;
965 /* KPrintF( "cd->cd_Offset=0x%08lx:%08lx, " */
966 /* "cd->cd_LastOffset=0x%08lx:%08lx," */
967 /* "cd->cd_FirstOffset=%08lx\n", */
968 /* (IPTR) (cd->cd_Offset >> 32), (IPTR) cd->cd_Offset, */
969 /* (IPTR) (cd->cd_LastOffset >> 32), (IPTR) cd->cd_LastOffset, */
970 /* cd->cd_FirstOffsetI ); */
973 ** Offset should now be added to the NEXT Offset. Offset
974 ** is positive of the sample was mixed forwards, and
975 ** negative if the sample was mixed backwards. There is
976 ** one catch, however. If the direction is about to
977 ** change now, Offset should instead be SUBTRACTED.
978 ** Let's check:
981 if( (cd->cd_Type ^ cd->cd_NextType) & AHIST_BW )
983 cd->cd_Offset = -cd->cd_Offset;
986 cd->cd_Offset += cd->cd_NextOffset;
988 // cd->cd_FirstOffsetI = cd->cd_Offset >> 32;
989 cd->cd_FirstOffsetI = cd->cd_NextOffset >> 32;
991 /* KPrintF( "cd->cd_Offset=0x%08lx:%08lx, " */
992 /* "cd->cd_LastOffset=0x%08lx:%08lx," */
993 /* "cd->cd_FirstOffset=%08lx\n", */
994 /* (IPTR) (cd->cd_Offset >> 32), (IPTR) cd->cd_Offset, */
995 /* (IPTR) (cd->cd_LastOffset >> 32), (IPTR) cd->cd_LastOffset, */
996 /* cd->cd_FirstOffsetI ); */
998 ** But what if the next sample is so short that we just
999 ** passed it!? Here is the nice part. CalcSamples
1000 ** checks this, and sets cd_Samples to 0 in that case.
1001 ** And the add routines doesn't do anything when asked to
1002 ** mix 0 samples. Assume we have passed a sample with 4
1003 ** samples, and the next one is only 3. CalcSamples
1004 ** returns 0. The (ADDFUNC) call above does not do
1005 ** anything at all, OffsetI is still 4. Now we subtract
1006 ** LastOffsetI, which is 3. Result: We have passed the
1007 ** sample with 1. And guess what? That's in range.
1010 /* Now, let's copy the rest of the cd_Next#? stuff... */
1012 cd->cd_FreqOK = cd->cd_NextFreqOK;
1013 cd->cd_SoundOK = cd->cd_NextSoundOK;
1014 cd->cd_Add = cd->cd_NextAdd;
1015 cd->cd_DataStart = cd->cd_NextDataStart;
1016 cd->cd_LastOffset = cd->cd_NextLastOffset;
1017 cd->cd_ScaleLeft = cd->cd_NextScaleLeft;
1018 cd->cd_ScaleRight = cd->cd_NextScaleRight;
1019 cd->cd_AddRoutine = cd->cd_NextAddRoutine;
1020 cd->cd_VolumeLeft = cd->cd_NextVolumeLeft;
1021 cd->cd_VolumeRight = cd->cd_NextVolumeRight;
1022 cd->cd_Type = cd->cd_NextType;
1024 cd->cd_Samples = CalcSamples( cd->cd_Add,
1025 cd->cd_Type,
1026 cd->cd_LastOffset,
1027 cd->cd_Offset );
1029 /* Also update all cd_Delayed#? stuff */
1031 if( !cd->cd_VolDelayed )
1033 cd->cd_DelayedVolumeLeft = cd->cd_NextVolumeLeft;
1034 cd->cd_DelayedVolumeRight = cd->cd_NextVolumeRight;
1037 if( !cd->cd_FreqDelayed )
1039 cd->cd_DelayedFreqOK = cd->cd_NextFreqOK;
1040 cd->cd_DelayedAdd = cd->cd_NextAdd;
1043 if( !cd->cd_SoundDelayed )
1045 cd->cd_DelayedSoundOK = cd->cd_NextSoundOK;
1046 cd->cd_DelayedOffset = cd->cd_NextOffset;
1047 cd->cd_DelayedFirstOffsetI = cd->cd_FirstOffsetI; // See above
1048 cd->cd_DelayedLastOffset = cd->cd_NextLastOffset;
1049 cd->cd_DelayedType = cd->cd_NextType;
1050 cd->cd_DelayedDataStart = cd->cd_NextDataStart;
1053 if( !cd->cd_VolDelayed && !cd->cd_SoundDelayed )
1055 cd->cd_DelayedScaleLeft = cd->cd_NextScaleLeft;
1056 cd->cd_DelayedScaleRight = cd->cd_NextScaleRight;
1057 cd->cd_DelayedAddRoutine = cd->cd_NextAddRoutine;
1060 if( !cd->cd_FreqDelayed && !cd->cd_SoundDelayed )
1062 cd->cd_DelayedSamples = cd->cd_Samples;
1065 cd->cd_EOS = TRUE; // signal End-Of-Sample
1066 continue; // .contchannel (same channel, new sound)
1068 } // FreqOK && SoundOK
1069 break; // .contchannel
1071 } // while(TRUE)
1073 cd = cd->cd_Succ;
1074 } // while(cd)
1076 if(audioctrl->ahiac_WetOrDry == AHIEDM_WET)
1078 audioctrl->ahiac_WetOrDry = AHIEDM_DRY;
1080 /*** AHIET_DSPECHO ***/
1081 if(audioctrl->ahiac_EffDSPEchoStruct != NULL)
1083 audioctrl->ahiac_EffDSPEchoStruct->ahiecho_Code(
1084 audioctrl->ahiac_EffDSPEchoStruct, dst, audioctrl);
1087 cd = audioctrl->ahiac_DryList;
1089 if(audioctrl->ac.ahiac_Flags & AHIACF_POSTPROC)
1091 /*** AHIET_MASTERVOLUME ***/
1093 DoMasterVolume(dst, audioctrl);
1096 ** When AHIACB_POSTPROC is set, the dry data shall be placed
1097 ** immediate after the wet data. This is done by modifying the
1098 ** dst pointer
1101 dst = (char *) dst + audioctrl->ac.ahiac_BuffSamples *
1102 _AHI_SampleFrameSize( audioctrl->ac.ahiac_BuffType, AHIBase );
1105 continue; /* while(TRUE) */
1107 else
1109 break; /* while(TRUE) */
1111 } // while(TRUE)
1113 return;
1117 /******************************************************************************
1118 ** DoMasterVolume *************************************************************
1119 ******************************************************************************/
1122 ** This function would be better if it was written in assembler,
1123 ** since overflow could then be detected. Instead we reduce the
1124 ** number of bits to 20 and then scale and compare.
1127 void
1128 DoMasterVolume( void *buffer,
1129 struct AHIPrivAudioCtrl *audioctrl )
1131 int cnt;
1132 LONG vol;
1133 LONG sample;
1135 cnt = audioctrl->ac.ahiac_BuffSamples;
1137 switch(audioctrl->ac.ahiac_BuffType)
1140 case AHIST_M16S:
1141 case AHIST_M32S:
1142 break;
1144 case AHIST_S16S:
1145 case AHIST_S32S:
1146 cnt *= 2;
1147 break;
1149 case AHIST_L7_1:
1150 cnt *= 8;
1151 break;
1153 default:
1154 return; // Panic
1157 if( audioctrl->ac.ahiac_BuffType == AHIST_M32S
1158 || audioctrl->ac.ahiac_BuffType == AHIST_S32S
1159 || audioctrl->ac.ahiac_BuffType == AHIST_L7_1 )
1161 LONG *dst = buffer;
1163 vol = audioctrl->ahiac_SetMasterVolume >> 8;
1165 while(cnt > 0)
1167 cnt--;
1169 sample = (*dst >> 12) * vol;
1171 if(sample > (LONG) 0x07ffffff)
1172 sample = 0x07ffffff;
1173 else if(sample < (LONG) 0xf8000000)
1174 sample = 0xf8000000;
1176 *dst++ = sample << 4;
1179 else
1181 WORD *dst = buffer;
1183 vol = audioctrl->ahiac_SetMasterVolume >> 4;
1185 while(cnt > 0)
1187 cnt--;
1189 sample = *dst * vol;
1191 if(sample > (LONG) 0x07ffffff)
1192 sample = 0x07ffffff;
1193 else if(sample < (LONG) 0xf8000000)
1194 sample = 0xf8000000;
1196 *dst++ = sample >> 12;
1203 /******************************************************************************
1204 ** DoOutputBuffer *************************************************************
1205 ******************************************************************************/
1207 void
1208 DoOutputBuffer( void *buffer,
1209 struct AHIPrivAudioCtrl *audioctrl )
1211 struct AHIEffOutputBuffer *ob;
1213 ob = audioctrl->ahiac_EffOutputBufferStruct;
1215 if(ob != NULL)
1217 ob->ahieob_Buffer = buffer;
1218 ob->ahieob_Length = audioctrl->ac.ahiac_BuffSamples;
1219 ob->ahieob_Type = audioctrl->ac.ahiac_BuffType;
1221 CallHookPkt( ob->ahieob_Func,
1222 audioctrl,
1223 ob);
1228 /******************************************************************************
1229 ** DoChannelInfo **************************************************************
1230 ******************************************************************************/
1232 void
1233 DoChannelInfo( struct AHIPrivAudioCtrl *audioctrl )
1235 struct AHIEffChannelInfo *ci;
1236 struct AHIChannelData *cd;
1237 ULONG *offsets;
1239 ci = audioctrl->ahiac_EffChannelInfoStruct;
1241 if(ci != NULL)
1243 int i;
1245 cd = audioctrl->ahiac_ChannelDatas;
1246 offsets = ci->ahieci_Offset;
1248 for(i = ci->ahieci_Channels; i > 0; i--)
1250 *offsets++ = cd->cd_Offset >> 32;
1251 cd++;
1254 CallHookPkt( ci->ahieci_Func,
1255 audioctrl,
1256 ci );
1261 /******************************************************************************
1262 ** CalcSamples ****************************************************************
1263 ******************************************************************************/
1265 LONG
1266 CalcSamples ( Fixed64 Add,
1267 ULONG Type,
1268 Fixed64 LastOffset,
1269 Fixed64 Offset )
1272 Fixed64 len;
1274 if( Type & AHIST_BW )
1276 len = Offset - LastOffset;
1278 else
1280 len = LastOffset - Offset;
1283 if(len < 0 || Add == 0) return 0; // Error!
1285 return (LONG) ( len / Add ) + 1;