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 #ifndef TITANIC_SOUND_MANAGER_H
24 #define TITANIC_SOUND_MANAGER_H
25 
26 #include "titanic/core/list.h"
27 #include "titanic/support/simple_file.h"
28 #include "titanic/sound/audio_buffer.h"
29 #include "titanic/sound/proximity.h"
30 #include "titanic/sound/qmixer.h"
31 #include "titanic/sound/wave_file.h"
32 #include "titanic/true_talk/dialogue_file.h"
33 
34 namespace Titanic {
35 
36 enum VolumeMode {
37 	VOL_NORMAL = -1, VOL_QUIET = -2, VOL_VERY_QUIET = -3, VOL_MUTE = -4
38 };
39 
40 /**
41  * Abstract interface class for a sound manager
42  */
43 class CSoundManager {
44 protected:
45 	uint _handleCtr;
46 	// Old volume levels, deprecated in favor of setting the volumes
47 	// directly in the ScummVM mixer
48 	double _musicPercent;
49 	double _speechPercent;
50 	double _masterPercent;
51 	double _parrotPercent;
52 public:
53 	CSoundManager();
~CSoundManager()54 	virtual ~CSoundManager() {}
55 
56 	/**
57 	 * Loads a sound
58 	 * @param name		Name of sound resource
59 	 * @returns			Loaded wave file
60 	 */
loadSound(const CString & name)61 	virtual CWaveFile *loadSound(const CString &name) { return nullptr; }
62 
63 	/**
64 	 * Loads a speech resource from a dialogue file
65 	 * @param name		Name of sound resource
66 	 * @returns			Loaded wave file
67 	 */
loadSpeech(CDialogueFile * dialogueFile,int speechId)68 	virtual CWaveFile *loadSpeech(CDialogueFile *dialogueFile, int speechId) { return 0; }
69 
70 	/**
71 	 * Loads a music file
72 	 * @param name		Name of music resource
73 	 * @returns			Loaded wave file
74 	 * @remarks The original only classified music as what's produced in the
75 	 * music room puzzle. For ScummVM, we've reclassified some wave files that
76 	 * contain background music as music as well.
77 	 */
loadMusic(const CString & name)78 	virtual CWaveFile *loadMusic(const CString &name) { return nullptr; }
79 
80 	/**
81 	 * Loads a music file from a streaming audio buffer
82 	 * @param buffer	Audio buffer
83 	 * @returns			Loaded wave file
84 	 */
loadMusic(CAudioBuffer * buffer,DisposeAfterUse::Flag disposeAfterUse)85 	virtual CWaveFile *loadMusic(CAudioBuffer *buffer, DisposeAfterUse::Flag disposeAfterUse) { return nullptr; }
86 
87 	/**
88 	 * Start playing a previously loaded wave file
89 	 */
90 	virtual int playSound(CWaveFile &waveFile, CProximity &prox) = 0;
91 
92 	/**
93 	 * Stop playing the specified sound
94 	 */
95 	virtual void stopSound(int handle) = 0;
96 
97 	/**
98 	 * Stops a designated range of channels
99 	 */
100 	virtual void stopChannel(int channel) = 0;
101 
proc9(int handle)102 	virtual void proc9(int handle) {}
103 
104 	/**
105 	 * Stops sounds on all playing channels
106 	 */
107 	virtual void stopAllChannels() = 0;
108 
109 	/**
110 	 * Sets the volume for a sound
111 	 * @param handle	Handle for sound
112 	 * @param volume	New volume
113 	 * @param seconds	Number of seconds to transition to the new volume
114 	 */
115 	virtual void setVolume(int handle, uint volume, uint seconds) = 0;
116 
117 	/**
118 	 * Set the position for a sound
119 	 * @param handle	Handle for sound
120 	 * @param x			x position in metres
121 	 * @param y			y position in metres
122 	 * @param z			z position in metres
123 	 * @param panRate	Rate in milliseconds to transition
124 	 */
setVectorPosition(int handle,double x,double y,double z,uint panRate)125 	virtual void setVectorPosition(int handle, double x, double y, double z, uint panRate) {}
126 
127 	/**
128 	 * Set the position for a sound
129 	 * @param handle	Handle for sound
130 	 * @param range		Range value in metres
131 	 * @param azimuth	Azimuth value in degrees
132 	 * @param elevation	Elevation value in degrees
133 	 * @param panRate	Rate in milliseconds to transition
134 	 */
setPolarPosition(int handle,double range,double azimuth,double elevation,uint panRate)135 	virtual void setPolarPosition(int handle, double range, double azimuth, double elevation, uint panRate) {}
136 
137 	/**
138 	 * Returns true if the given sound is currently active
139 	 */
140 	virtual bool isActive(int handle) = 0;
141 
142 	/**
143 	 * Returns true if the given sound is currently active
144 	 */
isActive(const CWaveFile * waveFile)145 	virtual bool isActive(const CWaveFile *waveFile) { return false; }
146 
147 	/**
148 	 * Handles regularly updating the mixer
149 	 */
150 	virtual void waveMixPump() = 0;
151 
152 	/**
153 	 * Returns the movie latency
154 	 */
getLatency()155 	virtual uint getLatency() const { return 0; }
156 
157 	/**
158 	 * Sets the music volume percent
159 	 */
160 	virtual void setMusicPercent(double percent) = 0;
161 
162 	/**
163 	 * Sets the speech volume percent
164 	 */
165 	virtual void setSpeechPercent(double percent) = 0;
166 
167 	/**
168 	 * Sets the master volume percent
169 	 */
170 	virtual void setMasterPercent(double percent) = 0;
171 
172 	/**
173 	 * Sets the Parrot NPC volume percent
174 	 */
175 	virtual void setParrotPercent(double percent) = 0;
176 
177 	/**
178 	 * Called when a game is about to be loaded
179 	 */
preLoad()180 	virtual void preLoad() { stopAllChannels(); }
181 
182 	/**
183 	 * Load the data for the class from file
184 	 */
load(SimpleFile * file)185 	void load(SimpleFile *file) {}
186 
187 	/**
188 	 * Called after loading of a game is completed
189 	 */
postLoad()190 	virtual void postLoad() {}
191 
192 	/**
193 	 * Called when a game is about to be saved
194 	 */
preSave()195 	virtual void preSave() {}
196 
197 	/**
198 	 * Save the data for the class to file
199 	 */
save(SimpleFile * file)200 	void save(SimpleFile *file) const {}
201 
202 	/**
203 	 * Called after saving is complete
204 	 */
postSave()205 	virtual void postSave() {}
206 
207 	/**
208 	 * Sets the position and orientation for the listener (player)
209 	 */
setListenerPosition(double posX,double posY,double posZ,double directionX,double directionY,double directionZ,bool stopSounds)210 	virtual void setListenerPosition(double posX, double posY, double posZ,
211 		double directionX, double directionY, double directionZ, bool stopSounds) {}
212 
213 	/**
214 	 * Returns the music volume percent
215 	 */
getMusicVolume()216 	double getMusicVolume() const { return _musicPercent; }
217 
218 	/**
219 	 * Returns the speech volume percent
220 	 */
getSpeechVolume()221 	double getSpeechVolume() const { return _speechPercent; }
222 
223 	/**
224 	 * Returns the parrot volume percent
225 	 */
getParrotVolume()226 	double getParrotVolume() const { return _parrotPercent; }
227 
228 	/**
229 	 * Gets the volume for a given mode? value
230 	 */
231 	uint getModeVolume(VolumeMode mode);
232 };
233 
234 class QSoundManagerSound : public ListItem {
235 public:
236 	CWaveFile *_waveFile;
237 	int _iChannel;
238 	CEndTalkerFn _endFn;
239 	TTtalker *_talker;
240 public:
QSoundManagerSound()241 	QSoundManagerSound() : ListItem(), _waveFile(nullptr),
242 		_iChannel(0), _endFn(nullptr), _talker(nullptr) {}
QSoundManagerSound(CWaveFile * waveFile,int iChannel,CEndTalkerFn endFn,TTtalker * talker)243 	QSoundManagerSound(CWaveFile *waveFile, int iChannel, CEndTalkerFn endFn, TTtalker *talker) :
244 		ListItem(), _waveFile(waveFile), _iChannel(iChannel), _endFn(endFn), _talker(talker) {}
245 };
246 
247 class QSoundManagerSounds : public List<QSoundManagerSound> {
248 public:
249 	/**
250 	 * Adds a new sound entry to the list
251 	 */
252 	void add(CWaveFile *waveFile, int iChannel, CEndTalkerFn endFn, TTtalker *talker);
253 
254 	/**
255 	 * Flushes a wave file attached to the specified channel
256 	 */
257 	void flushChannel(int iChannel);
258 
259 	/**
260 	 * Flushes a wave file attached to the specified channel
261 	 */
262 	void flushChannel(CWaveFile *waveFile, int iChannel);
263 
264 	/**
265 	 * Returns true if the list contains the specified wave file
266 	 */
267 	bool contains(const CWaveFile *waveFile) const;
268 };
269 
270 /**
271  * Concrete sound manager class that handles interfacing with
272  * the QMixer sound mixer class
273  */
274 class QSoundManager : public CSoundManager, public QMixer {
275 	struct Slot {
276 		CWaveFile *_waveFile;
277 		bool _isTimed;
278 		uint _ticks;
279 		int _channel;
280 		int _handle;
281 		PositioningMode _positioningMode;
282 
SlotSlot283 		Slot() : _waveFile(0), _isTimed(0), _ticks(0), _channel(-1),
284 			_handle(0), _positioningMode(POSMODE_NONE) {}
285 		void clear();
286 	};
287 private:
288 	QSoundManagerSounds _sounds;
289 	Common::Array<Slot> _slots;
290 	uint _channelsVolume[16];
291 	int _channelsMode[16];
292 private:
293 	/**
294 	 * Updates the volume for a channel
295 	 * @param channel	Channel to be update
296 	 * @param panRate	Time in milliseconds for change to occur
297 	 */
298 	void updateVolume(int channel, uint panRate);
299 
300 	/**
301 	 * Updates all the volumes
302 	 */
303 	void updateVolumes();
304 
305 	/**
306 	 * Called by the QMixer when a sound finishes playing
307 	 */
308 	static void soundFinished(int iChannel, CWaveFile *waveFile, void *soundManager);
309 
310 	/**
311 	 * Finds the first free slot
312 	 */
313 	int findFreeSlot();
314 
315 	/**
316 	 * Sets a channel volume
317 	 */
318 	void setChannelVolume(int iChannel, uint volume, uint mode);
319 
320 	/**
321 	 * Resets the specified channel and returns a new free one
322 	 */
323 	int resetChannel(int iChannel);
324 public:
325 	int _field18;
326 	int _field1C;
327 
328 public:
329 	QSoundManager(Audio::Mixer *mixer);
330 	~QSoundManager() override;
331 
332 	/**
333 	 * Loads a sound
334 	 * @param name		Name of sound resource
335 	 * @returns			Loaded wave file
336 	 */
337 	CWaveFile *loadSound(const CString &name) override;
338 
339 	/**
340 	 * Loads a speech resource from a dialogue file
341 	 * @param name		Name of sound resource
342 	 * @returns			Loaded wave file
343 	 */
344 	CWaveFile *loadSpeech(CDialogueFile *dialogueFile, int speechId) override;
345 
346 	/**
347 	 * Loads a music file
348 	 * @param name		Name of music resource
349 	 * @returns			Loaded wave file
350 	 * @remarks The original only classified music as what's produced in the
351 	 * music room puzzle. For ScummVM, we've reclassified some wave files that
352 	 * contain background music as music as well.
353 	 */
354 	CWaveFile *loadMusic(const CString &name) override;
355 
356 	/**
357 	 * Loads a music file from a streaming audio buffer
358 	 * @param buffer	Audio buffer
359 	 * @returns			Loaded wave file
360 	 */
361 	CWaveFile *loadMusic(CAudioBuffer *buffer, DisposeAfterUse::Flag disposeAfterUse) override;
362 
363 	/**
364 	 * Start playing a previously loaded sound resource
365 	 */
366 	int playSound(CWaveFile &waveFile, CProximity &prox) override;
367 
368 	/**
369 	 * Stop playing the specified sound
370 	 */
371 	void stopSound(int handle) override;
372 
373 	/**
374 	 * Stops a designated range of channels
375 	 */
376 	void stopChannel(int channel) override;
377 
378 	/**
379 	 * Flags that a sound can be freed if a timeout is set
380 	 */
381 	virtual void setCanFree(int handle);
382 
383 	/**
384 	 * Stops sounds on all playing channels
385 	 */
386 	void stopAllChannels() override;
387 
388 	/**
389 	 * Sets the volume for a sound
390 	 * @param handle	Handle for sound
391 	 * @param volume	New volume
392 	 * @param seconds	Number of seconds to transition to the new volume
393 	 */
394 	void setVolume(int handle, uint volume, uint seconds) override;
395 
396 	/**
397 	 * Set the position for a sound
398 	 * @param handle	Handle for sound
399 	 * @param x			x position in metres
400 	 * @param y			y position in metres
401 	 * @param z			z position in metres
402 	 * @param panRate	Rate in milliseconds to transition
403 	 */
404 	void setVectorPosition(int handle, double x, double y, double z, uint panRate) override;
405 
406 	/**
407 	 * Set the position for a sound
408 	 * @param handle	Handle for sound
409 	 * @param range		Range value in metres
410 	 * @param azimuth	Azimuth value in degrees
411 	 * @param elevation	Elevation value in degrees
412 	 * @param panRate	Rate in milliseconds to transition
413 	 */
414 	void setPolarPosition(int handle, double range, double azimuth, double elevation, uint panRate) override;
415 
416 	/**
417 	 * Returns true if the given sound is currently active
418 	 */
419 	bool isActive(int handle) override;
420 
421 	/**
422 	 * Returns true if the given sound is currently active
423 	 */
424 	bool isActive(const CWaveFile *waveFile) override;
425 
426 	/**
427 	 * Handles regularly updating the mixer
428 	 */
429 	void waveMixPump() override;
430 
431 	/**
432 	 * Returns the movie latency
433 	 */
434 	uint getLatency() const override;
435 
436 	/**
437 	 * Sets the music volume percent
438 	 */
439 	void setMusicPercent(double percent) override;
440 
441 	/**
442 	 * Sets the speech volume percent
443 	 */
444 	void setSpeechPercent(double percent) override;
445 
446 	/**
447 	 * Sets the master volume percent
448 	 */
449 	void setMasterPercent(double percent) override;
450 
451 	/**
452 	 * Sets the Parrot NPC volume percent
453 	 */
454 	void setParrotPercent(double percent) override;
455 
456 	/**
457 	 * Sets the position and orientation for the listener (player)
458 	 */
459 	void setListenerPosition(double posX, double posY, double posZ,
460 		double directionX, double directionY, double directionZ, bool stopSounds) override;
461 
462 	/**
463 	 * Starts a wave file playing
464 	 */
465 	virtual int playWave(CWaveFile *waveFile, int iChannel, uint flags, CProximity &prox);
466 
467 	/**
468 	 * Called when a wave file is freed
469 	 */
470 	void soundFreed(Audio::SoundHandle &handle);
471 };
472 
473 } // End of namespace Titanic
474 
475 #endif /* TITANIC_QSOUND_MANAGER_H */
476