aboutsummaryrefslogtreecommitdiff
path: root/engines/lastexpress/game/sound.h
blob: 5b1fe64cd8a5ad3721364dbce2896e1edbf881cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#ifndef LASTEXPRESS_SOUND_H
#define LASTEXPRESS_SOUND_H

/*

	Sound entry: 68 bytes (this is what appears in the savegames)
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    uint32 {4}      - entity
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    char {16}       - name 1
	    char {16}       - name 2

	Sound queue entry: 120 bytes
	    uint16 {2}      - status
	    byte {1}        - ??
	    byte {1}        - ??
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    uint32 {4}      - file data pointer
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    uint32 {4}      - archive structure pointer
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    uint32 {4}      - entity
	    uint32 {4}      - ??
	    uint32 {4}      - ??
	    char {16}       - name 1
	    char {16}       - name 2
	    uint32 {4}      - pointer to next entry in the queue
	    uint32 {4}      - subtitle data pointer

*/

#include "lastexpress/data/snd.h"
#include "lastexpress/data/subtitle.h"

#include "lastexpress/shared.h"

#include "lastexpress/helpers.h"

#include "common/list.h"
#include "common/mutex.h"
#include "common/system.h"
#include "common/serializer.h"

namespace LastExpress {

class LastExpressEngine;
class SubtitleManager;

class SoundManager : Common::Serializable {
public:
	enum SoundType {
		kSoundTypeNone = 0,
		kSoundType1,
		kSoundType2,
		kSoundType3,
		kSoundType4,
		kSoundType5,
		kSoundType6,
		kSoundType7,
		kSoundType8,
		kSoundType9,
		kSoundType10,
		kSoundType11,
		kSoundType12,
		kSoundType13,
		kSoundType14,
		kSoundType15,
		kSoundType16
	};

	enum FlagType {
		kFlagInvalid     = -1,
		kFlagNone        = 0x0,
		kFlag2           = 0x2,
		kFlag3           = 0x3,
		kFlag4           = 0x4,
		kFlag5           = 0x5,
		kFlag6           = 0x6,
		kFlag7           = 0x7,
		kFlag8           = 0x8,
		kFlag9           = 0x9,
		kFlag10          = 0xA,
		kFlag11          = 0xB,
		kFlag12          = 0xC,
		kFlag13          = 0xD,
		kFlag14          = 0xE,
		kFlag15          = 0xF,
		kFlagDefault     = 0x10,

		kFlagType1_2     = 0x1000000,
		kFlagSteam       = 0x1001007,
		kFlagType13      = 0x3000000,
		kFlagMenuClock   = 0x3080010,
		kFlagType7       = 0x4000000,
		kFlagType11      = 0x5000000,
		kFlagMusic       = 0x5000010,
		kFlagType3       = 0x6000000,
		kFlagLoop        = 0x6001008,
		kFlagType9       = 0x7000000
	};

	SoundManager(LastExpressEngine *engine);
	~SoundManager();

	// Timer
	void handleTimer();

	// State
	void resetState() { _state |= kSoundType1; }

	// Sound queue
	void updateQueue();
	void resetQueue(SoundType type1, SoundType type2 = kSoundTypeNone);
	void clearQueue();

	// Subtitles
	void updateSubtitles();

	// Entry
	bool isBuffered(Common::String filename, bool testForEntity = false);
	bool isBuffered(EntityIndex entity);
	void setupEntry(SoundType type, EntityIndex index);
	void processEntry(EntityIndex entity);
	void processEntry(SoundType type);
	void processEntry(Common::String filename);
	void processEntries();
	void removeFromQueue(Common::String filename);
	void removeFromQueue(EntityIndex entity);
	uint32 getEntryTime(EntityIndex index);

	// Misc
	void unknownFunction4();
	void clearStatus();

	// Sound playing
	void playSound(EntityIndex entity, Common::String filename, FlagType flag = kFlagInvalid, byte a4 = 0);
	bool playSoundWithSubtitles(Common::String filename, FlagType flag, EntityIndex entity, byte a4 = 0);
	void playSoundEvent(EntityIndex entity, byte action, byte a3 = 0);
	void playDialog(EntityIndex entity, EntityIndex entityDialog, FlagType flag, byte a4);
	void playSteam(CityIndex index);
	void playFightSound(byte action, byte a4);
	void playLocomotiveSound();
	void playWarningCompartment(EntityIndex entity, ObjectIndex compartment);

	// Dialog & Letters
	void readText(int id);
	const char *getDialogName(EntityIndex entity) const;

	// Sound bites
	void excuseMe(EntityIndex entity, EntityIndex entity2 = kEntityPlayer, FlagType flag = kFlagNone);
	void excuseMeCath();
	const char *justCheckingCath() const;
	const char *wrongDoorCath() const;
	const char *justAMinuteCath() const;

	// FLags
	SoundManager::FlagType getSoundFlag(EntityIndex index) const;

	// Debug
	void stopAllSound();

	// Serializable
	void saveLoadWithSerializer(Common::Serializer &ser);
	uint32 count();

private:
	typedef int32 *SoundBuffer;

