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 DIRECTOR_SOUND_H 24 #define DIRECTOR_SOUND_H 25 26 #include "audio/mixer.h" 27 28 namespace Audio { 29 class AudioStream; 30 class SoundHandle; 31 class PCSpeaker; 32 class RewindableAudioStream; 33 } 34 35 namespace Director { 36 37 class AudioDecoder; 38 39 struct FadeParams { 40 int startVol; 41 int targetVol; 42 int totalTicks; 43 int startTicks; 44 int lapsedTicks; 45 bool fadeIn; 46 FadeParamsFadeParams47 FadeParams(int sv, int tv, int tt, int st, bool f) : 48 startVol(sv), targetVol(tv), totalTicks(tt), startTicks(st), lapsedTicks(0), fadeIn(f) {} 49 }; 50 51 const uint16 kMinSampledMenu = 10; 52 const uint16 kMaxSampledMenu = 15; 53 const uint16 kNumSampledMenus = kMaxSampledMenu - kMinSampledMenu + 1; 54 55 struct ExternalSoundID { 56 uint16 menu; 57 uint16 submenu; 58 ExternalSoundIDExternalSoundID59 ExternalSoundID() : menu(0), submenu(0) {} ExternalSoundIDExternalSoundID60 ExternalSoundID(uint16 menuID, uint16 submenuID) 61 : menu(menuID), submenu(submenuID) {} 62 63 bool operator==(const ExternalSoundID &b) { 64 return menu == b.menu && submenu == b.submenu; 65 } 66 bool operator!=(const ExternalSoundID &b) { 67 return !(*this == b); 68 } 69 }; 70 71 enum SoundIDType { 72 kSoundCast, 73 kSoundExternal 74 }; 75 76 struct SoundID { 77 SoundIDType type; 78 union { 79 struct { 80 int member; 81 int castLib; 82 } cast; 83 struct { 84 uint16 menu; 85 uint16 submenu; 86 } external; 87 } u; 88 SoundIDSoundID89 SoundID() { 90 type = kSoundCast; 91 u.cast.member = 0; 92 u.cast.castLib = 0; 93 } SoundIDSoundID94 SoundID(SoundIDType type_, int a, int b) { 95 type = type_; 96 switch (type) { 97 case kSoundCast: 98 u.cast.member = a; 99 u.cast.castLib = b; 100 break; 101 case kSoundExternal: 102 u.external.menu = a; 103 u.external.submenu = b; 104 } 105 } SoundIDSoundID106 SoundID(CastMemberID memberID) { 107 type = kSoundCast; 108 u.cast.member = memberID.member; 109 u.cast.castLib = memberID.castLib; 110 } 111 112 bool operator==(const SoundID &b) { 113 if (type != b.type) 114 return false; 115 116 switch (type) { 117 case kSoundCast: 118 return u.cast.member == b.u.cast.member && u.cast.castLib == b.u.cast.castLib; 119 case kSoundExternal: 120 return u.external.menu == b.u.external.menu && u.external.submenu == b.u.external.submenu; 121 } 122 123 return false; 124 } 125 bool operator!=(const SoundID &b) { 126 return !(*this == b); 127 } 128 }; 129 130 struct SoundChannel { 131 Audio::SoundHandle handle; 132 SoundID lastPlayedSound; 133 bool stopOnZero; // Should the sound be stopped when the channel contains cast member 0? 134 byte volume; 135 FadeParams *fade; 136 137 // a non-zero sound ID if the channel is a puppet. i.e. it's controlled by lingo 138 SoundID puppet; 139 bool newPuppet; 140 141 // this indicate whether the sound is playing across the movie. Because the cast name may be the same while the actual sounds are changing. 142 // And we will override the sound when ever the sound is changing. thus we use a flag to indicate whether the movie is changed. 143 bool movieChanged; 144 SoundChannelSoundChannel145 SoundChannel(): handle(), lastPlayedSound(SoundID()), stopOnZero(true), volume(255), fade(nullptr), puppet(SoundID()), newPuppet(false), movieChanged(false) {} 146 }; 147 148 class DirectorSound { 149 150 private: 151 Window *_window; 152 Common::Array<SoundChannel> _channels; 153 Audio::SoundHandle _scriptSound; 154 Audio::Mixer *_mixer; 155 Audio::PCSpeaker *_speaker; 156 Audio::SoundHandle _pcSpeakerHandle; 157 158 // these two were used in fplay xobj 159 Common::Queue<Common::String> _fplayQueue; 160 Common::String _currentSoundName; 161 162 bool _enable; 163 164 Common::Array<AudioDecoder *> _sampleSounds[kNumSampledMenus]; 165 166 public: 167 DirectorSound(Window *window); 168 ~DirectorSound(); 169 170 SoundChannel *getChannel(uint8 soundChannel); 171 void playFile(Common::String filename, uint8 soundChannel); 172 void playMCI(Audio::AudioStream &stream, uint32 from, uint32 to); 173 void playStream(Audio::AudioStream &stream, uint8 soundChannel); 174 void playSound(SoundID soundId, uint8 soundChannel, bool forPuppet = false); 175 void playCastMember(CastMemberID memberID, uint8 soundChannel, bool forPuppet = false); 176 void playExternalSound(uint16 menu, uint16 submenu, uint8 soundChannel); 177 void playFPlaySound(const Common::Array<Common::String> &fplayList); 178 void playFPlaySound(); 179 void setSouldLevel(int channel, uint8 soundLevel); 180 uint8 getSoundLevel(uint8 soundChannel); 181 void setSoundEnabled(bool enabled); 182 void systemBeep(); 183 void changingMovie(); 184 185 void loadSampleSounds(uint type); 186 void unloadSampleSounds(); 187 188 void setLastPlayedSound(uint8 soundChannel, SoundID soundId, bool stopOnZero = true); 189 bool isLastPlayedSound(uint8 soundChannel, const SoundID &soundId); 190 bool shouldStopOnZero(uint8 soundChannel); 191 192 bool isChannelPuppet(uint8 soundChannel); 193 void setPuppetSound(SoundID soundId, uint8 soundChannel); 194 void playPuppetSound(uint8 soundChannel); 195 getSoundEnabled()196 bool getSoundEnabled() { return _enable; } 197 getCurrentSound()198 Common::String getCurrentSound() { return _currentSoundName; } 199 200 void registerFade(uint8 soundChannel, bool fadeIn, int ticks); 201 bool fadeChannel(uint8 soundChannel); 202 203 bool isChannelActive(uint8 soundChannel); 204 void stopSound(uint8 soundChannel); 205 void stopSound(); 206 207 private: 208 uint8 getChannelVolume(uint8 soundChannel); 209 void setSoundLevelInternal(uint8 soundChannel, uint8 soundLevel); 210 bool isChannelValid(uint8 soundChannel); 211 void cancelFade(uint8 soundChannel); 212 }; 213 214 class AudioDecoder { 215 public: AudioDecoder()216 AudioDecoder() {}; ~AudioDecoder()217 virtual ~AudioDecoder() {}; 218 public: 219 virtual Audio::AudioStream *getAudioStream(bool looping = false, bool forPuppet = false, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES) { return nullptr; } 220 }; 221 222 class SNDDecoder : public AudioDecoder { 223 public: 224 SNDDecoder(); 225 ~SNDDecoder(); 226 227 bool loadStream(Common::SeekableReadStreamEndian &stream); 228 void loadExternalSoundStream(Common::SeekableReadStreamEndian &stream); 229 bool processCommands(Common::SeekableReadStreamEndian &stream); 230 bool processBufferCommand(Common::SeekableReadStreamEndian &stream); 231 Audio::AudioStream *getAudioStream(bool looping = false, bool forPuppet = false, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES) override; 232 bool hasLoopBounds(); 233 234 private: 235 byte *_data; 236 uint16 _channels; 237 uint32 _size; 238 uint16 _rate; 239 byte _flags; 240 uint32 _loopStart; 241 uint32 _loopEnd; 242 }; 243 244 class AudioFileDecoder : public AudioDecoder { 245 public: 246 AudioFileDecoder(Common::String &path); ~AudioFileDecoder()247 ~AudioFileDecoder() {}; 248 249 void setPath(Common::String &path); 250 251 Audio::AudioStream *getAudioStream(bool looping = false, bool forPuppet = false, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES) override; 252 253 private: 254 Common::String _path; 255 }; 256 257 } // End of namespace Director 258 259 #endif 260