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