	enum SoundStatus {
		kSoundStatus_20       = 0x20,
		kSoundStatus_40       = 0x40,
		kSoundStatus_180      = 0x180,
		kSoundStatusRemoved   = 0x200,
		kSoundStatus_400      = 0x400,

		kSoundStatus_8000     = 0x8000,
		kSoundStatus_20000    = 0x20000,
		kSoundStatus_100000   = 0x100000,
		kSoundStatus_40000000 = 0x40000000,

		kSoundStatusClear0    = 0x10,
		kSoundStatusClear1    = 0x1F,
		kSoundStatusClear2    = 0x80,
		kSoundStatusClear3    = 0x200,
		kSoundStatusClear4    = 0x800,
		kSoundStatusClearAll  = 0xFFFFFFE0
	};

	enum SoundState {
		kSoundState0 = 0,
		kSoundState1 = 1,
		kSoundState2 = 2
	};

	union SoundStatusUnion {
		uint32 status;
		byte status1;
		byte status2;
		byte status3;
		byte status4;

		SoundStatusUnion() {
			status = 0;
		}
	};

	struct SubtitleEntry;

	struct SoundEntry {
		SoundStatusUnion status;
		SoundType type;    // int
		//int field_8;
		//int field_C;
		int processedFrameCount;
		void *soundData;
		//int field_18;
		int field_1C;
		uint32 time;
		//int field_24;
		//int field_28;
		Common::SeekableReadStream *stream;	// int
		//int field_30;
		int field_34;
		int field_38;
		int field_3C;
		int field_40;
		EntityIndex entity;
		int field_48;
		uint32 field_4C;
		Common::String name1; //char[16];
		Common::String name2; //char[16];
		//int next; // offset to the next structure in the list (not used)
		SubtitleEntry *subtitle;

		// Sound stream
		StreamedSound *soundStream;

		SoundEntry() {
			status.status = 0;
			type = kSoundTypeNone;

			processedFrameCount = 0;
			soundData = NULL;

			field_1C = 0;
			time = 0;

			stream = NULL;

			field_34 = 0;
			field_38 = 0;
			field_3C = 0;
			field_40 = 0;
			entity = kEntityPlayer;
			field_48 = 0;
			field_4C = 0;

			subtitle = NULL;

			soundStream = NULL;
		}

		~SoundEntry() {
			// Entries that have been queued would have their streamed disposed automatically
			if (!soundStream)
				SAFE_DELETE(stream);

			delete soundStream;
		}
	};

	struct SubtitleEntry {
		Common::String filename;
		SoundStatusUnion status;
		SoundEntry *sound;
		SubtitleManager *data;

		SubtitleEntry() {
			status.status = 0;
			sound = NULL;
			data = NULL;
		}

		~SubtitleEntry() {
			SAFE_DELETE(data);
		}
	};

	// Engine
	LastExpressEngine *_engine;

	// State flag
	int _state;
	SoundType _currentType;

	Common::Mutex _mutex;

	// Unknown data
	uint32 _data0;
	uint32 _data1;
	uint32 _data2;
	uint32 _flag;

	// Filters
	int32 _buffer[2940];    ///< Static sound buffer

	// Compartment warnings by Mertens or Coudert
	uint32 _lastWarning[12];

	// Looping sound
	void playLoopingSound();

	// Sound entries
	Common::List<SoundEntry *> _soundList;    ///< List of all sound entries
	Common::List<SoundEntry *> _soundCache;   ///< List of entries with a data buffer
	void *_soundCacheData;

	SoundEntry *getEntry(EntityIndex index);
	SoundEntry *getEntry(Common::String name);
	SoundEntry *getEntry(SoundType type);

	void setupEntry(SoundEntry *entry, Common::String name, FlagType flag, int a4);
	void setEntryType(SoundEntry *entry, FlagType flag);
	void setEntryStatus(SoundEntry *entry, FlagType flag) const;
	void setInCache(SoundEntry *entry);
	bool setupCache(SoundEntry *entry);
	void removeFromCache(SoundEntry *entry);
	void loadSoundData(SoundEntry *entry, Common::String name);

	void updateEntry(SoundEntry *entry, uint value) const;
	void updateEntryState(SoundEntry *entry) const;
	void resetEntry(SoundEntry *entry) const;
	void removeEntry(SoundEntry *entry);

	// Subtitles
	int _drawSubtitles;
	Common::List<SubtitleEntry *> _subtitles;
	SubtitleEntry *_currentSubtitle;
	void showSubtitle(SoundEntry *entry, Common::String filename);
	SubtitleEntry *loadSubtitle(Common::String filename, SoundEntry *soundEntry);
	void loadSubtitleData(SubtitleEntry * entry);
	void setupSubtitleAndDraw(SubtitleEntry *subtitle);
	void drawSubtitle(SubtitleEntry *subtitle);
	void drawSubtitleOnScreen(SubtitleEntry *subtitle);

	// Sound filter
	void applyFilter(SoundEntry *entry, int16 *buffer);
};

} // End of namespace LastExpress

#endif // LASTEXPRESS_SOUND_H