1 /*
2 Copyright (C) 2005 The Pentagram team
3 Copyright (C) 2010-2013 The Exult Team
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 */
19 #include "pent_include.h"
20 #include "AudioMixer.h"
21 #include "Configuration.h"
22 
23 #include "AudioChannel.h"
24 
25 #include "MidiDriver.h"
26 
27 #include <SDL.h>
28 
29 #include <algorithm>
30 #include <iostream>
31 #include <limits>
32 #include <mutex>
33 
34 #include "Midi.h"
35 
36 namespace Pentagram {
37 	class SDLAudioDevice {
38 	public:
SDLAudioDevice(SDL_AudioDeviceID dev_)39 		SDLAudioDevice(SDL_AudioDeviceID dev_) : dev(dev_) {}
~SDLAudioDevice()40 		~SDLAudioDevice() {
41 			SDL_CloseAudioDevice(dev);
42 		}
43 
pause()44 		void pause() {
45 			SDL_PauseAudioDevice(dev, 1);
46 		}
47 
unpause()48 		void unpause() {
49 			SDL_PauseAudioDevice(dev, 0);
50 		}
51 
lock()52 		void lock() {
53 			SDL_LockAudioDevice(dev);
54 		}
55 
unlock()56 		void unlock() {
57 			SDL_UnlockAudioDevice(dev);
58 		}
59 
60 	private:
61 		SDL_AudioDeviceID dev;
62 	};
63 }
64 
65 using namespace Pentagram;
66 
67 AudioMixer *AudioMixer::the_audio_mixer = nullptr;
68 
AudioMixer(int sample_rate_,bool stereo_,int num_channels_)69 AudioMixer::AudioMixer(int sample_rate_, bool stereo_, int num_channels_) :
70 audio_ok(false),
71 sample_rate(sample_rate_), stereo(stereo_),
72 midi(nullptr), midi_volume(255),
73 id_counter(0), device(nullptr)
74 {
75 	the_audio_mixer = this;
76 
77 	std::cout << "Creating AudioMixer..." << std::endl;
78 
79 	SDL_AudioSpec desired{};
80 	SDL_AudioSpec obtained;
81 
82 	desired.format = AUDIO_S16SYS;
83 	desired.freq = sample_rate_;
84 	desired.channels = stereo_?2:1;
85 	desired.callback = sdlAudioCallback;
86 	desired.userdata = this;
87 
88 	// Set update rate to 20 Hz, or there abouts. This should be more then adequate for everyone
89 	desired.samples=1;
90 	while(desired.samples<=desired.freq/30) desired.samples<<=1;
91 
92 	// Open SDL Audio (even though we may not need it)
93 	SDL_InitSubSystem(SDL_INIT_AUDIO);
94 	SDL_AudioDeviceID dev = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, SDL_AUDIO_ALLOW_ANY_CHANGE);
95 	audio_ok = (dev != 0);
96 
97 	if (audio_ok) {
98 		pout << "Audio opened using format: " << obtained.freq << " Hz "
99 		     << static_cast<int>(obtained.channels) << " Channels" <<  std::endl;
100 		device = new SDLAudioDevice(dev);
101 		{
102 			std::lock_guard<SDLAudioDevice> lock(*device);
103 			sample_rate = obtained.freq;
104 			stereo = obtained.channels == 2;
105 
106 			internal_buffer.resize((obtained.size + 1) / 2);
107 			for (int i = 0; i < num_channels_; i++)
108 				channels.emplace_back(sample_rate, stereo);
109 		}
110 
111 		// GO GO GO!
112 		device->unpause();
113 	}
114 }
115 
~AudioMixer()116 AudioMixer::~AudioMixer()
117 {
118 	std::cout << "Destroying AudioMixer..." << std::endl;
119 
120 	closeMidiOutput();
121 
122 	delete device;
123 
124 	the_audio_mixer = nullptr;
125 }
126 
reset()127 void AudioMixer::reset()
128 {
129 	if (!audio_ok) return;
130 
131 	std::cout << "Resetting AudioMixer..." << std::endl;
132 
133 	midi->stop_music();
134 
135 	std::lock_guard<SDLAudioDevice> lock(*device);
136 	for (auto& channel : channels) channel.stop();
137 }
138 
playSample(AudioSample * sample,int loop,int priority,bool paused,uint32 pitch_shift_,int lvol,int rvol)139 sint32 AudioMixer::playSample(AudioSample *sample, int loop, int priority, bool paused, uint32 pitch_shift_, int lvol, int rvol)
140 {
141 	if (!audio_ok || channels.empty()) return -1;
142 
143 	std::lock_guard<SDLAudioDevice> lock(*device);
144 	auto it = std::find_if(channels.begin(), channels.end(), [](auto& channel) {
145 		return !channel.isPlaying();
146 	});
147 	if (it == channels.end()) {
148 		it = std::min_element(channels.begin(), channels.end(), [](auto& c1, auto& c2) {
149 			return c1.getPriority() < c2.getPriority();
150 		});
151 	}
152 	if (it != channels.end() && (!it->isPlaying() || it->getPriority() < priority)) {
153 		if (id_counter == std::numeric_limits<decltype(id_counter)>::max()) {
154 			id_counter = 0;
155 		} else {
156 			++id_counter;
157 		}
158 		it->playSample(sample, loop, priority, paused, pitch_shift_, lvol, rvol, id_counter);
159 		return id_counter;
160 	}
161 	return -1;
162 }
163 
isPlaying(sint32 instance_id) const164 bool AudioMixer::isPlaying(sint32 instance_id) const
165 {
166 	if (instance_id < 0 || channels.empty() || !audio_ok) return false;
167 
168 	std::lock_guard<SDLAudioDevice> lock(*device);
169 	auto it = std::find_if(channels.cbegin(), channels.cend(), [instance_id](auto& channel) {
170 		return channel.getInstanceId() == instance_id;
171 	});
172 	return it != channels.end() && it->isPlaying();
173 }
174 
isPlaying(AudioSample * sample) const175 bool AudioMixer::isPlaying(AudioSample *sample) const
176 {
177 	if (!sample || channels.empty() || !audio_ok) return false;
178 
179 	std::lock_guard<SDLAudioDevice> lock(*device);
180 	auto it = std::find_if(channels.cbegin(), channels.cend(), [sample](auto& channel) {
181 		return channel.getSample() == sample;
182 	});
183 	return it != channels.end();
184 }
185 
isPlayingVoice() const186 bool AudioMixer::isPlayingVoice() const
187 {
188 	if (channels.empty() || !audio_ok) return false;
189 
190 	std::lock_guard<SDLAudioDevice> lock(*device);
191 	auto it = std::find_if(channels.cbegin(), channels.cend(), [](auto& channel) {
192 		return channel.isPlaying() && channel.getSample()->isVocSample();
193 	});
194 	return it != channels.end();
195 }
196 
stopSample(sint32 instance_id)197 void AudioMixer::stopSample(sint32 instance_id)
198 {
199 	if (instance_id < 0 || channels.empty() || !audio_ok) return;
200 
201 	std::lock_guard<SDLAudioDevice> lock(*device);
202 	auto it = std::find_if(channels.begin(), channels.end(), [instance_id](auto& channel) {
203 		return channel.getInstanceId() == instance_id;
204 	});
205 	if (it != channels.end()) {
206 		it->stop();
207 	}
208 }
209 
stopSample(AudioSample * sample)210 void AudioMixer::stopSample(AudioSample *sample)
211 {
212 	if (!sample || channels.empty() || !audio_ok) return;
213 
214 	std::lock_guard<SDLAudioDevice> lock(*device);
215 	for (auto& channel : channels)
216 	{
217 		if (channel.getSample() == sample)
218 			channel.stop();
219 	}
220 }
221 
setPaused(sint32 instance_id,bool paused)222 void AudioMixer::setPaused(sint32 instance_id, bool paused)
223 {
224 	if (instance_id < 0 || channels.empty() || !audio_ok) return;
225 
226 	std::lock_guard<SDLAudioDevice> lock(*device);
227 	auto it = std::find_if(channels.begin(), channels.end(), [instance_id](auto& channel) {
228 		return channel.getInstanceId() == instance_id;
229 	});
230 	if (it != channels.end()) {
231 		it->setPaused(paused);
232 	}
233 }
234 
isPaused(sint32 instance_id) const235 bool AudioMixer::isPaused(sint32 instance_id) const
236 {
237 	if (instance_id < 0 || channels.empty() || !audio_ok) return false;
238 
239 	std::lock_guard<SDLAudioDevice> lock(*device);
240 	auto it = std::find_if(channels.cbegin(), channels.cend(), [instance_id](auto& channel) {
241 		return channel.getInstanceId() == instance_id;
242 	});
243 	return it != channels.end() && it->isPaused();
244 }
245 
setPausedAll(bool paused)246 void AudioMixer::setPausedAll(bool paused)
247 {
248 	if (channels.empty() || !audio_ok) return;
249 
250 	std::lock_guard<SDLAudioDevice> lock(*device);
251 	for (auto& channel : channels)
252 		channel.setPaused(paused);
253 }
254 
setVolume(sint32 instance_id,int lvol,int rvol)255 void AudioMixer::setVolume(sint32 instance_id, int lvol, int rvol)
256 {
257 	if (instance_id < 0 || channels.empty() || !audio_ok) return;
258 
259 	std::lock_guard<SDLAudioDevice> lock(*device);
260 	auto it = std::find_if(channels.begin(), channels.end(), [instance_id](auto& channel) {
261 		return channel.getInstanceId() == instance_id;
262 	});
263 	if (it != channels.end()) {
264 		it->setVolume(lvol, rvol);
265 	}
266 }
267 
getVolume(sint32 instance_id,int & lvol,int & rvol) const268 void AudioMixer::getVolume(sint32 instance_id, int &lvol, int &rvol) const
269 {
270 	if (instance_id < 0 || channels.empty() || !audio_ok) return;
271 
272 	std::lock_guard<SDLAudioDevice> lock(*device);
273 	auto it = std::find_if(channels.cbegin(), channels.cend(), [instance_id](auto& channel) {
274 		return channel.getInstanceId() == instance_id;
275 	});
276 	if (it != channels.end()) {
277 		it->getVolume(lvol, rvol);
278 	}
279 }
280 
281 
set2DPosition(sint32 instance_id,int distance,int angle)282 bool AudioMixer::set2DPosition(sint32 instance_id, int distance, int angle)
283 {
284 	if (instance_id < 0 || channels.empty() || !audio_ok) return false;
285 
286 	std::lock_guard<SDLAudioDevice> lock(*device);
287 	auto it = std::find_if(channels.begin(), channels.end(), [instance_id](auto& channel) {
288 		return channel.getInstanceId() == instance_id;
289 	});
290 	if (it != channels.end()) {
291 		it->set2DPosition(distance, angle);
292 		return it->isPlaying();
293 	}
294 	return false;
295 }
296 
get2DPosition(sint32 instance_id,int & distance,int & angle) const297 void AudioMixer::get2DPosition(sint32 instance_id, int &distance, int &angle) const
298 {
299 	if (instance_id < 0 || channels.empty() || !audio_ok) return;
300 
301 	std::lock_guard<SDLAudioDevice> lock(*device);
302 	auto it = std::find_if(channels.cbegin(), channels.cend(), [instance_id](auto& channel) {
303 		return channel.getInstanceId() == instance_id;
304 	});
305 	if (it != channels.end()) {
306 		it->get2DPosition(distance, angle);
307 	}
308 }
309 
sdlAudioCallback(void * userdata,Uint8 * stream,int len)310 void AudioMixer::sdlAudioCallback(void *userdata, Uint8 *stream, int len)
311 {
312 	auto *mixer = static_cast<AudioMixer *>(userdata);
313 	// Unfortunately, SDL does not guarantee that stream will be aligned to
314 	// the correct alignment for sint16.
315 	// There is no real solution except using an aligned buffer and copying.
316 	size_t newlen = size_t(len + 1) / 2;
317 	// This should never be needed, as we set the vector length
318 	// based on information provided by SDL. Lets leave it in anyway
319 	// just in case...
320 	if (newlen > mixer->internal_buffer.size()) {
321 		mixer->internal_buffer.resize(newlen);
322 	}
323 	mixer->MixAudio(mixer->internal_buffer.data(), len);
324 	std::memcpy(stream, mixer->internal_buffer.data(), len);
325 }
326 
MixAudio(sint16 * stream,uint32 bytes)327 void AudioMixer::MixAudio(sint16 *stream, uint32 bytes)
328 {
329 	if (!audio_ok) return;
330 	std::memset(stream,0,bytes);
331 	if (midi) midi->produceSamples(stream, bytes);
332 	for (auto& channel : channels)
333 		if (channel.isPlaying()) channel.resampleAndMix(stream,bytes);
334 }
335 
openMidiOutput()336 void AudioMixer::openMidiOutput()
337 {
338 	if (midi) return;
339 	if (!audio_ok) return;
340 
341 	auto * new_driver = new MyMidiPlayer();
342 
343 	{
344 		std::lock_guard<SDLAudioDevice> lock(*device);
345 		midi = new_driver;
346 	}
347 	midi->load_timbres();
348 	//midi_driver->setGlobalVolume(midi_volume);
349 }
350 
closeMidiOutput()351 void AudioMixer::closeMidiOutput()
352 {
353 	if (!midi) return;
354 	std::cout << "Destroying MidiDriver..." << std::endl;
355 
356 	midi->stop_music(true);
357 	midi->destroyMidiDriver();
358 
359 	std::lock_guard<SDLAudioDevice> lock(*device);
360 	delete midi;
361 	midi = nullptr;
362 }
363