1 /*
2  Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
3 
4  This program is free software; you can redistribute it and/or
5  modify it under the terms of the GNU General Public License
6  as published by the Free Software Foundation; either version 2
7  of the License, or (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13  See the GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 
19  */
20 
21 #include "_multivc.h"
22 
23 template uint32_t MV_MixMono<uint8_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
24 template uint32_t MV_MixStereo<uint8_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
25 template uint32_t MV_MixMono<int16_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
26 template uint32_t MV_MixStereo<int16_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
27 template void MV_Reverb<int16_t>(char const *src, char * const dest, const fix16_t volume, int count);
28 
29 /*
30  length = count of samples to mix
31  position = offset of starting sample in source
32  rate = resampling increment
33  volume = direct volume adjustment, 1.0 = no change
34  */
35 
36 // mono source, mono output
37 template <typename S, typename D>
MV_MixMono(struct VoiceNode * const voice,uint32_t length)38 uint32_t MV_MixMono(struct VoiceNode * const voice, uint32_t length)
39 {
40     auto const * __restrict source = (S const *)voice->sound;
41     auto       * __restrict dest   = (D *)MV_MixDestination;
42 
43     uint32_t       position = voice->position;
44     uint32_t const rate     = voice->RateScale;
45     fix16_t const  volume   = fix16_fast_trunc_mul(voice->volume, MV_GlobalVolume);
46 
47     do
48     {
49         auto const isample0 = CONVERT_LE_SAMPLE_TO_SIGNED<S, D>(source[position >> 16]);
50 
51         position += rate;
52 
53         *dest = MIX_SAMPLES<D>(SCALE_SAMPLE(isample0, fix16_fast_trunc_mul(volume, voice->PannedVolume.Left)), *dest);
54         dest++;
55 
56         voice->PannedVolume.Left = SMOOTH_VOLUME(voice->PannedVolume.Left, voice->GoalVolume.Left);
57     }
58     while (--length);
59 
60     MV_MixDestination = (char *)dest;
61 
62     return position;
63 }
64 
65 // mono source, stereo output
66 template <typename S, typename D>
MV_MixStereo(struct VoiceNode * const voice,uint32_t length)67 uint32_t MV_MixStereo(struct VoiceNode * const voice, uint32_t length)
68 {
69     auto const * __restrict source = (S const *)voice->sound;
70     auto       * __restrict dest   = (D *)MV_MixDestination;
71 
72     uint32_t       position = voice->position;
73     uint32_t const rate     = voice->RateScale;
74     fix16_t  const volume   = fix16_fast_trunc_mul(voice->volume, MV_GlobalVolume);
75 
76     do
77     {
78         auto const isample0 = CONVERT_LE_SAMPLE_TO_SIGNED<S, D>(source[position >> 16]);
79 
80         position += rate;
81 
82         *dest = MIX_SAMPLES<D>(SCALE_SAMPLE(isample0, fix16_fast_trunc_mul(volume, voice->PannedVolume.Left)), *dest);
83         *(dest + (MV_RightChannelOffset / sizeof(*dest)))
84             = MIX_SAMPLES<D>(SCALE_SAMPLE(isample0, fix16_fast_trunc_mul(volume, voice->PannedVolume.Right)), *(dest + (MV_RightChannelOffset / sizeof(*dest))));
85         dest += 2;
86 
87         voice->PannedVolume = { SMOOTH_VOLUME(voice->PannedVolume.Left, voice->GoalVolume.Left), SMOOTH_VOLUME(voice->PannedVolume.Right, voice->GoalVolume.Right) };
88     }
89     while (--length);
90 
91     MV_MixDestination = (char *)dest;
92 
93     return position;
94 }
95 
96 template <typename T>
MV_Reverb(char const * src,char * const dest,const fix16_t volume,int count)97 void MV_Reverb(char const *src, char * const dest, const fix16_t volume, int count)
98 {
99     auto input  = (T const *)src;
100     auto output = (T *)dest;
101 
102     do
103     {
104         auto const isample0 = CONVERT_SAMPLE_TO_SIGNED<T>(*input++);
105         *output++ = CONVERT_SAMPLE_FROM_SIGNED<T>(SCALE_SAMPLE(isample0, volume));
106     }
107     while (--count > 0);
108 }
109