mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-11 07:12:16 +00:00
Rewroter 'writemidi' CCMD to work independently of the currently playing song's data.
The first benefit of separating the MIDI data sources from the playback classes. :)
This commit is contained in:
parent
16f17deb0f
commit
adebd644f2
9 changed files with 228 additions and 198 deletions
|
@ -3154,3 +3154,15 @@ CCMD(listsoundchannels)
|
||||||
}
|
}
|
||||||
Printf("%d sounds playing\n", count);
|
Printf("%d sounds playing\n", count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CCMD(currentmusic)
|
||||||
|
{
|
||||||
|
if (mus_playing.name.IsNotEmpty())
|
||||||
|
{
|
||||||
|
Printf("Currently playing music '%s'\n", mus_playing.name.GetChars());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Printf("Currently no music playing\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -787,38 +787,57 @@ UNSAFE_CCMD (writewave)
|
||||||
//
|
//
|
||||||
// CCMD writemidi
|
// CCMD writemidi
|
||||||
//
|
//
|
||||||
// If the currently playing song is a MIDI variant, write it to disk.
|
// Writes a given MIDI song to disk. This does not affect playback anymore,
|
||||||
// If successful, the current song will restart, since MIDI file generation
|
// like older versions did.
|
||||||
// involves a simulated playthrough of the song.
|
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
extern MusPlayingInfo mus_playing;
|
||||||
|
|
||||||
|
|
||||||
UNSAFE_CCMD (writemidi)
|
UNSAFE_CCMD (writemidi)
|
||||||
{
|
{
|
||||||
if (argv.argc() != 2)
|
if (argv.argc() != 3)
|
||||||
{
|
{
|
||||||
Printf("Usage: writemidi <filename>");
|
Printf("Usage: writemidi <midisong> <filename> - use '*' as song name to dump the currently playing song");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (currSong == NULL)
|
FString src = argv[1];
|
||||||
|
if (src.Compare("*") == 0) src= mus_playing.name;
|
||||||
|
|
||||||
|
auto lump = Wads.CheckNumForName(src, ns_music);
|
||||||
|
if (lump < 0) lump = Wads.CheckNumForFullName(src);
|
||||||
|
if (lump < 0)
|
||||||
{
|
{
|
||||||
Printf("No song is currently playing.\n");
|
Printf("Cannot find MIDI lump %s.\n", src.GetChars());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!currSong->IsMIDI())
|
|
||||||
|
FWadLump wlump = Wads.OpenLumpNum(lump);
|
||||||
|
uint32_t id[32/4];
|
||||||
|
|
||||||
|
if(wlump.Read(id, 32) != 32 || wlump.Seek(-32, SEEK_CUR) != 0)
|
||||||
{
|
{
|
||||||
Printf("Current song is not MIDI-based.\n");
|
Printf("Unable to read lump %s\n", src.GetChars());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto type = IdentifyMIDIType(id, 32);
|
||||||
|
auto source = CreateMIDISource(wlump, type);
|
||||||
|
|
||||||
|
if (source == nullptr)
|
||||||
|
{
|
||||||
|
Printf("%s is not MIDI-based.\n", src.GetChars());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TArray<uint8_t> midi;
|
TArray<uint8_t> midi;
|
||||||
bool success;
|
bool success;
|
||||||
|
|
||||||
static_cast<MIDIStreamer *>(currSong)->CreateSMF(midi, 1);
|
source->CreateSMF(midi, 1);
|
||||||
auto f = FileWriter::Open(argv[1]);
|
auto f = FileWriter::Open(argv[2]);
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
{
|
{
|
||||||
Printf("Could not open %s.\n", argv[1]);
|
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()) == (size_t)midi.Size());
|
||||||
|
@ -826,6 +845,6 @@ UNSAFE_CCMD (writemidi)
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
Printf("Could not write to music file.\n");
|
Printf("Could not write to music file %s.\n", argv[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -317,23 +317,22 @@ public:
|
||||||
MIDIStreamer(EMidiDevice type, const char *args);
|
MIDIStreamer(EMidiDevice type, const char *args);
|
||||||
~MIDIStreamer();
|
~MIDIStreamer();
|
||||||
|
|
||||||
void MusicVolumeChanged();
|
void MusicVolumeChanged() override;
|
||||||
void TimidityVolumeChanged();
|
void TimidityVolumeChanged() override;
|
||||||
void Play(bool looping, int subsong);
|
void Play(bool looping, int subsong) override;
|
||||||
void Pause();
|
void Pause() override;
|
||||||
void Resume();
|
void Resume() override;
|
||||||
void Stop();
|
void Stop() override;
|
||||||
bool IsPlaying();
|
bool IsPlaying() override;
|
||||||
bool IsMIDI() const;
|
bool IsMIDI() const override;
|
||||||
bool IsValid() const;
|
bool IsValid() const override;
|
||||||
bool SetSubsong(int subsong);
|
bool SetSubsong(int subsong) override;
|
||||||
void Update();
|
void Update() override;
|
||||||
FString GetStats();
|
FString GetStats() override;
|
||||||
void FluidSettingInt(const char *setting, int value);
|
void FluidSettingInt(const char *setting, int value) override;
|
||||||
void FluidSettingNum(const char *setting, double value);
|
void FluidSettingNum(const char *setting, double value) override;
|
||||||
void FluidSettingStr(const char *setting, const char *value);
|
void FluidSettingStr(const char *setting, const char *value) override;
|
||||||
void WildMidiSetOption(int opt, int set);
|
void WildMidiSetOption(int opt, int set) override;
|
||||||
void CreateSMF(TArray<uint8_t> &file, int looplimit=0);
|
|
||||||
int ServiceEvent();
|
int ServiceEvent();
|
||||||
void SetMIDISource(MIDISource *_source);
|
void SetMIDISource(MIDISource *_source);
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,10 @@
|
||||||
#include "midisources.h"
|
#include "midisources.h"
|
||||||
|
|
||||||
|
|
||||||
|
char MIDI_EventLengths[7] = { 2, 2, 2, 2, 1, 1, 2 };
|
||||||
|
char MIDI_CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// MIDISource :: SetTempo
|
// MIDISource :: SetTempo
|
||||||
|
@ -239,3 +243,161 @@ bool MIDISource::SetMIDISubsong(int subsong)
|
||||||
{
|
{
|
||||||
return subsong == 0;
|
return subsong == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// WriteVarLen
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
static void WriteVarLen (TArray<uint8_t> &file, uint32_t value)
|
||||||
|
{
|
||||||
|
uint32_t buffer = value & 0x7F;
|
||||||
|
|
||||||
|
while ( (value >>= 7) )
|
||||||
|
{
|
||||||
|
buffer <<= 8;
|
||||||
|
buffer |= (value & 0x7F) | 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
file.Push(uint8_t(buffer));
|
||||||
|
if (buffer & 0x80)
|
||||||
|
{
|
||||||
|
buffer >>= 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// MIDIStreamer :: CreateSMF
|
||||||
|
//
|
||||||
|
// Simulates playback to create a Standard MIDI File.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void MIDISource::CreateSMF(TArray<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)
|
||||||
|
|
||||||
|
static const uint8_t StaticMIDIhead[] =
|
||||||
|
{
|
||||||
|
'M','T','h','d', 0, 0, 0, 6,
|
||||||
|
0, 0, // format 0: only one track
|
||||||
|
0, 1, // yes, there is really only one track
|
||||||
|
0, 0, // divisions (filled in)
|
||||||
|
'M','T','r','k', 0, 0, 0, 0,
|
||||||
|
// The first event sets the tempo (filled in)
|
||||||
|
0, 255, 81, 3, 0, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t Events[2][MAX_MIDI_EVENTS*3];
|
||||||
|
uint32_t delay = 0;
|
||||||
|
uint8_t running_status = 255;
|
||||||
|
|
||||||
|
// Always create songs aimed at GM devices.
|
||||||
|
CheckCaps(MIDIDEV_MIDIPORT);
|
||||||
|
LoopLimit = looplimit <= 0 ? EXPORT_LOOP_LIMIT : looplimit;
|
||||||
|
DoRestart();
|
||||||
|
StartPlayback(false, LoopLimit);
|
||||||
|
|
||||||
|
file.Reserve(sizeof(StaticMIDIhead));
|
||||||
|
memcpy(&file[0], StaticMIDIhead, sizeof(StaticMIDIhead));
|
||||||
|
file[12] = Division >> 8;
|
||||||
|
file[13] = Division & 0xFF;
|
||||||
|
file[26] = InitialTempo >> 16;
|
||||||
|
file[27] = InitialTempo >> 8;
|
||||||
|
file[28] = InitialTempo;
|
||||||
|
|
||||||
|
while (!CheckDone())
|
||||||
|
{
|
||||||
|
uint32_t *event_end = MakeEvents(Events[0], &Events[0][MAX_MIDI_EVENTS*3], 1000000*600);
|
||||||
|
for (uint32_t *event = Events[0]; event < event_end; )
|
||||||
|
{
|
||||||
|
delay += event[0];
|
||||||
|
if (MEVENT_EVENTTYPE(event[2]) == MEVENT_TEMPO)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
running_status = 255;
|
||||||
|
}
|
||||||
|
else if (MEVENT_EVENTTYPE(event[2]) == MEVENT_LONGMSG)
|
||||||
|
{
|
||||||
|
WriteVarLen(file, delay);
|
||||||
|
delay = 0;
|
||||||
|
uint32_t len = MEVENT_EVENTPARM(event[2]);
|
||||||
|
uint8_t *bytes = (uint8_t *)&event[3];
|
||||||
|
if (bytes[0] == MIDI_SYSEX)
|
||||||
|
{
|
||||||
|
len--;
|
||||||
|
file.Push(MIDI_SYSEX);
|
||||||
|
WriteVarLen(file, len);
|
||||||
|
memcpy(&file[file.Reserve(len)], bytes + 1, len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file.Push(MIDI_SYSEXEND);
|
||||||
|
WriteVarLen(file, len);
|
||||||
|
memcpy(&file[file.Reserve(len)], bytes, len);
|
||||||
|
}
|
||||||
|
running_status = 255;
|
||||||
|
}
|
||||||
|
else if (MEVENT_EVENTTYPE(event[2]) == 0)
|
||||||
|
{
|
||||||
|
WriteVarLen(file, delay);
|
||||||
|
delay = 0;
|
||||||
|
uint8_t status = uint8_t(event[2]);
|
||||||
|
if (status != running_status)
|
||||||
|
{
|
||||||
|
running_status = status;
|
||||||
|
file.Push(status);
|
||||||
|
}
|
||||||
|
file.Push(uint8_t((event[2] >> 8) & 0x7F));
|
||||||
|
if (MIDI_EventLengths[(status >> 4) & 7] == 2)
|
||||||
|
{
|
||||||
|
file.Push(uint8_t((event[2] >> 16) & 0x7F));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Advance to next event
|
||||||
|
if (event[2] < 0x80000000)
|
||||||
|
{ // short message
|
||||||
|
event += 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // long message
|
||||||
|
event += 3 + ((MEVENT_EVENTPARM(event[2]) + 3) >> 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// End track
|
||||||
|
WriteVarLen(file, delay);
|
||||||
|
file.Push(MIDI_META);
|
||||||
|
file.Push(MIDI_META_EOT);
|
||||||
|
file.Push(0);
|
||||||
|
|
||||||
|
// Fill in track length
|
||||||
|
uint32_t len = file.Size() - 22;
|
||||||
|
file[18] = uint8_t(len >> 24);
|
||||||
|
file[19] = uint8_t(len >> 16);
|
||||||
|
file[20] = uint8_t(len >> 8);
|
||||||
|
file[21] = uint8_t(len & 255);
|
||||||
|
|
||||||
|
LoopLimit = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
extern char MIDI_EventLengths[7];
|
||||||
|
extern char MIDI_CommonLengths[15];
|
||||||
|
|
||||||
// base class for the different MIDI sources --------------------------------------
|
// base class for the different MIDI sources --------------------------------------
|
||||||
|
|
||||||
class MIDISource
|
class MIDISource
|
||||||
|
@ -63,6 +66,9 @@ public:
|
||||||
{
|
{
|
||||||
TempoCallback = cb;
|
TempoCallback = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CreateSMF(TArray<uint8_t> &file, int looplimit);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// MUS file played with a MIDI stream ---------------------------------------
|
// MUS file played with a MIDI stream ---------------------------------------
|
||||||
|
|
|
@ -112,9 +112,6 @@ struct HMISong::TrackInfo
|
||||||
|
|
||||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||||
|
|
||||||
extern char MIDI_EventLengths[7];
|
|
||||||
extern char MIDI_CommonLengths[15];
|
|
||||||
|
|
||||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||||
|
|
||||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||||
|
|
|
@ -45,8 +45,6 @@
|
||||||
|
|
||||||
#define MAX_TIME (1000000/10) // Send out 1/10 of a sec of events at a time.
|
#define MAX_TIME (1000000/10) // Send out 1/10 of a sec of events at a time.
|
||||||
|
|
||||||
#define EXPORT_LOOP_LIMIT 30 // Maximum number of times to loop when exporting a MIDI file.
|
|
||||||
// (for songs with loop controller events)
|
|
||||||
|
|
||||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||||
|
|
||||||
|
@ -65,21 +63,8 @@ EXTERN_CVAR(Int, snd_mididevice)
|
||||||
extern unsigned mididevice;
|
extern unsigned mididevice;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern char MIDI_EventLengths[7];
|
|
||||||
|
|
||||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||||
|
|
||||||
static const uint8_t StaticMIDIhead[] =
|
|
||||||
{
|
|
||||||
'M','T','h','d', 0, 0, 0, 6,
|
|
||||||
0, 0, // format 0: only one track
|
|
||||||
0, 1, // yes, there is really only one track
|
|
||||||
0, 0, // divisions (filled in)
|
|
||||||
'M','T','r','k', 0, 0, 0, 0,
|
|
||||||
// The first event sets the tempo (filled in)
|
|
||||||
0, 255, 81, 3, 0, 0, 0
|
|
||||||
};
|
|
||||||
|
|
||||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||||
|
|
||||||
// CODE --------------------------------------------------------------------
|
// CODE --------------------------------------------------------------------
|
||||||
|
@ -852,150 +837,6 @@ void MIDIStreamer::SetMIDISource(MIDISource *_source)
|
||||||
source->setTempoCallback([=](int tempo) { return MIDI->SetTempo(tempo); } );
|
source->setTempoCallback([=](int tempo) { return MIDI->SetTempo(tempo); } );
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// MIDIStreamer :: CreateSMF
|
|
||||||
//
|
|
||||||
// Simulates playback to create a Standard MIDI File.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
void MIDIStreamer::CreateSMF(TArray<uint8_t> &file, int looplimit)
|
|
||||||
{
|
|
||||||
uint32_t delay = 0;
|
|
||||||
uint8_t running_status = 255;
|
|
||||||
|
|
||||||
// Always create songs aimed at GM devices.
|
|
||||||
if (source == nullptr) return;
|
|
||||||
source->CheckCaps(MIDIDEV_MIDIPORT);
|
|
||||||
LoopLimit = looplimit <= 0 ? EXPORT_LOOP_LIMIT : looplimit;
|
|
||||||
source->DoRestart();
|
|
||||||
source->StartPlayback(false, LoopLimit);
|
|
||||||
auto InitialTempo = source->getInitialTempo();
|
|
||||||
auto Division = source->getDivision();
|
|
||||||
|
|
||||||
file.Reserve(sizeof(StaticMIDIhead));
|
|
||||||
memcpy(&file[0], StaticMIDIhead, sizeof(StaticMIDIhead));
|
|
||||||
file[12] = Division >> 8;
|
|
||||||
file[13] = Division & 0xFF;
|
|
||||||
file[26] = InitialTempo >> 16;
|
|
||||||
file[27] = InitialTempo >> 8;
|
|
||||||
file[28] = InitialTempo;
|
|
||||||
|
|
||||||
while (!source->CheckDone())
|
|
||||||
{
|
|
||||||
uint32_t *event_end = source->MakeEvents(Events[0], &Events[0][MAX_MIDI_EVENTS*3], 1000000*600);
|
|
||||||
for (uint32_t *event = Events[0]; event < event_end; )
|
|
||||||
{
|
|
||||||
delay += event[0];
|
|
||||||
if (MEVENT_EVENTTYPE(event[2]) == MEVENT_TEMPO)
|
|
||||||
{
|
|
||||||
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));
|
|
||||||
running_status = 255;
|
|
||||||
}
|
|
||||||
else if (MEVENT_EVENTTYPE(event[2]) == MEVENT_LONGMSG)
|
|
||||||
{
|
|
||||||
WriteVarLen(file, delay);
|
|
||||||
delay = 0;
|
|
||||||
uint32_t len = MEVENT_EVENTPARM(event[2]);
|
|
||||||
uint8_t *bytes = (uint8_t *)&event[3];
|
|
||||||
if (bytes[0] == MIDI_SYSEX)
|
|
||||||
{
|
|
||||||
len--;
|
|
||||||
file.Push(MIDI_SYSEX);
|
|
||||||
WriteVarLen(file, len);
|
|
||||||
memcpy(&file[file.Reserve(len)], bytes + 1, len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
file.Push(MIDI_SYSEXEND);
|
|
||||||
WriteVarLen(file, len);
|
|
||||||
memcpy(&file[file.Reserve(len)], bytes, len);
|
|
||||||
}
|
|
||||||
running_status = 255;
|
|
||||||
}
|
|
||||||
else if (MEVENT_EVENTTYPE(event[2]) == 0)
|
|
||||||
{
|
|
||||||
WriteVarLen(file, delay);
|
|
||||||
delay = 0;
|
|
||||||
uint8_t status = uint8_t(event[2]);
|
|
||||||
if (status != running_status)
|
|
||||||
{
|
|
||||||
running_status = status;
|
|
||||||
file.Push(status);
|
|
||||||
}
|
|
||||||
file.Push(uint8_t((event[2] >> 8) & 0x7F));
|
|
||||||
if (MIDI_EventLengths[(status >> 4) & 7] == 2)
|
|
||||||
{
|
|
||||||
file.Push(uint8_t((event[2] >> 16) & 0x7F));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Advance to next event
|
|
||||||
if (event[2] < 0x80000000)
|
|
||||||
{ // short message
|
|
||||||
event += 3;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // long message
|
|
||||||
event += 3 + ((MEVENT_EVENTPARM(event[2]) + 3) >> 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// End track
|
|
||||||
WriteVarLen(file, delay);
|
|
||||||
file.Push(MIDI_META);
|
|
||||||
file.Push(MIDI_META_EOT);
|
|
||||||
file.Push(0);
|
|
||||||
|
|
||||||
// Fill in track length
|
|
||||||
uint32_t len = file.Size() - 22;
|
|
||||||
file[18] = uint8_t(len >> 24);
|
|
||||||
file[19] = uint8_t(len >> 16);
|
|
||||||
file[20] = uint8_t(len >> 8);
|
|
||||||
file[21] = uint8_t(len & 255);
|
|
||||||
|
|
||||||
LoopLimit = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// WriteVarLen
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
static void WriteVarLen (TArray<uint8_t> &file, uint32_t value)
|
|
||||||
{
|
|
||||||
uint32_t buffer = value & 0x7F;
|
|
||||||
|
|
||||||
while ( (value >>= 7) )
|
|
||||||
{
|
|
||||||
buffer <<= 8;
|
|
||||||
buffer |= (value & 0x7F) | 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
file.Push(uint8_t(buffer));
|
|
||||||
if (buffer & 0x80)
|
|
||||||
{
|
|
||||||
buffer >>= 8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
|
|
@ -89,9 +89,6 @@ struct MIDISong2::TrackInfo
|
||||||
|
|
||||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||||
|
|
||||||
char MIDI_EventLengths[7] = { 2, 2, 2, 2, 1, 1, 2 };
|
|
||||||
char MIDI_CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
||||||
|
|
||||||
// CODE --------------------------------------------------------------------
|
// CODE --------------------------------------------------------------------
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -91,9 +91,6 @@ struct XMISong::TrackInfo
|
||||||
|
|
||||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||||
|
|
||||||
extern char MIDI_EventLengths[7];
|
|
||||||
extern char MIDI_CommonLengths[15];
|
|
||||||
|
|
||||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||||
|
|
||||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue