Remove second template parameter from class GUIList
[openttd/fttd.git] / src / mixer.cpp
blob401a9c0ba284bb83628508fb25971ea9b4472e5d
1 /* $Id$ */
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 */
10 /** @file mixer.cpp Mixing of sound samples. */
12 #include "stdafx.h"
13 #include <math.h>
14 #include "core/math_func.hpp"
16 struct MixerChannel {
17 bool active;
19 /* pointer to allocated buffer memory */
20 int8 *memory;
22 /* current position in memory */
23 uint32 pos;
24 uint32 frac_pos;
25 uint32 frac_speed;
26 uint32 samples_left;
28 /* Mixing volume */
29 int volume_left;
30 int volume_right;
32 bool is16bit;
35 static MixerChannel _channels[8];
36 static uint32 _play_rate = 11025;
37 static uint32 _max_size = UINT_MAX;
39 /**
40 * The theoretical maximum volume for a single sound sample. Multiple sound
41 * samples should not exceed this limit as it will sound too loud. It also
42 * stops overflowing when too many sounds are played at the same time, which
43 * causes an even worse sound quality.
45 static const int MAX_VOLUME = 128 * 128;
47 /**
48 * Perform the rate conversion between the input and output.
49 * @param b the buffer to read the data from
50 * @param frac_pos the position from the begin of the buffer till the next element
51 * @tparam T the size of the buffer (8 or 16 bits)
52 * @return the converted value.
54 template <typename T>
55 static int RateConversion(T *b, int frac_pos)
57 return ((b[0] * ((1 << 16) - frac_pos)) + (b[1] * frac_pos)) >> 16;
60 static void mix_int16(MixerChannel *sc, int16 *buffer, uint samples)
62 if (samples > sc->samples_left) samples = sc->samples_left;
63 sc->samples_left -= samples;
64 assert(samples > 0);
66 const int16 *b = (const int16 *)sc->memory + sc->pos;
67 uint32 frac_pos = sc->frac_pos;
68 uint32 frac_speed = sc->frac_speed;
69 int volume_left = sc->volume_left;
70 int volume_right = sc->volume_right;
72 if (frac_speed == 0x10000) {
73 /* Special case when frac_speed is 0x10000 */
74 do {
75 buffer[0] = Clamp(buffer[0] + (*b * volume_left >> 16), -MAX_VOLUME, MAX_VOLUME);
76 buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 16), -MAX_VOLUME, MAX_VOLUME);
77 b++;
78 buffer += 2;
79 } while (--samples > 0);
80 } else {
81 do {
82 int data = RateConversion(b, frac_pos);
83 buffer[0] = Clamp(buffer[0] + (data * volume_left >> 16), -MAX_VOLUME, MAX_VOLUME);
84 buffer[1] = Clamp(buffer[1] + (data * volume_right >> 16), -MAX_VOLUME, MAX_VOLUME);
85 buffer += 2;
86 frac_pos += frac_speed;
87 b += frac_pos >> 16;
88 frac_pos &= 0xffff;
89 } while (--samples > 0);
92 sc->frac_pos = frac_pos;
93 sc->pos = b - (const int16 *)sc->memory;
96 static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
98 if (samples > sc->samples_left) samples = sc->samples_left;
99 sc->samples_left -= samples;
100 assert(samples > 0);
102 const int8 *b = sc->memory + sc->pos;
103 uint32 frac_pos = sc->frac_pos;
104 uint32 frac_speed = sc->frac_speed;
105 int volume_left = sc->volume_left;
106 int volume_right = sc->volume_right;
108 if (frac_speed == 0x10000) {
109 /* Special case when frac_speed is 0x10000 */
110 do {
111 buffer[0] = Clamp(buffer[0] + (*b * volume_left >> 8), -MAX_VOLUME, MAX_VOLUME);
112 buffer[1] = Clamp(buffer[1] + (*b * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
113 b++;
114 buffer += 2;
115 } while (--samples > 0);
116 } else {
117 do {
118 int data = RateConversion(b, frac_pos);
119 buffer[0] = Clamp(buffer[0] + (data * volume_left >> 8), -MAX_VOLUME, MAX_VOLUME);
120 buffer[1] = Clamp(buffer[1] + (data * volume_right >> 8), -MAX_VOLUME, MAX_VOLUME);
121 buffer += 2;
122 frac_pos += frac_speed;
123 b += frac_pos >> 16;
124 frac_pos &= 0xffff;
125 } while (--samples > 0);
128 sc->frac_pos = frac_pos;
129 sc->pos = b - sc->memory;
132 static void MxCloseChannel(MixerChannel *mc)
134 mc->active = false;
137 void MxMixSamples(void *buffer, uint samples)
139 MixerChannel *mc;
141 /* Clear the buffer */
142 memset(buffer, 0, sizeof(int16) * 2 * samples);
144 /* Mix each channel */
145 for (mc = _channels; mc != endof(_channels); mc++) {
146 if (mc->active) {
147 if (mc->is16bit) {
148 mix_int16(mc, (int16*)buffer, samples);
149 } else {
150 mix_int8_to_int16(mc, (int16*)buffer, samples);
152 if (mc->samples_left == 0) MxCloseChannel(mc);
157 MixerChannel *MxAllocateChannel()
159 MixerChannel *mc;
160 for (mc = _channels; mc != endof(_channels); mc++) {
161 if (!mc->active) {
162 free(mc->memory);
163 mc->memory = NULL;
164 return mc;
167 return NULL;
170 void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, size_t size, uint rate, bool is16bit)
172 mc->memory = mem;
173 mc->frac_pos = 0;
174 mc->pos = 0;
176 mc->frac_speed = (rate << 16) / _play_rate;
178 if (is16bit) size /= 2;
180 /* adjust the magnitude to prevent overflow */
181 while (size >= _max_size) {
182 size >>= 1;
183 rate = (rate >> 1) + 1;
186 mc->samples_left = (uint)size * _play_rate / rate;
187 mc->is16bit = is16bit;
191 * Set volume and pan parameters for a sound.
192 * @param mc MixerChannel to set
193 * @param volume Volume level for sound, range is 0..16384
194 * @param pan Pan position for sound, range is 0..1
196 void MxSetChannelVolume(MixerChannel *mc, uint volume, float pan)
198 /* Use sinusoidal pan to maintain overall sound power level regardless
199 * of position. */
200 mc->volume_left = (uint)(sin((1.0 - pan) * M_PI / 2.0) * volume);
201 mc->volume_right = (uint)(sin(pan * M_PI / 2.0) * volume);
205 void MxActivateChannel(MixerChannel *mc)
207 mc->active = true;
211 bool MxInitialize(uint rate)
213 _play_rate = rate;
214 _max_size = UINT_MAX / _play_rate;
215 return true;