1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM 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 "common/textconsole.h"
24 
25 #include "engines/grim/imuse/imuse.h"
26 
27 #include "engines/grim/debug.h"
28 
29 namespace Grim {
30 
flushTrack(Track * track)31 void Imuse::flushTrack(Track *track) {
32 	track->toBeRemoved = true;
33 
34 	if (track->stream) {
35 		// Finalize the appendable stream, then remove our reference to it.
36 		// Note that there might still be some data left in the buffers of the
37 		// appendable stream. We play it nice and wait till all of it
38 		// played. The audio mixer will take care of it afterwards (and dispose it).
39 		track->stream->finish();
40 		track->stream = nullptr;
41 		if (track->soundDesc) {
42 			_sound->closeSound(track->soundDesc);
43 			track->soundDesc = nullptr;
44 		}
45 	}
46 
47 	if (!g_system->getMixer()->isSoundHandleActive(track->handle)) {
48 		track->clear();
49 	}
50 }
51 
flushTracks()52 void Imuse::flushTracks() {
53 	Common::StackLock lock(_mutex);
54 	for (int l = 0; l < MAX_IMUSE_TRACKS + MAX_IMUSE_FADETRACKS; l++) {
55 		Track *track = _track[l];
56 		if (track->used && track->toBeRemoved && !g_system->getMixer()->isSoundHandleActive(track->handle)) {
57 			track->clear();
58 		}
59 	}
60 }
61 
refreshScripts()62 void Imuse::refreshScripts() {
63 	Common::StackLock lock(_mutex);
64 	bool found = false;
65 
66 	for (int l = 0; l < MAX_IMUSE_TRACKS; l++) {
67 		Track *track = _track[l];
68 		if (track->used && !track->toBeRemoved && (track->volGroupId == IMUSE_VOLGRP_MUSIC)) {
69 			found = true;
70 		}
71 	}
72 
73 	if (!found && _curMusicState) {
74 		setMusicSequence(0);
75 	}
76 }
77 
startVoice(const char * soundName,int volume,int pan)78 bool Imuse::startVoice(const char *soundName, int volume, int pan) {
79 	Debug::debug(Debug::Sound, "Imuse::startVoice(): SoundName %s, vol:%d, pan:%d", soundName, volume, pan);
80 	return startSound(soundName, IMUSE_VOLGRP_VOICE, 0, volume, pan, 127, nullptr);
81 }
82 
startMusic(const char * soundName,int hookId,int volume,int pan)83 void Imuse::startMusic(const char *soundName, int hookId, int volume, int pan) {
84 	Debug::debug(Debug::Sound, "Imuse::startMusic(): SoundName %s, hookId:%d, vol:%d, pan:%d", soundName, hookId, volume, pan);
85 	startSound(soundName, IMUSE_VOLGRP_MUSIC, hookId, volume, pan, 126, nullptr);
86 }
87 
startMusicWithOtherPos(const char * soundName,int hookId,int volume,int pan,Track * otherTrack)88 void Imuse::startMusicWithOtherPos(const char *soundName, int hookId, int volume, int pan, Track *otherTrack) {
89 	Debug::debug(Debug::Sound, "Imuse::startMusicWithOtherPos(): SoundName %s, hookId:%d, vol:%d, pan:%d", soundName, hookId, volume, pan);
90 	startSound(soundName, IMUSE_VOLGRP_MUSIC, hookId, volume, pan, 126, otherTrack);
91 }
92 
startSfx(const char * soundName,int priority)93 void Imuse::startSfx(const char *soundName, int priority) {
94 	Debug::debug(Debug::Sound, "Imuse::startSfx(): SoundName %s, priority:%d", soundName, priority);
95 	startSound(soundName, IMUSE_VOLGRP_SFX, 0, 127, 0, priority, nullptr);
96 }
97 
getPosIn16msTicks(const char * soundName)98 int32 Imuse::getPosIn16msTicks(const char *soundName) {
99 	Common::StackLock lock(_mutex);
100 	Track *getTrack = nullptr;
101 
102 	getTrack = findTrack(soundName);
103 	// Warn the user if the track was not found
104 	if (getTrack == nullptr) {
105 		Debug::warning(Debug::Sound, "Sound '%s' could not be found to get ticks", soundName);
106 		return false;
107 	}
108 
109 	int32 pos = (62.5 / 60.0) * (5 * (getTrack->dataOffset + getTrack->regionOffset)) / (getTrack->feedSize / 12); // 16ms is 62.5 Hz
110 	return pos;
111 }
112 
isVoicePlaying()113 bool Imuse::isVoicePlaying() {
114 	Common::StackLock lock(_mutex);
115 	for (int l = 0; l < MAX_IMUSE_TRACKS; l++) {
116 		Track *track = _track[l];
117 		if (track->used && track->volGroupId == IMUSE_VOLGRP_VOICE) {
118 			if (g_system->getMixer()->isSoundHandleActive(track->handle))
119 				return true;
120 		}
121 	}
122 
123 	return false;
124 }
125 
getSoundStatus(const char * soundName)126 bool Imuse::getSoundStatus(const char *soundName) {
127 	Common::StackLock lock(_mutex);
128 	Track *track = nullptr;
129 
130 	// If there's no name then don't try to get the status!
131 	if (strlen(soundName) == 0)
132 		return false;
133 
134 	track = findTrack(soundName);
135 	// Warn the user if the track was not found
136 	if (track == nullptr || !g_system->getMixer()->isSoundHandleActive(track->handle)) {
137 		// This debug warning should be "light" since this function gets called
138 		// on occassion to see if a sound has stopped yet
139 		Debug::debug(Debug::Sound, "Sound '%s' could not be found to get status, assume inactive.", soundName);
140 		return false;
141 	}
142 	return true;
143 }
144 
stopSound(const char * soundName)145 void Imuse::stopSound(const char *soundName) {
146 	Common::StackLock lock(_mutex);
147 	Debug::debug(Debug::Sound, "Imuse::stopSound(): SoundName %s", soundName);
148 	Track *removeTrack = nullptr;
149 
150 	removeTrack = findTrack(soundName);
151 	// Warn the user if the track was not found
152 	if (removeTrack == nullptr) {
153 		Debug::warning(Debug::Sound, "Sound track '%s' could not be found to stop", soundName);
154 		return;
155 	}
156 	flushTrack(removeTrack);
157 }
158 
stopAllSounds()159 void Imuse::stopAllSounds() {
160 	Common::StackLock lock(_mutex);
161 	Debug::debug(Debug::Sound, "Imuse::stopAllSounds()");
162 
163 	for (int l = 0; l < MAX_IMUSE_TRACKS + MAX_IMUSE_FADETRACKS; l++) {
164 		Track *track = _track[l];
165 		if (track->used) {
166 			g_system->getMixer()->stopHandle(track->handle);
167 			if (track->soundDesc) {
168 				_sound->closeSound(track->soundDesc);
169 			}
170 			track->clear();
171 		}
172 	}
173 }
174 
pause(bool p)175 void Imuse::pause(bool p) {
176 	_pause = p;
177 }
178 
179 } // end of namespace Grim
180