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 SCI_MUSIC_H
24 #define SCI_MUSIC_H
25 
26 #include "common/serializer.h"
27 #include "common/mutex.h"
28 
29 #include "audio/mixer.h"
30 
31 #include "sci/sci.h"
32 #include "sci/resource/resource.h"
33 #include "sci/sound/drivers/mididriver.h"
34 #ifdef ENABLE_SCI32
35 #include "sci/sound/audio32.h"
36 #endif
37 
38 namespace Audio {
39 class LoopingAudioStream;
40 class RewindableAudioStream;
41 }
42 
43 namespace Sci {
44 
45 enum SoundStatus {
46 	kSoundStopped = 0,
47 	kSoundInitialized = 1,
48 	kSoundPaused = 2,
49 	kSoundPlaying = 3
50 };
51 
52 #define MUSIC_VOLUME_DEFAULT 127
53 #define MUSIC_VOLUME_MAX 127
54 #define MUSIC_MASTERVOLUME_DEFAULT 15
55 #define MUSIC_MASTERVOLUME_MAX 15
56 
57 class MidiParser_SCI;
58 class SegManager;
59 
60 typedef Common::Array<uint16> SignalQueue;
61 
62 
63 struct MusicEntryChannel {
64 	// Channel info
65 	int8 _prio; // 0 = essential; lower is higher priority
66 	int8 _voices;
67 	bool _dontRemap;
68 	bool _dontMap;
69 	bool _mute;
70 };
71 
72 
73 class MusicEntry : public Common::Serializable {
74 public:
75 	// Do not get these directly for the sound objects!
76 	// It's a bad idea, as the sound code (i.e. the SciMusic
77 	// class) should be as separate as possible from the rest
78 	// of the engine
79 
80 	reg_t soundObj;
81 
82 	SoundResource *soundRes;
83 	uint16 resourceId;
84 
85 	int time; // "tim"estamp to indicate in which order songs have been added
86 
87 	uint16 dataInc;
88 	uint16 ticker;
89 	uint16 signal;
90 	int16 priority; // must be int16, at least in Laura Bow 1, main music (object conMusic) uses priority -1
91 	uint16 loop;
92 	int16 volume;
93 	int16 hold;
94 	int8 reverb;
95 	bool playBed;
96 	bool overridePriority; // Use soundObj's priority instead of resource's
97 
98 	int16 pauseCounter;
99 	uint sampleLoopCounter;
100 
101 	byte fadeTo;
102 	short fadeStep;
103 	uint32 fadeTicker;
104 	uint32 fadeTickerStep;
105 	bool fadeSetVolume;
106 	bool fadeCompleted;
107 	bool stopAfterFading;
108 
109 	SoundStatus status;
110 
111 	Audio::Mixer::SoundType soundType;
112 
113 	int _usedChannels[16];
114 	MusicEntryChannel _chan[16];
115 	MidiParser_SCI *pMidiParser;
116 
117 	// this is used for storing signals, when the current signal is not yet
118 	//  sent to the scripts. We shouldn't need to save it, this normally only
119 	//  happens in rare situations like lb1, knocking on the door in the attic
120 	SignalQueue signalQueue;
121 
122 	// TODO: We need to revise how we store the different
123 	// audio stream objects we require.
124 	Audio::RewindableAudioStream *pStreamAud;
125 	Audio::LoopingAudioStream *pLoopStream;
126 	Audio::SoundHandle hCurrentAud;
127 	bool isSample;
128 
129 public:
130 	MusicEntry();
131 	~MusicEntry() override;
132 
133 	void doFade();
134 	void onTimer();
135 	void setSignal(int signal);
136 
137 	void saveLoadWithSerializer(Common::Serializer &ser) override;
138 };
139 
140 struct DeviceChannelUsage {
141 	MusicEntry *_song;
142 	int _channel;
143 	bool operator==(const DeviceChannelUsage& other) const { return _song == other._song && _channel == other._channel; }
144 	bool operator!=(const DeviceChannelUsage& other) const { return !(*this == other); }
145 };
146 
147 struct ChannelRemapping {
148 	DeviceChannelUsage _map[16];
149 	int _prio[16];
150 	int _voices[16];
151 	bool _dontRemap[16];
152 	int _freeVoices;
153 
154 	void clear();
155 	void swap(int i, int j);
156 	void evict(int i);
157 	ChannelRemapping& operator=(ChannelRemapping& other);
158 	int lowestPrio() const;
159 };
160 
161 struct MidiCommand {
162 	enum CmdType {
163 		kTypeMidiMessage = 0,
164 		kTypeTrackInit
165 	};
166 	// Keeping this very simple, due to the very limited purpose of it.
MidiCommandMidiCommand167 	MidiCommand(CmdType type, uint32 val) : _type(type), _dataPtr(0), _dataVal(val) {}
MidiCommandMidiCommand168 	MidiCommand(CmdType type, void *ptr) : _type(type), _dataPtr(ptr), _dataVal(0) {}
169 	CmdType _type;
170 	void *_dataPtr;
171 	uint32 _dataVal;
172 };
173 
174 typedef Common::Array<MusicEntry *> MusicList;
175 typedef Common::Array<MidiCommand> MidiCommandQueue;
176 
177 class SciMusic : public Common::Serializable {
178 
179 public:
180 	SciMusic(SciVersion soundVersion, bool useDigitalSFX);
181 	~SciMusic() override;
182 
183 	void init();
184 
185 	void onTimer();
186 	void putMidiCommandInQueue(byte status, byte firstOp, byte secondOp);
187 	void putMidiCommandInQueue(uint32 midi);
188 	void putTrackInitCommandInQueue(MusicEntry *psnd);
189 	void removeTrackInitCommandsFromQueue(MusicEntry *psnd);
190 private:
191 	static void miditimerCallback(void *p);
192 	void sendMidiCommandsFromQueue();
193 
194 public:
195 	void clearPlayList();
196 	void pauseAll(bool pause);
197 	void stopAll();
198 	void stopAllSamples();
199 
200 	// sound and midi functions
201 	void soundInitSnd(MusicEntry *pSnd);
202 	void soundPlay(MusicEntry *pSnd, bool restoring = false);
203 	void soundStop(MusicEntry *pSnd);
204 	void soundKill(MusicEntry *pSnd);
205 	void soundPause(MusicEntry *pSnd);
206 	void soundResume(MusicEntry *pSnd);
207 	void soundToggle(MusicEntry *pSnd, bool pause);
208 	void soundSetVolume(MusicEntry *pSnd, byte volume);
209 	void soundSetSampleVolume(MusicEntry *pSnd, byte volume);
210 	void soundSetPriority(MusicEntry *pSnd, byte prio);
211 	uint16 soundGetMasterVolume();
212 	void soundSetMasterVolume(uint16 vol);
soundGetSoundOn()213 	uint16 soundGetSoundOn() const { return _soundOn; }
214 	void soundSetSoundOn(bool soundOnFlag);
215 	uint16 soundGetVoices();
soundGetTempo()216 	uint32 soundGetTempo() const { return _dwTempo; }
soundGetMusicType()217 	MusicType soundGetMusicType() const { return _musicType; }
218 
soundIsActive(MusicEntry * pSnd)219 	bool soundIsActive(MusicEntry *pSnd) {
220 		assert(pSnd->pStreamAud != 0);
221 		return _pMixer->isSoundHandleActive(pSnd->hCurrentAud);
222 	}
223 
updateAudioStreamTicker(MusicEntry * pSnd)224 	void updateAudioStreamTicker(MusicEntry *pSnd) {
225 		assert(pSnd->pStreamAud != 0);
226 		pSnd->ticker = (uint16)(_pMixer->getSoundElapsedTime(pSnd->hCurrentAud) * 0.06);
227 	}
228 
229 	MusicEntry *getSlot(reg_t obj);
230 	MusicEntry *getFirstSlotWithStatus(SoundStatus status);
231 
pushBackSlot(MusicEntry * slotEntry)232 	void pushBackSlot(MusicEntry *slotEntry) {
233 		Common::StackLock lock(_mutex);
234 		_playList.push_back(slotEntry);
235 		if (_soundVersion <= SCI_VERSION_0_LATE) // I limit this to SCI0, since it always inserts the nodes at the correct position, but no idea about >=SCI1
236 			sortPlayList();
237 	}
238 
239 	void printPlayList(Console *con);
240 	void printSongInfo(reg_t obj, Console *con);
241 
242 	// The following two methods are NOT thread safe - make sure that
243 	// the mutex is always locked before calling them
getPlayListStart()244 	MusicList::iterator getPlayListStart() { return _playList.begin(); }
getPlayListEnd()245 	MusicList::iterator getPlayListEnd() { return _playList.end(); }
246 
247 	void sendMidiCommand(uint32 cmd);
248 	void sendMidiCommand(MusicEntry *pSnd, uint32 cmd);
249 
250 	void setGlobalReverb(int8 reverb);
getGlobalReverb()251 	int8 getGlobalReverb() { return _globalReverb; }
252 
253 	byte getCurrentReverb();
254 
needsRemap()255 	void needsRemap() { _needsRemap = true; }
256 
257 	void saveLoadWithSerializer(Common::Serializer &ser) override;
258 
259 	// Mutex for music code. Used to guard access to the song playlist, to the
260 	// MIDI parser and to the MIDI driver/player. Note that guarded code must NOT
261 	// include references to the mixer, otherwise there will probably be situations
262 	// where a deadlock can occur
263 	Common::Mutex _mutex;
264 
265 protected:
266 	void sortPlayList();
267 
268 	SciVersion _soundVersion;
269 
270 	Audio::Mixer *_pMixer;
271 	MidiPlayer *_pMidiDrv;
272 
273 	uint32 _dwTempo;
274 	// If true and a sound has a digital track, the sound from the AdLib track is played
275 	bool _useDigitalSFX;
276 
277 	// remapping:
278 	void remapChannels(bool mainThread = true);
279 	ChannelRemapping *determineChannelMap();
280 	void resetDeviceChannel(int devChannel, bool mainThread);
281 
282 private:
283 	MusicList _playList;
284 	bool _soundOn;
285 	byte _masterVolume;
286 	MusicEntry *_usedChannel[16];
287 	int8 _channelRemap[16];
288 	int8 _globalReverb;
289 	bool _needsRemap;
290 	int _globalPause;
291 	bool _needsResume;
292 
293 	DeviceChannelUsage _channelMap[16];
294 
295 	MidiCommandQueue _queuedCommands;
296 	MusicType _musicType;
297 
298 	int _driverFirstChannel;
299 	int _driverLastChannel;
300 
301 	MusicEntry *_currentlyPlayingSample;
302 
303 	int _timeCounter; // Used to keep track of the order in which MusicEntries
304 	                  // are added, for priority purposes.
305 };
306 
307 } // End of namespace Sci
308 
309 #endif
310