Add: INR currency (#8136)
[openttd-github.git] / src / mixer.cpp
blob90e3951cb01ba2a189bd1d8f1b828a86b9f0c737
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 */
8 /** @file mixer.cpp Mixing of sound samples. */
10 #include "stdafx.h"
11 #include <math.h>
12 #include "core/math_func.hpp"
13 #include "framerate_type.h"
15 #include "safeguards.h"
16 #include "mixer.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;
40 static MxStreamCallback _music_stream = nullptr;
42 /**
43 * The theoretical maximum volume for a single sound sample. Multiple sound
44 * samples should not exceed this limit as it will sound too loud. It also
45 * stops overflowing when too many sounds are played at the same time, which
46 * causes an even worse sound quality.
48 static const int MAX_VOLUME = 128 * 128;
50 /**
51 * Perform the rate conversion between the input and output.
52 * @param b the buffer to read the data from
53 * @param frac_pos the position from the begin of the buffer till the next element
54 * @tparam T the size of the buffer (8 or 16 bits)
55 * @return the converted value.
57 template <typename T>
58 static int RateConversion(T *b, int frac_pos)
60 return ((b[0] * ((1 << 16) - frac_pos)) + (b[1] * frac_pos)) >> 16;
63 static void mix_int16(MixerChannel *sc, int16 *buffer, uint samples)
65 if (samples > sc->samples_left) samples = sc->samples_left;
66 sc->samples_left -= samples;
67 assert(samples > 0);
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;
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);
95 sc->frac_pos = frac_pos;
96 sc->pos = b - (const int16 *)sc->memory;
99 static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
101 if (samples > sc->samples_left) samples = sc->samples_left;
102 sc->samples_left -= samples;
103 assert(samples > 0);
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;
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);
131 sc->frac_pos = frac_pos;
132 sc->pos = b - sc->memory;
135 static void MxCloseChannel(MixerChannel *mc)
137 mc->active = false;
140 void MxMixSamples(void *buffer, uint samples)
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;
149 MixerChannel *mc;
151 /* Clear the buffer */
152 memset(buffer, 0, sizeof(int16) * 2 * samples);
154 /* Fetch music if a sampled stream is available */
155 if (_music_stream) _music_stream((int16*)buffer, samples);
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);
165 if (mc->samples_left == 0) MxCloseChannel(mc);
170 MixerChannel *MxAllocateChannel()
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;
180 return nullptr;
183 void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, size_t size, uint rate, bool is16bit)
185 mc->memory = mem;
186 mc->frac_pos = 0;
187 mc->pos = 0;
189 mc->frac_speed = (rate << 16) / _play_rate;
191 if (is16bit) size /= 2;
193 /* adjust the magnitude to prevent overflow */
194 while (size >= _max_size) {
195 size >>= 1;
196 rate = (rate >> 1) + 1;
199 mc->samples_left = (uint)size * _play_rate / rate;
200 mc->is16bit = is16bit;
204 * Set volume and pan parameters for a sound.
205 * @param mc MixerChannel to set
206 * @param volume Volume level for sound, range is 0..16384
207 * @param pan Pan position for sound, range is 0..1
209 void MxSetChannelVolume(MixerChannel *mc, uint volume, float pan)
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);
218 void MxActivateChannel(MixerChannel *mc)
220 mc->active = true;
224 * Set source of PCM music
225 * @param music_callback Function that will be called to fill sample buffers with music data.
226 * @return Sample rate of mixer, which the buffers supplied to the callback must be rendered at.
228 uint32 MxSetMusicSource(MxStreamCallback music_callback)
230 _music_stream = music_callback;
231 return _play_rate;
235 bool MxInitialize(uint rate)
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;