1 #ifdef _WIN32
2 #define WIN32_LEAN_AND_MEAN
3 #define USE_WINDOWS_DWORD
4 #if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0400
5 #undef _WIN32_WINNT
6 #endif
7 #ifndef _WIN32_WINNT
8 #define _WIN32_WINNT 0x0400
9 #endif
10 #ifndef USE_WINDOWS_DWORD
11 #define USE_WINDOWS_DWORD
12 #endif
13 #include <windows.h>
14 #include <mmsystem.h>
15 #else
16 #define FALSE 0
17 #define TRUE 1
18 #endif
19 #include "tempfiles.h"
20 #include "oplsynth/opl_mus_player.h"
21 #include "c_cvars.h"
22 #include "mus2midi.h"
23 #include "i_sound.h"
24 #include "i_music.h"
25 #include "s_sound.h"
26 #include "files.h"
27 #include "wildmidi/wildmidi_lib.h"
28 
29 void I_InitMusicWin32 ();
30 void I_ShutdownMusicWin32 ();
31 
32 extern float relative_volume;
33 
34 EXTERN_CVAR (Float, timidity_mastervolume)
35 
36 
37 // A device that provides a WinMM-like MIDI streaming interface -------------
38 
39 #ifndef _WIN32
40 struct MIDIHDR
41 {
42 	BYTE *lpData;
43 	DWORD dwBufferLength;
44 	DWORD dwBytesRecorded;
45 	MIDIHDR *lpNext;
46 };
47 
48 enum
49 {
50 	MOD_MIDIPORT = 1,
51 	MOD_SYNTH,
52 	MOD_SQSYNTH,
53 	MOD_FMSYNTH,
54 	MOD_MAPPER,
55 	MOD_WAVETABLE,
56 	MOD_SWSYNTH
57 };
58 
59 typedef BYTE *LPSTR;
60 
61 #define MEVT_TEMPO			((BYTE)1)
62 #define MEVT_NOP			((BYTE)2)
63 #define MEVT_LONGMSG		((BYTE)128)
64 
65 #define MEVT_EVENTTYPE(x)	((BYTE)((x) >> 24))
66 #define MEVT_EVENTPARM(x)   ((x) & 0xffffff)
67 
68 #define MOM_DONE			969
69 #else
70 // w32api does not define these
71 #ifndef MOD_WAVETABLE
72 #define MOD_WAVETABLE   6
73 #define MOD_SWSYNTH     7
74 #endif
75 #endif
76 
77 class MIDIStreamer;
78 
79 class MIDIDevice
80 {
81 public:
82 	MIDIDevice();
83 	virtual ~MIDIDevice();
84 
85 	virtual int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) = 0;
86 	virtual void Close() = 0;
87 	virtual bool IsOpen() const = 0;
88 	virtual int GetTechnology() const = 0;
89 	virtual int SetTempo(int tempo) = 0;
90 	virtual int SetTimeDiv(int timediv) = 0;
91 	virtual int StreamOut(MIDIHDR *data) = 0;
92 	virtual int StreamOutSync(MIDIHDR *data) = 0;
93 	virtual int Resume() = 0;
94 	virtual void Stop() = 0;
95 	virtual int PrepareHeader(MIDIHDR *data);
96 	virtual int UnprepareHeader(MIDIHDR *data);
97 	virtual bool FakeVolume();
98 	virtual bool Pause(bool paused) = 0;
99 	virtual bool NeedThreadedCallback();
100 	virtual void PrecacheInstruments(const WORD *instruments, int count);
101 	virtual void TimidityVolumeChanged();
102 	virtual void FluidSettingInt(const char *setting, int value);
103 	virtual void FluidSettingNum(const char *setting, double value);
104 	virtual void FluidSettingStr(const char *setting, const char *value);
105 	virtual void WildMidiSetOption(int opt, int set);
106 	virtual bool Preprocess(MIDIStreamer *song, bool looping);
107 	virtual FString GetStats();
108 };
109 
110 // WinMM implementation of a MIDI output device -----------------------------
111 
112 #ifdef _WIN32
113 class WinMIDIDevice : public MIDIDevice
114 {
115 public:
116 	WinMIDIDevice(int dev_id);
117 	~WinMIDIDevice();
118 	int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
119 	void Close();
120 	bool IsOpen() const;
121 	int GetTechnology() const;
122 	int SetTempo(int tempo);
123 	int SetTimeDiv(int timediv);
124 	int StreamOut(MIDIHDR *data);
125 	int StreamOutSync(MIDIHDR *data);
126 	int Resume();
127 	void Stop();
128 	int PrepareHeader(MIDIHDR *data);
129 	int UnprepareHeader(MIDIHDR *data);
130 	bool FakeVolume();
131 	bool NeedThreadedCallback();
132 	bool Pause(bool paused);
133 	void PrecacheInstruments(const WORD *instruments, int count);
134 
135 protected:
136 	static void CALLBACK CallbackFunc(HMIDIOUT, UINT, DWORD_PTR, DWORD, DWORD);
137 
138 	HMIDISTRM MidiOut;
139 	UINT DeviceID;
140 	DWORD SavedVolume;
141 	bool VolumeWorks;
142 
143 	void (*Callback)(unsigned int, void *, DWORD, DWORD);
144 	void *CallbackData;
145 };
146 #endif
147 
148 // Base class for pseudo-MIDI devices ---------------------------------------
149 
150 class PseudoMIDIDevice : public MIDIDevice
151 {
152 public:
153 	PseudoMIDIDevice();
154 	~PseudoMIDIDevice();
155 
156 	void Close();
157 	bool IsOpen() const;
158 	int GetTechnology() const;
159 	bool Pause(bool paused);
160 	int Resume();
161 	void Stop();
162 	int StreamOut(MIDIHDR *data);
163 	int StreamOutSync(MIDIHDR *data);
164 	int SetTempo(int tempo);
165 	int SetTimeDiv(int timediv);
166 	FString GetStats();
167 
168 protected:
169 	SoundStream *Stream;
170 	bool Started;
171 	bool bLooping;
172 };
173 
174 // Sound System pseudo-MIDI device ------------------------------------------
175 
176 class SndSysMIDIDevice : public PseudoMIDIDevice
177 {
178 public:
179 	int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
180 	bool Preprocess(MIDIStreamer *song, bool looping);
181 };
182 
183 // MIDI file played with TiMidity++ and possibly streamed through the Sound System
184 
185 class TimidityPPMIDIDevice : public PseudoMIDIDevice
186 {
187 public:
188 	TimidityPPMIDIDevice(const char *args);
189 	~TimidityPPMIDIDevice();
190 
191 	int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
192 	bool Preprocess(MIDIStreamer *song, bool looping);
193 	bool IsOpen() const;
194 	int Resume();
195 
196 	void Stop();
197 	bool IsOpen();
198 	void TimidityVolumeChanged();
199 
200 protected:
201 	bool LaunchTimidity();
202 
203 	FTempFileName DiskName;
204 #ifdef _WIN32
205 	HANDLE ReadWavePipe;
206 	HANDLE WriteWavePipe;
207 	HANDLE ChildProcess;
208 	bool Validated;
209 	bool ValidateTimidity();
210 #else // _WIN32
211 	int WavePipe[2];
212 	pid_t ChildProcess;
213 #endif
214 	FString CommandLine;
215 	size_t LoopPos;
216 
217 	static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata);
218 #ifdef _WIN32
219 	static const char EventName[];
220 #endif
221 };
222 
223 // Base class for software synthesizer MIDI output devices ------------------
224 
225 class SoftSynthMIDIDevice : public MIDIDevice
226 {
227 public:
228 	SoftSynthMIDIDevice();
229 	~SoftSynthMIDIDevice();
230 
231 	void Close();
232 	bool IsOpen() const;
233 	int GetTechnology() const;
234 	int SetTempo(int tempo);
235 	int SetTimeDiv(int timediv);
236 	int StreamOut(MIDIHDR *data);
237 	int StreamOutSync(MIDIHDR *data);
238 	int Resume();
239 	void Stop();
240 	bool Pause(bool paused);
241 
242 protected:
243 	FCriticalSection CritSec;
244 	SoundStream *Stream;
245 	double Tempo;
246 	double Division;
247 	double SamplesPerTick;
248 	double NextTickIn;
249 	MIDIHDR *Events;
250 	bool Started;
251 	DWORD Position;
252 	int SampleRate;
253 
254 	void (*Callback)(unsigned int, void *, DWORD, DWORD);
255 	void *CallbackData;
256 
257 	virtual void CalcTickRate();
258 	int PlayTick();
259 	int OpenStream(int chunks, int flags, void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
260 	static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata);
261 	virtual bool ServiceStream (void *buff, int numbytes);
262 
263 	virtual void HandleEvent(int status, int parm1, int parm2) = 0;
264 	virtual void HandleLongEvent(const BYTE *data, int len) = 0;
265 	virtual void ComputeOutput(float *buffer, int len) = 0;
266 };
267 
268 // OPL implementation of a MIDI output device -------------------------------
269 
270 class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock
271 {
272 public:
273 	OPLMIDIDevice(const char *args);
274 	int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
275 	void Close();
276 	int GetTechnology() const;
277 	FString GetStats();
278 
279 protected:
280 	void CalcTickRate();
281 	int PlayTick();
282 	void HandleEvent(int status, int parm1, int parm2);
283 	void HandleLongEvent(const BYTE *data, int len);
284 	void ComputeOutput(float *buffer, int len);
285 	bool ServiceStream(void *buff, int numbytes);
286 };
287 
288 // OPL dumper implementation of a MIDI output device ------------------------
289 
290 class OPLDumperMIDIDevice : public OPLMIDIDevice
291 {
292 public:
293 	OPLDumperMIDIDevice(const char *filename);
294 	~OPLDumperMIDIDevice();
295 	int Resume();
296 	void Stop();
297 };
298 
299 // Internal TiMidity MIDI device --------------------------------------------
300 
301 namespace Timidity { struct Renderer; }
302 
303 class TimidityMIDIDevice : public SoftSynthMIDIDevice
304 {
305 public:
306 	TimidityMIDIDevice(const char *args);
307 	~TimidityMIDIDevice();
308 
309 	int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
310 	void PrecacheInstruments(const WORD *instruments, int count);
311 	FString GetStats();
312 
313 protected:
314 	Timidity::Renderer *Renderer;
315 
316 	void HandleEvent(int status, int parm1, int parm2);
317 	void HandleLongEvent(const BYTE *data, int len);
318 	void ComputeOutput(float *buffer, int len);
319 };
320 
321 // Internal TiMidity disk writing version of a MIDI device ------------------
322 
323 class TimidityWaveWriterMIDIDevice : public TimidityMIDIDevice
324 {
325 public:
326 	TimidityWaveWriterMIDIDevice(const char *filename, int rate);
327 	~TimidityWaveWriterMIDIDevice();
328 	int Resume();
329 	void Stop();
330 
331 protected:
332 	FILE *File;
333 };
334 
335 // WildMidi implementation of a MIDI device ---------------------------------
336 
337 class WildMIDIDevice : public SoftSynthMIDIDevice
338 {
339 public:
340 	WildMIDIDevice(const char *args);
341 	~WildMIDIDevice();
342 
343 	int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
344 	void PrecacheInstruments(const WORD *instruments, int count);
345 	FString GetStats();
346 
347 protected:
348 	WildMidi_Renderer *Renderer;
349 
350 	void HandleEvent(int status, int parm1, int parm2);
351 	void HandleLongEvent(const BYTE *data, int len);
352 	void ComputeOutput(float *buffer, int len);
353 	void WildMidiSetOption(int opt, int set);
354 };
355 
356 // FluidSynth implementation of a MIDI device -------------------------------
357 
358 #ifdef HAVE_FLUIDSYNTH
359 #ifndef DYN_FLUIDSYNTH
360 #include <fluidsynth.h>
361 #else
362 struct fluid_settings_t;
363 struct fluid_synth_t;
364 #endif
365 
366 class FluidSynthMIDIDevice : public SoftSynthMIDIDevice
367 {
368 public:
369 	FluidSynthMIDIDevice(const char *args);
370 	~FluidSynthMIDIDevice();
371 
372 	int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
373 	FString GetStats();
374 	void FluidSettingInt(const char *setting, int value);
375 	void FluidSettingNum(const char *setting, double value);
376 	void FluidSettingStr(const char *setting, const char *value);
377 
378 protected:
379 	void HandleEvent(int status, int parm1, int parm2);
380 	void HandleLongEvent(const BYTE *data, int len);
381 	void ComputeOutput(float *buffer, int len);
382 	int LoadPatchSets(const char *patches);
383 
384 	fluid_settings_t *FluidSettings;
385 	fluid_synth_t *FluidSynth;
386 
387 #ifdef DYN_FLUIDSYNTH
388 	enum { FLUID_FAILED = -1, FLUID_OK = 0 };
389 	fluid_settings_t *(STACK_ARGS *new_fluid_settings)();
390 	fluid_synth_t *(STACK_ARGS *new_fluid_synth)(fluid_settings_t *);
391 	int (STACK_ARGS *delete_fluid_synth)(fluid_synth_t *);
392 	void (STACK_ARGS *delete_fluid_settings)(fluid_settings_t *);
393 	int (STACK_ARGS *fluid_settings_setnum)(fluid_settings_t *, const char *, double);
394 	int (STACK_ARGS *fluid_settings_setstr)(fluid_settings_t *, const char *, const char *);
395 	int (STACK_ARGS *fluid_settings_setint)(fluid_settings_t *, const char *, int);
396 	int (STACK_ARGS *fluid_settings_getstr)(fluid_settings_t *, const char *, char **);
397 	int (STACK_ARGS *fluid_settings_getint)(fluid_settings_t *, const char *, int *);
398 	void (STACK_ARGS *fluid_synth_set_reverb_on)(fluid_synth_t *, int);
399 	void (STACK_ARGS *fluid_synth_set_chorus_on)(fluid_synth_t *, int);
400 	int (STACK_ARGS *fluid_synth_set_interp_method)(fluid_synth_t *, int, int);
401 	int (STACK_ARGS *fluid_synth_set_polyphony)(fluid_synth_t *, int);
402 	int (STACK_ARGS *fluid_synth_get_polyphony)(fluid_synth_t *);
403 	int (STACK_ARGS *fluid_synth_get_active_voice_count)(fluid_synth_t *);
404 	double (STACK_ARGS *fluid_synth_get_cpu_load)(fluid_synth_t *);
405 	int (STACK_ARGS *fluid_synth_system_reset)(fluid_synth_t *);
406 	int (STACK_ARGS *fluid_synth_noteon)(fluid_synth_t *, int, int, int);
407 	int (STACK_ARGS *fluid_synth_noteoff)(fluid_synth_t *, int, int);
408 	int (STACK_ARGS *fluid_synth_cc)(fluid_synth_t *, int, int, int);
409 	int (STACK_ARGS *fluid_synth_program_change)(fluid_synth_t *, int, int);
410 	int (STACK_ARGS *fluid_synth_channel_pressure)(fluid_synth_t *, int, int);
411 	int (STACK_ARGS *fluid_synth_pitch_bend)(fluid_synth_t *, int, int);
412 	int (STACK_ARGS *fluid_synth_write_float)(fluid_synth_t *, int, void *, int, int, void *, int, int);
413 	int (STACK_ARGS *fluid_synth_sfload)(fluid_synth_t *, const char *, int);
414 	void (STACK_ARGS *fluid_synth_set_reverb)(fluid_synth_t *, double, double, double, double);
415 	void (STACK_ARGS *fluid_synth_set_chorus)(fluid_synth_t *, int, double, double, double, int);
416 	int (STACK_ARGS *fluid_synth_sysex)(fluid_synth_t *, const char *, int, char *, int *, int *, int);
417 
418 #ifdef _WIN32
419 	HMODULE FluidSynthDLL;
420 #else
421 	void *FluidSynthSO;
422 #endif
423 	bool LoadFluidSynth();
424 	void UnloadFluidSynth();
425 #endif
426 };
427 #endif
428 
429 // Base class for streaming MUS and MIDI files ------------------------------
430 
431 class MIDIStreamer : public MusInfo
432 {
433 public:
434 	MIDIStreamer(EMidiDevice type, const char *args);
435 	~MIDIStreamer();
436 
437 	void MusicVolumeChanged();
438 	void TimidityVolumeChanged();
439 	void Play(bool looping, int subsong);
440 	void Pause();
441 	void Resume();
442 	void Stop();
443 	bool IsPlaying();
444 	bool IsMIDI() const;
445 	bool IsValid() const;
446 	bool SetSubsong(int subsong);
447 	void Update();
448 	FString GetStats();
449 	void FluidSettingInt(const char *setting, int value);
450 	void FluidSettingNum(const char *setting, double value);
451 	void FluidSettingStr(const char *setting, const char *value);
452 	void WildMidiSetOption(int opt, int set);
453 	void CreateSMF(TArray<BYTE> &file, int looplimit=0);
454 
455 protected:
456 	MIDIStreamer(const char *dumpname, EMidiDevice type);
457 
458 	void OutputVolume (DWORD volume);
459 	int FillBuffer(int buffer_num, int max_events, DWORD max_time);
460 	int FillStopBuffer(int buffer_num);
461 	DWORD *WriteStopNotes(DWORD *events);
462 	int ServiceEvent();
463 	int VolumeControllerChange(int channel, int volume);
464 	int ClampLoopCount(int loopcount);
465 	void SetTempo(int new_tempo);
466 	static EMidiDevice SelectMIDIDevice(EMidiDevice devtype);
467 	MIDIDevice *CreateMIDIDevice(EMidiDevice devtype) const;
468 
469 	static void Callback(unsigned int uMsg, void *userdata, DWORD dwParam1, DWORD dwParam2);
470 
471 	// Virtuals for subclasses to override
472 	virtual void StartPlayback();
473 	virtual void CheckCaps(int tech);
474 	virtual void DoInitialSetup() = 0;
475 	virtual void DoRestart() = 0;
476 	virtual bool CheckDone() = 0;
477 	virtual void Precache();
478 	virtual bool SetMIDISubsong(int subsong);
479 	virtual DWORD *MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time) = 0;
480 
481 	enum
482 	{
483 		MAX_EVENTS = 128
484 	};
485 
486 	enum
487 	{
488 		SONG_MORE,
489 		SONG_DONE,
490 		SONG_ERROR
491 	};
492 
493 #ifdef _WIN32
494 	static DWORD WINAPI PlayerProc (LPVOID lpParameter);
495 	DWORD PlayerLoop();
496 
497 	HANDLE PlayerThread;
498 	HANDLE ExitEvent;
499 	HANDLE BufferDoneEvent;
500 #endif
501 
502 	MIDIDevice *MIDI;
503 	DWORD Events[2][MAX_EVENTS*3];
504 	MIDIHDR Buffer[2];
505 	int BufferNum;
506 	int EndQueued;
507 	bool VolumeChanged;
508 	bool Restarting;
509 	bool InitialPlayback;
510 	DWORD NewVolume;
511 	int Division;
512 	int Tempo;
513 	int InitialTempo;
514 	BYTE ChannelVolumes[16];
515 	DWORD Volume;
516 	EMidiDevice DeviceType;
517 	bool CallbackIsThreaded;
518 	int LoopLimit;
519 	FString DumpFilename;
520 	FString Args;
521 };
522 
523 // MUS file played with a MIDI stream ---------------------------------------
524 
525 class MUSSong2 : public MIDIStreamer
526 {
527 public:
528 	MUSSong2(FileReader &reader, EMidiDevice type, const char *args);
529 	~MUSSong2();
530 
531 	MusInfo *GetOPLDumper(const char *filename);
532 	MusInfo *GetWaveDumper(const char *filename, int rate);
533 
534 protected:
535 	MUSSong2(const MUSSong2 *original, const char *filename, EMidiDevice type);	// file dump constructor
536 
537 	void DoInitialSetup();
538 	void DoRestart();
539 	bool CheckDone();
540 	void Precache();
541 	DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time);
542 
543 	MUSHeader *MusHeader;
544 	BYTE *MusBuffer;
545 	BYTE LastVelocity[16];
546 	size_t MusP, MaxMusP;
547 };
548 
549 // MIDI file played with a MIDI stream --------------------------------------
550 
551 class MIDISong2 : public MIDIStreamer
552 {
553 public:
554 	MIDISong2(FileReader &reader, EMidiDevice type, const char *args);
555 	~MIDISong2();
556 
557 	MusInfo *GetOPLDumper(const char *filename);
558 	MusInfo *GetWaveDumper(const char *filename, int rate);
559 
560 protected:
561 	MIDISong2(const MIDISong2 *original, const char *filename, EMidiDevice type);	// file dump constructor
562 
563 	void CheckCaps(int tech);
564 	void DoInitialSetup();
565 	void DoRestart();
566 	bool CheckDone();
567 	DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time);
568 	void AdvanceTracks(DWORD time);
569 
570 	struct TrackInfo;
571 
572 	void ProcessInitialMetaEvents ();
573 	DWORD *SendCommand (DWORD *event, TrackInfo *track, DWORD delay, ptrdiff_t room, bool &sysex_noroom);
574 	TrackInfo *FindNextDue ();
575 
576 	BYTE *MusHeader;
577 	int SongLen;
578 	TrackInfo *Tracks;
579 	TrackInfo *TrackDue;
580 	int NumTracks;
581 	int Format;
582 	WORD DesignationMask;
583 };
584 
585 // HMI file played with a MIDI stream ---------------------------------------
586 
587 struct AutoNoteOff
588 {
589 	DWORD Delay;
590 	BYTE Channel, Key;
591 };
592 // Sorry, std::priority_queue, but I want to be able to modify the contents of the heap.
593 class NoteOffQueue : public TArray<AutoNoteOff>
594 {
595 public:
596 	void AddNoteOff(DWORD delay, BYTE channel, BYTE key);
597 	void AdvanceTime(DWORD time);
598 	bool Pop(AutoNoteOff &item);
599 
600 protected:
601 	void Heapify();
602 
Parent(unsigned int i)603 	unsigned int Parent(unsigned int i) const { return (i + 1u) / 2u - 1u; }
Left(unsigned int i)604 	unsigned int Left(unsigned int i) const { return (i + 1u) * 2u - 1u; }
Right(unsigned int i)605 	unsigned int Right(unsigned int i) const { return (i + 1u) * 2u; }
606 };
607 
608 class HMISong : public MIDIStreamer
609 {
610 public:
611 	HMISong(FileReader &reader, EMidiDevice type, const char *args);
612 	~HMISong();
613 
614 	MusInfo *GetOPLDumper(const char *filename);
615 	MusInfo *GetWaveDumper(const char *filename, int rate);
616 
617 protected:
618 	HMISong(const HMISong *original, const char *filename, EMidiDevice type);	// file dump constructor
619 
620 	void SetupForHMI(int len);
621 	void SetupForHMP(int len);
622 	void CheckCaps(int tech);
623 
624 	void DoInitialSetup();
625 	void DoRestart();
626 	bool CheckDone();
627 	DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time);
628 	void AdvanceTracks(DWORD time);
629 
630 	struct TrackInfo;
631 
632 	void ProcessInitialMetaEvents ();
633 	DWORD *SendCommand (DWORD *event, TrackInfo *track, DWORD delay, ptrdiff_t room, bool &sysex_noroom);
634 	TrackInfo *FindNextDue ();
635 
636 	static DWORD ReadVarLenHMI(TrackInfo *);
637 	static DWORD ReadVarLenHMP(TrackInfo *);
638 
639 	BYTE *MusHeader;
640 	int SongLen;
641 	int NumTracks;
642 	TrackInfo *Tracks;
643 	TrackInfo *TrackDue;
644 	TrackInfo *FakeTrack;
645 	DWORD (*ReadVarLen)(TrackInfo *);
646 	NoteOffQueue NoteOffs;
647 };
648 
649 // XMI file played with a MIDI stream ---------------------------------------
650 
651 class XMISong : public MIDIStreamer
652 {
653 public:
654 	XMISong(FileReader &reader, EMidiDevice type, const char *args);
655 	~XMISong();
656 
657 	MusInfo *GetOPLDumper(const char *filename);
658 	MusInfo *GetWaveDumper(const char *filename, int rate);
659 
660 protected:
661 	struct TrackInfo;
662 	enum EventSource { EVENT_None, EVENT_Real, EVENT_Fake };
663 
664 	XMISong(const XMISong *original, const char *filename, EMidiDevice type);	// file dump constructor
665 
666 	int FindXMIDforms(const BYTE *chunk, int len, TrackInfo *songs) const;
667 	void FoundXMID(const BYTE *chunk, int len, TrackInfo *song) const;
668 	bool SetMIDISubsong(int subsong);
669 	void DoInitialSetup();
670 	void DoRestart();
671 	bool CheckDone();
672 	DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time);
673 	void AdvanceSong(DWORD time);
674 
675 	void ProcessInitialMetaEvents();
676 	DWORD *SendCommand (DWORD *event, EventSource track, DWORD delay, ptrdiff_t room, bool &sysex_noroom);
677 	EventSource FindNextDue();
678 
679 	BYTE *MusHeader;
680 	int SongLen;		// length of the entire file
681 	int NumSongs;
682 	TrackInfo *Songs;
683 	TrackInfo *CurrSong;
684 	NoteOffQueue NoteOffs;
685 	EventSource EventDue;
686 };
687 
688 // Anything supported by the sound system out of the box --------------------
689 
690 class StreamSong : public MusInfo
691 {
692 public:
693     StreamSong (FileReader *reader);
694 	StreamSong (const char *url);
695 	~StreamSong ();
696 	void Play (bool looping, int subsong);
697 	void Pause ();
698 	void Resume ();
699 	void Stop ();
700 	bool IsPlaying ();
IsValid()701 	bool IsValid () const { return m_Stream != NULL; }
702 	bool SetPosition (unsigned int pos);
703 	bool SetSubsong (int subsong);
704 	FString GetStats();
705 
706 protected:
StreamSong()707 	StreamSong () : m_Stream(NULL) {}
708 
709 	SoundStream *m_Stream;
710 };
711 
712 // MUS file played by a software OPL2 synth and streamed through the sound system
713 
714 class OPLMUSSong : public StreamSong
715 {
716 public:
717 	OPLMUSSong (FileReader &reader, const char *args);
718 	~OPLMUSSong ();
719 	void Play (bool looping, int subsong);
720 	bool IsPlaying ();
721 	bool IsValid () const;
722 	void ResetChips ();
723 	MusInfo *GetOPLDumper(const char *filename);
724 
725 protected:
726 	OPLMUSSong(const OPLMUSSong *original, const char *filename);	// OPL dump constructor
727 
728 	static bool FillStream (SoundStream *stream, void *buff, int len, void *userdata);
729 
730 	OPLmusicFile *Music;
731 };
732 
733 class OPLMUSDumper : public OPLMUSSong
734 {
735 public:
736 	OPLMUSDumper(const OPLMUSSong *original, const char *filename);
737 	void Play(bool looping, int);
738 };
739 
740 // CD track/disk played through the multimedia system -----------------------
741 
742 class CDSong : public MusInfo
743 {
744 public:
745 	CDSong (int track, int id);
746 	~CDSong ();
747 	void Play (bool looping, int subsong);
748 	void Pause ();
749 	void Resume ();
750 	void Stop ();
751 	bool IsPlaying ();
IsValid()752 	bool IsValid () const { return m_Inited; }
753 
754 protected:
CDSong()755 	CDSong () : m_Inited(false) {}
756 
757 	int m_Track;
758 	bool m_Inited;
759 };
760 
761 // CD track on a specific disk played through the multimedia system ---------
762 
763 class CDDAFile : public CDSong
764 {
765 public:
766 	CDDAFile (FileReader &reader);
767 };
768 
769 // Module played via foo_dumb -----------------------------------------------
770 
771 MusInfo *MOD_OpenSong(FileReader &reader);
772 
773 // Music played via Game Music Emu ------------------------------------------
774 
775 const char *GME_CheckFormat(uint32 header);
776 MusInfo *GME_OpenSong(FileReader &reader, const char *fmt);
777 
778 // --------------------------------------------------------------------------
779 
780 extern MusInfo *currSong;
781 
782 EXTERN_CVAR (Float, snd_musicvolume)
783