OpenTTD: src/mixer.cpp Source File

OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

mixer.cpp
Go to the documentation of this file.
1 /* $Id: mixer.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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 */
9
12 #include "stdafx.h"
13 #include <math.h>
14 #include "core/math_func.hpp"
15
16 #include "safeguards.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
47 static const int MAX_VOLUME = 128 * 128;
48
56 template <typename T>
57 static int RateConversion(T *b, int frac_pos)
58 {
59 return ((b[0] * ((1 << 16) - frac_pos)) + (b[1] * frac_pos)) >> 16;
60 }
61
62 static void mix_int16(MixerChannel *sc, int16 *buffer, uint samples)
63 {
64 if (samples > sc->samples_left) samples = sc->samples_left;
65 sc->samples_left -= samples;
66 assert(samples > 0);
67
68 const int16 *b = (const int16 *)sc->memory + sc->pos;
69 uint32 frac_pos = sc->frac_pos;
70 uint32 frac_speed = sc->frac_speed;
71 int volume_left = sc->volume_left;
72 int volume_right = sc->volume_right;
73
74 if (frac_speed == 0x10000) {
75 /* Special case when frac_speed is 0x10000 */
76 do {
77 buffer[0] = Clamp(buffer[0] + (*b * volume_left >> 16), -MAX_VOLUME, MAX_VOLUME);
78 buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 16), -MAX_VOLUME, MAX_VOLUME);
79 b++;
80 buffer += 2;
81 } while (--samples > 0);
82 } else {
83 do {
84 int data = RateConversion(b, frac_pos);
85 buffer[0] = Clamp(buffer[0] + (data * volume_left >> 16), -MAX_VOLUME, MAX_VOLUME);
86 buffer[1] = Clamp(buffer[1] + (data * volume_right >> 16), -MAX_VOLUME, MAX_VOLUME);
87 buffer += 2;
88 frac_pos += frac_speed;
89 b += frac_pos >> 16;
90 frac_pos &= 0xffff;
91 } while (--samples > 0);
92 }
93
94 sc->frac_pos = frac_pos;
95 sc->pos = b - (const int16 *)sc->memory;
96 }
97
98 static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
99 {
100 if (samples > sc->samples_left) samples = sc->samples_left;
101 sc->samples_left -= samples;
102 assert(samples > 0);
103
104 const int8 *b = sc->memory + sc->pos;
105 uint32 frac_pos = sc->frac_pos;
106 uint32 frac_speed = sc->frac_speed;
107 int volume_left = sc->volume_left;
108 int volume_right = sc->volume_right;
109
110 if (frac_speed == 0x10000) {
111 /* Special case when frac_speed is 0x10000 */
112 do {
113 buffer[0] = Clamp(buffer[0] + (*b * volume_left >> 8), -MAX_VOLUME, MAX_VOLUME);
114 buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
115 b++;
116 buffer += 2;
117 } while (--samples > 0);
118 } else {
119 do {
120 int data = RateConversion(b, frac_pos);
121 buffer[0] = Clamp(buffer[0] + (data * volume_left >> 8), -MAX_VOLUME, MAX_VOLUME);
122 buffer[1] = Clamp(buffer[1] + (data * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
123 buffer += 2;
124 frac_pos += frac_speed;
125 b += frac_pos >> 16;
126 frac_pos &= 0xffff;
127 } while (--samples > 0);
128 }
129
130 sc->frac_pos = frac_pos;
131 sc->pos = b - sc->memory;
132 }
133
134 static void MxCloseChannel(MixerChannel *mc)
135 {
136 mc->active = false;
137 }
138
139 void MxMixSamples(void *buffer, uint samples)
140 {
141 MixerChannel *mc;
142
143 /* Clear the buffer */
144 memset(buffer, 0, sizeof(int16) * 2 * samples);
145
146 /* Mix each channel */
147 for (mc = _channels; mc != endof(_channels); mc++) {
148 if (mc->active) {
149 if (mc->is16bit) {
150 mix_int16(mc, (int16*)buffer, samples);
151 } else {
152 mix_int8_to_int16(mc, (int16*)buffer, samples);
153 }
154 if (mc->samples_left == 0) MxCloseChannel(mc);
155 }
156 }
157 }
158
159 MixerChannel *MxAllocateChannel()
160 {
161 MixerChannel *mc;
162 for (mc = _channels; mc != endof(_channels); mc++) {
163 if (!mc->active) {
164 free(mc->memory);
165 mc->memory = NULL;
166 return mc;
167 }
168 }
169 return NULL;
170 }
171
172 void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, size_t size, uint rate, bool is16bit)
173 {
174 mc->memory = mem;
175 mc->frac_pos = 0;
176 mc->pos = 0;
177
178 mc->frac_speed = (rate << 16) / _play_rate;
179
180 if (is16bit) size /= 2;
181
182 /* adjust the magnitude to prevent overflow */
183 while (size >= _max_size) {
184 size >>= 1;
185 rate = (rate >> 1) + 1;
186 }
187
188 mc->samples_left = (uint)size * _play_rate / rate;
189 mc->is16bit = is16bit;
190 }
191
198 void MxSetChannelVolume(MixerChannel *mc, uint volume, float pan)
199 {
200 /* Use sinusoidal pan to maintain overall sound power level regardless
201 * of position. */
202 mc->volume_left = (uint)(sin((1.0 - pan) * M_PI / 2.0) * volume);
203 mc->volume_right = (uint)(sin(pan * M_PI / 2.0) * volume);
204 }
205
206
207 void MxActivateChannel(MixerChannel *mc)
208 {
209 mc->active = true;
210 }
211
212
213 bool MxInitialize(uint rate)
214 {
215 _play_rate = rate;
216 _max_size = UINT_MAX / _play_rate;
217 return true;
218 }