mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-26 22:11:43 +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];
|
||||
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);
|
||||
|
|
|
@ -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,18 +83,17 @@ 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;
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 --------------------
|
||||
|
|
|
@ -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); } );
|
||||
}
|
||||
|
||||
|
|
|
@ -369,9 +369,17 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
|||
}
|
||||
}
|
||||
else if (!mus_playing.handle->IsPlaying())
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -446,9 +454,16 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
|||
mus_playing.handle = handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mus_playing.loop = looping;
|
||||
|
@ -458,8 +473,15 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
|||
|
||||
if (mus_playing.handle != 0)
|
||||
{ // play it
|
||||
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;
|
||||
|
@ -502,10 +524,18 @@ void S_RestartMusic ()
|
|||
void S_MIDIDeviceChanged()
|
||||
{
|
||||
if (mus_playing.handle != nullptr && mus_playing.handle->IsMIDI())
|
||||
{
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -538,6 +568,8 @@ int S_GetMusic (const char **name)
|
|||
//==========================================================================
|
||||
|
||||
void S_StopMusic (bool force)
|
||||
{
|
||||
try
|
||||
{
|
||||
// [RH] Don't stop if a playlist is active.
|
||||
if ((force || PlayList == nullptr) && !mus_playing.name.IsEmpty())
|
||||
|
@ -555,6 +587,17 @@ void S_StopMusic (bool force)
|
|||
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)
|
||||
{
|
||||
delete mus_playing.handle;
|
||||
mus_playing.handle = nullptr;
|
||||
}
|
||||
mus_playing.name = "";
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
Loading…
Reference in a new issue