1 // 2 // midisources.h 3 // GZDoom 4 // 5 // Created by Christoph Oelckers on 23.02.18. 6 // 7 8 #ifndef midisources_h 9 #define midisources_h 10 11 #include <stddef.h> 12 #include <string.h> 13 #include <stdint.h> 14 #include <functional> 15 #include <vector> 16 #include "zmusic/mus2midi.h" 17 #include "zmusic/mididefs.h" 18 19 extern char MIDI_EventLengths[7]; 20 extern char MIDI_CommonLengths[15]; 21 22 23 // base class for the different MIDI sources -------------------------------------- 24 25 class MIDISource 26 { 27 int Volume = 0xffff; 28 int LoopLimit = 0; 29 std::function<bool(int)> TempoCallback = [](int t) { return false; }; 30 31 protected: 32 33 bool isLooping = false; 34 bool skipSysex = false; 35 int Division = 0; 36 int Tempo = 500000; 37 int InitialTempo = 500000; 38 uint8_t ChannelVolumes[16]; 39 40 int VolumeControllerChange(int channel, int volume); 41 void SetTempo(int new_tempo); 42 int ClampLoopCount(int loopcount); 43 44 45 public: 46 bool Exporting = false; 47 48 // Virtuals for subclasses to override ~MIDISource()49 virtual ~MIDISource() {} 50 virtual void CheckCaps(int tech); 51 virtual void DoInitialSetup() = 0; 52 virtual void DoRestart() = 0; 53 virtual bool CheckDone() = 0; 54 virtual std::vector<uint16_t> PrecacheData(); 55 virtual bool SetMIDISubsong(int subsong); 56 virtual uint32_t *MakeEvents(uint32_t *events, uint32_t *max_event_p, uint32_t max_time) = 0; 57 58 void StartPlayback(bool looped = true, int looplimit = 0) 59 { 60 Tempo = InitialTempo; 61 LoopLimit = looplimit; 62 isLooping = looped; 63 } 64 SkipSysex()65 void SkipSysex() { skipSysex = true; } 66 isValid()67 bool isValid() const { return Division > 0; } getDivision()68 int getDivision() const { return Division; } getInitialTempo()69 int getInitialTempo() const { return InitialTempo; } getTempo()70 int getTempo() const { return Tempo; } getChannelVolume(int ch)71 int getChannelVolume(int ch) const { return ChannelVolumes[ch]; } setVolume(int vol)72 void setVolume(int vol) { Volume = vol; } setLoopLimit(int lim)73 void setLoopLimit(int lim) { LoopLimit = lim; } setTempoCallback(std::function<bool (int)> cb)74 void setTempoCallback(std::function<bool(int)> cb) 75 { 76 TempoCallback = cb; 77 } 78 79 void CreateSMF(std::vector<uint8_t> &file, int looplimit); 80 81 }; 82 83 // MUS file played with a MIDI stream --------------------------------------- 84 85 class MUSSong2 : public MIDISource 86 { 87 public: 88 MUSSong2(const uint8_t *data, size_t len); 89 90 protected: 91 void DoInitialSetup() override; 92 void DoRestart() override; 93 bool CheckDone() override; 94 std::vector<uint16_t> PrecacheData() override; 95 uint32_t *MakeEvents(uint32_t *events, uint32_t *max_events_p, uint32_t max_time) override; 96 97 private: 98 std::vector<uint8_t> MusData; 99 uint8_t* MusBuffer; 100 uint8_t LastVelocity[16]; 101 size_t MusP, MaxMusP; 102 }; 103 104 105 // MIDI file played with a MIDI stream -------------------------------------- 106 107 class MIDISong2 : public MIDISource 108 { 109 public: 110 MIDISong2(const uint8_t* data, size_t len); 111 112 protected: 113 void CheckCaps(int tech) override; 114 void DoInitialSetup() override; 115 void DoRestart() override; 116 bool CheckDone() override; 117 uint32_t *MakeEvents(uint32_t *events, uint32_t *max_events_p, uint32_t max_time) override; 118 119 private: 120 void AdvanceTracks(uint32_t time); 121 122 struct TrackInfo; 123 124 void ProcessInitialMetaEvents (); 125 uint32_t *SendCommand (uint32_t *event, TrackInfo *track, uint32_t delay, ptrdiff_t room, bool &sysex_noroom); 126 TrackInfo *FindNextDue (); 127 128 std::vector<uint8_t> MusHeader; 129 std::vector<TrackInfo> Tracks; 130 TrackInfo *TrackDue; 131 int NumTracks; 132 int Format; 133 uint16_t DesignationMask; 134 }; 135 136 // HMI file played with a MIDI stream --------------------------------------- 137 138 struct AutoNoteOff 139 { 140 uint32_t Delay; 141 uint8_t Channel, Key; 142 }; 143 // Sorry, std::priority_queue, but I want to be able to modify the contents of the heap. 144 class NoteOffQueue : public std::vector<AutoNoteOff> 145 { 146 public: 147 void AddNoteOff(uint32_t delay, uint8_t channel, uint8_t key); 148 void AdvanceTime(uint32_t time); 149 bool Pop(AutoNoteOff &item); 150 151 protected: 152 void Heapify(); 153 Parent(unsigned int i)154 unsigned int Parent(unsigned int i) const { return (i + 1u) / 2u - 1u; } Left(unsigned int i)155 unsigned int Left(unsigned int i) const { return (i + 1u) * 2u - 1u; } Right(unsigned int i)156 unsigned int Right(unsigned int i) const { return (i + 1u) * 2u; } 157 }; 158 159 class HMISong : public MIDISource 160 { 161 public: 162 HMISong(const uint8_t* data, size_t len); 163 164 protected: 165 166 void DoInitialSetup() override; 167 void DoRestart() override; 168 bool CheckDone() override; 169 void CheckCaps(int tech) override; 170 uint32_t *MakeEvents(uint32_t *events, uint32_t *max_events_p, uint32_t max_time) override; 171 172 private: 173 void SetupForHMI(int len); 174 void SetupForHMP(int len); 175 void AdvanceTracks(uint32_t time); 176 177 struct TrackInfo; 178 179 void ProcessInitialMetaEvents (); 180 uint32_t *SendCommand (uint32_t *event, TrackInfo *track, uint32_t delay, ptrdiff_t room, bool &sysex_noroom); 181 TrackInfo *FindNextDue (); 182 183 static uint32_t ReadVarLenHMI(TrackInfo *); 184 static uint32_t ReadVarLenHMP(TrackInfo *); 185 186 std::vector<uint8_t> MusHeader; 187 int NumTracks; 188 std::vector<TrackInfo> Tracks; 189 TrackInfo *TrackDue; 190 TrackInfo *FakeTrack; 191 uint32_t (*ReadVarLen)(TrackInfo *); 192 NoteOffQueue NoteOffs; 193 }; 194 195 // XMI file played with a MIDI stream --------------------------------------- 196 197 class XMISong : public MIDISource 198 { 199 public: 200 XMISong(const uint8_t* data, size_t len); 201 202 protected: 203 bool SetMIDISubsong(int subsong) override; 204 void DoInitialSetup() override; 205 void DoRestart() override; 206 bool CheckDone() override; 207 uint32_t *MakeEvents(uint32_t *events, uint32_t *max_events_p, uint32_t max_time) override; 208 209 private: 210 struct TrackInfo; 211 enum EventSource { EVENT_None, EVENT_Real, EVENT_Fake }; 212 213 int FindXMIDforms(const uint8_t *chunk, int len, TrackInfo *songs) const; 214 void FoundXMID(const uint8_t *chunk, int len, TrackInfo *song) const; 215 void AdvanceSong(uint32_t time); 216 217 void ProcessInitialMetaEvents(); 218 uint32_t *SendCommand (uint32_t *event, EventSource track, uint32_t delay, ptrdiff_t room, bool &sysex_noroom); 219 EventSource FindNextDue(); 220 221 std::vector<uint8_t> MusHeader; 222 int NumSongs; 223 std::vector<TrackInfo> Songs; 224 TrackInfo *CurrSong; 225 NoteOffQueue NoteOffs; 226 EventSource EventDue; 227 }; 228 229 // MIDS file played with a MIDI Stream 230 231 class MIDSSong : public MIDISource 232 { 233 public: 234 MIDSSong(const uint8_t* data, size_t len); 235 236 protected: 237 void DoInitialSetup() override; 238 void DoRestart() override; 239 bool CheckDone() override; 240 uint32_t *MakeEvents(uint32_t *events, uint32_t *max_events_p, uint32_t max_time) override; 241 242 private: 243 std::vector<uint32_t> MidsBuffer; 244 size_t MidsP, MaxMidsP; 245 int FormatFlags; 246 247 void ProcessInitialTempoEvents(); 248 }; 249 250 #endif /* midisources_h */ 251