OpenTTD Source: src/mixer.cpp Source File

OpenTTD Source 1.11.0-RC1

mixer.cpp
Go to the documentation of this file.
1 /*
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/>.
6 */
7
10 #include "stdafx.h"
11 #include <math.h>
12 #include "core/math_func.hpp"
13 #include "framerate_type.h"
14
15 #include "safeguards.h"
16 #include "mixer.h"
17
18 struct MixerChannel {
19 bool active;
20
21 /* pointer to allocated buffer memory */
22 int8 *memory;
23
24 /* current position in memory */
25 uint32 pos;
26 uint32 frac_pos;
27 uint32 frac_speed;
28 uint32 samples_left;
29
30 /* Mixing volume */
31 int volume_left;
32 int volume_right;
33
34 bool is16bit;
35 };
36
37 static MixerChannel _channels[8];
38 static uint32 _play_rate = 11025;
39 static uint32 _max_size = UINT_MAX;
40 static MxStreamCallback _music_stream = nullptr;
41
48 static const int MAX_VOLUME = 128 * 128;
49
57 template <typename T>
58 static int RateConversion(T *b, int frac_pos)
59 {
60 return ((b[0] * ((1 << 16) - frac_pos)) + (b[1] * frac_pos)) >> 16;
61 }
62
63 static void mix_int16(MixerChannel *sc, int16 *buffer, uint samples)
64 {
65 if (samples > sc->samples_left) samples = sc->samples_left;
66 sc->samples_left -= samples;
67 assert(samples > 0);
68
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;
74
75 if (frac_speed == 0x10000) {
76 /* Special case when frac_speed is 0x10000 */
77 do {
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);
80 b++;
81 buffer += 2;
82 } while (--samples > 0);
83 } else {
84 do {
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);
88 buffer += 2;
89 frac_pos += frac_speed;
90 b += frac_pos >> 16;
91 frac_pos &= 0xffff;
92 } while (--samples > 0);
93 }
94
95 sc->frac_pos = frac_pos;
96 sc->pos = b - (const int16 *)sc->memory;
97 }
98
99 static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
100 {
101 if (samples > sc->samples_left) samples = sc->samples_left;
102 sc->samples_left -= samples;
103 assert(samples > 0);
104
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;
110
111 if (frac_speed == 0x10000) {
112 /* Special case when frac_speed is 0x10000 */
113 do {
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);
116 b++;
117 buffer += 2;
118 } while (--samples > 0);
119 } else {
120 do {
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);
124 buffer += 2;
125 frac_pos += frac_speed;
126 b += frac_pos >> 16;
127 frac_pos &= 0xffff;
128 } while (--samples > 0);
129 }
130
131 sc->frac_pos = frac_pos;
132 sc->pos = b - sc->memory;
133 }
134
135 static void MxCloseChannel(MixerChannel *mc)
136 {
137 mc->active = false;
138 }
139
140 void MxMixSamples(void *buffer, uint samples)
141 {
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;
147 }
148
149 MixerChannel *mc;
150
151 /* Clear the buffer */
152 memset(buffer, 0, sizeof(int16) * 2 * samples);
153
154 /* Fetch music if a sampled stream is available */
155 if (_music_stream) _music_stream((int16*)buffer, samples);
156
157 /* Mix each channel */
158 for (mc = _channels; mc != endof(_channels); mc++) {
159 if (mc->active) {
160 if (mc->is16bit) {
161 mix_int16(mc, (int16*)buffer, samples);
162 } else {
163 mix_int8_to_int16(mc, (int16*)buffer, samples);
164 }
165 if (mc->samples_left == 0) MxCloseChannel(mc);
166 }
167 }
168 }
169
170 MixerChannel *MxAllocateChannel()
171 {
172 MixerChannel *mc;
173 for (mc = _channels; mc != endof(_channels); mc++) {
174 if (!mc->active) {
175 free(mc->memory);
176 mc->memory = nullptr;
177 return mc;
178 }
179 }
180 return nullptr;
181 }
182
183 void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, size_t size, uint rate, bool is16bit)
184 {
185 mc->memory = mem;
186 mc->frac_pos = 0;
187 mc->pos = 0;
188
189 mc->frac_speed = (rate << 16) / _play_rate;
190
191 if (is16bit) size /= 2;
192
193 /* adjust the magnitude to prevent overflow */
194 while (size >= _max_size) {
195 size >>= 1;
196 rate = (rate >> 1) + 1;
197 }
198
199 mc->samples_left = (uint)size * _play_rate / rate;
200 mc->is16bit = is16bit;
201 }
202
209 void MxSetChannelVolume(MixerChannel *mc, uint volume, float pan)
210 {
211 /* Use sinusoidal pan to maintain overall sound power level regardless
212 * of position. */
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);
215 }
216
217
218 void MxActivateChannel(MixerChannel *mc)
219 {
220 mc->active = true;
221 }
222
228 uint32 MxSetMusicSource(MxStreamCallback music_callback)
229 {
230 _music_stream = music_callback;
231 return _play_rate;
232 }
233
234
235 bool MxInitialize(uint rate)
236 {
237 _play_rate = rate;
238 _max_size = UINT_MAX / _play_rate;
239 _music_stream = nullptr; /* rate may have changed, any music source is now invalid */
240 return true;
241 }
math_func.hpp
PerformanceMeasurer
RAII class for measuring simple elements of performance.
Definition: framerate_type.h:92
safeguards.h
MxStreamCallback
void(* MxStreamCallback)(int16 *buffer, size_t samples)
Type of callback functions for supplying PCM music.
Definition: mixer.h:21
stdafx.h
PFE_SOUND
@ PFE_SOUND
Speed of mixing audio samples.
Definition: framerate_type.h:60
Clamp
static T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:77
MixerChannel
Definition: mixer.cpp:18
endof
#define endof(x)
Get the end element of an fixed size array.
Definition: stdafx.h:375
framerate_type.h
MAX_VOLUME
static const int MAX_VOLUME
The theoretical maximum volume for a single sound sample.
Definition: mixer.cpp:48
RateConversion
static int RateConversion(T *b, int frac_pos)
Perform the rate conversion between the input and output.
Definition: mixer.cpp:58
MxSetChannelVolume
void MxSetChannelVolume(MixerChannel *mc, uint volume, float pan)
Set volume and pan parameters for a sound.
Definition: mixer.cpp:209
MxSetMusicSource
uint32 MxSetMusicSource(MxStreamCallback music_callback)
Set source of PCM music.
Definition: mixer.cpp:228
free
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: stdafx.h:454
mixer.h