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