OpenTTD
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 }
Definition of base types and functions in a cross-platform compatible way.
A number of safeguards to prevent using unsafe methods.
void MxSetChannelVolume(MixerChannel *mc, uint volume, float pan)
Set volume and pan parameters for a sound.
Definition: mixer.cpp:198
static int RateConversion(T *b, int frac_pos)
Perform the rate conversion between the input and output.
Definition: mixer.cpp:57
Integer math functions.
static T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:139
#define endof(x)
Get the end element of an fixed size array.
Definition: stdafx.h:427
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: depend.cpp:114
static const int MAX_VOLUME
The theoretical maximum volume for a single sound sample.
Definition: mixer.cpp:47