ScummVM API documentation
imuse_internal.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 SCUMM_IMUSE_INTERNAL
23#define SCUMM_IMUSE_INTERNAL
24
25#include "common/scummsys.h"
26#include "common/serializer.h"
27#include "scumm/imuse/imuse.h"
28#include "scumm/imuse/instrument.h"
29#include "audio/mididrv.h"
30
31class MidiParser;
32class OSystem;
33
34namespace Scumm {
35
36struct ParameterFader;
37struct DeferredCommand;
38struct ImTrigger;
39struct SustainingNotes;
40struct CommandQueue;
41struct IsNoteCmdData;
42class Player;
43struct Part;
44class IMuseInternal;
45class IMuseSysex_Scumm;
46
47
48
50//
51// Some constants
52//
54
55#define TICKS_PER_BEAT 480
56
57#define TRIGGER_ID 0
58#define COMMAND_ID 1
59
60#define MUS_REDUCTION_TIMER_TICKS 16667 // 60 Hz
61
62
64//
65// Helper functions
66//
68
69inline int clamp(int val, int min, int max) {
70 if (val < min)
71 return min;
72 if (val > max)
73 return max;
74 return val;
75}
76
77inline int transpose_clamp(int a, int b, int c) {
78 if (b > a)
79 a += (b - a + 11) / 12 * 12;
80 if (c < a)
81 a -= (a - c + 11) / 12 * 12;
82 return a;
83}
84
85
86
88//
89// Entity declarations
90//
92
94 IMuseInternal *imuse = nullptr;
95 MidiDriver *driver = nullptr;
96};
97
98struct HookDatas {
99 byte _jump[2];
100 byte _transpose;
101 byte _part_onoff[16];
102 byte _part_volume[16];
103 byte _part_program[16];
104 byte _part_transpose[16];
105
106 int query_param(int param, byte chan);
107 int set(byte cls, byte value, byte chan);
108 HookDatas() { reset(); }
109 void reset() {
110 _transpose = 0;
111 memset(_jump, 0, sizeof(_jump));
112 memset(_part_onoff, 0, sizeof(_part_onoff));
113 memset(_part_volume, 0, sizeof(_part_volume));
114 memset(_part_program, 0, sizeof(_part_program));
115 memset(_part_transpose, 0, sizeof(_part_transpose));
116 }
117};
118
120 enum {
121 pfVolume = 1,
122 pfTranspose = 3,
123 pfSpeed = 4
124 };
125
126 int param;
127 int8 dir;
128 int16 incr;
129 uint16 ifrac;
130 uint16 irem;
131 uint16 ttime;
132 uint16 cntdwn;
133 int16 state;
134
135 ParameterFader() : param(0), dir(0), incr(0), ifrac(0), irem(0), ttime(0), cntdwn(0), state(0) {}
136 void init() { param = 0; }
137};
138
140 uint32 time_left;
141 int a, b, c, d, e, f;
142 DeferredCommand() { memset(this, 0, sizeof(DeferredCommand)); }
143};
144
145struct ImTrigger {
146 int sound;
147 byte id;
148 uint16 expire;
149 int command[8];
150 ImTrigger() { memset(this, 0, sizeof(ImTrigger)); }
151};
152
154 uint16 array[8];
155 CommandQueue() { memset(this, 0, sizeof(CommandQueue)); }
156};
157
158
159
161//
162// Player class definition
163//
165
167 /*
168 * External SysEx handler functions shall each be defined in
169 * a separate file. This header file shall be included at the
170 * top of the file immediately following this special #define:
171 * #define SYSEX_CALLBACK_FUNCTION nameOfHandlerFunction
172 */
173#ifdef SYSEX_CALLBACK_FUNCTION
174 friend void SYSEX_CALLBACK_FUNCTION(Player *, const byte *, uint16);
175#endif
176
177protected:
178 // Moved from IMuseInternal.
179 // This is only used by one player at a time.
180 static uint16 _active_notes[128];
181
182protected:
183 enum ParserType {
184 kParserTypeNone = 0,
185 kParserTypeRO,
186 kParserTypeXMI,
187 kParserTypeSMF
188 };
189
190 MidiDriver *_midi;
191 MidiParser *_parser;
192 ParserType _parserType;
193
194 Part *_parts;
195 bool _active;
196 bool _scanning;
197 int _id;
198 byte _priority;
199 byte _volume;
200 int8 _pan;
201 int8 _transpose;
202 int16 _detune;
203 int _note_offset;
204 byte _vol_eff;
205
206 uint _track_index;
207 uint _loop_to_beat;
208 uint _loop_from_beat;
209 uint _loop_counter;
210 uint _loop_to_tick;
211 uint _loop_from_tick;
212 byte _speed;
213 bool _abort;
214
215 uint32 _transitionTimer;
216
217 // This does not get used by us! It is only
218 // here for save/load purposes, and gets
219 // passed on to the MidiParser during
220 // fixAfterLoad().
221 uint32 _music_tick;
222
223 HookDatas _hook;
224 ParameterFader _parameterFaders[4];
225
226 bool _isMIDI;
227 bool _isMT32;
228 bool _supportsPercussion;
229
230protected:
231 // Player part
232 void hook_clear();
233 void uninit_parts();
234 void part_set_transpose(uint8 chan, byte relative, int8 b);
235 void maybe_jump(byte cmd, uint track, uint beat, uint tick);
236 void maybe_set_transpose(byte *data);
237 void maybe_part_onoff(byte *data);
238 void maybe_set_volume(byte *data);
239 void maybe_set_program(byte *data);
240 void maybe_set_transpose_part(byte *data);
241 void turn_off_pedals();
242 int query_part_param(int param, byte chan);
243 void turn_off_parts();
244 void play_active_notes();
245
246 void transitionParameters();
247
248 static void decode_sysex_bytes(const byte *src, byte *dst, int len);
249
250 // Sequencer part
251 int start_seq_sound(int sound, bool reset_vars = true);
252 void loadStartParameters(int sound);
253
254public:
255 IMuseInternal *_se;
256 uint _vol_chan;
257
258public:
259 Player();
260 ~Player() override;
261
262 int addParameterFader(int param, int target, int time);
263 void clear();
264 void clearLoop();
265 void fixAfterLoad();
266 Part *getActivePart(uint8 part);
267 uint getBeatIndex();
268 int16 getDetune() const { return _detune; }
269 byte getEffectiveVolume() const { return _vol_eff; }
270 int getID() const { return _id; }
271 MidiDriver *getMidiDriver() const { return _midi; }
272 int getParam(int param, byte chan);
273 int8 getPan() const { return _pan; }
274 Part *getPart(uint8 part);
275 byte getPriority() const { return _priority; }
276 uint getTicksPerBeat() const { return TICKS_PER_BEAT; }
277 int8 getTranspose() const { return _transpose; }
278 byte getVolume() const { return _volume; }
279 bool isActive() const { return _active; }
280 bool isFadingOut() const;
281 bool isMIDI() const { return _isMIDI; }
282 bool isMT32() const { return _isMT32; }
283 bool jump(uint track, uint beat, uint tick);
284 void onTimer();
285 void removePart(Part *part);
286 int scan(uint totrack, uint tobeat, uint totick);
287 void saveLoadWithSerializer(Common::Serializer &ser) override;
288 int setHook(byte cls, byte value, byte chan) { return _hook.set(cls, value, chan); }
289 void setDetune(int detune);
290 void setOffsetNote(int offset);
291 bool setLoop(uint count, uint tobeat, uint totick, uint frombeat, uint fromtick);
292 void setPan(int pan);
293 void setPriority(int pri);
294 void setSpeed(byte speed);
295 int setTranspose(byte relative, int b);
296 int setVolume(byte vol);
297 bool startSound(int sound, MidiDriver *midi);
298 int getMusicTimer() const;
299
300public:
301 // MidiDriver interface
302 void send(uint32 b) override;
303 void sysEx(const byte *msg, uint16 length) override;
304 uint16 sysExNoDelay(const byte *msg, uint16 length) override;
305 void metaEvent(byte type, const byte *data, uint16 length) override;
306};
307
308
309
311//
312// Part pseudo-class definition
313//
315
316struct Part : public Common::Serializable {
317 IMuseInternal *_se;
318 int _slot;
319 Part *_next, *_prev;
320 MidiChannel *_mc;
321 Player *_player;
322 int16 _pitchbend;
323 byte _pitchbend_factor;
324 byte _volControlSensitivity;
325 int8 _transpose, _transpose_eff;
326 byte _vol, _vol_eff;
327 int8 _detune;
328 int16 _detune_eff;
329 int8 _pan, _pan_eff;
330 byte _polyphony;
331 bool _on;
332 byte _modwheel;
333 bool _pedal;
334 int8 _pri;
335 byte _pri_eff;
336 byte _chan;
337 byte _effect_level;
338 byte _chorus;
339 byte _percussion;
340 byte _bank;
341
342 // New abstract instrument definition
343 Instrument _instrument;
344 bool _unassigned_instrument; // For diagnostic reporting purposes only
345
346 // MidiChannel interface
347 // (We don't currently derive from MidiChannel,
348 // but if we ever do, this will make it easy.)
349 void noteOff(byte note);
350 void noteOn(byte note, byte velocity);
351 void programChange(byte value);
352 void pitchBend(int16 value);
353 void modulationWheel(byte value);
354 void volume(byte value);
355 void volControlSensitivity(byte value);
356 void pitchBendFactor(byte value);
357 void sustain(bool value);
358 void effectLevel(byte value);
359 void chorusLevel(byte value);
360 void allNotesOff();
361
362 void set_param(byte param, int value) { }
363 void init(bool useNativeMT32);
364 void setup(Player *player);
365 void uninit();
366 void off(bool releaseChannel);
367 void set_instrument(uint b);
368 void set_instrument(byte *data);
369 void load_global_instrument(byte b);
370
371 void set_transpose(int8 transpose, int8 clipRangeLow, int8 clipRangeHi);
372 void set_detune(int8 detune);
373 void set_pri(int8 pri);
374 void set_pan(int8 pan);
375
376 void set_polyphony(byte val);
377 void set_onoff(bool on);
378 void fix_after_load();
379
380 void sendAll();
381 bool clearToTransmit();
382
383 Part();
384
385 void saveLoadWithSerializer(Common::Serializer &ser) override;
386
387private:
388 void sendPitchBend();
389 void sendVolume(int8 fadeModifier);
390 void sendVolumeFade();
391 void sendTranspose();
392 void sendDetune();
393 void sendPanPosition(uint8 value);
394 void sendEffectLevel(uint8 value);
395 void sendPolyphony();
396};
397
398
399
404class IMuseInternal : public IMuse {
405 friend class Player;
406 friend struct Part;
407
408 /*
409 * External SysEx handler functions shall each be defined in
410 * a separate file. This header file shall be included at the
411 * top of the file immediately following this special #define:
412 * #define SYSEX_CALLBACK_FUNCTION nameOfHandlerFunction
413 */
414#ifdef SYSEX_CALLBACK_FUNCTION
415 friend void SYSEX_CALLBACK_FUNCTION(Player *, const byte *, uint16);
416#endif
417
418protected:
419 ScummEngine *_vm;
420 const bool _native_mt32;
421 const bool _newSystem;
422 const bool _dynamicChanAllocation;
423 const MidiDriverFlags _soundType;
424 MidiDriver *_midi_adlib;
425 MidiDriver *_midi_native;
426 TimerCallbackInfo _timer_info_adlib;
427 TimerCallbackInfo _timer_info_native;
428
429 const uint32 _game_id;
430
431 // Plug-in SysEx handling. Right now this only supports one
432 // custom SysEx handler for the hardcoded IMUSE_SYSEX_ID
433 // manufacturer code. TODO: Expand this to support multiple
434 // SysEx handlers for client-specified manufacturer codes.
435 sysexfunc _sysex;
436
437 Common::Mutex &_mutex;
438 Common::Mutex _dummyMutex;
439
440protected:
441 bool _paused;
442 bool _initialized;
443
444 int _tempoFactor;
445
446 int _player_limit; // Limits how many simultaneous music tracks are played
447 bool _recycle_players; // Can we stop a player in order to start another one?
448
449 int _musicVolumeReductionTimer = 0; // 60 Hz
450
451 uint _queue_end, _queue_pos, _queue_sound;
452 byte _queue_adding;
453
454 byte _queue_marker;
455 byte _queue_cleared;
456 byte _master_volume; // Master volume. 0-255
457 byte _music_volume; // Music volume which can be reduced during speech. 0-255
458 byte _music_volume_eff; // Global effective music volume. 0-255
459
460 uint16 _trigger_count;
461 ImTrigger _snm_triggers[16]; // Sam & Max triggers
462 uint16 _snm_trigger_index;
463
464 uint16 _channel_volume[8];
465 uint16 _channel_volume_eff[8]; // No Save
466 uint16 _volchan_table[8];
467
468 Player _players[8];
469 Part _parts[32];
470
471 Instrument _global_instruments[32];
472 CommandQueue _cmd_queue[64];
473 DeferredCommand _deferredCommands[4];
474
475 // These are basically static vars in the original drivers
476 struct RhyState {
477 RhyState() : RhyState(127, 1, 0) {}
478 RhyState(byte volume, byte polyphony, byte priority) : vol(volume), poly(polyphony), prio(priority) {}
479 byte vol;
480 byte poly;
481 byte prio;
482 } _rhyState;
483
484protected:
485 IMuseInternal(ScummEngine *vm, MidiDriverFlags sndType, bool nativeMT32);
486 ~IMuseInternal() override;
487
488 int initialize(OSystem *syst, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver);
489
490 static void midiTimerCallback(void *data);
491 void on_timer(MidiDriver *midi) override;
492
493 enum ChunkType {
494 kMThd = 1,
495 kFORM = 2,
496 kMDhd = 4, // Used in MI2 and INDY4. Contain certain start parameters (priority, volume, etc. ) for the player.
497 kMDpg = 8 // These chunks exist in DOTT and SAMNMAX. They don't get processed, however.
498 };
499
500 byte *findStartOfSound(int sound, int ct = (kMThd | kFORM));
501 bool isMT32(int sound);
502 bool isMIDI(int sound);
503 bool supportsPercussion(int sound);
504 int get_queue_sound_status(int sound) const;
505 void handle_marker(uint id, byte data);
506 int get_channel_volume(uint a);
507 void initMidiDriver(TimerCallbackInfo *info);
508 void init_players();
509 void init_parts();
510 void init_queue();
511
512 void sequencer_timers(MidiDriver *midi);
513
514 MidiDriver *getBestMidiDriver(int sound);
515 Player *allocate_player(byte priority);
516 Part *allocate_part(byte pri, MidiDriver *midi);
517
518 int32 ImSetTrigger(int sound, int id, int a, int b, int c, int d, int e, int f, int g, int h);
519 int32 ImClearTrigger(int sound, int id);
520 int32 ImFireAllTriggers(int sound);
521
522 void addDeferredCommand(int time, int a, int b, int c, int d, int e, int f);
523 void handleDeferredCommands(MidiDriver *midi);
524
525 int enqueue_command(int a, int b, int c, int d, int e, int f, int g);
526 int enqueue_trigger(int sound, int marker);
527 int clear_queue() override;
528 int query_queue(int param);
529 Player *findActivePlayer(int id);
530
531 int get_volchan_entry(uint a);
532 int set_volchan_entry(uint a, uint b);
533 int set_channel_volume(uint chan, uint vol);
534 void update_volumes();
535 void musicVolumeReduction(MidiDriver *midi);
536
537 int set_volchan(int sound, int volchan);
538
539 void fix_parts_after_load();
540 void fix_players_after_load(ScummEngine *scumm);
541 int setImuseMasterVolume(uint vol);
542
543 MidiChannel *allocateChannel(MidiDriver *midi, byte prio);
544 bool reassignChannelAndResumePart(MidiChannel *mc);
545 void suspendPart(Part *part);
546 void removeSuspendedPart(Part *part);
547 void reallocateMidiChannels(MidiDriver *midi);
548 void setGlobalInstrument(byte slot, byte *data);
549 void copyGlobalInstrument(byte slot, Instrument *dest);
550 bool isNativeMT32() { return _native_mt32; }
551
552protected:
553 Common::Array<Part*> _waitingPartsQueue;
554
555protected:
556 // Internal mutex-free versions of the IMuse and MusicEngine methods.
557 bool startSound_internal(int sound, int offset = 0);
558 int stopSound_internal(int sound);
559 int stopAllSounds_internal();
560 int getSoundStatus_internal(int sound, bool ignoreFadeouts) const;
561 int32 doCommand_internal(int a, int b, int c, int d, int e, int f, int g, int h);
562 int32 doCommand_internal(int numargs, int args[]);
563
564public:
565 // IMuse interface
566 void pause(bool paused) override;
567 void saveLoadIMuse(Common::Serializer &ser, ScummEngine *scumm, bool fixAfterLoad = true) override;
568 bool get_sound_active(int sound) const override;
569 int32 doCommand(int numargs, int args[]) override;
570 uint32 property(int prop, uint32 value) override;
571 void addSysexHandler(byte mfgID, sysexfunc handler) override;
572
573public:
574 void startSoundWithNoteOffset(int sound, int offset) override;
575
576 // MusicEngine interface
577 void setMusicVolume(int vol) override;
578 void setSfxVolume(int vol) override;
579 void startSound(int sound) override;
580 void stopSound(int sound) override;
581 void stopAllSounds() override;
582 int getSoundStatus(int sound) const override;
583 int getMusicTimer() override;
584
585protected:
586 // Our normal volume control is high-level, i. e. it uses the imuse engine to generate the proper volume values and send these to the midi driver.
587 // For older titles (like MI2 and INDY4) who never had music and sfx volume controls in the original interpreters, this works well only if the
588 // engine can somehow distinguish between music and sound effects. It works for targets/platforms where this can be done by resource type, where
589 // the sfx resources aren't even played through the imuse engine. The imuse engine can then just assume that everything it plays is music. For
590 // MI2/INDY4 Macintosh it won't work like this, because both music and sound effects have the same resource type and are played through the imuse
591 // engine. For these targets it works better to pass the volume values on to the driver where other methods of distinction may be available.
592 // This isn't needed for SCUMM6, since these games don't have MIDI sound effects.
593 const bool _lowLevelVolumeControl;
594
595public:
596 // Factory function
597 static IMuseInternal *create(ScummEngine *vm, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver, MidiDriverFlags sndType, bool nativeMT32);
598};
599
600} // End of namespace Scumm
601
602#endif
Definition: array.h:52
Definition: mutex.h:67
Definition: serializer.h:352
Definition: serializer.h:80
Definition: mididrv.h:541
Definition: mididrv.h:114
Definition: mididrv.h:313
Definition: midiparser.h:354
Definition: system.h:166
Definition: imuse.h:50
Definition: imuse_internal.h:404
int getMusicTimer() override
void startSound(int sound) override
void stopSound(int sound) override
void stopAllSounds() override
void setSfxVolume(int vol) override
void setMusicVolume(int vol) override
int getSoundStatus(int sound) const override
Definition: instrument.h:43
Definition: imuse_internal.h:166
void send(uint32 b) override
void sysEx(const byte *msg, uint16 length) override
uint16 sysExNoDelay(const byte *msg, uint16 length) override
Definition: scumm.h:536
MidiDriverFlags
Definition: mididrv.h:83
Definition: actor.h:30
Definition: imuse_internal.h:153
Definition: imuse_internal.h:139
Definition: imuse_internal.h:98
Definition: imuse_internal.h:476
Definition: imuse_internal.h:145
Definition: imuse_internal.h:119
Definition: imuse_internal.h:316
Definition: imuse_internal.h:93