Rework the way the ReinitSeparation command is called. The old way was way too danger...
[openttd-joker.git] / src / mixer.cpp
blobac81183e850c197bfd295adb9eea08b7ab4e764e
1 /* $Id: mixer.cpp 20211 2010-07-24 10:14:39Z alberth $ */
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 #include "safeguards.h"
18 struct MixerChannel {
19 bool active;
21 /* pointer to allocated buffer memory */
22 int8 *memory;
24 /* current position in memory */
25 uint32 pos;
26 uint32 frac_pos;
27 uint32 frac_speed;
28 uint32 samples_left;
30 /* Mixing volume */
31 int volume_left;
32 int volume_right;
34 bool is16bit;
37 static MixerChannel _channels[8];
38 static uint32 _play_rate = 11025;
39 static uint32 _max_size = UINT_MAX;
41 /**
42 * The theoretical maximum volume for a single sound sample. Multiple sound
43 * samples should not exceed this limit as it will sound too loud. It also
44 * stops overflowing when too many sounds are played at the same time, which
45 * causes an even worse sound quality.
47 static const int MAX_VOLUME = 128 * 128;
49 /**
50 * Perform the rate conversion between the input and output.
51 * @param b the buffer to read the data from
52 * @param frac_pos the position from the begin of the buffer till the next element
53 * @tparam T the size of the buffer (8 or 16 bits)
54 * @return the converted value.
56 template <typename T>
57 static int RateConversion(T *b, int frac_pos)
59 return ((b[0] * ((1 << 16) - frac_pos)) + (b[1] * frac_pos)) >> 16;
62 static void mix_int16(MixerChannel *sc, int16 *buffer, uint samples)
64 if (samples > sc->samples_left) samples = sc->samples_left;
65 sc->samples_left -= samples;
66 assert(samples > 0);
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;
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);
94 sc->frac_pos = frac_pos;
95 sc->pos = b - (const int16 *)sc->memory;
98 static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
100 if (samples > sc->samples_left) samples = sc->samples_left;
101 sc->samples_left -= samples;
102 assert(samples > 0);
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;
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);
130 sc->frac_pos = frac_pos;
131 sc->pos = b - sc->memory;
134 static void MxCloseChannel(MixerChannel *mc)
136 mc->active = false;
139 void MxMixSamples(void *buffer, uint samples)
141 MixerChannel *mc;
143 /* Clear the buffer */
144 memset(buffer, 0, sizeof(int16) * 2 * samples);
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);
154 if (mc->samples_left == 0) MxCloseChannel(mc);
159 MixerChannel *MxAllocateChannel()
161 MixerChannel *mc;
162 for (mc = _channels; mc != endof(_channels); mc++) {
163 if (!mc->active) {
164 free(mc->memory);
165 mc->memory = nullptr;
166 return mc;
169 return nullptr;
172 void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, size_t size, uint rate, bool is16bit)
174 mc->memory = mem;
175 mc->frac_pos = 0;
176 mc->pos = 0;
178 mc->frac_speed = (rate << 16) / _play_rate;
180 if (is16bit) size /= 2;
182 /* adjust the magnitude to prevent overflow */
183 while (size >= _max_size) {
184 size >>= 1;
185 rate = (rate >> 1) + 1;
188 mc->samples_left = (uint)size * _play_rate / rate;
189 mc->is16bit = is16bit;
193 * Set volume and pan parameters for a sound.
194 * @param mc MixerChannel to set
195 * @param volume Volume level for sound, range is 0..16384
196 * @param pan Pan position for sound, range is 0..1
198 void MxSetChannelVolume(MixerChannel *mc, uint volume, float pan)
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);
207 void MxActivateChannel(MixerChannel *mc)
209 mc->active = true;
213 bool MxInitialize(uint rate)
215 _play_rate = rate;
216 _max_size = UINT_MAX / _play_rate;
217 return true;