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