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