2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 /** @file mixer.cpp Mixing of sound samples. */
12 #include "core/math_func.hpp"
13 #include "framerate_type.h"
15 #include "safeguards.h"
21 /* pointer to allocated buffer memory */
24 /* current position in memory */
37 static MixerChannel _channels
[8];
38 static uint32 _play_rate
= 11025;
39 static uint32 _max_size
= UINT_MAX
;
40 static MxStreamCallback _music_stream
= nullptr;
43 * The theoretical maximum volume for a single sound sample. Multiple sound
44 * samples should not exceed this limit as it will sound too loud. It also
45 * stops overflowing when too many sounds are played at the same time, which
46 * causes an even worse sound quality.
48 static const int MAX_VOLUME
= 128 * 128;
51 * Perform the rate conversion between the input and output.
52 * @param b the buffer to read the data from
53 * @param frac_pos the position from the begin of the buffer till the next element
54 * @tparam T the size of the buffer (8 or 16 bits)
55 * @return the converted value.
58 static int RateConversion(T
*b
, int frac_pos
)
60 return ((b
[0] * ((1 << 16) - frac_pos
)) + (b
[1] * frac_pos
)) >> 16;
63 static void mix_int16(MixerChannel
*sc
, int16
*buffer
, uint samples
)
65 if (samples
> sc
->samples_left
) samples
= sc
->samples_left
;
66 sc
->samples_left
-= samples
;
69 const int16
*b
= (const int16
*)sc
->memory
+ sc
->pos
;
70 uint32 frac_pos
= sc
->frac_pos
;
71 uint32 frac_speed
= sc
->frac_speed
;
72 int volume_left
= sc
->volume_left
;
73 int volume_right
= sc
->volume_right
;
75 if (frac_speed
== 0x10000) {
76 /* Special case when frac_speed is 0x10000 */
78 buffer
[0] = Clamp(buffer
[0] + (*b
* volume_left
>> 16), -MAX_VOLUME
, MAX_VOLUME
);
79 buffer
[1] = Clamp(buffer
[1] + (*b
* volume_right
>> 16), -MAX_VOLUME
, MAX_VOLUME
);
82 } while (--samples
> 0);
85 int data
= RateConversion(b
, frac_pos
);
86 buffer
[0] = Clamp(buffer
[0] + (data
* volume_left
>> 16), -MAX_VOLUME
, MAX_VOLUME
);
87 buffer
[1] = Clamp(buffer
[1] + (data
* volume_right
>> 16), -MAX_VOLUME
, MAX_VOLUME
);
89 frac_pos
+= frac_speed
;
92 } while (--samples
> 0);
95 sc
->frac_pos
= frac_pos
;
96 sc
->pos
= b
- (const int16
*)sc
->memory
;
99 static void mix_int8_to_int16(MixerChannel
*sc
, int16
*buffer
, uint samples
)
101 if (samples
> sc
->samples_left
) samples
= sc
->samples_left
;
102 sc
->samples_left
-= samples
;
105 const int8
*b
= sc
->memory
+ sc
->pos
;
106 uint32 frac_pos
= sc
->frac_pos
;
107 uint32 frac_speed
= sc
->frac_speed
;
108 int volume_left
= sc
->volume_left
;
109 int volume_right
= sc
->volume_right
;
111 if (frac_speed
== 0x10000) {
112 /* Special case when frac_speed is 0x10000 */
114 buffer
[0] = Clamp(buffer
[0] + (*b
* volume_left
>> 8), -MAX_VOLUME
, MAX_VOLUME
);
115 buffer
[1] = Clamp(buffer
[1] + (*b
* volume_right
>> 8), -MAX_VOLUME
, MAX_VOLUME
);
118 } while (--samples
> 0);
121 int data
= RateConversion(b
, frac_pos
);
122 buffer
[0] = Clamp(buffer
[0] + (data
* volume_left
>> 8), -MAX_VOLUME
, MAX_VOLUME
);
123 buffer
[1] = Clamp(buffer
[1] + (data
* volume_right
>> 8), -MAX_VOLUME
, MAX_VOLUME
);
125 frac_pos
+= frac_speed
;
128 } while (--samples
> 0);
131 sc
->frac_pos
= frac_pos
;
132 sc
->pos
= b
- sc
->memory
;
135 static void MxCloseChannel(MixerChannel
*mc
)
140 void MxMixSamples(void *buffer
, uint samples
)
142 PerformanceMeasurer
framerate(PFE_SOUND
);
143 static uint last_samples
= 0;
144 if (samples
!= last_samples
) {
145 framerate
.SetExpectedRate((double)_play_rate
/ samples
);
146 last_samples
= samples
;
151 /* Clear the buffer */
152 memset(buffer
, 0, sizeof(int16
) * 2 * samples
);
154 /* Fetch music if a sampled stream is available */
155 if (_music_stream
) _music_stream((int16
*)buffer
, samples
);
157 /* Mix each channel */
158 for (mc
= _channels
; mc
!= endof(_channels
); mc
++) {
161 mix_int16(mc
, (int16
*)buffer
, samples
);
163 mix_int8_to_int16(mc
, (int16
*)buffer
, samples
);
165 if (mc
->samples_left
== 0) MxCloseChannel(mc
);
170 MixerChannel
*MxAllocateChannel()
173 for (mc
= _channels
; mc
!= endof(_channels
); mc
++) {
176 mc
->memory
= nullptr;
183 void MxSetChannelRawSrc(MixerChannel
*mc
, int8
*mem
, size_t size
, uint rate
, bool is16bit
)
189 mc
->frac_speed
= (rate
<< 16) / _play_rate
;
191 if (is16bit
) size
/= 2;
193 /* adjust the magnitude to prevent overflow */
194 while (size
>= _max_size
) {
196 rate
= (rate
>> 1) + 1;
199 mc
->samples_left
= (uint
)size
* _play_rate
/ rate
;
200 mc
->is16bit
= is16bit
;
204 * Set volume and pan parameters for a sound.
205 * @param mc MixerChannel to set
206 * @param volume Volume level for sound, range is 0..16384
207 * @param pan Pan position for sound, range is 0..1
209 void MxSetChannelVolume(MixerChannel
*mc
, uint volume
, float pan
)
211 /* Use sinusoidal pan to maintain overall sound power level regardless
213 mc
->volume_left
= (uint
)(sin((1.0 - pan
) * M_PI
/ 2.0) * volume
);
214 mc
->volume_right
= (uint
)(sin(pan
* M_PI
/ 2.0) * volume
);
218 void MxActivateChannel(MixerChannel
*mc
)
224 * Set source of PCM music
225 * @param music_callback Function that will be called to fill sample buffers with music data.
226 * @return Sample rate of mixer, which the buffers supplied to the callback must be rendered at.
228 uint32
MxSetMusicSource(MxStreamCallback music_callback
)
230 _music_stream
= music_callback
;
235 bool MxInitialize(uint rate
)
238 _max_size
= UINT_MAX
/ _play_rate
;
239 _music_stream
= nullptr; /* rate may have changed, any music source is now invalid */