1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "bladerunner/audio_player.h"
24 
25 #include "bladerunner/archive.h"
26 #include "bladerunner/aud_stream.h"
27 #include "bladerunner/audio_cache.h"
28 #include "bladerunner/audio_mixer.h"
29 #include "bladerunner/bladerunner.h"
30 
31 #include "common/debug.h"
32 #include "common/stream.h"
33 #include "common/random.h"
34 
35 namespace Common {
36 	class MemoryReadStream;
37 }
38 
39 namespace BladeRunner {
40 
AudioPlayer(BladeRunnerEngine * vm)41 AudioPlayer::AudioPlayer(BladeRunnerEngine *vm) {
42 	_vm = vm;
43 
44 	for (int i = 0; i != kTracks; ++i) {
45 		_tracks[i].priority = 0;
46 		_tracks[i].isActive = false;
47 		_tracks[i].channel = -1;
48 		_tracks[i].stream = nullptr;
49 	}
50 
51 	_sfxVolume = BLADERUNNER_ORIGINAL_SETTINGS ? 65 : 100;
52 }
53 
~AudioPlayer()54 AudioPlayer::~AudioPlayer() {
55 	stopAll();
56 }
57 
stopAll()58 void AudioPlayer::stopAll() {
59 	for (int i = 0; i != kTracks; ++i) {
60 		stop(i, true);
61 	}
62 	for (int i = 0; i != kTracks; ++i) {
63 		while (isActive(i)) {
64 			// wait for all tracks to finish
65 		}
66 	}
67 }
68 
adjustVolume(int track,int volume,uint32 delay,bool overrideVolume)69 void AudioPlayer::adjustVolume(int track, int volume, uint32 delay, bool overrideVolume) {
70 	if (track < 0 || track >= kTracks || !_tracks[track].isActive || _tracks[track].channel == -1) {
71 		return;
72 	}
73 
74 	int actualVolume = volume;
75 	if (!overrideVolume) {
76 		actualVolume = actualVolume * _sfxVolume / 100;
77 	}
78 
79 	_tracks[track].volume = actualVolume;
80 	_vm->_audioMixer->adjustVolume(_tracks[track].channel, actualVolume, 60u * delay);
81 }
82 
adjustPan(int track,int pan,uint32 delay)83 void AudioPlayer::adjustPan(int track, int pan, uint32 delay) {
84 	if (track < 0 || track >= kTracks || !_tracks[track].isActive || _tracks[track].channel == -1) {
85 		return;
86 	}
87 
88 	_tracks[track].pan = pan;
89 	_vm->_audioMixer->adjustPan(_tracks[track].channel, pan, 60u * delay);
90 }
91 
setVolume(int volume)92 void AudioPlayer::setVolume(int volume) {
93 	_sfxVolume = volume;
94 }
95 
getVolume() const96 int AudioPlayer::getVolume() const {
97 	return _sfxVolume;
98 }
99 
playSample()100 void AudioPlayer::playSample() {
101 	Common::String name;
102 
103 	int rnd = _vm->_rnd.getRandomNumber(3);
104 	if (rnd == 0) {
105 		name = "gunmiss1.aud";
106 	} else if (rnd == 1) {
107 		name = "gunmiss2.aud";
108 	} else if (rnd == 2) {
109 		name = "gunmiss3.aud";
110 	} else {
111 		name = "gunmiss4.aud";
112 	}
113 
114 	playAud(name, 100, 0, 0, 100, 0);
115 }
116 
remove(int channel)117 void AudioPlayer::remove(int channel) {
118 	Common::StackLock lock(_mutex);
119 	for (int i = 0; i != kTracks; ++i) {
120 		if (_tracks[i].channel == channel) {
121 			_tracks[i].isActive = false;
122 			_tracks[i].priority = 0;
123 			_tracks[i].channel = -1;
124 			_tracks[i].stream = nullptr;
125 			break;
126 		}
127 	}
128 }
129 
mixerChannelEnded(int channel,void * data)130 void AudioPlayer::mixerChannelEnded(int channel, void *data) {
131 	AudioPlayer *audioPlayer = (AudioPlayer *)data;
132 	audioPlayer->remove(channel);
133 }
134 
playAud(const Common::String & name,int volume,int panFrom,int panTo,int priority,byte flags,Audio::Mixer::SoundType type)135 int AudioPlayer::playAud(const Common::String &name, int volume, int panFrom, int panTo, int priority, byte flags, Audio::Mixer::SoundType type) {
136 	/* Find first available track or, alternatively, the lowest priority playing track */
137 	int track = -1;
138 	int lowestPriority = 1000000;
139 	int lowestPriorityTrack = -1;
140 
141 	for (int i = 0; i != kTracks; ++i) {
142 		if (!isActive(i)) {
143 			//debug ("Assigned track %i to %s", i, name.c_str());
144 			track = i;
145 			break;
146 		}
147 
148 		if (lowestPriorityTrack == -1 || _tracks[i].priority < lowestPriority) {
149 			lowestPriority = _tracks[i].priority;
150 			lowestPriorityTrack = i;
151 		}
152 	}
153 
154 	/* If there's no available track, stop the lowest priority track if it's lower than
155 	 * the new priority
156 	 */
157 	if (track == -1 && lowestPriority < priority) {
158 		//debug ("Stop lowest priority  track (with lower prio: %d %d), for %s %d!", lowestPriorityTrack, lowestPriority, name.c_str(), priority);
159 		stop(lowestPriorityTrack, true);
160 		track = lowestPriorityTrack;
161 	}
162 
163 	/* If there's still no available track, give up */
164 	if (track == -1) {
165 		//debug ("No available track for %s %d - giving up", name.c_str(), priority);
166 		return -1;
167 	}
168 
169 	/* Load audio resource and store in cache. Playback will happen directly from there. */
170 	int32 hash = MIXArchive::getHash(name);
171 	if (!_vm->_audioCache->findByHash(hash)) {
172 		Common::SeekableReadStream *r = _vm->getResourceStream(name);
173 		if (!r) {
174 			//debug ("Could not get stream for %s %d - giving up", name.c_str(), priority);
175 			return -1;
176 		}
177 
178 		int32 size = r->size();
179 		while (!_vm->_audioCache->canAllocate(size)) {
180 			if (!_vm->_audioCache->dropOldest()) {
181 				delete r;
182 				//debug ("No available mem in cache for %s %d - giving up", name.c_str(), priority);
183 				return -1;
184 			}
185 		}
186 		_vm->_audioCache->storeByHash(hash, r);
187 		delete r;
188 	}
189 
190 	AudStream *audioStream = new AudStream(_vm->_audioCache, hash);
191 
192 	int actualVolume = volume;
193 	if (!(flags & kAudioPlayerOverrideVolume)) {
194 		actualVolume = _sfxVolume * volume / 100;
195 	}
196 
197 	int channel = _vm->_audioMixer->play(
198 		type,
199 		audioStream,
200 		priority,
201 		flags & kAudioPlayerLoop,
202 		actualVolume,
203 		panFrom,
204 		mixerChannelEnded,
205 		this);
206 
207 	if (channel == -1) {
208 		delete audioStream;
209 		//debug ("No available channel for %s %d - giving up", name.c_str(), priority);
210 		return -1;
211 	}
212 
213 	if (panFrom != panTo) {
214 		_vm->_audioMixer->adjustPan(channel, panTo, (60 * audioStream->getLength()) / 1000);
215 	}
216 
217 	_tracks[track].isActive = true;
218 	_tracks[track].channel  = channel;
219 	_tracks[track].priority = priority;
220 	_tracks[track].volume   = actualVolume;
221 	_tracks[track].stream   = audioStream;
222 
223 	return track;
224 }
225 
isActive(int track) const226 bool AudioPlayer::isActive(int track) const {
227 	Common::StackLock lock(_mutex);
228 	if (track < 0 || track >= kTracks) {
229 		return false;
230 	}
231 
232 	return _tracks[track].isActive;
233 }
234 
stop(int track,bool immediately)235 void AudioPlayer::stop(int track, bool immediately) {
236 	if (isActive(track)) {
237 		_vm->_audioMixer->stop(_tracks[track].channel, immediately ? 0 : 60);
238 	}
239 }
240 
241 } // End of namespace BladeRunner
242