mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-28 15:02:39 +00:00
- removed all dependencies on ZDoom code from the MIDI sources (including TArray and FileReader.)
This commit is contained in:
parent
d8a1005c76
commit
820cbcc689
10 changed files with 207 additions and 245 deletions
|
@ -124,7 +124,7 @@ int MIDISource::VolumeControllerChange(int channel, int volume)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
TArray<uint16_t> MIDISource::PrecacheData()
|
std::vector<uint16_t> MIDISource::PrecacheData()
|
||||||
{
|
{
|
||||||
uint32_t Events[2][MAX_MIDI_EVENTS*3];
|
uint32_t Events[2][MAX_MIDI_EVENTS*3];
|
||||||
uint8_t found_instruments[256] = { 0, };
|
uint8_t found_instruments[256] = { 0, };
|
||||||
|
@ -189,7 +189,7 @@ TArray<uint16_t> MIDISource::PrecacheData()
|
||||||
DoRestart();
|
DoRestart();
|
||||||
|
|
||||||
// Now pack everything into a contiguous region for the PrecacheInstruments call().
|
// Now pack everything into a contiguous region for the PrecacheInstruments call().
|
||||||
TArray<uint16_t> packed;
|
std::vector<uint16_t> packed;
|
||||||
|
|
||||||
for (int i = 0; i < 256; ++i)
|
for (int i = 0; i < 256; ++i)
|
||||||
{
|
{
|
||||||
|
@ -198,7 +198,7 @@ TArray<uint16_t> MIDISource::PrecacheData()
|
||||||
uint16_t packnum = (i & 127) | ((i & 128) << 7);
|
uint16_t packnum = (i & 127) | ((i & 128) << 7);
|
||||||
if (!multiple_banks)
|
if (!multiple_banks)
|
||||||
{
|
{
|
||||||
packed.Push(packnum);
|
packed.push_back(packnum);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // In order to avoid having to multiplex tracks in a type 1 file,
|
{ // In order to avoid having to multiplex tracks in a type 1 file,
|
||||||
|
@ -208,7 +208,7 @@ TArray<uint16_t> MIDISource::PrecacheData()
|
||||||
{
|
{
|
||||||
if (found_banks[j + (i & 128)])
|
if (found_banks[j + (i & 128)])
|
||||||
{
|
{
|
||||||
packed.Push(packnum | (j << 7));
|
packed.push_back(packnum | (j << 7));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,7 +249,7 @@ bool MIDISource::SetMIDISubsong(int subsong)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
static void WriteVarLen (TArray<uint8_t> &file, uint32_t value)
|
static void WriteVarLen (std::vector<uint8_t> &file, uint32_t value)
|
||||||
{
|
{
|
||||||
uint32_t buffer = value & 0x7F;
|
uint32_t buffer = value & 0x7F;
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ static void WriteVarLen (TArray<uint8_t> &file, uint32_t value)
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
file.Push(uint8_t(buffer));
|
file.push_back(uint8_t(buffer));
|
||||||
if (buffer & 0x80)
|
if (buffer & 0x80)
|
||||||
{
|
{
|
||||||
buffer >>= 8;
|
buffer >>= 8;
|
||||||
|
@ -281,7 +281,7 @@ static void WriteVarLen (TArray<uint8_t> &file, uint32_t value)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void MIDISource::CreateSMF(TArray<uint8_t> &file, int looplimit)
|
void MIDISource::CreateSMF(std::vector<uint8_t> &file, int looplimit)
|
||||||
{
|
{
|
||||||
const int EXPORT_LOOP_LIMIT = 30; // Maximum number of times to loop when exporting a MIDI file.
|
const int EXPORT_LOOP_LIMIT = 30; // Maximum number of times to loop when exporting a MIDI file.
|
||||||
// (for songs with loop controller events)
|
// (for songs with loop controller events)
|
||||||
|
@ -307,8 +307,8 @@ void MIDISource::CreateSMF(TArray<uint8_t> &file, int looplimit)
|
||||||
DoRestart();
|
DoRestart();
|
||||||
StartPlayback(false, LoopLimit);
|
StartPlayback(false, LoopLimit);
|
||||||
|
|
||||||
file.Reserve(sizeof(StaticMIDIhead));
|
file.resize(sizeof(StaticMIDIhead));
|
||||||
memcpy(&file[0], StaticMIDIhead, sizeof(StaticMIDIhead));
|
memcpy(file.data(), StaticMIDIhead, sizeof(StaticMIDIhead));
|
||||||
file[12] = Division >> 8;
|
file[12] = Division >> 8;
|
||||||
file[13] = Division & 0xFF;
|
file[13] = Division & 0xFF;
|
||||||
file[26] = InitialTempo >> 16;
|
file[26] = InitialTempo >> 16;
|
||||||
|
@ -326,12 +326,12 @@ void MIDISource::CreateSMF(TArray<uint8_t> &file, int looplimit)
|
||||||
WriteVarLen(file, delay);
|
WriteVarLen(file, delay);
|
||||||
delay = 0;
|
delay = 0;
|
||||||
uint32_t tempo = MEVENT_EVENTPARM(event[2]);
|
uint32_t tempo = MEVENT_EVENTPARM(event[2]);
|
||||||
file.Push(MIDI_META);
|
file.push_back(MIDI_META);
|
||||||
file.Push(MIDI_META_TEMPO);
|
file.push_back(MIDI_META_TEMPO);
|
||||||
file.Push(3);
|
file.push_back(3);
|
||||||
file.Push(uint8_t(tempo >> 16));
|
file.push_back(uint8_t(tempo >> 16));
|
||||||
file.Push(uint8_t(tempo >> 8));
|
file.push_back(uint8_t(tempo >> 8));
|
||||||
file.Push(uint8_t(tempo));
|
file.push_back(uint8_t(tempo));
|
||||||
running_status = 255;
|
running_status = 255;
|
||||||
}
|
}
|
||||||
else if (MEVENT_EVENTTYPE(event[2]) == MEVENT_LONGMSG)
|
else if (MEVENT_EVENTTYPE(event[2]) == MEVENT_LONGMSG)
|
||||||
|
@ -343,15 +343,19 @@ void MIDISource::CreateSMF(TArray<uint8_t> &file, int looplimit)
|
||||||
if (bytes[0] == MIDI_SYSEX)
|
if (bytes[0] == MIDI_SYSEX)
|
||||||
{
|
{
|
||||||
len--;
|
len--;
|
||||||
file.Push(MIDI_SYSEX);
|
file.push_back(MIDI_SYSEX);
|
||||||
WriteVarLen(file, len);
|
WriteVarLen(file, len);
|
||||||
memcpy(&file[file.Reserve(len)], bytes + 1, len);
|
auto p = file.size();
|
||||||
|
file.resize(p + len);
|
||||||
|
memcpy(&file[p], bytes + 1, len);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
file.Push(MIDI_SYSEXEND);
|
file.push_back(MIDI_SYSEXEND);
|
||||||
WriteVarLen(file, len);
|
WriteVarLen(file, len);
|
||||||
memcpy(&file[file.Reserve(len)], bytes, len);
|
auto p = file.size();
|
||||||
|
file.resize(p + len);
|
||||||
|
memcpy(&file[p], bytes, len);
|
||||||
}
|
}
|
||||||
running_status = 255;
|
running_status = 255;
|
||||||
}
|
}
|
||||||
|
@ -363,12 +367,12 @@ void MIDISource::CreateSMF(TArray<uint8_t> &file, int looplimit)
|
||||||
if (status != running_status)
|
if (status != running_status)
|
||||||
{
|
{
|
||||||
running_status = status;
|
running_status = status;
|
||||||
file.Push(status);
|
file.push_back(status);
|
||||||
}
|
}
|
||||||
file.Push(uint8_t((event[2] >> 8) & 0x7F));
|
file.push_back(uint8_t((event[2] >> 8) & 0x7F));
|
||||||
if (MIDI_EventLengths[(status >> 4) & 7] == 2)
|
if (MIDI_EventLengths[(status >> 4) & 7] == 2)
|
||||||
{
|
{
|
||||||
file.Push(uint8_t((event[2] >> 16) & 0x7F));
|
file.push_back(uint8_t((event[2] >> 16) & 0x7F));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Advance to next event
|
// Advance to next event
|
||||||
|
@ -385,12 +389,12 @@ void MIDISource::CreateSMF(TArray<uint8_t> &file, int looplimit)
|
||||||
|
|
||||||
// End track
|
// End track
|
||||||
WriteVarLen(file, delay);
|
WriteVarLen(file, delay);
|
||||||
file.Push(MIDI_META);
|
file.push_back(MIDI_META);
|
||||||
file.Push(MIDI_META_EOT);
|
file.push_back(MIDI_META_EOT);
|
||||||
file.Push(0);
|
file.push_back(0);
|
||||||
|
|
||||||
// Fill in track length
|
// Fill in track length
|
||||||
uint32_t len = file.Size() - 22;
|
uint32_t len = (uint32_t)file.size() - 22;
|
||||||
file[18] = uint8_t(len >> 24);
|
file[18] = uint8_t(len >> 24);
|
||||||
file[19] = uint8_t(len >> 16);
|
file[19] = uint8_t(len >> 16);
|
||||||
file[20] = uint8_t(len >> 8);
|
file[20] = uint8_t(len >> 8);
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include "files.h"
|
#include <vector>
|
||||||
#include "mus2midi.h"
|
#include "mus2midi.h"
|
||||||
#include "mididefs.h"
|
#include "mididefs.h"
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ public:
|
||||||
virtual void DoInitialSetup() = 0;
|
virtual void DoInitialSetup() = 0;
|
||||||
virtual void DoRestart() = 0;
|
virtual void DoRestart() = 0;
|
||||||
virtual bool CheckDone() = 0;
|
virtual bool CheckDone() = 0;
|
||||||
virtual TArray<uint16_t> PrecacheData();
|
virtual std::vector<uint16_t> PrecacheData();
|
||||||
virtual bool SetMIDISubsong(int subsong);
|
virtual bool SetMIDISubsong(int subsong);
|
||||||
virtual uint32_t *MakeEvents(uint32_t *events, uint32_t *max_event_p, uint32_t max_time) = 0;
|
virtual uint32_t *MakeEvents(uint32_t *events, uint32_t *max_event_p, uint32_t max_time) = 0;
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ public:
|
||||||
TempoCallback = cb;
|
TempoCallback = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateSMF(TArray<uint8_t> &file, int looplimit);
|
void CreateSMF(std::vector<uint8_t> &file, int looplimit);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -83,19 +83,18 @@ public:
|
||||||
class MUSSong2 : public MIDISource
|
class MUSSong2 : public MIDISource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MUSSong2(FileReader &reader);
|
MUSSong2(const uint8_t *data, size_t len);
|
||||||
~MUSSong2();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void DoInitialSetup() override;
|
void DoInitialSetup() override;
|
||||||
void DoRestart() override;
|
void DoRestart() override;
|
||||||
bool CheckDone() override;
|
bool CheckDone() override;
|
||||||
TArray<uint16_t> PrecacheData() override;
|
std::vector<uint16_t> PrecacheData() override;
|
||||||
uint32_t *MakeEvents(uint32_t *events, uint32_t *max_events_p, uint32_t max_time) override;
|
uint32_t *MakeEvents(uint32_t *events, uint32_t *max_events_p, uint32_t max_time) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MUSHeader *MusHeader;
|
std::vector<uint8_t> MusData;
|
||||||
uint8_t *MusBuffer;
|
uint8_t* MusBuffer;
|
||||||
uint8_t LastVelocity[16];
|
uint8_t LastVelocity[16];
|
||||||
size_t MusP, MaxMusP;
|
size_t MusP, MaxMusP;
|
||||||
};
|
};
|
||||||
|
@ -106,8 +105,7 @@ private:
|
||||||
class MIDISong2 : public MIDISource
|
class MIDISong2 : public MIDISource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MIDISong2(FileReader &reader);
|
MIDISong2(const uint8_t* data, size_t len);
|
||||||
~MIDISong2();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void CheckCaps(int tech) override;
|
void CheckCaps(int tech) override;
|
||||||
|
@ -125,8 +123,8 @@ private:
|
||||||
uint32_t *SendCommand (uint32_t *event, TrackInfo *track, uint32_t delay, ptrdiff_t room, bool &sysex_noroom);
|
uint32_t *SendCommand (uint32_t *event, TrackInfo *track, uint32_t delay, ptrdiff_t room, bool &sysex_noroom);
|
||||||
TrackInfo *FindNextDue ();
|
TrackInfo *FindNextDue ();
|
||||||
|
|
||||||
TArray<uint8_t> MusHeader;
|
std::vector<uint8_t> MusHeader;
|
||||||
TrackInfo *Tracks;
|
std::vector<TrackInfo> Tracks;
|
||||||
TrackInfo *TrackDue;
|
TrackInfo *TrackDue;
|
||||||
int NumTracks;
|
int NumTracks;
|
||||||
int Format;
|
int Format;
|
||||||
|
@ -141,7 +139,7 @@ struct AutoNoteOff
|
||||||
uint8_t Channel, Key;
|
uint8_t Channel, Key;
|
||||||
};
|
};
|
||||||
// Sorry, std::priority_queue, but I want to be able to modify the contents of the heap.
|
// Sorry, std::priority_queue, but I want to be able to modify the contents of the heap.
|
||||||
class NoteOffQueue : public TArray<AutoNoteOff>
|
class NoteOffQueue : public std::vector<AutoNoteOff>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void AddNoteOff(uint32_t delay, uint8_t channel, uint8_t key);
|
void AddNoteOff(uint32_t delay, uint8_t channel, uint8_t key);
|
||||||
|
@ -159,8 +157,7 @@ protected:
|
||||||
class HMISong : public MIDISource
|
class HMISong : public MIDISource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HMISong(FileReader &reader);
|
HMISong(const uint8_t* data, size_t len);
|
||||||
~HMISong();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -184,9 +181,9 @@ private:
|
||||||
static uint32_t ReadVarLenHMI(TrackInfo *);
|
static uint32_t ReadVarLenHMI(TrackInfo *);
|
||||||
static uint32_t ReadVarLenHMP(TrackInfo *);
|
static uint32_t ReadVarLenHMP(TrackInfo *);
|
||||||
|
|
||||||
TArray<uint8_t> MusHeader;
|
std::vector<uint8_t> MusHeader;
|
||||||
int NumTracks;
|
int NumTracks;
|
||||||
TrackInfo *Tracks;
|
std::vector<TrackInfo> Tracks;
|
||||||
TrackInfo *TrackDue;
|
TrackInfo *TrackDue;
|
||||||
TrackInfo *FakeTrack;
|
TrackInfo *FakeTrack;
|
||||||
uint32_t (*ReadVarLen)(TrackInfo *);
|
uint32_t (*ReadVarLen)(TrackInfo *);
|
||||||
|
@ -198,8 +195,7 @@ private:
|
||||||
class XMISong : public MIDISource
|
class XMISong : public MIDISource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
XMISong(FileReader &reader);
|
XMISong(const uint8_t* data, size_t len);
|
||||||
~XMISong();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool SetMIDISubsong(int subsong) override;
|
bool SetMIDISubsong(int subsong) override;
|
||||||
|
@ -220,9 +216,9 @@ private:
|
||||||
uint32_t *SendCommand (uint32_t *event, EventSource track, uint32_t delay, ptrdiff_t room, bool &sysex_noroom);
|
uint32_t *SendCommand (uint32_t *event, EventSource track, uint32_t delay, ptrdiff_t room, bool &sysex_noroom);
|
||||||
EventSource FindNextDue();
|
EventSource FindNextDue();
|
||||||
|
|
||||||
TArray<uint8_t> MusHeader;
|
std::vector<uint8_t> MusHeader;
|
||||||
int NumSongs;
|
int NumSongs;
|
||||||
TrackInfo *Songs;
|
std::vector<TrackInfo> Songs;
|
||||||
TrackInfo *CurrSong;
|
TrackInfo *CurrSong;
|
||||||
NoteOffQueue NoteOffs;
|
NoteOffQueue NoteOffs;
|
||||||
EventSource EventDue;
|
EventSource EventDue;
|
||||||
|
|
|
@ -34,9 +34,9 @@
|
||||||
|
|
||||||
// HEADER FILES ------------------------------------------------------------
|
// HEADER FILES ------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include "midisource.h"
|
#include "midisource.h"
|
||||||
#include "basictypes.h"
|
#include "m_swap.h"
|
||||||
#include "templates.h"
|
|
||||||
|
|
||||||
// MACROS ------------------------------------------------------------------
|
// MACROS ------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -123,40 +123,24 @@ struct HMISong::TrackInfo
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
HMISong::HMISong (FileReader &reader)
|
HMISong::HMISong (const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
int len = (int)reader.GetLength();
|
|
||||||
if (len < 0x100)
|
if (len < 0x100)
|
||||||
{ // Way too small to be HMI.
|
{ // Way too small to be HMI.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MusHeader = reader.Read();
|
MusHeader.resize(len);
|
||||||
|
memcpy(MusHeader.data(), data, len);
|
||||||
NumTracks = 0;
|
NumTracks = 0;
|
||||||
if (MusHeader.Size() == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Do some validation of the MIDI file
|
// Do some validation of the MIDI file
|
||||||
if (memcmp(&MusHeader[0], HMI_SONG_MAGIC, sizeof(HMI_SONG_MAGIC)) == 0)
|
if (memcmp(&MusHeader[0], HMI_SONG_MAGIC, sizeof(HMI_SONG_MAGIC)) == 0)
|
||||||
{
|
{
|
||||||
SetupForHMI(len);
|
SetupForHMI((int)len);
|
||||||
}
|
}
|
||||||
else if (memcmp(&MusHeader[0], "HMIMIDIP", 8) == 0)
|
else if (memcmp(&MusHeader[0], "HMIMIDIP", 8) == 0)
|
||||||
{
|
{
|
||||||
SetupForHMP(len);
|
SetupForHMP((int)len);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// HMISong Destructor
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
HMISong::~HMISong()
|
|
||||||
{
|
|
||||||
if (Tracks != nullptr)
|
|
||||||
{
|
|
||||||
delete[] Tracks;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +171,7 @@ void HMISong::SetupForHMI(int len)
|
||||||
Division = GetShort(MusPtr + HMI_DIVISION_OFFSET) << 2;
|
Division = GetShort(MusPtr + HMI_DIVISION_OFFSET) << 2;
|
||||||
Tempo = InitialTempo = 4000000;
|
Tempo = InitialTempo = 4000000;
|
||||||
|
|
||||||
Tracks = new TrackInfo[NumTracks + 1];
|
Tracks.resize(NumTracks + 1);
|
||||||
int track_dir = GetInt(MusPtr + HMI_TRACK_DIR_PTR_OFFSET);
|
int track_dir = GetInt(MusPtr + HMI_TRACK_DIR_PTR_OFFSET);
|
||||||
|
|
||||||
// Gather information about each track
|
// Gather information about each track
|
||||||
|
@ -218,7 +202,7 @@ void HMISong::SetupForHMI(int len)
|
||||||
tracklen = GetInt(MusPtr + track_dir + i*4 + 4) - start;
|
tracklen = GetInt(MusPtr + track_dir + i*4 + 4) - start;
|
||||||
}
|
}
|
||||||
// Clamp incomplete tracks to the end of the file.
|
// Clamp incomplete tracks to the end of the file.
|
||||||
tracklen = MIN(tracklen, len - start);
|
tracklen = std::min(tracklen, len - start);
|
||||||
if (tracklen <= 0)
|
if (tracklen <= 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -290,7 +274,7 @@ void HMISong::SetupForHMP(int len)
|
||||||
Division = GetInt(MusPtr + HMP_DIVISION_OFFSET);
|
Division = GetInt(MusPtr + HMP_DIVISION_OFFSET);
|
||||||
Tempo = InitialTempo = 1000000;
|
Tempo = InitialTempo = 1000000;
|
||||||
|
|
||||||
Tracks = new TrackInfo[NumTracks + 1];
|
Tracks.resize(NumTracks + 1);
|
||||||
|
|
||||||
// Gather information about each track
|
// Gather information about each track
|
||||||
for (i = 0, p = 0; i < NumTracks; ++i)
|
for (i = 0, p = 0; i < NumTracks; ++i)
|
||||||
|
@ -307,7 +291,7 @@ void HMISong::SetupForHMP(int len)
|
||||||
track_data += tracklen;
|
track_data += tracklen;
|
||||||
|
|
||||||
// Clamp incomplete tracks to the end of the file.
|
// Clamp incomplete tracks to the end of the file.
|
||||||
tracklen = MIN(tracklen, len - start);
|
tracklen = std::min(tracklen, len - start);
|
||||||
if (tracklen <= 0)
|
if (tracklen <= 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -385,7 +369,7 @@ void HMISong::CheckCaps(int tech)
|
||||||
{
|
{
|
||||||
Tracks[i].Enabled = false;
|
Tracks[i].Enabled = false;
|
||||||
// Track designations are stored in a 0-terminated array.
|
// Track designations are stored in a 0-terminated array.
|
||||||
for (unsigned int j = 0; j < countof(Tracks[i].Designation) && Tracks[i].Designation[j] != 0; ++j)
|
for (unsigned int j = 0; j < NUM_HMI_DESIGNATIONS && Tracks[i].Designation[j] != 0; ++j)
|
||||||
{
|
{
|
||||||
if (Tracks[i].Designation[j] == tech)
|
if (Tracks[i].Designation[j] == tech)
|
||||||
{
|
{
|
||||||
|
@ -446,7 +430,7 @@ void HMISong :: DoRestart()
|
||||||
|
|
||||||
// Set initial state.
|
// Set initial state.
|
||||||
FakeTrack = &Tracks[NumTracks];
|
FakeTrack = &Tracks[NumTracks];
|
||||||
NoteOffs.Clear();
|
NoteOffs.clear();
|
||||||
for (i = 0; i <= NumTracks; ++i)
|
for (i = 0; i <= NumTracks; ++i)
|
||||||
{
|
{
|
||||||
Tracks[i].TrackP = 0;
|
Tracks[i].TrackP = 0;
|
||||||
|
@ -461,7 +445,7 @@ void HMISong :: DoRestart()
|
||||||
}
|
}
|
||||||
Tracks[i].Delay = 0; // for the FakeTrack
|
Tracks[i].Delay = 0; // for the FakeTrack
|
||||||
Tracks[i].Enabled = true;
|
Tracks[i].Enabled = true;
|
||||||
TrackDue = Tracks;
|
TrackDue = Tracks.data();
|
||||||
TrackDue = FindNextDue();
|
TrackDue = FindNextDue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -883,7 +867,8 @@ uint32_t HMISong::TrackInfo::ReadVarLenHMP()
|
||||||
|
|
||||||
void NoteOffQueue::AddNoteOff(uint32_t delay, uint8_t channel, uint8_t key)
|
void NoteOffQueue::AddNoteOff(uint32_t delay, uint8_t channel, uint8_t key)
|
||||||
{
|
{
|
||||||
unsigned int i = Reserve(1);
|
uint32_t i = (uint32_t)size();
|
||||||
|
resize(i + 1);
|
||||||
while (i > 0 && (*this)[Parent(i)].Delay > delay)
|
while (i > 0 && (*this)[Parent(i)].Delay > delay)
|
||||||
{
|
{
|
||||||
(*this)[i] = (*this)[Parent(i)];
|
(*this)[i] = (*this)[Parent(i)];
|
||||||
|
@ -902,9 +887,11 @@ void NoteOffQueue::AddNoteOff(uint32_t delay, uint8_t channel, uint8_t key)
|
||||||
|
|
||||||
bool NoteOffQueue::Pop(AutoNoteOff &item)
|
bool NoteOffQueue::Pop(AutoNoteOff &item)
|
||||||
{
|
{
|
||||||
item = (*this)[0];
|
if (size() > 0)
|
||||||
if (TArray<AutoNoteOff>::Pop((*this)[0]))
|
|
||||||
{
|
{
|
||||||
|
item = front();
|
||||||
|
front() = back();
|
||||||
|
pop_back();
|
||||||
Heapify();
|
Heapify();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -921,10 +908,10 @@ void NoteOffQueue::AdvanceTime(uint32_t time)
|
||||||
{
|
{
|
||||||
// Because the time is decreasing by the same amount for every entry,
|
// Because the time is decreasing by the same amount for every entry,
|
||||||
// the heap property is maintained.
|
// the heap property is maintained.
|
||||||
for (unsigned int i = 0; i < Size(); ++i)
|
for (auto &item : *this)
|
||||||
{
|
{
|
||||||
assert((*this)[i].Delay >= time);
|
assert(item.Delay >= time);
|
||||||
(*this)[i].Delay -= time;
|
item.Delay -= time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -942,11 +929,11 @@ void NoteOffQueue::Heapify()
|
||||||
unsigned int l = Left(i);
|
unsigned int l = Left(i);
|
||||||
unsigned int r = Right(i);
|
unsigned int r = Right(i);
|
||||||
unsigned int smallest = i;
|
unsigned int smallest = i;
|
||||||
if (l < Size() && (*this)[l].Delay < (*this)[i].Delay)
|
if (l < (unsigned)size() && (*this)[l].Delay < (*this)[i].Delay)
|
||||||
{
|
{
|
||||||
smallest = l;
|
smallest = l;
|
||||||
}
|
}
|
||||||
if (r < Size() && (*this)[r].Delay < (*this)[smallest].Delay)
|
if (r < (unsigned)size() && (*this)[r].Delay < (*this)[smallest].Delay)
|
||||||
{
|
{
|
||||||
smallest = r;
|
smallest = r;
|
||||||
}
|
}
|
||||||
|
@ -954,7 +941,7 @@ void NoteOffQueue::Heapify()
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
swapvalues((*this)[i], (*this)[smallest]);
|
std::swap((*this)[i], (*this)[smallest]);
|
||||||
i = smallest;
|
i = smallest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -979,7 +966,7 @@ HMISong::TrackInfo *HMISong::FindNextDue ()
|
||||||
{
|
{
|
||||||
return TrackDue;
|
return TrackDue;
|
||||||
}
|
}
|
||||||
if (TrackDue == FakeTrack && NoteOffs.Size() != 0 && NoteOffs[0].Delay == 0)
|
if (TrackDue == FakeTrack && NoteOffs.size() != 0 && NoteOffs[0].Delay == 0)
|
||||||
{
|
{
|
||||||
FakeTrack->Delay = 0;
|
FakeTrack->Delay = 0;
|
||||||
return FakeTrack;
|
return FakeTrack;
|
||||||
|
@ -997,7 +984,7 @@ HMISong::TrackInfo *HMISong::FindNextDue ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check automatic note-offs.
|
// Check automatic note-offs.
|
||||||
if (NoteOffs.Size() != 0 && NoteOffs[0].Delay <= best)
|
if (NoteOffs.size() != 0 && NoteOffs[0].Delay <= best)
|
||||||
{
|
{
|
||||||
FakeTrack->Delay = NoteOffs[0].Delay;
|
FakeTrack->Delay = NoteOffs[0].Delay;
|
||||||
return FakeTrack;
|
return FakeTrack;
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
// HEADER FILES ------------------------------------------------------------
|
// HEADER FILES ------------------------------------------------------------
|
||||||
|
|
||||||
#include "midisource.h"
|
#include "midisource.h"
|
||||||
#include "templates.h"
|
#include "m_swap.h"
|
||||||
|
|
||||||
// MACROS ------------------------------------------------------------------
|
// MACROS ------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -84,39 +84,30 @@ static const uint8_t CtrlTranslate[15] =
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
MUSSong2::MUSSong2 (FileReader &reader)
|
MUSSong2::MUSSong2 (const uint8_t *data, size_t len)
|
||||||
: MusHeader(0), MusBuffer(0)
|
|
||||||
{
|
{
|
||||||
uint8_t front[32];
|
|
||||||
int start;
|
int start;
|
||||||
|
|
||||||
if (reader.Read(front, sizeof(front)) != sizeof(front))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// To tolerate sloppy wads (diescum.wad, I'm looking at you), we search
|
// To tolerate sloppy wads (diescum.wad, I'm looking at you), we search
|
||||||
// the first 32 bytes of the file for a signature. My guess is that DMX
|
// the first 32 bytes of the file for a signature. My guess is that DMX
|
||||||
// does no validation whatsoever and just assumes it was passed a valid
|
// does no validation whatsoever and just assumes it was passed a valid
|
||||||
// MUS file, since where the header is offset affects how it plays.
|
// MUS file, since where the header is offset affects how it plays.
|
||||||
start = MUSHeaderSearch(front, sizeof(front));
|
start = MUSHeaderSearch(data, 32);
|
||||||
if (start < 0)
|
if (start < 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
data += start;
|
||||||
|
len -= start;
|
||||||
|
|
||||||
// Read the remainder of the song.
|
// Read the remainder of the song.
|
||||||
int len = int(reader.GetLength() - start);
|
if (len < sizeof(MUSHeader))
|
||||||
if (len < (int)sizeof(MusHeader))
|
|
||||||
{ // It's too short.
|
{ // It's too short.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MusHeader = (MUSHeader *)new uint8_t[len];
|
MusData.resize(len);
|
||||||
memcpy(MusHeader, front + start, sizeof(front) - start);
|
memcpy(MusData.data(), data, len);
|
||||||
if (reader.Read((uint8_t *)MusHeader + sizeof(front) - start, len - (sizeof(front) - start)) != (len - (32 - start)))
|
auto MusHeader = (MUSHeader*)MusData.data();
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do some validation of the MUS file.
|
// Do some validation of the MUS file.
|
||||||
if (LittleShort(MusHeader->NumChans) > 15)
|
if (LittleShort(MusHeader->NumChans) > 15)
|
||||||
|
@ -124,26 +115,12 @@ MUSSong2::MUSSong2 (FileReader &reader)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MusBuffer = (uint8_t *)MusHeader + LittleShort(MusHeader->SongStart);
|
MusBuffer = MusData.data() + LittleShort(MusHeader->SongStart);
|
||||||
MaxMusP = MIN<int>(LittleShort(MusHeader->SongLen), len - LittleShort(MusHeader->SongStart));
|
MaxMusP = std::min<int>(LittleShort(MusHeader->SongLen), int(len) - LittleShort(MusHeader->SongStart));
|
||||||
Division = 140;
|
Division = 140;
|
||||||
Tempo = InitialTempo = 1000000;
|
Tempo = InitialTempo = 1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// MUSSong2 Destructor
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
MUSSong2::~MUSSong2 ()
|
|
||||||
{
|
|
||||||
if (MusHeader != NULL)
|
|
||||||
{
|
|
||||||
delete[] (uint8_t *)MusHeader;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// MUSSong2 :: DoInitialSetup
|
// MUSSong2 :: DoInitialSetup
|
||||||
|
@ -193,13 +170,17 @@ bool MUSSong2::CheckDone()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
TArray<uint16_t> MUSSong2::PrecacheData()
|
std::vector<uint16_t> MUSSong2::PrecacheData()
|
||||||
{
|
{
|
||||||
TArray<uint16_t> work(LittleShort(MusHeader->NumInstruments));
|
auto MusHeader = (MUSHeader*)MusData.data();
|
||||||
const uint8_t *used = (uint8_t *)MusHeader + sizeof(MUSHeader) / sizeof(uint8_t);
|
std::vector<uint16_t> work;
|
||||||
|
const uint8_t *used = MusData.data() + sizeof(MUSHeader) / sizeof(uint8_t);
|
||||||
int i, k;
|
int i, k;
|
||||||
|
size_t p = 0;
|
||||||
|
|
||||||
for (i = k = 0; i < LittleShort(MusHeader->NumInstruments); ++i)
|
int numinstr = LittleShort(MusHeader->NumInstruments);
|
||||||
|
work.reserve(LittleShort(MusHeader->NumInstruments));
|
||||||
|
for (i = k = 0; i < numinstr; ++i)
|
||||||
{
|
{
|
||||||
uint8_t instr = used[k++];
|
uint8_t instr = used[k++];
|
||||||
uint16_t val;
|
uint16_t val;
|
||||||
|
@ -224,12 +205,12 @@ TArray<uint16_t> MUSSong2::PrecacheData()
|
||||||
{
|
{
|
||||||
for (int b = 0; b < numbanks; b++)
|
for (int b = 0; b < numbanks; b++)
|
||||||
{
|
{
|
||||||
work.Push(val | (used[k++] << 7));
|
work.push_back(val | (used[k++] << 7));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
work.Push(val);
|
work.push_back(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return work;
|
return work;
|
||||||
|
@ -248,6 +229,7 @@ uint32_t *MUSSong2::MakeEvents(uint32_t *events, uint32_t *max_event_p, uint32_t
|
||||||
{
|
{
|
||||||
uint32_t tot_time = 0;
|
uint32_t tot_time = 0;
|
||||||
uint32_t time = 0;
|
uint32_t time = 0;
|
||||||
|
auto MusHeader = (MUSHeader*)MusData.data();
|
||||||
|
|
||||||
max_time = max_time * Division / Tempo;
|
max_time = max_time * Division / Tempo;
|
||||||
|
|
||||||
|
@ -321,7 +303,7 @@ uint32_t *MUSSong2::MakeEvents(uint32_t *events, uint32_t *max_event_p, uint32_t
|
||||||
if (mid1 == 7)
|
if (mid1 == 7)
|
||||||
{ // Clamp volume to 127, since DMX apparently allows 8-bit volumes.
|
{ // Clamp volume to 127, since DMX apparently allows 8-bit volumes.
|
||||||
// Fix courtesy of Gez, courtesy of Ben Ryves.
|
// Fix courtesy of Gez, courtesy of Ben Ryves.
|
||||||
mid2 = VolumeControllerChange(channel, MIN<int>(mid2, 0x7F));
|
mid2 = VolumeControllerChange(channel, std::min<int>(mid2, 0x7F));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -95,14 +95,14 @@ struct MIDISong2::TrackInfo
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
MIDISong2::MIDISong2 (FileReader &reader)
|
MIDISong2::MIDISong2 (const uint8_t* data, size_t len)
|
||||||
: MusHeader(0), Tracks(0)
|
: MusHeader(0), Tracks(0)
|
||||||
{
|
{
|
||||||
unsigned p;
|
unsigned p;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
MusHeader = reader.Read();
|
MusHeader.resize(len);
|
||||||
if (MusHeader.Size() == 0) return;
|
memcpy(MusHeader.data(), data, len);
|
||||||
|
|
||||||
// Do some validation of the MIDI file
|
// Do some validation of the MIDI file
|
||||||
if (MusHeader[4] != 0 || MusHeader[5] != 0 || MusHeader[6] != 0 || MusHeader[7] != 6)
|
if (MusHeader[4] != 0 || MusHeader[5] != 0 || MusHeader[6] != 0 || MusHeader[7] != 6)
|
||||||
|
@ -129,10 +129,10 @@ MIDISong2::MIDISong2 (FileReader &reader)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tracks = new TrackInfo[NumTracks];
|
Tracks.resize(NumTracks);
|
||||||
|
|
||||||
// Gather information about each track
|
// Gather information about each track
|
||||||
for (i = 0, p = 14; i < NumTracks && p < MusHeader.Size() + 8; ++i)
|
for (i = 0, p = 14; i < NumTracks && p < MusHeader.size() + 8; ++i)
|
||||||
{
|
{
|
||||||
uint32_t chunkLen =
|
uint32_t chunkLen =
|
||||||
(MusHeader[p+4]<<24) |
|
(MusHeader[p+4]<<24) |
|
||||||
|
@ -140,9 +140,9 @@ MIDISong2::MIDISong2 (FileReader &reader)
|
||||||
(MusHeader[p+6]<<8) |
|
(MusHeader[p+6]<<8) |
|
||||||
(MusHeader[p+7]);
|
(MusHeader[p+7]);
|
||||||
|
|
||||||
if (chunkLen + p + 8 > MusHeader.Size())
|
if (chunkLen + p + 8 > MusHeader.size())
|
||||||
{ // Track too long, so truncate it
|
{ // Track too long, so truncate it
|
||||||
chunkLen = MusHeader.Size() - p - 8;
|
chunkLen = (uint32_t)MusHeader.size() - p - 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MusHeader[p+0] == 'M' &&
|
if (MusHeader[p+0] == 'M' &&
|
||||||
|
@ -168,20 +168,6 @@ MIDISong2::MIDISong2 (FileReader &reader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// MIDISong2 Destructor
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
MIDISong2::~MIDISong2 ()
|
|
||||||
{
|
|
||||||
if (Tracks != nullptr)
|
|
||||||
{
|
|
||||||
delete[] Tracks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// MIDISong2 :: CheckCaps
|
// MIDISong2 :: CheckCaps
|
||||||
|
@ -255,7 +241,7 @@ void MIDISong2 :: DoRestart()
|
||||||
{
|
{
|
||||||
Tracks[i].Delay = Tracks[i].ReadVarLen();
|
Tracks[i].Delay = Tracks[i].ReadVarLen();
|
||||||
}
|
}
|
||||||
TrackDue = Tracks;
|
TrackDue = Tracks.data();
|
||||||
TrackDue = FindNextDue();
|
TrackDue = FindNextDue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -764,7 +750,7 @@ MIDISong2::TrackInfo *MIDISong2::FindNextDue ()
|
||||||
switch (Format)
|
switch (Format)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
return Tracks[0].Finished ? nullptr : Tracks;
|
return Tracks[0].Finished ? nullptr : Tracks.data();
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
track = nullptr;
|
track = nullptr;
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
// HEADER FILES ------------------------------------------------------------
|
// HEADER FILES ------------------------------------------------------------
|
||||||
|
|
||||||
#include "midisource.h"
|
#include "midisource.h"
|
||||||
#include "basictypes.h"
|
#include "m_swap.h"
|
||||||
|
|
||||||
// MACROS ------------------------------------------------------------------
|
// MACROS ------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -51,6 +51,14 @@
|
||||||
return events; \
|
return events; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef MAKE_ID
|
||||||
|
#ifndef __BIG_ENDIAN__
|
||||||
|
#define MAKE_ID(a,b,c,d) ((uint32_t)((a)|((b)<<8)|((c)<<16)|((d)<<24)))
|
||||||
|
#else
|
||||||
|
#define MAKE_ID(a,b,c,d) ((uint32_t)((d)|((c)<<8)|((b)<<16)|((a)<<24)))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
// TYPES -------------------------------------------------------------------
|
// TYPES -------------------------------------------------------------------
|
||||||
|
|
||||||
struct LoopInfo
|
struct LoopInfo
|
||||||
|
@ -102,14 +110,14 @@ struct XMISong::TrackInfo
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
XMISong::XMISong (FileReader &reader)
|
XMISong::XMISong (const uint8_t* data, size_t len)
|
||||||
: MusHeader(0), Songs(0)
|
: MusHeader(0), Songs(0)
|
||||||
{
|
{
|
||||||
MusHeader = reader.Read();
|
MusHeader.resize(len);
|
||||||
if (MusHeader.Size() == 0) return;
|
memcpy(MusHeader.data(), data, len);
|
||||||
|
|
||||||
// Find all the songs in this file.
|
// Find all the songs in this file.
|
||||||
NumSongs = FindXMIDforms(&MusHeader[0], MusHeader.Size(), nullptr);
|
NumSongs = FindXMIDforms(&MusHeader[0], (int)MusHeader.size(), nullptr);
|
||||||
if (NumSongs == 0)
|
if (NumSongs == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -125,27 +133,13 @@ XMISong::XMISong (FileReader &reader)
|
||||||
Division = 60;
|
Division = 60;
|
||||||
Tempo = InitialTempo = 500000;
|
Tempo = InitialTempo = 500000;
|
||||||
|
|
||||||
Songs = new TrackInfo[NumSongs];
|
Songs.resize(NumSongs);
|
||||||
memset(Songs, 0, sizeof(*Songs) * NumSongs);
|
memset(Songs.data(), 0, sizeof(Songs[0]) * NumSongs);
|
||||||
FindXMIDforms(&MusHeader[0], MusHeader.Size(), Songs);
|
FindXMIDforms(&MusHeader[0], (int)MusHeader.size(), Songs.data());
|
||||||
CurrSong = Songs;
|
CurrSong = Songs.data();
|
||||||
//DPrintf(DMSG_SPAMMY, "XMI song count: %d\n", NumSongs);
|
//DPrintf(DMSG_SPAMMY, "XMI song count: %d\n", NumSongs);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// XMISong Destructor
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
XMISong::~XMISong ()
|
|
||||||
{
|
|
||||||
if (Songs != nullptr)
|
|
||||||
{
|
|
||||||
delete[] Songs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// XMISong :: FindXMIDforms
|
// XMISong :: FindXMIDforms
|
||||||
|
@ -267,7 +261,7 @@ void XMISong::DoRestart()
|
||||||
CurrSong->Finished = false;
|
CurrSong->Finished = false;
|
||||||
CurrSong->PlayedTime = 0;
|
CurrSong->PlayedTime = 0;
|
||||||
CurrSong->ForDepth = 0;
|
CurrSong->ForDepth = 0;
|
||||||
NoteOffs.Clear();
|
NoteOffs.clear();
|
||||||
|
|
||||||
ProcessInitialMetaEvents ();
|
ProcessInitialMetaEvents ();
|
||||||
|
|
||||||
|
@ -673,14 +667,14 @@ uint32_t XMISong::TrackInfo::ReadDelay()
|
||||||
XMISong::EventSource XMISong::FindNextDue()
|
XMISong::EventSource XMISong::FindNextDue()
|
||||||
{
|
{
|
||||||
// Are there still events available?
|
// Are there still events available?
|
||||||
if (CurrSong->Finished && NoteOffs.Size() == 0)
|
if (CurrSong->Finished && NoteOffs.size() == 0)
|
||||||
{
|
{
|
||||||
return EVENT_None;
|
return EVENT_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Which is due sooner? The current song or the note-offs?
|
// Which is due sooner? The current song or the note-offs?
|
||||||
uint32_t real_delay = CurrSong->Finished ? 0xFFFFFFFF : CurrSong->Delay;
|
uint32_t real_delay = CurrSong->Finished ? 0xFFFFFFFF : CurrSong->Delay;
|
||||||
uint32_t fake_delay = NoteOffs.Size() == 0 ? 0xFFFFFFFF : NoteOffs[0].Delay;
|
uint32_t fake_delay = NoteOffs.size() == 0 ? 0xFFFFFFFF : NoteOffs[0].Delay;
|
||||||
|
|
||||||
return (fake_delay <= real_delay) ? EVENT_Fake : EVENT_Real;
|
return (fake_delay <= real_delay) ? EVENT_Fake : EVENT_Real;
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,19 +280,21 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate)
|
||||||
static MIDISource *CreateMIDISource(FileReader &reader, EMIDIType miditype)
|
static MIDISource *CreateMIDISource(FileReader &reader, EMIDIType miditype)
|
||||||
{
|
{
|
||||||
MIDISource *source = nullptr;
|
MIDISource *source = nullptr;
|
||||||
|
auto data = reader.Read();
|
||||||
|
if (data.Size() <= 0) return nullptr;
|
||||||
switch (miditype)
|
switch (miditype)
|
||||||
{
|
{
|
||||||
case MIDI_MUS:
|
case MIDI_MUS:
|
||||||
return new MUSSong2(reader);
|
return new MUSSong2(data.Data(), data.Size());
|
||||||
|
|
||||||
case MIDI_MIDI:
|
case MIDI_MIDI:
|
||||||
return new MIDISong2(reader);
|
return new MIDISong2(data.Data(), data.Size());
|
||||||
|
|
||||||
case MIDI_HMI:
|
case MIDI_HMI:
|
||||||
return new HMISong(reader);
|
return new HMISong(data.Data(), data.Size());
|
||||||
|
|
||||||
case MIDI_XMI:
|
case MIDI_XMI:
|
||||||
return new XMISong(reader);
|
return new XMISong(data.Data(), data.Size());
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -760,7 +762,7 @@ UNSAFE_CCMD(writemidi)
|
||||||
auto source = GetMIDISource(argv[1]);
|
auto source = GetMIDISource(argv[1]);
|
||||||
if (source == nullptr) return;
|
if (source == nullptr) return;
|
||||||
|
|
||||||
TArray<uint8_t> midi;
|
std::vector<uint8_t> midi;
|
||||||
bool success;
|
bool success;
|
||||||
|
|
||||||
source->CreateSMF(midi, 1);
|
source->CreateSMF(midi, 1);
|
||||||
|
@ -770,7 +772,7 @@ UNSAFE_CCMD(writemidi)
|
||||||
Printf("Could not open %s.\n", argv[2]);
|
Printf("Could not open %s.\n", argv[2]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
success = (f->Write(&midi[0], midi.Size()) == (size_t)midi.Size());
|
success = (f->Write(&midi[0], midi.size()) == midi.size());
|
||||||
delete f;
|
delete f;
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
|
|
|
@ -359,7 +359,7 @@ protected:
|
||||||
SONG_ERROR
|
SONG_ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
MIDIDevice *MIDI = nullptr;
|
std::unique_ptr<MIDIDevice> MIDI;
|
||||||
uint32_t Events[2][MAX_MIDI_EVENTS*3];
|
uint32_t Events[2][MAX_MIDI_EVENTS*3];
|
||||||
MidiHeader Buffer[2];
|
MidiHeader Buffer[2];
|
||||||
int BufferNum;
|
int BufferNum;
|
||||||
|
@ -373,8 +373,8 @@ protected:
|
||||||
bool CallbackIsThreaded;
|
bool CallbackIsThreaded;
|
||||||
int LoopLimit;
|
int LoopLimit;
|
||||||
FString Args;
|
FString Args;
|
||||||
MIDISource *source = nullptr;
|
std::unique_ptr<MIDISource> source;
|
||||||
SoundStream* Stream = nullptr;
|
std::unique_ptr<SoundStream> Stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Anything supported by the sound system out of the box --------------------
|
// Anything supported by the sound system out of the box --------------------
|
||||||
|
|
|
@ -91,18 +91,6 @@ MIDIStreamer::MIDIStreamer(EMidiDevice type, const char *args)
|
||||||
MIDIStreamer::~MIDIStreamer()
|
MIDIStreamer::~MIDIStreamer()
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
if (MIDI != nullptr)
|
|
||||||
{
|
|
||||||
delete MIDI;
|
|
||||||
}
|
|
||||||
if (Stream != nullptr)
|
|
||||||
{
|
|
||||||
delete Stream;
|
|
||||||
}
|
|
||||||
if (source != nullptr)
|
|
||||||
{
|
|
||||||
delete source;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -305,7 +293,7 @@ void MIDIStreamer::Play(bool looping, int subsong)
|
||||||
m_Looping = looping;
|
m_Looping = looping;
|
||||||
source->SetMIDISubsong(subsong);
|
source->SetMIDISubsong(subsong);
|
||||||
devtype = SelectMIDIDevice(DeviceType);
|
devtype = SelectMIDIDevice(DeviceType);
|
||||||
MIDI = CreateMIDIDevice(devtype, (int)GSnd->GetOutputRate());
|
MIDI.reset(CreateMIDIDevice(devtype, (int)GSnd->GetOutputRate()));
|
||||||
InitPlayback();
|
InitPlayback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,11 +313,10 @@ bool MIDIStreamer::DumpWave(const char *filename, int subsong, int samplerate)
|
||||||
auto devtype = SelectMIDIDevice(DeviceType);
|
auto devtype = SelectMIDIDevice(DeviceType);
|
||||||
if (devtype == MDEV_MMAPI)
|
if (devtype == MDEV_MMAPI)
|
||||||
{
|
{
|
||||||
Printf("MMAPI device is not supported\n");
|
throw std::runtime_error("MMAPI device is not supported");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
MIDI = CreateMIDIDevice(devtype, samplerate);
|
auto iMIDI = CreateMIDIDevice(devtype, samplerate);
|
||||||
MIDI = new MIDIWaveWriter(filename, reinterpret_cast<SoftSynthMIDIDevice *>(MIDI));
|
MIDI.reset(new MIDIWaveWriter(filename, static_cast<SoftSynthMIDIDevice *>(iMIDI)));
|
||||||
return InitPlayback();
|
return InitPlayback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,13 +337,7 @@ bool MIDIStreamer::InitPlayback()
|
||||||
|
|
||||||
if (MIDI == NULL || 0 != MIDI->Open())
|
if (MIDI == NULL || 0 != MIDI->Open())
|
||||||
{
|
{
|
||||||
Printf(PRINT_BOLD, "Could not open MIDI out device\n");
|
throw std::runtime_error("Could not open MIDI out device");
|
||||||
if (MIDI != NULL)
|
|
||||||
{
|
|
||||||
delete MIDI;
|
|
||||||
MIDI = NULL;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
source->CheckCaps(MIDI->GetTechnology());
|
source->CheckCaps(MIDI->GetTechnology());
|
||||||
|
@ -365,7 +346,7 @@ bool MIDIStreamer::InitPlayback()
|
||||||
auto streamInfo = MIDI->GetStreamInfo();
|
auto streamInfo = MIDI->GetStreamInfo();
|
||||||
if (streamInfo.mBufferSize > 0)
|
if (streamInfo.mBufferSize > 0)
|
||||||
{
|
{
|
||||||
Stream = GSnd->CreateStream(FillStream, streamInfo.mBufferSize, streamInfo.mNumChannels == 1 ? SoundStream::Float | SoundStream::Mono : SoundStream::Float, streamInfo.mSampleRate, MIDI);
|
Stream.reset(GSnd->CreateStream(FillStream, streamInfo.mBufferSize, streamInfo.mNumChannels == 1 ? SoundStream::Float | SoundStream::Mono : SoundStream::Float, streamInfo.mSampleRate, MIDI.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MIDI->Preprocess(this, m_Looping))
|
if (MIDI->Preprocess(this, m_Looping))
|
||||||
|
@ -373,11 +354,6 @@ bool MIDIStreamer::InitPlayback()
|
||||||
StartPlayback();
|
StartPlayback();
|
||||||
if (MIDI == nullptr)
|
if (MIDI == nullptr)
|
||||||
{ // The MIDI file had no content and has been automatically closed.
|
{ // The MIDI file had no content and has been automatically closed.
|
||||||
if (Stream)
|
|
||||||
{
|
|
||||||
delete Stream;
|
|
||||||
Stream = nullptr;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,9 +364,7 @@ bool MIDIStreamer::InitPlayback()
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
Printf ("Starting MIDI playback failed\n");
|
throw std::runtime_error("Starting MIDI playback failed");
|
||||||
Stop();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -408,16 +382,14 @@ bool MIDIStreamer::InitPlayback()
|
||||||
void MIDIStreamer::StartPlayback()
|
void MIDIStreamer::StartPlayback()
|
||||||
{
|
{
|
||||||
auto data = source->PrecacheData();
|
auto data = source->PrecacheData();
|
||||||
MIDI->PrecacheInstruments(&data[0], data.Size());
|
MIDI->PrecacheInstruments(data.data(), (int)data.size());
|
||||||
source->StartPlayback(m_Looping);
|
source->StartPlayback(m_Looping);
|
||||||
|
|
||||||
// Set time division and tempo.
|
// Set time division and tempo.
|
||||||
if (0 != MIDI->SetTimeDiv(source->getDivision()) ||
|
if (0 != MIDI->SetTimeDiv(source->getDivision()) ||
|
||||||
0 != MIDI->SetTempo(source->getInitialTempo()))
|
0 != MIDI->SetTempo(source->getInitialTempo()))
|
||||||
{
|
{
|
||||||
Printf(PRINT_BOLD, "Setting MIDI stream speed failed\n");
|
throw std::runtime_error("Setting MIDI stream speed failed");
|
||||||
MIDI->Close();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MusicVolumeChanged(); // set volume to current music's properties
|
MusicVolumeChanged(); // set volume to current music's properties
|
||||||
|
@ -434,9 +406,7 @@ void MIDIStreamer::StartPlayback()
|
||||||
{
|
{
|
||||||
if (0 != MIDI->StreamOutSync(&Buffer[BufferNum]))
|
if (0 != MIDI->StreamOutSync(&Buffer[BufferNum]))
|
||||||
{
|
{
|
||||||
Printf ("Initial midiStreamOut failed\n");
|
throw std::runtime_error("Initial midiStreamOut failed");
|
||||||
Stop();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
BufferNum ^= 1;
|
BufferNum ^= 1;
|
||||||
}
|
}
|
||||||
|
@ -527,14 +497,12 @@ void MIDIStreamer::Stop()
|
||||||
}
|
}
|
||||||
if (MIDI != nullptr)
|
if (MIDI != nullptr)
|
||||||
{
|
{
|
||||||
delete MIDI;
|
MIDI.reset();
|
||||||
MIDI = nullptr;
|
|
||||||
}
|
}
|
||||||
if (Stream != nullptr)
|
if (Stream != nullptr)
|
||||||
{
|
{
|
||||||
Stream->Stop();
|
Stream->Stop();
|
||||||
delete Stream;
|
Stream.reset();
|
||||||
Stream = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Status = STATE_Stopped;
|
m_Status = STATE_Stopped;
|
||||||
|
@ -908,7 +876,7 @@ uint32_t *MIDIStreamer::WriteStopNotes(uint32_t *events)
|
||||||
|
|
||||||
void MIDIStreamer::SetMIDISource(MIDISource *_source)
|
void MIDIStreamer::SetMIDISource(MIDISource *_source)
|
||||||
{
|
{
|
||||||
source = _source;
|
source.reset(_source);
|
||||||
source->setTempoCallback([=](int tempo) { return !!MIDI->SetTempo(tempo); } );
|
source->setTempoCallback([=](int tempo) { return !!MIDI->SetTempo(tempo); } );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -370,7 +370,15 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
||||||
}
|
}
|
||||||
else if (!mus_playing.handle->IsPlaying())
|
else if (!mus_playing.handle->IsPlaying())
|
||||||
{
|
{
|
||||||
mus_playing.handle->Play(looping, order);
|
try
|
||||||
|
{
|
||||||
|
mus_playing.handle->Play(looping, order);
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error& err)
|
||||||
|
{
|
||||||
|
Printf("Unable to start %s: %s\n", mus_playing.name.GetChars(), err.what());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -447,7 +455,14 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mus_playing.handle = I_RegisterSong (reader, devp);
|
try
|
||||||
|
{
|
||||||
|
mus_playing.handle = I_RegisterSong(reader, devp);
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error& err)
|
||||||
|
{
|
||||||
|
Printf("Unable to load %s: %s\n", mus_playing.name.GetChars(), err.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,8 +473,15 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
||||||
|
|
||||||
if (mus_playing.handle != 0)
|
if (mus_playing.handle != 0)
|
||||||
{ // play it
|
{ // play it
|
||||||
mus_playing.handle->Start(looping, S_GetMusicVolume (musicname), order);
|
try
|
||||||
mus_playing.baseorder = order;
|
{
|
||||||
|
mus_playing.handle->Start(looping, S_GetMusicVolume(musicname), order);
|
||||||
|
mus_playing.baseorder = order;
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error& err)
|
||||||
|
{
|
||||||
|
Printf("Unable to start %s: %s\n", mus_playing.name.GetChars(), err.what());
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -503,8 +525,16 @@ void S_MIDIDeviceChanged()
|
||||||
{
|
{
|
||||||
if (mus_playing.handle != nullptr && mus_playing.handle->IsMIDI())
|
if (mus_playing.handle != nullptr && mus_playing.handle->IsMIDI())
|
||||||
{
|
{
|
||||||
mus_playing.handle->Stop();
|
try
|
||||||
mus_playing.handle->Start(mus_playing.loop, -1, mus_playing.baseorder);
|
{
|
||||||
|
mus_playing.handle->Stop();
|
||||||
|
mus_playing.handle->Start(mus_playing.loop, -1, mus_playing.baseorder);
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error& err)
|
||||||
|
{
|
||||||
|
Printf("Unable to restart music %s: %s\n", mus_playing.name.GetChars(), err.what());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,19 +569,32 @@ int S_GetMusic (const char **name)
|
||||||
|
|
||||||
void S_StopMusic (bool force)
|
void S_StopMusic (bool force)
|
||||||
{
|
{
|
||||||
// [RH] Don't stop if a playlist is active.
|
try
|
||||||
if ((force || PlayList == nullptr) && !mus_playing.name.IsEmpty())
|
|
||||||
{
|
{
|
||||||
|
// [RH] Don't stop if a playlist is active.
|
||||||
|
if ((force || PlayList == nullptr) && !mus_playing.name.IsEmpty())
|
||||||
|
{
|
||||||
|
if (mus_playing.handle != nullptr)
|
||||||
|
{
|
||||||
|
if (MusicPaused)
|
||||||
|
mus_playing.handle->Resume();
|
||||||
|
|
||||||
|
mus_playing.handle->Stop();
|
||||||
|
delete mus_playing.handle;
|
||||||
|
mus_playing.handle = nullptr;
|
||||||
|
}
|
||||||
|
LastSong = mus_playing.name;
|
||||||
|
mus_playing.name = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error& err)
|
||||||
|
{
|
||||||
|
//Printf("Unable to stop %s: %s\n", mus_playing.name.GetChars(), err.what());
|
||||||
if (mus_playing.handle != nullptr)
|
if (mus_playing.handle != nullptr)
|
||||||
{
|
{
|
||||||
if (MusicPaused)
|
|
||||||
mus_playing.handle->Resume();
|
|
||||||
|
|
||||||
mus_playing.handle->Stop();
|
|
||||||
delete mus_playing.handle;
|
delete mus_playing.handle;
|
||||||
mus_playing.handle = nullptr;
|
mus_playing.handle = nullptr;
|
||||||
}
|
}
|
||||||
LastSong = mus_playing.name;
|
|
||||||
mus_playing.name = "";
|
mus_playing.name = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue