- 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];
uint8_t found_instruments[256] = { 0, };
@ -189,7 +189,7 @@ TArray<uint16_t> MIDISource::PrecacheData()
DoRestart();
// 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)
{
@ -198,7 +198,7 @@ TArray<uint16_t> MIDISource::PrecacheData()
uint16_t packnum = (i & 127) | ((i & 128) << 7);
if (!multiple_banks)
{
packed.Push(packnum);
packed.push_back(packnum);
}
else
{ // 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)])
{
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;
@ -261,7 +261,7 @@ static void WriteVarLen (TArray<uint8_t> &file, uint32_t value)
for (;;)
{
file.Push(uint8_t(buffer));
file.push_back(uint8_t(buffer));
if (buffer & 0x80)
{
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.
// (for songs with loop controller events)
@ -307,8 +307,8 @@ void MIDISource::CreateSMF(TArray<uint8_t> &file, int looplimit)
DoRestart();
StartPlayback(false, LoopLimit);
file.Reserve(sizeof(StaticMIDIhead));
memcpy(&file[0], StaticMIDIhead, sizeof(StaticMIDIhead));
file.resize(sizeof(StaticMIDIhead));
memcpy(file.data(), StaticMIDIhead, sizeof(StaticMIDIhead));
file[12] = Division >> 8;
file[13] = Division & 0xFF;
file[26] = InitialTempo >> 16;
@ -326,12 +326,12 @@ void MIDISource::CreateSMF(TArray<uint8_t> &file, int looplimit)
WriteVarLen(file, delay);
delay = 0;
uint32_t tempo = MEVENT_EVENTPARM(event[2]);
file.Push(MIDI_META);
file.Push(MIDI_META_TEMPO);
file.Push(3);
file.Push(uint8_t(tempo >> 16));
file.Push(uint8_t(tempo >> 8));
file.Push(uint8_t(tempo));
file.push_back(MIDI_META);
file.push_back(MIDI_META_TEMPO);
file.push_back(3);
file.push_back(uint8_t(tempo >> 16));
file.push_back(uint8_t(tempo >> 8));
file.push_back(uint8_t(tempo));
running_status = 255;
}
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)
{
len--;
file.Push(MIDI_SYSEX);
file.push_back(MIDI_SYSEX);
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
{
file.Push(MIDI_SYSEXEND);
file.push_back(MIDI_SYSEXEND);
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;
}
@ -363,12 +367,12 @@ void MIDISource::CreateSMF(TArray<uint8_t> &file, int looplimit)
if (status != running_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)
{
file.Push(uint8_t((event[2] >> 16) & 0x7F));
file.push_back(uint8_t((event[2] >> 16) & 0x7F));
}
}
// Advance to next event
@ -385,12 +389,12 @@ void MIDISource::CreateSMF(TArray<uint8_t> &file, int looplimit)
// End track
WriteVarLen(file, delay);
file.Push(MIDI_META);
file.Push(MIDI_META_EOT);
file.Push(0);
file.push_back(MIDI_META);
file.push_back(MIDI_META_EOT);
file.push_back(0);
// 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[19] = uint8_t(len >> 16);
file[20] = uint8_t(len >> 8);

View file

@ -10,7 +10,7 @@
#include <stdint.h>
#include <functional>
#include "files.h"
#include <vector>
#include "mus2midi.h"
#include "mididefs.h"
@ -49,7 +49,7 @@ public:
virtual void DoInitialSetup() = 0;
virtual void DoRestart() = 0;
virtual bool CheckDone() = 0;
virtual TArray<uint16_t> PrecacheData();
virtual std::vector<uint16_t> PrecacheData();
virtual bool SetMIDISubsong(int subsong);
virtual uint32_t *MakeEvents(uint32_t *events, uint32_t *max_event_p, uint32_t max_time) = 0;
@ -74,7 +74,7 @@ public:
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
{
public:
MUSSong2(FileReader &reader);
~MUSSong2();
MUSSong2(const uint8_t *data, size_t len);
protected:
void DoInitialSetup() override;
void DoRestart() 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;
private:
MUSHeader *MusHeader;
uint8_t *MusBuffer;
std::vector<uint8_t> MusData;
uint8_t* MusBuffer;
uint8_t LastVelocity[16];
size_t MusP, MaxMusP;
};
@ -106,8 +105,7 @@ private:
class MIDISong2 : public MIDISource
{
public:
MIDISong2(FileReader &reader);
~MIDISong2();
MIDISong2(const uint8_t* data, size_t len);
protected:
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);
TrackInfo *FindNextDue ();
TArray<uint8_t> MusHeader;
TrackInfo *Tracks;
std::vector<uint8_t> MusHeader;
std::vector<TrackInfo> Tracks;
TrackInfo *TrackDue;
int NumTracks;
int Format;
@ -141,7 +139,7 @@ struct AutoNoteOff
uint8_t Channel, Key;
};
// 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:
void AddNoteOff(uint32_t delay, uint8_t channel, uint8_t key);
@ -159,8 +157,7 @@ protected:
class HMISong : public MIDISource
{
public:
HMISong(FileReader &reader);
~HMISong();
HMISong(const uint8_t* data, size_t len);
protected:
@ -184,9 +181,9 @@ private:
static uint32_t ReadVarLenHMI(TrackInfo *);
static uint32_t ReadVarLenHMP(TrackInfo *);
TArray<uint8_t> MusHeader;
std::vector<uint8_t> MusHeader;
int NumTracks;
TrackInfo *Tracks;
std::vector<TrackInfo> Tracks;
TrackInfo *TrackDue;
TrackInfo *FakeTrack;
uint32_t (*ReadVarLen)(TrackInfo *);
@ -198,8 +195,7 @@ private:
class XMISong : public MIDISource
{
public:
XMISong(FileReader &reader);
~XMISong();
XMISong(const uint8_t* data, size_t len);
protected:
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);
EventSource FindNextDue();
TArray<uint8_t> MusHeader;
std::vector<uint8_t> MusHeader;
int NumSongs;
TrackInfo *Songs;
std::vector<TrackInfo> Songs;
TrackInfo *CurrSong;
NoteOffQueue NoteOffs;
EventSource EventDue;

View file

@ -34,9 +34,9 @@
// HEADER FILES ------------------------------------------------------------
#include <algorithm>
#include "midisource.h"
#include "basictypes.h"
#include "templates.h"
#include "m_swap.h"
// 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)
{ // Way too small to be HMI.
return;
}
MusHeader = reader.Read();
MusHeader.resize(len);
memcpy(MusHeader.data(), data, len);
NumTracks = 0;
if (MusHeader.Size() == 0)
return;
// Do some validation of the MIDI file
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)
{
SetupForHMP(len);
}
}
//==========================================================================
//
// HMISong Destructor
//
//==========================================================================
HMISong::~HMISong()
{
if (Tracks != nullptr)
{
delete[] Tracks;
SetupForHMP((int)len);
}
}
@ -187,7 +171,7 @@ void HMISong::SetupForHMI(int len)
Division = GetShort(MusPtr + HMI_DIVISION_OFFSET) << 2;
Tempo = InitialTempo = 4000000;
Tracks = new TrackInfo[NumTracks + 1];
Tracks.resize(NumTracks + 1);
int track_dir = GetInt(MusPtr + HMI_TRACK_DIR_PTR_OFFSET);
// Gather information about each track
@ -218,7 +202,7 @@ void HMISong::SetupForHMI(int len)
tracklen = GetInt(MusPtr + track_dir + i*4 + 4) - start;
}
// Clamp incomplete tracks to the end of the file.
tracklen = MIN(tracklen, len - start);
tracklen = std::min(tracklen, len - start);
if (tracklen <= 0)
{
continue;
@ -290,7 +274,7 @@ void HMISong::SetupForHMP(int len)
Division = GetInt(MusPtr + HMP_DIVISION_OFFSET);
Tempo = InitialTempo = 1000000;
Tracks = new TrackInfo[NumTracks + 1];
Tracks.resize(NumTracks + 1);
// Gather information about each track
for (i = 0, p = 0; i < NumTracks; ++i)
@ -307,7 +291,7 @@ void HMISong::SetupForHMP(int len)
track_data += tracklen;
// Clamp incomplete tracks to the end of the file.
tracklen = MIN(tracklen, len - start);
tracklen = std::min(tracklen, len - start);
if (tracklen <= 0)
{
continue;
@ -385,7 +369,7 @@ void HMISong::CheckCaps(int tech)
{
Tracks[i].Enabled = false;
// 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)
{
@ -446,7 +430,7 @@ void HMISong :: DoRestart()
// Set initial state.
FakeTrack = &Tracks[NumTracks];
NoteOffs.Clear();
NoteOffs.clear();
for (i = 0; i <= NumTracks; ++i)
{
Tracks[i].TrackP = 0;
@ -461,7 +445,7 @@ void HMISong :: DoRestart()
}
Tracks[i].Delay = 0; // for the FakeTrack
Tracks[i].Enabled = true;
TrackDue = Tracks;
TrackDue = Tracks.data();
TrackDue = FindNextDue();
}
@ -883,7 +867,8 @@ uint32_t HMISong::TrackInfo::ReadVarLenHMP()
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)
{
(*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)
{
item = (*this)[0];
if (TArray<AutoNoteOff>::Pop((*this)[0]))
if (size() > 0)
{
item = front();
front() = back();
pop_back();
Heapify();
return true;
}
@ -921,10 +908,10 @@ void NoteOffQueue::AdvanceTime(uint32_t time)
{
// Because the time is decreasing by the same amount for every entry,
// the heap property is maintained.
for (unsigned int i = 0; i < Size(); ++i)
for (auto &item : *this)
{
assert((*this)[i].Delay >= time);
(*this)[i].Delay -= time;
assert(item.Delay >= time);
item.Delay -= time;
}
}
@ -942,11 +929,11 @@ void NoteOffQueue::Heapify()
unsigned int l = Left(i);
unsigned int r = Right(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;
}
if (r < Size() && (*this)[r].Delay < (*this)[smallest].Delay)
if (r < (unsigned)size() && (*this)[r].Delay < (*this)[smallest].Delay)
{
smallest = r;
}
@ -954,7 +941,7 @@ void NoteOffQueue::Heapify()
{
break;
}
swapvalues((*this)[i], (*this)[smallest]);
std::swap((*this)[i], (*this)[smallest]);
i = smallest;
}
}
@ -979,7 +966,7 @@ HMISong::TrackInfo *HMISong::FindNextDue ()
{
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;
return FakeTrack;
@ -997,7 +984,7 @@ HMISong::TrackInfo *HMISong::FindNextDue ()
}
}
// 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;
return FakeTrack;

View file

@ -34,7 +34,7 @@
// HEADER FILES ------------------------------------------------------------
#include "midisource.h"
#include "templates.h"
#include "m_swap.h"
// MACROS ------------------------------------------------------------------
@ -84,39 +84,30 @@ static const uint8_t CtrlTranslate[15] =
//
//==========================================================================
MUSSong2::MUSSong2 (FileReader &reader)
: MusHeader(0), MusBuffer(0)
MUSSong2::MUSSong2 (const uint8_t *data, size_t len)
{
uint8_t front[32];
int start;
if (reader.Read(front, sizeof(front)) != sizeof(front))
{
return;
}
// 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
// does no validation whatsoever and just assumes it was passed a valid
// MUS file, since where the header is offset affects how it plays.
start = MUSHeaderSearch(front, sizeof(front));
start = MUSHeaderSearch(data, 32);
if (start < 0)
{
return;
}
data += start;
len -= start;
// Read the remainder of the song.
int len = int(reader.GetLength() - start);
if (len < (int)sizeof(MusHeader))
if (len < sizeof(MUSHeader))
{ // It's too short.
return;
}
MusHeader = (MUSHeader *)new uint8_t[len];
memcpy(MusHeader, front + start, sizeof(front) - start);
if (reader.Read((uint8_t *)MusHeader + sizeof(front) - start, len - (sizeof(front) - start)) != (len - (32 - start)))
{
return;
}
MusData.resize(len);
memcpy(MusData.data(), data, len);
auto MusHeader = (MUSHeader*)MusData.data();
// Do some validation of the MUS file.
if (LittleShort(MusHeader->NumChans) > 15)
@ -124,26 +115,12 @@ MUSSong2::MUSSong2 (FileReader &reader)
return;
}
MusBuffer = (uint8_t *)MusHeader + LittleShort(MusHeader->SongStart);
MaxMusP = MIN<int>(LittleShort(MusHeader->SongLen), len - LittleShort(MusHeader->SongStart));
MusBuffer = MusData.data() + LittleShort(MusHeader->SongStart);
MaxMusP = std::min<int>(LittleShort(MusHeader->SongLen), int(len) - LittleShort(MusHeader->SongStart));
Division = 140;
Tempo = InitialTempo = 1000000;
}
//==========================================================================
//
// MUSSong2 Destructor
//
//==========================================================================
MUSSong2::~MUSSong2 ()
{
if (MusHeader != NULL)
{
delete[] (uint8_t *)MusHeader;
}
}
//==========================================================================
//
// 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));
const uint8_t *used = (uint8_t *)MusHeader + sizeof(MUSHeader) / sizeof(uint8_t);
auto MusHeader = (MUSHeader*)MusData.data();
std::vector<uint16_t> work;
const uint8_t *used = MusData.data() + sizeof(MUSHeader) / sizeof(uint8_t);
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++];
uint16_t val;
@ -224,12 +205,12 @@ TArray<uint16_t> MUSSong2::PrecacheData()
{
for (int b = 0; b < numbanks; b++)
{
work.Push(val | (used[k++] << 7));
work.push_back(val | (used[k++] << 7));
}
}
else
{
work.Push(val);
work.push_back(val);
}
}
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 time = 0;
auto MusHeader = (MUSHeader*)MusData.data();
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)
{ // Clamp volume to 127, since DMX apparently allows 8-bit volumes.
// Fix courtesy of Gez, courtesy of Ben Ryves.
mid2 = VolumeControllerChange(channel, MIN<int>(mid2, 0x7F));
mid2 = VolumeControllerChange(channel, std::min<int>(mid2, 0x7F));
}
}
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)
{
unsigned p;
int i;
MusHeader = reader.Read();
if (MusHeader.Size() == 0) return;
MusHeader.resize(len);
memcpy(MusHeader.data(), data, len);
// Do some validation of the MIDI file
if (MusHeader[4] != 0 || MusHeader[5] != 0 || MusHeader[6] != 0 || MusHeader[7] != 6)
@ -129,10 +129,10 @@ MIDISong2::MIDISong2 (FileReader &reader)
return;
}
Tracks = new TrackInfo[NumTracks];
Tracks.resize(NumTracks);
// 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 =
(MusHeader[p+4]<<24) |
@ -140,9 +140,9 @@ MIDISong2::MIDISong2 (FileReader &reader)
(MusHeader[p+6]<<8) |
(MusHeader[p+7]);
if (chunkLen + p + 8 > MusHeader.Size())
if (chunkLen + p + 8 > MusHeader.size())
{ // Track too long, so truncate it
chunkLen = MusHeader.Size() - p - 8;
chunkLen = (uint32_t)MusHeader.size() - p - 8;
}
if (MusHeader[p+0] == 'M' &&
@ -168,20 +168,6 @@ MIDISong2::MIDISong2 (FileReader &reader)
}
}
//==========================================================================
//
// MIDISong2 Destructor
//
//==========================================================================
MIDISong2::~MIDISong2 ()
{
if (Tracks != nullptr)
{
delete[] Tracks;
}
}
//==========================================================================
//
// MIDISong2 :: CheckCaps
@ -255,7 +241,7 @@ void MIDISong2 :: DoRestart()
{
Tracks[i].Delay = Tracks[i].ReadVarLen();
}
TrackDue = Tracks;
TrackDue = Tracks.data();
TrackDue = FindNextDue();
}
@ -764,7 +750,7 @@ MIDISong2::TrackInfo *MIDISong2::FindNextDue ()
switch (Format)
{
case 0:
return Tracks[0].Finished ? nullptr : Tracks;
return Tracks[0].Finished ? nullptr : Tracks.data();
case 1:
track = nullptr;

View file

@ -35,7 +35,7 @@
// HEADER FILES ------------------------------------------------------------
#include "midisource.h"
#include "basictypes.h"
#include "m_swap.h"
// MACROS ------------------------------------------------------------------
@ -51,6 +51,14 @@
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 -------------------------------------------------------------------
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 = reader.Read();
if (MusHeader.Size() == 0) return;
MusHeader.resize(len);
memcpy(MusHeader.data(), data, len);
// 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)
{
return;
@ -125,27 +133,13 @@ XMISong::XMISong (FileReader &reader)
Division = 60;
Tempo = InitialTempo = 500000;
Songs = new TrackInfo[NumSongs];
memset(Songs, 0, sizeof(*Songs) * NumSongs);
FindXMIDforms(&MusHeader[0], MusHeader.Size(), Songs);
CurrSong = Songs;
Songs.resize(NumSongs);
memset(Songs.data(), 0, sizeof(Songs[0]) * NumSongs);
FindXMIDforms(&MusHeader[0], (int)MusHeader.size(), Songs.data());
CurrSong = Songs.data();
//DPrintf(DMSG_SPAMMY, "XMI song count: %d\n", NumSongs);
}
//==========================================================================
//
// XMISong Destructor
//
//==========================================================================
XMISong::~XMISong ()
{
if (Songs != nullptr)
{
delete[] Songs;
}
}
//==========================================================================
//
// XMISong :: FindXMIDforms
@ -267,7 +261,7 @@ void XMISong::DoRestart()
CurrSong->Finished = false;
CurrSong->PlayedTime = 0;
CurrSong->ForDepth = 0;
NoteOffs.Clear();
NoteOffs.clear();
ProcessInitialMetaEvents ();
@ -673,14 +667,14 @@ uint32_t XMISong::TrackInfo::ReadDelay()
XMISong::EventSource XMISong::FindNextDue()
{
// Are there still events available?
if (CurrSong->Finished && NoteOffs.Size() == 0)
if (CurrSong->Finished && NoteOffs.size() == 0)
{
return EVENT_None;
}
// Which is due sooner? The current song or the note-offs?
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;
}

View file

@ -280,19 +280,21 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate)
static MIDISource *CreateMIDISource(FileReader &reader, EMIDIType miditype)
{
MIDISource *source = nullptr;
auto data = reader.Read();
if (data.Size() <= 0) return nullptr;
switch (miditype)
{
case MIDI_MUS:
return new MUSSong2(reader);
return new MUSSong2(data.Data(), data.Size());
case MIDI_MIDI:
return new MIDISong2(reader);
return new MIDISong2(data.Data(), data.Size());
case MIDI_HMI:
return new HMISong(reader);
return new HMISong(data.Data(), data.Size());
case MIDI_XMI:
return new XMISong(reader);
return new XMISong(data.Data(), data.Size());
default:
return nullptr;
@ -760,7 +762,7 @@ UNSAFE_CCMD(writemidi)
auto source = GetMIDISource(argv[1]);
if (source == nullptr) return;
TArray<uint8_t> midi;
std::vector<uint8_t> midi;
bool success;
source->CreateSMF(midi, 1);
@ -770,7 +772,7 @@ UNSAFE_CCMD(writemidi)
Printf("Could not open %s.\n", argv[2]);
return;
}
success = (f->Write(&midi[0], midi.Size()) == (size_t)midi.Size());
success = (f->Write(&midi[0], midi.size()) == midi.size());
delete f;
if (!success)

View file

@ -359,7 +359,7 @@ protected:
SONG_ERROR
};
MIDIDevice *MIDI = nullptr;
std::unique_ptr<MIDIDevice> MIDI;
uint32_t Events[2][MAX_MIDI_EVENTS*3];
MidiHeader Buffer[2];
int BufferNum;
@ -373,8 +373,8 @@ protected:
bool CallbackIsThreaded;
int LoopLimit;
FString Args;
MIDISource *source = nullptr;
SoundStream* Stream = nullptr;
std::unique_ptr<MIDISource> source;
std::unique_ptr<SoundStream> Stream;
};
// 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()
{
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;
source->SetMIDISubsong(subsong);
devtype = SelectMIDIDevice(DeviceType);
MIDI = CreateMIDIDevice(devtype, (int)GSnd->GetOutputRate());
MIDI.reset(CreateMIDIDevice(devtype, (int)GSnd->GetOutputRate()));
InitPlayback();
}
@ -325,11 +313,10 @@ bool MIDIStreamer::DumpWave(const char *filename, int subsong, int samplerate)
auto devtype = SelectMIDIDevice(DeviceType);
if (devtype == MDEV_MMAPI)
{
Printf("MMAPI device is not supported\n");
return false;
throw std::runtime_error("MMAPI device is not supported");
}
MIDI = CreateMIDIDevice(devtype, samplerate);
MIDI = new MIDIWaveWriter(filename, reinterpret_cast<SoftSynthMIDIDevice *>(MIDI));
auto iMIDI = CreateMIDIDevice(devtype, samplerate);
MIDI.reset(new MIDIWaveWriter(filename, static_cast<SoftSynthMIDIDevice *>(iMIDI)));
return InitPlayback();
}
@ -350,13 +337,7 @@ bool MIDIStreamer::InitPlayback()
if (MIDI == NULL || 0 != MIDI->Open())
{
Printf(PRINT_BOLD, "Could not open MIDI out device\n");
if (MIDI != NULL)
{
delete MIDI;
MIDI = NULL;
}
return false;
throw std::runtime_error("Could not open MIDI out device");
}
source->CheckCaps(MIDI->GetTechnology());
@ -365,7 +346,7 @@ bool MIDIStreamer::InitPlayback()
auto streamInfo = MIDI->GetStreamInfo();
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))
@ -373,11 +354,6 @@ bool MIDIStreamer::InitPlayback()
StartPlayback();
if (MIDI == nullptr)
{ // The MIDI file had no content and has been automatically closed.
if (Stream)
{
delete Stream;
Stream = nullptr;
}
return false;
}
}
@ -388,9 +364,7 @@ bool MIDIStreamer::InitPlayback()
if (res)
{
Printf ("Starting MIDI playback failed\n");
Stop();
return false;
throw std::runtime_error("Starting MIDI playback failed");
}
else
{
@ -408,16 +382,14 @@ bool MIDIStreamer::InitPlayback()
void MIDIStreamer::StartPlayback()
{
auto data = source->PrecacheData();
MIDI->PrecacheInstruments(&data[0], data.Size());
MIDI->PrecacheInstruments(data.data(), (int)data.size());
source->StartPlayback(m_Looping);
// Set time division and tempo.
if (0 != MIDI->SetTimeDiv(source->getDivision()) ||
0 != MIDI->SetTempo(source->getInitialTempo()))
{
Printf(PRINT_BOLD, "Setting MIDI stream speed failed\n");
MIDI->Close();
return;
throw std::runtime_error("Setting MIDI stream speed failed");
}
MusicVolumeChanged(); // set volume to current music's properties
@ -434,9 +406,7 @@ void MIDIStreamer::StartPlayback()
{
if (0 != MIDI->StreamOutSync(&Buffer[BufferNum]))
{
Printf ("Initial midiStreamOut failed\n");
Stop();
return;
throw std::runtime_error("Initial midiStreamOut failed");
}
BufferNum ^= 1;
}
@ -527,14 +497,12 @@ void MIDIStreamer::Stop()
}
if (MIDI != nullptr)
{
delete MIDI;
MIDI = nullptr;
MIDI.reset();
}
if (Stream != nullptr)
{
Stream->Stop();
delete Stream;
Stream = nullptr;
Stream.reset();
}
m_Status = STATE_Stopped;
@ -908,7 +876,7 @@ uint32_t *MIDIStreamer::WriteStopNotes(uint32_t *events)
void MIDIStreamer::SetMIDISource(MIDISource *_source)
{
source = _source;
source.reset(_source);
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())
{
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;
}
@ -447,7 +455,14 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
}
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)
{ // play it
mus_playing.handle->Start(looping, S_GetMusicVolume (musicname), order);
mus_playing.baseorder = order;
try
{
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 false;
@ -503,8 +525,16 @@ void S_MIDIDeviceChanged()
{
if (mus_playing.handle != nullptr && mus_playing.handle->IsMIDI())
{
mus_playing.handle->Stop();
mus_playing.handle->Start(mus_playing.loop, -1, mus_playing.baseorder);
try
{
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)
{
// [RH] Don't stop if a playlist is active.
if ((force || PlayList == nullptr) && !mus_playing.name.IsEmpty())
try
{
// [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 (MusicPaused)
mus_playing.handle->Resume();
mus_playing.handle->Stop();
delete mus_playing.handle;
mus_playing.handle = nullptr;
}
LastSong = mus_playing.name;
mus_playing.name = "";
}
}