1 /*****************************************************************************
2  * Copyright (c) 2014-2020 OpenRCT2 developers
3  *
4  * For a complete list of all authors, please refer to contributors.md
5  * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6  *
7  * OpenRCT2 is licensed under the GNU General Public License version 3.
8  *****************************************************************************/
9 
10 #include "AudioContext.h"
11 #include "AudioFormat.h"
12 
13 #include <algorithm>
14 #include <cmath>
15 #include <openrct2/audio/AudioSource.h>
16 #include <openrct2/common.h>
17 #include <speex/speex_resampler.h>
18 
19 namespace OpenRCT2::Audio
20 {
21     template<typename AudioSource_ = ISDLAudioSource> class AudioChannelImpl : public ISDLAudioChannel
22     {
23         static_assert(std::is_base_of_v<IAudioSource, AudioSource_>);
24 
25     private:
26         AudioSource_* _source = nullptr;
27         SpeexResamplerState* _resampler = nullptr;
28 
29         MixerGroup _group = MixerGroup::Sound;
30         double _rate = 0;
31         uint64_t _offset = 0;
32         int32_t _loop = 0;
33 
34         int32_t _volume = 1;
35         float _volume_l = 0.f;
36         float _volume_r = 0.f;
37         float _oldvolume_l = 0.f;
38         float _oldvolume_r = 0.f;
39         int32_t _oldvolume = 0;
40         float _pan = 0;
41 
42         bool _stopping = false;
43         bool _done = true;
44         bool _deleteondone = false;
45         bool _deletesourceondone = false;
46 
47     public:
AudioChannelImpl()48         AudioChannelImpl()
49         {
50             AudioChannelImpl::SetRate(1);
51             AudioChannelImpl::SetVolume(MIXER_VOLUME_MAX);
52             AudioChannelImpl::SetPan(0.5f);
53         }
54 
~AudioChannelImpl()55         ~AudioChannelImpl() override
56         {
57             if (_resampler != nullptr)
58             {
59                 speex_resampler_destroy(_resampler);
60                 _resampler = nullptr;
61             }
62             if (_deletesourceondone)
63             {
64                 delete _source;
65             }
66         }
67 
GetSource() const68         [[nodiscard]] IAudioSource* GetSource() const override
69         {
70             return _source;
71         }
72 
GetResampler() const73         [[nodiscard]] SpeexResamplerState* GetResampler() const override
74         {
75             return _resampler;
76         }
77 
SetResampler(SpeexResamplerState * value)78         void SetResampler(SpeexResamplerState* value) override
79         {
80             _resampler = value;
81         }
82 
GetGroup() const83         [[nodiscard]] MixerGroup GetGroup() const override
84         {
85             return _group;
86         }
87 
SetGroup(MixerGroup group)88         void SetGroup(MixerGroup group) override
89         {
90             _group = group;
91         }
92 
GetRate() const93         [[nodiscard]] double GetRate() const override
94         {
95             return _rate;
96         }
97 
SetRate(double rate)98         void SetRate(double rate) override
99         {
100             _rate = std::max(0.001, rate);
101         }
102 
GetOffset() const103         [[nodiscard]] uint64_t GetOffset() const override
104         {
105             return _offset;
106         }
107 
SetOffset(uint64_t offset)108         bool SetOffset(uint64_t offset) override
109         {
110             if (_source != nullptr && offset < _source->GetLength())
111             {
112                 AudioFormat format = _source->GetFormat();
113                 int32_t samplesize = format.channels * format.BytesPerSample();
114                 _offset = (offset / samplesize) * samplesize;
115                 return true;
116             }
117             return false;
118         }
119 
GetLoop() const120         [[nodiscard]] int32_t GetLoop() const override
121         {
122             return _loop;
123         }
124 
SetLoop(int32_t value)125         void SetLoop(int32_t value) override
126         {
127             _loop = value;
128         }
129 
GetVolume() const130         [[nodiscard]] int32_t GetVolume() const override
131         {
132             return _volume;
133         }
134 
GetVolumeL() const135         [[nodiscard]] float GetVolumeL() const override
136         {
137             return _volume_l;
138         }
139 
GetVolumeR() const140         [[nodiscard]] float GetVolumeR() const override
141         {
142             return _volume_r;
143         }
144 
GetOldVolumeL() const145         [[nodiscard]] float GetOldVolumeL() const override
146         {
147             return _oldvolume_l;
148         }
149 
GetOldVolumeR() const150         [[nodiscard]] float GetOldVolumeR() const override
151         {
152             return _oldvolume_r;
153         }
154 
GetOldVolume() const155         [[nodiscard]] int32_t GetOldVolume() const override
156         {
157             return _oldvolume;
158         }
159 
SetVolume(int32_t volume)160         void SetVolume(int32_t volume) override
161         {
162             _volume = std::clamp(volume, 0, MIXER_VOLUME_MAX);
163         }
164 
GetPan() const165         [[nodiscard]] float GetPan() const override
166         {
167             return _pan;
168         }
169 
SetPan(float pan)170         void SetPan(float pan) override
171         {
172             _pan = std::clamp(pan, 0.0f, 1.0f);
173             double decibels = (std::abs(_pan - 0.5) * 2.0) * 100.0;
174             double attenuation = pow(10, decibels / 20.0);
175             if (_pan <= 0.5)
176             {
177                 _volume_l = 1.0;
178                 _volume_r = static_cast<float>(1.0 / attenuation);
179             }
180             else
181             {
182                 _volume_r = 1.0;
183                 _volume_l = static_cast<float>(1.0 / attenuation);
184             }
185         }
186 
IsStopping() const187         [[nodiscard]] bool IsStopping() const override
188         {
189             return _stopping;
190         }
191 
SetStopping(bool value)192         void SetStopping(bool value) override
193         {
194             _stopping = value;
195         }
196 
IsDone() const197         [[nodiscard]] bool IsDone() const override
198         {
199             return _done;
200         }
201 
SetDone(bool value)202         void SetDone(bool value) override
203         {
204             _done = value;
205         }
206 
DeleteOnDone() const207         [[nodiscard]] bool DeleteOnDone() const override
208         {
209             return _deleteondone;
210         }
211 
SetDeleteOnDone(bool value)212         void SetDeleteOnDone(bool value) override
213         {
214             _deleteondone = value;
215         }
216 
SetDeleteSourceOnDone(bool value)217         void SetDeleteSourceOnDone(bool value) override
218         {
219             _deletesourceondone = value;
220         }
221 
IsPlaying() const222         [[nodiscard]] bool IsPlaying() const override
223         {
224             return !_done;
225         }
226 
Play(IAudioSource * source,int32_t loop)227         void Play(IAudioSource* source, int32_t loop) override
228         {
229             _source = static_cast<AudioSource_*>(source);
230             _loop = loop;
231             _offset = 0;
232             _done = false;
233         }
234 
UpdateOldVolume()235         void UpdateOldVolume() override
236         {
237             _oldvolume = _volume;
238             _oldvolume_l = _volume_l;
239             _oldvolume_r = _volume_r;
240         }
241 
GetFormat() const242         [[nodiscard]] AudioFormat GetFormat() const override
243         {
244             AudioFormat result = {};
245             // The second check is there because NullAudioSource does not implement GetFormat. Avoid calling it.
246             if (_source != nullptr && _source->GetLength() > 0)
247             {
248                 result = _source->GetFormat();
249             }
250             return result;
251         }
252 
Read(void * dst,size_t len)253         size_t Read(void* dst, size_t len) override
254         {
255             size_t bytesRead = 0;
256             size_t bytesToRead = len;
257             while (bytesToRead > 0 && !_done)
258             {
259                 size_t readLen = _source->Read(dst, _offset, bytesToRead);
260                 if (readLen > 0)
261                 {
262                     dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + readLen);
263                     bytesToRead -= readLen;
264                     bytesRead += readLen;
265                     _offset += readLen;
266                 }
267                 if (_offset >= _source->GetLength())
268                 {
269                     if (_loop == 0)
270                     {
271                         _done = true;
272                     }
273                     else if (_loop == MIXER_LOOP_INFINITE)
274                     {
275                         _offset = 0;
276                     }
277                     else
278                     {
279                         _loop--;
280                         _offset = 0;
281                     }
282                 }
283             }
284             return bytesRead;
285         }
286     };
287 
Create()288     ISDLAudioChannel* AudioChannel::Create()
289     {
290         return new (std::nothrow) AudioChannelImpl();
291     }
292 } // namespace OpenRCT2::Audio
293