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