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