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 
31 class MidiParser;
32 class OSystem;
33 
34 namespace Scumm {
35 
36 struct ParameterFader;
37 struct DeferredCommand;
38 struct ImTrigger;
39 struct SustainingNotes;
40 struct CommandQueue;
41 struct IsNoteCmdData;
42 class Player;
43 struct Part;
44 class IMuseInternal;
45 class 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 
69 inline 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 
77 inline 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 
98 struct 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 
145 struct ImTrigger {
146  int sound;
147  byte id;
148  uint16 expire;
149  int command[8];
150  ImTrigger() { memset(this, 0, sizeof(ImTrigger)); }
151 };
152 
153 struct CommandQueue {
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 
177 protected:
178  // Moved from IMuseInternal.
179  // This is only used by one player at a time.
180  static uint16 _active_notes[128];
181 
182 protected:
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 
230 protected:
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 
254 public:
255  IMuseInternal *_se;
256  uint _vol_chan;
257 
258 public:
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 
300 public:
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, byte *data, uint16 length) override;
306 };
307 
308 
309 
311 //
312 // Part pseudo-class definition
313 //
315 
316 struct 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();
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 
387 private:
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 
404 class 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 
418 protected:
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 
440 protected:
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 
484 protected:
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 
552 protected:
553  Common::Array<Part*> _waitingPartsQueue;
554 
555 protected:
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 
564 public:
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 
573 public:
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 
585 protected:
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 
595 public:
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: imuse_internal.h:316
Definition: imuse_internal.h:98
Definition: array.h:52
Definition: imuse_internal.h:145
Definition: imuse_internal.h:404
MidiDriverFlags
Definition: mididrv.h:81
Definition: serializer.h:79
Definition: mididrv.h:309
Definition: imuse_internal.h:153
Definition: scumm.h:518
Definition: imuse_internal.h:476
Definition: mididrv.h:112
Definition: imuse.h:50
Definition: imuse_internal.h:166
Definition: mutex.h:67
Definition: serializer.h:308
Definition: mididrv.h:537
Definition: instrument.h:43
Definition: system.h:161
Definition: imuse_internal.h:93
Definition: imuse_internal.h:139
Definition: actor.h:30
Definition: midiparser.h:289
Definition: imuse_internal.h:119