OpenTTD Source 20241224-master-gf74b0cf984
mixer.cpp
Go to the documentation of this file.
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 */
7
10#include "stdafx.h"
11#include <mutex>
12#include <atomic>
13#include "core/math_func.hpp"
14#include "framerate_type.h"
15#include "mixer.h"
16#include "settings_type.h"
17
18#include "safeguards.h"
19
21 /* pointer to allocated buffer memory */
22 std::shared_ptr<std::vector<uint8_t>> memory;
23
24 /* current position in memory */
25 uint32_t pos;
26 uint32_t frac_pos;
27 uint32_t frac_speed;
28 uint32_t samples_left;
29
30 /* Mixing volume */
31 int volume_left;
32 int volume_right;
33
34 bool is16bit;
35};
36
37using MixerChannelMask = uint8_t;
38
39static std::atomic<MixerChannelMask> _active_channels;
40static std::atomic<MixerChannelMask> _stop_channels;
41static MixerChannel _channels[8];
42static uint32_t _play_rate = 11025;
43static uint32_t _max_size = UINT_MAX;
44static MxStreamCallback _music_stream = nullptr;
45static std::mutex _music_stream_mutex;
46static std::atomic<uint8_t> _effect_vol;
47
54static const int MAX_VOLUME = 32767;
55
63template <typename T>
64static int RateConversion(T *b, int frac_pos)
65{
66 return ((b[0] * ((1 << 16) - frac_pos)) + (b[1] * frac_pos)) >> 16;
67}
68
69template <typename T>
70static void mix_int16(MixerChannel *sc, int16_t *buffer, uint samples, uint8_t effect_vol)
71{
72 /* Shift required to get sample value into range for the data type. */
73 const uint SHIFT = sizeof(T) * CHAR_BIT;
74
75 if (samples > sc->samples_left) samples = sc->samples_left;
76 sc->samples_left -= samples;
77 assert(samples > 0);
78
79 const T *b = reinterpret_cast<const T *>(sc->memory->data()) + sc->pos;
80 uint32_t frac_pos = sc->frac_pos;
81 uint32_t frac_speed = sc->frac_speed;
82 int volume_left = sc->volume_left * effect_vol / 255;
83 int volume_right = sc->volume_right * effect_vol / 255;
84
85 if (frac_speed == 0x10000) {
86 /* Special case when frac_speed is 0x10000 */
87 do {
88 buffer[0] = Clamp(buffer[0] + (*b * volume_left >> SHIFT), -MAX_VOLUME, MAX_VOLUME);
89 buffer[1] = Clamp(buffer[1] + (*b * volume_right >> SHIFT), -MAX_VOLUME, MAX_VOLUME);
90 b++;
91 buffer += 2;
92 } while (--samples > 0);
93 } else {
94 do {
95 int data = RateConversion(b, frac_pos);
96 buffer[0] = Clamp(buffer[0] + (data * volume_left >> SHIFT), -MAX_VOLUME, MAX_VOLUME);
97 buffer[1] = Clamp(buffer[1] + (data * volume_right >> SHIFT), -MAX_VOLUME, MAX_VOLUME);
98 buffer += 2;
99 frac_pos += frac_speed;
100 b += frac_pos >> 16;
101 frac_pos &= 0xffff;
102 } while (--samples > 0);
103 }
104
105 sc->frac_pos = frac_pos;
106 sc->pos = b - reinterpret_cast<const T *>(sc->memory->data());
107}
108
109static void MxCloseChannel(uint8_t channel_index)
110{
111 _active_channels.fetch_and(~(1U << channel_index), std::memory_order_release);
112}
113
120{
121 _stop_channels.fetch_or(~0, std::memory_order_release);
122}
123
124void MxMixSamples(void *buffer, uint samples)
125{
127 static uint last_samples = 0;
128 if (samples != last_samples) {
129 framerate.SetExpectedRate((double)_play_rate / samples);
130 last_samples = samples;
131 }
132
133 /* Clear the buffer */
134 memset(buffer, 0, sizeof(int16_t) * 2 * samples);
135
136 {
137 std::lock_guard<std::mutex> lock{ _music_stream_mutex };
138 /* Fetch music if a sampled stream is available */
139 if (_music_stream) _music_stream((int16_t*)buffer, samples);
140 }
141
142 /* Check if any channels should be stopped. */
143 MixerChannelMask stop = _stop_channels.load(std::memory_order_acquire);
144 for (uint8_t idx : SetBitIterator(stop)) {
145 MxCloseChannel(idx);
146 }
147
148 /* Apply simple x^3 scaling to master effect volume. This increases the
149 * perceived difference in loudness to better match expectations. effect_vol
150 * is expected to be in the range 0-127 hence the division by 127 * 127 to
151 * get back into range. */
152 uint8_t effect_vol_setting = _effect_vol.load(std::memory_order_relaxed);
153 uint8_t effect_vol = (effect_vol_setting *
154 effect_vol_setting *
155 effect_vol_setting) / (127 * 127);
156
157 /* Mix each channel */
158 MixerChannelMask active = _active_channels.load(std::memory_order_acquire);
159 for (uint8_t idx : SetBitIterator(active)) {
160 MixerChannel *mc = &_channels[idx];
161 if (mc->is16bit) {
162 mix_int16<int16_t>(mc, (int16_t*)buffer, samples, effect_vol);
163 } else {
164 mix_int16<int8_t>(mc, (int16_t*)buffer, samples, effect_vol);
165 }
166 if (mc->samples_left == 0) MxCloseChannel(idx);
167 }
168}
169
170MixerChannel *MxAllocateChannel()
171{
172 MixerChannelMask currently_active = _active_channels.load(std::memory_order_acquire);
173 MixerChannelMask available = ~currently_active;
174 if (available == 0) return nullptr;
175
176 uint8_t channel_index = FindFirstBit(available);
177
178 MixerChannel *mc = &_channels[channel_index];
179 mc->memory = nullptr;
180 return mc;
181}
182
183void MxSetChannelRawSrc(MixerChannel *mc, const std::shared_ptr<std::vector<uint8_t>> &mem, uint rate, bool is16bit)
184{
185 mc->memory = mem;
186 mc->frac_pos = 0;
187 mc->pos = 0;
188
189 mc->frac_speed = (rate << 16U) / _play_rate;
190
191 size_t size = mc->memory->size();
192 if (is16bit) size /= 2;
193 /* Less 1 to allow for padding sample for the resampler. */
194 size -= 1;
195
196 /* adjust the magnitude to prevent overflow */
197 while (size >= _max_size) {
198 size >>= 1;
199 rate = (rate >> 1) + 1;
200 }
201
202 /* Scale number of samples by play rate. */
203 mc->samples_left = (uint)size * _play_rate / rate;
204 mc->is16bit = is16bit;
205}
206
213void MxSetChannelVolume(MixerChannel *mc, uint volume, float pan)
214{
215 /* Use sinusoidal pan to maintain overall sound power level regardless
216 * of position. */
217 mc->volume_left = (uint)(sin((1.0 - pan) * M_PI / 2.0) * volume);
218 mc->volume_right = (uint)(sin(pan * M_PI / 2.0) * volume);
219}
220
221
222void MxActivateChannel(MixerChannel *mc)
223{
224 uint8_t channel_index = mc - _channels;
225 _stop_channels.fetch_and(~(1U << channel_index), std::memory_order_release);
226 _active_channels.fetch_or((1U << channel_index), std::memory_order_release);
227}
228
234uint32_t MxSetMusicSource(MxStreamCallback music_callback)
235{
236 std::lock_guard<std::mutex> lock{ _music_stream_mutex };
237 _music_stream = music_callback;
238 return _play_rate;
239}
240
241
242bool MxInitialize(uint rate)
243{
244 std::lock_guard<std::mutex> lock{ _music_stream_mutex };
245 _play_rate = rate;
246 _max_size = UINT_MAX / _play_rate;
247 _music_stream = nullptr; /* rate may have changed, any music source is now invalid */
248 return true;
249}
250
251void SetEffectVolume(uint8_t volume)
252{
253 _effect_vol.store(volume, std::memory_order_relaxed);
254}
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
RAII class for measuring simple elements of performance.
Types for recording game performance data.
@ PFE_SOUND
Speed of mixing audio samples.
Integer math functions.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
void MxCloseAllChannels()
Close all mixer channels.
Definition mixer.cpp:119
static int RateConversion(T *b, int frac_pos)
Perform the rate conversion between the input and output.
Definition mixer.cpp:64
uint8_t MixerChannelMask
Type representing a bitmask of mixer channels.
Definition mixer.cpp:37
uint32_t MxSetMusicSource(MxStreamCallback music_callback)
Set source of PCM music.
Definition mixer.cpp:234
void MxSetChannelVolume(MixerChannel *mc, uint volume, float pan)
Set volume and pan parameters for a sound.
Definition mixer.cpp:213
static const int MAX_VOLUME
The theoretical maximum volume for a single sound sample.
Definition mixer.cpp:54
Functions to mix sound samples.
void(* MxStreamCallback)(int16_t *buffer, size_t samples)
Type of callback functions for supplying PCM music.
Definition mixer.h:21
A number of safeguards to prevent using unsafe methods.
Types related to global configuration settings.
Definition of base types and functions in a cross-platform compatible way.
Iterable ensemble of each set bit in a value.
std::mutex lock
synchronization for playback status fields
Definition win32_m.cpp:35