- removed all dependencies on ZDoom code from the MIDI sources (including TArray and FileReader.)

This commit is contained in:
Christoph Oelckers 2019-09-28 13:59:46 +02:00
parent d8a1005c76
commit 820cbcc689
10 changed files with 207 additions and 245 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;
} }

View file

@ -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)

View file

@ -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 --------------------

View file

@ -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); } );
} }

View file

@ -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 = "";
} }
} }