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