aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/adlmidi.cpp211
-rw-r--r--src/adlmidi_load.cpp118
-rw-r--r--src/adlmidi_midiplay.cpp619
-rw-r--r--src/adlmidi_opl3.cpp6
-rw-r--r--src/adlmidi_private.cpp14
-rw-r--r--src/adlmidi_private.hpp91
-rw-r--r--src/dbopl.h8
7 files changed, 575 insertions, 492 deletions
diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp
index 1bde95a..bbd80e4 100644
--- a/src/adlmidi.cpp
+++ b/src/adlmidi.cpp
@@ -31,36 +31,11 @@ ADLMIDI_EXPORT struct ADL_MIDIPlayer *adl_init(long sample_rate)
{
ADL_MIDIPlayer *midi_device;
midi_device = (ADL_MIDIPlayer *)malloc(sizeof(ADL_MIDIPlayer));
- midi_device->PCM_RATE = static_cast<unsigned long>(sample_rate);
- midi_device->AdlBank = 0;
- midi_device->NumFourOps = 7;
- midi_device->NumCards = 2;
- midi_device->HighTremoloMode = 0;
- midi_device->HighVibratoMode = 0;
- midi_device->AdlPercussionMode = 0;
- midi_device->LogarithmicVolumes = 0;
- midi_device->SkipForward = 0;
- midi_device->loopingIsEnabled = 0;
- midi_device->ScaleModulators = 0;
- midi_device->delay = 0.0;
- midi_device->carry = 0.0;
- midi_device->mindelay = 1.0 / (double)midi_device->PCM_RATE;
- midi_device->maxdelay = 512.0 / (double)midi_device->PCM_RATE;
- midi_device->stored_samples = 0;
- midi_device->backup_samples_size = 0;
-
MIDIplay *player = new MIDIplay;
midi_device->adl_midiPlayer = player;
- player->config = midi_device;
- player->opl._parent = midi_device;
- player->opl.NumCards = midi_device->NumCards;
- player->opl.AdlBank = midi_device->AdlBank;
- player->opl.NumFourOps = midi_device->NumFourOps;
- player->opl.LogarithmicVolumes = (midi_device->LogarithmicVolumes != 0);
- player->opl.HighTremoloMode = (midi_device->HighTremoloMode != 0);
- player->opl.HighVibratoMode = (midi_device->HighVibratoMode != 0);
- player->opl.AdlPercussionMode = (midi_device->AdlPercussionMode != 0);
- player->opl.ScaleModulators = (midi_device->ScaleModulators != 0);
+ player->m_setup.PCM_RATE = static_cast<unsigned long>(sample_rate);
+ player->m_setup.mindelay = 1.0 / (double)player->m_setup.PCM_RATE;
+ player->m_setup.maxdelay = 512.0 / (double)player->m_setup.PCM_RATE;
player->ChooseDevice("none");
adlRefreshNumCards(midi_device);
return midi_device;
@@ -71,10 +46,9 @@ ADLMIDI_EXPORT int adl_setNumCards(ADL_MIDIPlayer *device, int numCards)
if(device == NULL)
return -2;
- device->NumCards = static_cast<unsigned int>(numCards);
- reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.NumCards = device->NumCards;
-
- if(device->NumCards < 1 || device->NumCards > MaxCards)
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->m_setup.NumCards = static_cast<unsigned int>(numCards);
+ if(play->m_setup.NumCards < 1 || play->m_setup.NumCards > MaxCards)
{
std::stringstream s;
s << "number of cards may only be 1.." << MaxCards << ".\n";
@@ -82,6 +56,8 @@ ADLMIDI_EXPORT int adl_setNumCards(ADL_MIDIPlayer *device, int numCards)
return -1;
}
+ play->opl.NumCards = play->m_setup.NumCards;
+
return adlRefreshNumCards(device);
}
@@ -99,11 +75,11 @@ ADLMIDI_EXPORT int adl_setBank(ADL_MIDIPlayer *device, int bank)
if(bankno < 0)
bankno = 0;
- device->AdlBank = static_cast<uint32_t>(bankno);
MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
- play->opl.AdlBank = device->AdlBank;
+ play->m_setup.AdlBank = static_cast<uint32_t>(bankno);
+ play->opl.AdlBank = play->m_setup.AdlBank;
- if(device->AdlBank >= NumBanks)
+ if(play->m_setup.AdlBank >= NumBanks)
{
std::stringstream s;
s << "bank number may only be 0.." << (NumBanks - 1) << ".\n";
@@ -127,13 +103,16 @@ ADLMIDI_EXPORT const char *const *adl_getBankNames()
ADLMIDI_EXPORT int adl_setNumFourOpsChn(ADL_MIDIPlayer *device, int ops4)
{
- device->NumFourOps = static_cast<unsigned int>(ops4);
- reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.NumFourOps = device->NumFourOps;
+ if(!device)
+ return -1;
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->m_setup.NumFourOps = static_cast<unsigned int>(ops4);
+ play->opl.NumFourOps = play->m_setup.NumFourOps;
- if(device->NumFourOps > 6 * device->NumCards)
+ if(play->m_setup.NumFourOps > 6 * play->m_setup.NumCards)
{
std::stringstream s;
- s << "number of four-op channels may only be 0.." << (6 * (device->NumCards)) << " when " << device->NumCards << " OPL3 cards are used.\n";
+ s << "number of four-op channels may only be 0.." << (6 * (play->m_setup.NumCards)) << " when " << play->m_setup.NumCards << " OPL3 cards are used.\n";
ADLMIDI_ErrorString = s.str();
return -1;
}
@@ -145,55 +124,56 @@ ADLMIDI_EXPORT int adl_setNumFourOpsChn(ADL_MIDIPlayer *device, int ops4)
ADLMIDI_EXPORT void adl_setPercMode(ADL_MIDIPlayer *device, int percmod)
{
if(!device) return;
-
- device->AdlPercussionMode = static_cast<unsigned int>(percmod);
- reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.AdlPercussionMode = (device->AdlPercussionMode != 0);
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->m_setup.AdlPercussionMode = (percmod != 0);
+ play->opl.AdlPercussionMode = play->m_setup.AdlPercussionMode;
}
ADLMIDI_EXPORT void adl_setHVibrato(ADL_MIDIPlayer *device, int hvibro)
{
if(!device) return;
-
- device->HighVibratoMode = static_cast<unsigned int>(hvibro);
- reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.HighVibratoMode = (device->HighVibratoMode != 0);
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->m_setup.HighVibratoMode = (hvibro != 0);
+ play->opl.HighVibratoMode = play->m_setup.HighVibratoMode;
}
ADLMIDI_EXPORT void adl_setHTremolo(ADL_MIDIPlayer *device, int htremo)
{
if(!device) return;
-
- device->HighTremoloMode = static_cast<unsigned int>(htremo);
- reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.HighTremoloMode = (device->HighTremoloMode != 0);
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->m_setup.HighTremoloMode = (htremo != 0);
+ play->opl.HighTremoloMode = play->m_setup.HighTremoloMode;
}
ADLMIDI_EXPORT void adl_setScaleModulators(ADL_MIDIPlayer *device, int smod)
{
if(!device) return;
-
- device->ScaleModulators = static_cast<unsigned int>(smod);
- reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.ScaleModulators = (device->ScaleModulators != 0);
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->m_setup.ScaleModulators = (smod != 0);
+ play->opl.ScaleModulators = play->m_setup.ScaleModulators;
}
ADLMIDI_EXPORT void adl_setLoopEnabled(ADL_MIDIPlayer *device, int loopEn)
{
if(!device) return;
- device->loopingIsEnabled = (loopEn != 0);
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->m_setup.loopingIsEnabled = (loopEn != 0);
}
ADLMIDI_EXPORT void adl_setLogarithmicVolumes(struct ADL_MIDIPlayer *device, int logvol)
{
if(!device) return;
-
- device->LogarithmicVolumes = static_cast<unsigned int>(logvol);
- reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.LogarithmicVolumes = (device->LogarithmicVolumes != 0);
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->m_setup.LogarithmicVolumes = (logvol != 0);
+ play->opl.LogarithmicVolumes = play->m_setup.LogarithmicVolumes;
}
ADLMIDI_EXPORT void adl_setVolumeRangeModel(struct ADL_MIDIPlayer *device, int volumeModel)
{
if(!device) return;
-
- device->VolumeModel = volumeModel;
- reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.ChangeVolumeRangesModel(static_cast<ADLMIDI_VolumeModels>(volumeModel));
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->m_setup.VolumeModel = volumeModel;
+ play->opl.ChangeVolumeRangesModel(static_cast<ADLMIDI_VolumeModels>(volumeModel));
}
ADLMIDI_EXPORT int adl_openBankFile(struct ADL_MIDIPlayer *device, char *filePath)
@@ -202,10 +182,10 @@ ADLMIDI_EXPORT int adl_openBankFile(struct ADL_MIDIPlayer *device, char *filePat
if(device && device->adl_midiPlayer)
{
- device->stored_samples = 0;
- device->backup_samples_size = 0;
-
- if(!reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->LoadBank(filePath))
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->m_setup.stored_samples = 0;
+ play->m_setup.backup_samples_size = 0;
+ if(!play->LoadBank(filePath))
{
if(ADLMIDI_ErrorString.empty())
ADLMIDI_ErrorString = "ADL MIDI: Can't load file";
@@ -224,10 +204,10 @@ ADLMIDI_EXPORT int adl_openBankData(struct ADL_MIDIPlayer *device, void *mem, lo
if(device && device->adl_midiPlayer)
{
- device->stored_samples = 0;
- device->backup_samples_size = 0;
-
- if(!reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->LoadBank(mem, static_cast<size_t>(size)))
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->m_setup.stored_samples = 0;
+ play->m_setup.backup_samples_size = 0;
+ if(!play->LoadBank(mem, static_cast<size_t>(size)))
{
if(ADLMIDI_ErrorString.empty())
ADLMIDI_ErrorString = "ADL MIDI: Can't load data from memory";
@@ -246,14 +226,13 @@ ADLMIDI_EXPORT int adl_openFile(ADL_MIDIPlayer *device, char *filePath)
if(device && device->adl_midiPlayer)
{
- device->stored_samples = 0;
- device->backup_samples_size = 0;
-
- if(!reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->LoadMIDI(filePath))
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->m_setup.stored_samples = 0;
+ play->m_setup.backup_samples_size = 0;
+ if(!play->LoadMIDI(filePath))
{
if(ADLMIDI_ErrorString.empty())
ADLMIDI_ErrorString = "ADL MIDI: Can't load file";
-
return -1;
}
else return 0;
@@ -269,14 +248,13 @@ ADLMIDI_EXPORT int adl_openData(ADL_MIDIPlayer *device, void *mem, long size)
if(device && device->adl_midiPlayer)
{
- device->stored_samples = 0;
- device->backup_samples_size = 0;
-
- if(!reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->LoadMIDI(mem, static_cast<size_t>(size)))
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->m_setup.stored_samples = 0;
+ play->m_setup.backup_samples_size = 0;
+ if(!play->LoadMIDI(mem, static_cast<size_t>(size)))
{
if(ADLMIDI_ErrorString.empty())
ADLMIDI_ErrorString = "ADL MIDI: Can't load data from memory";
-
return -1;
}
else return 0;
@@ -294,8 +272,8 @@ ADLMIDI_EXPORT const char *adl_errorString()
ADLMIDI_EXPORT const char *adl_getMusicTitle(ADL_MIDIPlayer *device)
{
- if(!device) return "";
-
+ if(!device)
+ return "";
return reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->musTitle.c_str();
}
@@ -303,7 +281,6 @@ ADLMIDI_EXPORT void adl_close(ADL_MIDIPlayer *device)
{
if(device->adl_midiPlayer)
delete reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
-
device->adl_midiPlayer = NULL;
free(device);
device = NULL;
@@ -313,10 +290,10 @@ ADLMIDI_EXPORT void adl_reset(ADL_MIDIPlayer *device)
{
if(!device)
return;
-
- device->stored_samples = 0;
- device->backup_samples_size = 0;
- reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.Reset();
+ MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ play->m_setup.stored_samples = 0;
+ play->m_setup.backup_samples_size = 0;
+ play->opl.Reset(play->m_setup.PCM_RATE);
}
ADLMIDI_EXPORT double adl_totalTimeLength(ADL_MIDIPlayer *device)
@@ -353,7 +330,7 @@ ADLMIDI_EXPORT void adl_positionRewind(struct ADL_MIDIPlayer *device)
#define ADLMIDI_CLAMP(V, MIN, MAX) std::max(std::min(V, (MAX)), (MIN))
-inline static void SendStereoAudio(ADL_MIDIPlayer *device,
+inline static void SendStereoAudio(MIDIplay::Setup &device,
int &samples_requested,
ssize_t &in_size,
int *_in,
@@ -362,7 +339,7 @@ inline static void SendStereoAudio(ADL_MIDIPlayer *device,
{
if(!in_size) return;
- device->stored_samples = 0;
+ device.stored_samples = 0;
ssize_t out;
ssize_t offset;
ssize_t pos = static_cast<ssize_t>(out_pos);
@@ -378,15 +355,15 @@ inline static void SendStereoAudio(ADL_MIDIPlayer *device,
_out[offset] = static_cast<short>(ADLMIDI_CLAMP(out, static_cast<ssize_t>(INT16_MIN), static_cast<ssize_t>(INT16_MAX)));
else
{
- device->backup_samples[device->backup_samples_size] = static_cast<short>(out);
- device->backup_samples_size++;
- device->stored_samples++;
+ device.backup_samples[device.backup_samples_size] = static_cast<short>(out);
+ device.backup_samples_size++;
+ device.stored_samples++;
}
}
}
}
#else
-inline static void SendStereoAudio(ADL_MIDIPlayer *device,
+inline static void SendStereoAudio(MIDIplay::Setup &device,
int &samples_requested,
ssize_t &in_size,
short *_in,
@@ -396,7 +373,7 @@ inline static void SendStereoAudio(ADL_MIDIPlayer *device,
if(!in_size)
return;
- device->stored_samples = 0;
+ device.stored_samples = 0;
size_t offset = static_cast<size_t>(out_pos);
size_t inSamples = static_cast<size_t>(in_size * 2);
size_t maxSamples = static_cast<size_t>(samples_requested) - offset;
@@ -406,10 +383,10 @@ inline static void SendStereoAudio(ADL_MIDIPlayer *device,
if(maxSamples < inSamples)
{
size_t appendSize = inSamples - maxSamples;
- std::memcpy(device->backup_samples + device->backup_samples_size,
+ std::memcpy(device.backup_samples + device.backup_samples_size,
maxSamples + _in, appendSize * sizeof(short));
- device->backup_samples_size += (ssize_t)appendSize;
- device->stored_samples += (ssize_t)appendSize;
+ device.backup_samples_size += (ssize_t)appendSize;
+ device.stored_samples += (ssize_t)appendSize;
}
}
#endif
@@ -420,6 +397,9 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out)
if(!device)
return 0;
+ MIDIplay *player = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ MIDIplay::Setup &setup = player->m_setup;
+
sampleCount -= sampleCount % 2; //Avoid even sample requests
if(sampleCount < 0)
@@ -432,39 +412,39 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out)
while(left > 0)
{
- if(device->backup_samples_size > 0)
+ if(setup.backup_samples_size > 0)
{
//Send reserved samples if exist
ssize_t ate = 0;
- while((ate < device->backup_samples_size) && (ate < left))
+ while((ate < setup.backup_samples_size) && (ate < left))
{
- out[ate] = device->backup_samples[ate];
+ out[ate] = setup.backup_samples[ate];
ate++;
}
left -= (int)ate;
gotten_len += ate;
- if(ate < device->backup_samples_size)
+ if(ate < setup.backup_samples_size)
{
for(ssize_t j = 0; j < ate; j++)
- device->backup_samples[(ate - 1) - j] = device->backup_samples[(device->backup_samples_size - 1) - j];
+ setup.backup_samples[(ate - 1) - j] = setup.backup_samples[(setup.backup_samples_size - 1) - j];
}
- device->backup_samples_size -= ate;
+ setup.backup_samples_size -= ate;
}
else
{
- const double eat_delay = device->delay < device->maxdelay ? device->delay : device->maxdelay;
- device->delay -= eat_delay;
- device->carry += device->PCM_RATE * eat_delay;
- n_periodCountStereo = static_cast<ssize_t>(device->carry);
+ const double eat_delay = setup.delay < setup.maxdelay ? setup.delay : setup.maxdelay;
+ setup.delay -= eat_delay;
+ setup.carry += setup.PCM_RATE * eat_delay;
+ n_periodCountStereo = static_cast<ssize_t>(setup.carry);
//n_periodCountPhys = n_periodCountStereo * 2;
- device->carry -= n_periodCountStereo;
+ setup.carry -= n_periodCountStereo;
- if(device->SkipForward > 0)
- device->SkipForward -= 1;
+ if(setup.SkipForward > 0)
+ setup.SkipForward -= 1;
else
{
#ifdef ADLMIDI_USE_DOSBOX_OPL
@@ -472,11 +452,10 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out)
#else
std::vector<int16_t> out_buf;
#endif
- out_buf.resize(1024 /*n_samples * 2*/);
- MIDIplay *player = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer);
+ out_buf.resize(1024, 0);
- if((player->atEnd) && (device->delay <= 0.0))
- break;//Stop to fetch samples at reaching of song end with disabled loop
+ if((player->atEnd) && (setup.delay <= 0.0))
+ break;//Stop to fetch samples at reaching the song end with disabled loop
ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo;
ssize_t in_generatedPhys = in_generatedStereo * 2;
@@ -484,7 +463,7 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out)
//fill buffer with zeros
size_t in_countStereoU = static_cast<size_t>(in_generatedStereo * 2);
- if(device->NumCards == 1)
+ if(player->m_setup.NumCards == 1)
{
#ifdef ADLMIDI_USE_DOSBOX_OPL
player->opl.cards[0].GenerateArr(out_buf.data(), &in_generatedStereo);
@@ -493,7 +472,7 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out)
OPL3_GenerateStream(&player->opl.cards[0], out_buf.data(), static_cast<Bit32u>(in_generatedStereo));
#endif
/* Process it */
- SendStereoAudio(device, sampleCount, in_generatedStereo, out_buf.data(), gotten_len, out);
+ SendStereoAudio(setup, sampleCount, in_generatedStereo, out_buf.data(), gotten_len, out);
}
else if(n_periodCountStereo > 0)
{
@@ -505,7 +484,7 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out)
std::memset(out_buf.data(), 0, in_countStereoU * sizeof(short));
/* Generate data from every chip and mix result */
- for(unsigned card = 0; card < device->NumCards; ++card)
+ for(unsigned card = 0; card < player->m_setup.NumCards; ++card)
{
#ifdef ADLMIDI_USE_DOSBOX_OPL
player->opl.cards[card].GenerateArr(in_mixBuffer.data(), &in_generatedStereo);
@@ -519,15 +498,15 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out)
}
/* Process it */
- SendStereoAudio(device, sampleCount, in_generatedStereo, out_buf.data(), gotten_len, out);
+ SendStereoAudio(setup, sampleCount, in_generatedStereo, out_buf.data(), gotten_len, out);
}
left -= (int)in_generatedPhys;
- gotten_len += (in_generatedPhys) - device->stored_samples;
+ gotten_len += (in_generatedPhys) - setup.stored_samples;
out_buf.clear();
}
- device->delay = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->Tick(eat_delay, device->mindelay);
+ setup.delay = player->Tick(eat_delay, setup.mindelay);
}
}
diff --git a/src/adlmidi_load.cpp b/src/adlmidi_load.cpp
index 43b6a4c..aee5775 100644
--- a/src/adlmidi_load.cpp
+++ b/src/adlmidi_load.cpp
@@ -48,27 +48,45 @@ uint64_t MIDIplay::ReadLEint(const void *buffer, size_t nbytes)
return result;
}
-uint64_t MIDIplay::ReadVarLenEx(size_t tk, bool &ok)
+//uint64_t MIDIplay::ReadVarLenEx(size_t tk, bool &ok)
+//{
+// uint64_t result = 0;
+// ok = false;
+
+// for(;;)
+// {
+// if(tk >= TrackData.size())
+// return 1;
+
+// if(tk >= CurrentPosition.track.size())
+// return 2;
+
+// size_t ptr = CurrentPosition.track[tk].ptr;
+
+// if(ptr >= TrackData[tk].size())
+// return 3;
+
+// unsigned char byte = TrackData[tk][CurrentPosition.track[tk].ptr++];
+// result = (result << 7) + (byte & 0x7F);
+
+// if(!(byte & 0x80)) break;
+// }
+
+// ok = true;
+// return result;
+//}
+
+uint64_t MIDIplay::ReadVarLenEx(uint8_t **ptr, uint8_t *end, bool &ok)
{
uint64_t result = 0;
ok = false;
for(;;)
{
- if(tk >= TrackData.size())
- return 1;
-
- if(tk >= CurrentPosition.track.size())
+ if(*ptr >= end)
return 2;
-
- size_t ptr = CurrentPosition.track[tk].ptr;
-
- if(ptr >= TrackData[tk].size())
- return 3;
-
- unsigned char byte = TrackData[tk][CurrentPosition.track[tk].ptr++];
+ unsigned char byte = *((*ptr)++);
result = (result << 7) + (byte & 0x7F);
-
if(!(byte & 0x80)) break;
}
@@ -76,6 +94,7 @@ uint64_t MIDIplay::ReadVarLenEx(size_t tk, bool &ok)
return result;
}
+
bool MIDIplay::LoadBank(const std::string &filename)
{
fileReader file;
@@ -122,7 +141,7 @@ enum WOPL_InstrumentFlags
{
WOPL_Flags_NONE = 0,
WOPL_Flag_Enable4OP = 0x01,
- WOPL_Flag_Pseudo4OP = 0x02,
+ WOPL_Flag_Pseudo4OP = 0x02
};
struct WOPL_Inst
@@ -295,7 +314,7 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr)
}
}
- opl.AdlBank = opl._parent->AdlBank;
+ opl.AdlBank = m_setup.AdlBank;
opl.dynamic_metainstruments.clear();
opl.dynamic_instruments.clear();
@@ -389,18 +408,18 @@ bool MIDIplay::LoadMIDI(MIDIplay::fileReader &fr)
/**** Set all properties BEFORE starting of actial file reading! ****/
- config->stored_samples = 0;
- config->backup_samples_size = 0;
- opl.AdlPercussionMode = (config->AdlPercussionMode != 0);
- opl.HighTremoloMode = (config->HighTremoloMode != 0);
- opl.HighVibratoMode = (config->HighVibratoMode != 0);
- opl.ScaleModulators = (config->ScaleModulators != 0);
- opl.LogarithmicVolumes = (config->LogarithmicVolumes != 0);
- opl.ChangeVolumeRangesModel(static_cast<ADLMIDI_VolumeModels>(config->VolumeModel));
+ m_setup.stored_samples = 0;
+ m_setup.backup_samples_size = 0;
+ opl.AdlPercussionMode = m_setup.AdlPercussionMode;
+ opl.HighTremoloMode = m_setup.HighTremoloMode;
+ opl.HighVibratoMode = m_setup.HighVibratoMode;
+ opl.ScaleModulators = m_setup.ScaleModulators;
+ opl.LogarithmicVolumes = m_setup.LogarithmicVolumes;
+ opl.ChangeVolumeRangesModel(static_cast<ADLMIDI_VolumeModels>(m_setup.VolumeModel));
- if(config->VolumeModel == ADLMIDI_VolumeModel_AUTO)
+ if(m_setup.VolumeModel == ADLMIDI_VolumeModel_AUTO)
{
- switch(config->AdlBank)
+ switch(m_setup.AdlBank)
{
default:
opl.m_volumeScale = OPL3::VOLUME_Generic;
@@ -429,10 +448,10 @@ bool MIDIplay::LoadMIDI(MIDIplay::fileReader &fr)
}
}
- opl.NumCards = config->NumCards;
- opl.NumFourOps = config->NumFourOps;
+ opl.NumCards = m_setup.NumCards;
+ opl.NumFourOps = m_setup.NumFourOps;
cmf_percussion_mode = false;
- opl.Reset();
+ opl.Reset(m_setup.PCM_RATE);
trackStart = true;
atEnd = false;
@@ -655,8 +674,8 @@ InvFmt:
TrackData.clear();
TrackData.resize(TrackCount, std::vector<uint8_t>());
- CurrentPosition.track.clear();
- CurrentPosition.track.resize(TrackCount);
+ //CurrentPosition.track.clear();
+ //CurrentPosition.track.resize(TrackCount);
InvDeltaTicks = fraction<uint64_t>(1, 1000000l * static_cast<uint64_t>(DeltaTicks));
//Tempo = 1000000l * InvDeltaTicks;
Tempo = fraction<uint64_t>(1, static_cast<uint64_t>(DeltaTicks));
@@ -710,8 +729,8 @@ InvFmt:
}
TrackData[tk].insert(TrackData[tk].end(), EndTag + 0, EndTag + 4);
- CurrentPosition.track[tk].delay = 0;
- CurrentPosition.began = true;
+ //CurrentPosition.track[tk].delay = 0;
+ //CurrentPosition.began = true;
//std::fprintf(stderr, "Done reading IMF file\n");
opl.NumFourOps = 0; //Don't use 4-operator channels for IMF playing!
}
@@ -748,19 +767,18 @@ InvFmt:
if(is_GMF /*|| is_MUS*/) // Note: CMF does include the track end tag.
TrackData[tk].insert(TrackData[tk].end(), EndTag + 0, EndTag + 4);
- bool ok = false;
- // Read next event time
- uint64_t tkDelay = ReadVarLenEx(tk, ok);
-
- if(ok)
- CurrentPosition.track[tk].delay = tkDelay;
- else
- {
- std::stringstream msg;
- msg << fr._fileName << ": invalid variable length in the track " << tk << "! (error code " << tkDelay << ")";
- ADLMIDI_ErrorString = msg.str();
- return false;
- }
+ //bool ok = false;
+ //// Read next event time
+ //uint64_t tkDelay = ReadVarLenEx(tk, ok);
+ //if(ok)
+ // CurrentPosition.track[tk].delay = tkDelay;
+ //else
+ //{
+ // std::stringstream msg;
+ // msg << fr._fileName << ": invalid variable length in the track " << tk << "! (error code " << tkDelay << ")";
+ // ADLMIDI_ErrorString = msg.str();
+ // return false;
+ //}
}
}
@@ -773,10 +791,14 @@ InvFmt:
return false;
}
- //Build new MIDI events table (WIP!!!)
- buildTrackData();
+ //Build new MIDI events table (ALPHA!!!)
+ if(!buildTrackData())
+ {
+ ADLMIDI_ErrorString = fr._fileName + ": MIDI data parsing error has occouped!";
+ return false;
+ }
- opl.Reset(); // Reset AdLib
+ opl.Reset(m_setup.PCM_RATE); // Reset AdLib
//opl.Reset(); // ...twice (just in case someone misprogrammed OPL3 previously)
ch.clear();
ch.resize(opl.NumChannels);
diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp
index 5caa15e..70be39c 100644
--- a/src/adlmidi_midiplay.cpp
+++ b/src/adlmidi_midiplay.cpp
@@ -185,9 +185,10 @@ void MIDIplay::MidiTrackPos::sortEvents()
events.insert(events.end(), anyOther.begin(), anyOther.end());
}
-void MIDIplay::buildTrackData()
+bool MIDIplay::buildTrackData()
{
fullSongTimeLength = 0.0;
+ musTitle.clear();
trackDataNew.clear();
trackDataNewStatus.clear();
const size_t trackCount = TrackData.size();
@@ -210,11 +211,18 @@ void MIDIplay::buildTrackData()
uint64_t abs_position = 0;
int status = 0;
MidiEvent event;
+ bool ok = false;
+ uint8_t *end = TrackData[tk].data() + TrackData[tk].size();
uint8_t *trackPtr = TrackData[tk].data();
//Time delay that follows the first event in the track
{
MidiTrackPos evtPos;
- evtPos.delay = ReadVarLen(&trackPtr);
+ evtPos.delay = ReadVarLenEx(&trackPtr, end, ok);
+ if(!ok)
+ {
+ //TODO: Implement file parsing error here
+ return false;
+ }
CurrentPositionNew.wait = evtPos.delay;
evtPos.absPos = abs_position;
abs_position += evtPos.delay;
@@ -233,7 +241,14 @@ void MIDIplay::buildTrackData()
}
if(event.subtype != MidiEvent::ST_ENDTRACK)//Don't try to read delta after EndOfTrack event!
- evtPos.delay = ReadVarLen(&trackPtr);
+ {
+ evtPos.delay = ReadVarLenEx(&trackPtr, end, ok);
+ if(!ok)
+ {
+ //TODO: Implement file parsing error here
+ return false;
+ }
+ }
if((evtPos.delay > 0) || (event.subtype == MidiEvent::ST_ENDTRACK))
{
@@ -283,16 +298,11 @@ void MIDIplay::buildTrackData()
// If tempo event is going between of current and previous event
if(tempos[tempo_change_index].absPosition <= pos.absPos)
{
- struct TempoMarker
- {
- uint64_t absPos;
- fraction<uint64_t> tempo;
- };
//Stop points: begin point and tempo change points are before end point
std::vector<TempoMarker> points;
fraction<uint64_t> t;
-
- points.push_back({posPrev->absPos, currentTempo});
+ TempoMarker firstPoint = {posPrev->absPos, currentTempo};
+ points.push_back(firstPoint);
//Collect tempo change points between previous and current events
do
@@ -359,13 +369,14 @@ void MIDIplay::buildTrackData()
}
fullSongTimeLength += postSongWaitDelay;
+
+ return true;
}
MIDIplay::MIDIplay():
cmf_percussion_mode(false),
fullSongTimeLength(0.0),
postSongWaitDelay(1.0),
- config(NULL),
trackStart(false),
atEnd(false),
loopStart(false),
@@ -375,6 +386,30 @@ MIDIplay::MIDIplay():
loopStart_hit(false)
{
devices.clear();
+
+ m_setup.AdlBank = 0;
+ m_setup.NumFourOps = 7;
+ m_setup.NumCards = 2;
+ m_setup.HighTremoloMode = false;
+ m_setup.HighVibratoMode = false;
+ m_setup.AdlPercussionMode = false;
+ m_setup.LogarithmicVolumes = false;
+ m_setup.SkipForward = 0;
+ m_setup.loopingIsEnabled = false;
+ m_setup.ScaleModulators = false;
+ m_setup.delay = 0.0;
+ m_setup.carry = 0.0;
+ m_setup.stored_samples = 0;
+ m_setup.backup_samples_size = 0;
+
+ opl.NumCards = m_setup.NumCards;
+ opl.AdlBank = m_setup.AdlBank;
+ opl.NumFourOps = m_setup.NumFourOps;
+ opl.LogarithmicVolumes = m_setup.LogarithmicVolumes;
+ opl.HighTremoloMode = m_setup.HighTremoloMode;
+ opl.HighVibratoMode = m_setup.HighVibratoMode;
+ opl.AdlPercussionMode = m_setup.AdlPercussionMode;
+ opl.ScaleModulators = m_setup.ScaleModulators;
}
uint64_t MIDIplay::ReadVarLen(uint8_t **ptr)
@@ -390,18 +425,18 @@ uint64_t MIDIplay::ReadVarLen(uint8_t **ptr)
return result;
}
-uint64_t MIDIplay::ReadVarLen(size_t tk)
-{
- uint64_t result = 0;
- for(;;)
- {
- uint8_t byte = TrackData[tk][CurrentPosition.track[tk].ptr++];
- result = (result << 7) + (byte & 0x7F);
- if(!(byte & 0x80))
- break;
- }
- return result;
-}
+//uint64_t MIDIplay::ReadVarLen(size_t tk)
+//{
+// uint64_t result = 0;
+// for(;;)
+// {
+// uint8_t byte = TrackData[tk][CurrentPosition.track[tk].ptr++];
+// result = (result << 7) + (byte & 0x7F);
+// if(!(byte & 0x80))
+// break;
+// }
+// return result;
+//}
double MIDIplay::Tick(double s, double granularity)
@@ -465,12 +500,19 @@ void MIDIplay::seek(double seconds)
{
if(seconds < 0.0)
return;//Seeking negative position is forbidden! :-P
- ADL_MIDIPlayer *device = opl._parent;
- const double granularity = device->mindelay,
- s = device->delay < device->maxdelay ? device->delay : device->maxdelay;
+ const double granularity = m_setup.mindelay,
+ s = m_setup.delay < m_setup.maxdelay ? m_setup.delay : m_setup.maxdelay;
- unsigned int loopFlagState = opl._parent->loopingIsEnabled;
- opl._parent->loopingIsEnabled = 0;
+ bool loopFlagState = m_setup.loopingIsEnabled;
+ m_setup.loopingIsEnabled = false;
+
+ /*
+ * Seeking search is similar to regular ticking, except of next things:
+ * - We don't processsing arpeggio and vibrato
+ * - To keep correctness of the state after seek, begin every search from begin
+ * - All sustaining notes must be killed
+ * - Ignore Note-On events
+ */
rewind();
while((CurrentPositionNew.absTimePosition < seconds) &&
@@ -492,18 +534,14 @@ void MIDIplay::seek(double seconds)
if(antiFreezeCounter <= 0)
CurrentPositionNew.wait += 1.0;/* Add extra 1 second when over 10000 events
with zero delay are been detected */
- for(uint16_t c = 0; c < opl.NumChannels; ++c)
- ch[c].AddAge(static_cast<int64_t>(s * 1000.0));
}
if(CurrentPositionNew.wait < 0.0)
CurrentPositionNew.wait = 0.0;
- device->loopingIsEnabled = loopFlagState;
- device->delay = CurrentPositionNew.wait;
- device->carry = 0.0;
- //UpdateVibrato(s);
- UpdateArpeggio(s);
+ m_setup.loopingIsEnabled = loopFlagState;
+ m_setup.delay = CurrentPositionNew.wait;
+ m_setup.carry = 0.0;
}
double MIDIplay::tell()
@@ -520,7 +558,7 @@ void MIDIplay::rewind()
{
Panic();
KillSustainingNotes(-1, -1);
- CurrentPosition = trackBeginPosition;
+ //CurrentPosition = trackBeginPosition;
CurrentPositionNew = trackBeginPositionNew;
trackStart = true;
atEnd = false;
@@ -738,10 +776,8 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity)
for(unsigned ccount = 0; ccount < 2; ++ccount)
{
int32_t c = adlchannel[ccount];
-
if(c < 0)
continue;
-
ir.first->second.phys[ static_cast<uint16_t>(adlchannel[ccount]) ] = i[ccount];
}
NoteUpdate(channel, ir.first, Upd_All | Upd_Patch);
@@ -1152,102 +1188,102 @@ void MIDIplay::NoteUpdate(uint16_t MidCh,
}
-bool MIDIplay::ProcessEvents()
-{
- if(TrackData.size() == 0)
- atEnd = true;//No MIDI track data to play
- if(atEnd)
- return false;//No more events in the queue
-
- loopEnd = false;
- const size_t TrackCount = TrackData.size();
- const Position RowBeginPosition(CurrentPosition);
-
- for(size_t tk = 0; tk < TrackCount; ++tk)
- {
- if(CurrentPosition.track[tk].status >= 0
- && CurrentPosition.track[tk].delay <= 0)
- {
- // Handle event
- HandleEvent(tk);
+//bool MIDIplay::ProcessEvents()
+//{
+// if(TrackData.size() == 0)
+// atEnd = true;//No MIDI track data to play
+// if(atEnd)
+// return false;//No more events in the queue
- // Read next event time (unless the track just ended)
- if(CurrentPosition.track[tk].ptr >= TrackData[tk].size())
- CurrentPosition.track[tk].status = -1;
+// loopEnd = false;
+// const size_t TrackCount = TrackData.size();
+// const Position RowBeginPosition(CurrentPosition);
- if(CurrentPosition.track[tk].status >= 0)
- CurrentPosition.track[tk].delay += ReadVarLen(tk);
- }
- }
+// for(size_t tk = 0; tk < TrackCount; ++tk)
+// {
+// if(CurrentPosition.track[tk].status >= 0
+// && CurrentPosition.track[tk].delay <= 0)
+// {
+// // Handle event
+// HandleEvent(tk);
+
+// // Read next event time (unless the track just ended)
+// if(CurrentPosition.track[tk].ptr >= TrackData[tk].size())
+// CurrentPosition.track[tk].status = -1;
+
+// if(CurrentPosition.track[tk].status >= 0)
+// CurrentPosition.track[tk].delay += ReadVarLen(tk);
+// }
+// }
- // Find shortest delay from all track
- uint64_t shortest = 0;
- bool shortest_no = true;
+// // Find shortest delay from all track
+// uint64_t shortest = 0;
+// bool shortest_no = true;
- for(size_t tk = 0; tk < TrackCount; ++tk)
- if((CurrentPosition.track[tk].status >= 0) && (shortest_no || CurrentPosition.track[tk].delay < shortest))
- {
- shortest = CurrentPosition.track[tk].delay;
- shortest_no = false;
- }
+// for(size_t tk = 0; tk < TrackCount; ++tk)
+// if((CurrentPosition.track[tk].status >= 0) && (shortest_no || CurrentPosition.track[tk].delay < shortest))
+// {
+// shortest = CurrentPosition.track[tk].delay;
+// shortest_no = false;
+// }
- //if(shortest > 0) UI.PrintLn("shortest: %ld", shortest);
+// //if(shortest > 0) UI.PrintLn("shortest: %ld", shortest);
- // Schedule the next playevent to be processed after that delay
- for(size_t tk = 0; tk < TrackCount; ++tk)
- CurrentPosition.track[tk].delay -= shortest;
+// // Schedule the next playevent to be processed after that delay
+// for(size_t tk = 0; tk < TrackCount; ++tk)
+// CurrentPosition.track[tk].delay -= shortest;
- fraction<uint64_t> t = shortest * Tempo;
+// fraction<uint64_t> t = shortest * Tempo;
- if(CurrentPosition.began)
- CurrentPosition.wait += t.valuel();
+// if(CurrentPosition.began)
+// CurrentPosition.wait += t.valuel();
- //if(shortest > 0) UI.PrintLn("Delay %ld (%g)", shortest, (double)t.valuel());
- /*
- if(CurrentPosition.track[0].ptr > 8119)
- loopEnd = true;
- // ^HACK: CHRONO TRIGGER LOOP
- */
+// //if(shortest > 0) UI.PrintLn("Delay %ld (%g)", shortest, (double)t.valuel());
+// /*
+// if(CurrentPosition.track[0].ptr > 8119)
+// loopEnd = true;
+// // ^HACK: CHRONO TRIGGER LOOP
+// */
- if(loopStart_hit && (loopStart || loopEnd)) //Avoid invalid loops
- {
- invalidLoop = true;
- loopStart = false;
- loopEnd = false;
- LoopBeginPosition = trackBeginPosition;
- }
- else
- loopStart_hit = false;
+// if(loopStart_hit && (loopStart || loopEnd)) //Avoid invalid loops
+// {
+// invalidLoop = true;
+// loopStart = false;
+// loopEnd = false;
+// LoopBeginPosition = trackBeginPosition;
+// }
+// else
+// loopStart_hit = false;
- if(loopStart)
- {
- if(trackStart)
- {
- trackBeginPosition = RowBeginPosition;
- trackStart = false;
- atEnd = false;
- }
- LoopBeginPosition = RowBeginPosition;
- loopStart = false;
- loopStart_hit = true;
- }
+// if(loopStart)
+// {
+// if(trackStart)
+// {
+// trackBeginPosition = RowBeginPosition;
+// trackStart = false;
+// atEnd = false;
+// }
+// LoopBeginPosition = RowBeginPosition;
+// loopStart = false;
+// loopStart_hit = true;
+// }
- if(shortest_no || loopEnd)
- {
- //Loop if song end or loop end point has reached
- loopEnd = false;
- shortest = 0;
- if(opl._parent->loopingIsEnabled == 0)
- {
- atEnd = true; //Don't handle events anymore
- CurrentPosition.wait += 1.0;//One second delay until stop playing
- return true;//We have caugh end here!
- }
- CurrentPosition = LoopBeginPosition;
- }
+// if(shortest_no || loopEnd)
+// {
+// //Loop if song end or loop end point has reached
+// loopEnd = false;
+// shortest = 0;
+// if(!m_setup.loopingIsEnabled)
+// {
+// atEnd = true; //Don't handle events anymore
+// CurrentPosition.wait += 1.0;//One second delay until stop playing
+// return true;//We have caugh end here!
+// }
+// CurrentPosition = LoopBeginPosition;
+// }
- return true;//Has events in queue
-}
+// return true;//Has events in queue
+//}
bool MIDIplay::ProcessEventsNew(bool isSeek)
{
@@ -1363,7 +1399,7 @@ bool MIDIplay::ProcessEventsNew(bool isSeek)
//Loop if song end or loop end point has reached
loopEnd = false;
shortest = 0;
- if(opl._parent->loopingIsEnabled == 0)
+ if(!m_setup.loopingIsEnabled)
{
atEnd = true; //Don't handle events anymore
CurrentPositionNew.wait += postSongWaitDelay;//One second delay until stop playing
@@ -1404,6 +1440,9 @@ MIDIplay::MidiEvent MIDIplay::parseEvent(uint8_t**pptr, int &status)
* by external functions (to display song title and copyright in the player) */
if(evt.subtype == MidiEvent::ST_COPYRIGHT)
{
+ //TODO: Implement own field for this
+ //TODO: Implement API call to retreive this
+ //TODO: Implement a hook to catch this
std::string str((const char*)evt.data.data(), evt.data.size());
std::fprintf(stdout, "Copyright: %s\n", str.c_str());
std::fflush(stdout);
@@ -1411,13 +1450,15 @@ MIDIplay::MidiEvent MIDIplay::parseEvent(uint8_t**pptr, int &status)
else
if(evt.subtype == MidiEvent::ST_SQTRKTITLE)
{
- std::string str((const char*)evt.data.data(), evt.data.size());
- std::fprintf(stdout, "Sequence/Track title: %s\n", str.c_str());
- std::fflush(stdout);
+ //TODO: Implement API call to retreive this
+ //TODO: Implement a hook to catch this
+ if(musTitle.empty())
+ musTitle = std::string((const char*)evt.data.data(), evt.data.size());
}
else
if(evt.subtype == MidiEvent::ST_INSTRTITLE)
{
+ //TODO: Implement a hook to catch this
std::string str((const char*)evt.data.data(), evt.data.size());
std::fprintf(stdout, "Instrument: %s\n", str.c_str());
std::fflush(stdout);
@@ -1475,179 +1516,179 @@ MIDIplay::MidiEvent MIDIplay::parseEvent(uint8_t**pptr, int &status)
return evt;
}
-void MIDIplay::HandleEvent(size_t tk)
-{
- unsigned char byte = TrackData[tk][CurrentPosition.track[tk].ptr++];
-
- if(byte == 0xF7 || byte == 0xF0) // Ignore SysEx
- {
- uint64_t length = ReadVarLen(tk);
- //std::string data( length?(const char*) &TrackData[tk][CurrentPosition.track[tk].ptr]:0, length );
- CurrentPosition.track[tk].ptr += (size_t)length;
- //UI.PrintLn("SysEx %02X: %u bytes", byte, length/*, data.c_str()*/);
- return;
- }
-
- if(byte == 0xFF)
- {
- // Special event FF
- uint8_t evtype = TrackData[tk][CurrentPosition.track[tk].ptr++];
- uint64_t length = ReadVarLen(tk);
- std::string data(length ? (const char *) &TrackData[tk][CurrentPosition.track[tk].ptr] : 0, (size_t)length);
- CurrentPosition.track[tk].ptr += (size_t)length;
-
- if(evtype == 0x2F)//End Of Track
- {
- CurrentPosition.track[tk].status = -1;
- return;
- }
-
- if(evtype == 0x51)//Tempo change
- {
- Tempo = InvDeltaTicks * fraction<uint64_t>(ReadBEint(data.data(), data.size()));
- return;
- }
-
- if(evtype == 6)//Meta event
- {
- //Turn on/off Loop handling when loop is disabled
- if(opl._parent->loopingIsEnabled != 0)
- {
- /* Move this away from events handler */
- for(size_t i = 0; i < data.size(); i++)
- {
- if(data[i] <= 'Z' && data[i] >= 'A')
- data[i] = data[i] - ('Z' - 'z');
- }
-
- if((data == "loopstart") && (!invalidLoop))
- {
- loopStart = true;
- loopStart_passed = true;
- }
-
- if((data == "loopend") && (!invalidLoop))
- {
- if((loopStart_passed) && (!loopStart))
- loopEnd = true;
- else
- invalidLoop = true;
- }
- }
- }
-
- if(evtype == 9)
- current_device[tk] = ChooseDevice(data);
-
- //if(evtype >= 1 && evtype <= 6)
- // UI.PrintLn("Meta %d: %s", evtype, data.c_str());
-
- if(evtype == 0xE3) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib
- {
- uint8_t i = static_cast<uint8_t>(data[0]), v = static_cast<uint8_t>(data[1]);
-
- if((i & 0xF0) == 0xC0)
- v |= 0x30;
+//void MIDIplay::HandleEvent(size_t tk)
+//{
+// unsigned char byte = TrackData[tk][CurrentPosition.track[tk].ptr++];
- //std::printf("OPL poke %02X, %02X\n", i, v);
- //std::fflush(stdout);
- opl.PokeN(0, i, v);
- }
+// if(byte == 0xF7 || byte == 0xF0) // Ignore SysEx
+// {
+// uint64_t length = ReadVarLen(tk);
+// //std::string data( length?(const char*) &TrackData[tk][CurrentPosition.track[tk].ptr]:0, length );
+// CurrentPosition.track[tk].ptr += (size_t)length;
+// //UI.PrintLn("SysEx %02X: %u bytes", byte, length/*, data.c_str()*/);
+// return;
+// }
- return;
- }
+// if(byte == 0xFF)
+// {
+// // Special event FF
+// uint8_t evtype = TrackData[tk][CurrentPosition.track[tk].ptr++];
+// uint64_t length = ReadVarLen(tk);
+// std::string data(length ? (const char *) &TrackData[tk][CurrentPosition.track[tk].ptr] : 0, (size_t)length);
+// CurrentPosition.track[tk].ptr += (size_t)length;
+
+// if(evtype == 0x2F)//End Of Track
+// {
+// CurrentPosition.track[tk].status = -1;
+// return;
+// }
+
+// if(evtype == 0x51)//Tempo change
+// {
+// Tempo = InvDeltaTicks * fraction<uint64_t>(ReadBEint(data.data(), data.size()));
+// return;
+// }
+
+// if(evtype == 6)//Meta event
+// {
+// //Turn on/off Loop handling when loop is disabled
+// if(m_setup.loopingIsEnabled)
+// {
+// /* Move this away from events handler */
+// for(size_t i = 0; i < data.size(); i++)
+// {
+// if(data[i] <= 'Z' && data[i] >= 'A')
+// data[i] = data[i] - ('Z' - 'z');
+// }
+
+// if((data == "loopstart") && (!invalidLoop))
+// {
+// loopStart = true;
+// loopStart_passed = true;
+// }
+
+// if((data == "loopend") && (!invalidLoop))
+// {
+// if((loopStart_passed) && (!loopStart))
+// loopEnd = true;
+// else
+// invalidLoop = true;
+// }
+// }
+// }
+
+// if(evtype == 9)
+// current_device[tk] = ChooseDevice(data);
+
+// //if(evtype >= 1 && evtype <= 6)
+// // UI.PrintLn("Meta %d: %s", evtype, data.c_str());
+
+// if(evtype == 0xE3) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib
+// {
+// uint8_t i = static_cast<uint8_t>(data[0]), v = static_cast<uint8_t>(data[1]);
+
+// if((i & 0xF0) == 0xC0)
+// v |= 0x30;
+
+// //std::printf("OPL poke %02X, %02X\n", i, v);
+// //std::fflush(stdout);
+// opl.PokeN(0, i, v);
+// }
+
+// return;
+// }
- // Any normal event (80..EF)
- if(byte < 0x80)
- {
- byte = static_cast<uint8_t>(CurrentPosition.track[tk].status | 0x80);
- CurrentPosition.track[tk].ptr--;
- }
+// // Any normal event (80..EF)
+// if(byte < 0x80)
+// {
+// byte = static_cast<uint8_t>(CurrentPosition.track[tk].status | 0x80);
+// CurrentPosition.track[tk].ptr--;
+// }
- if(byte == 0xF3)
- {
- CurrentPosition.track[tk].ptr += 1;
- return;
- }
+// if(byte == 0xF3)
+// {
+// CurrentPosition.track[tk].ptr += 1;
+// return;
+// }
- if(byte == 0xF2)
- {
- CurrentPosition.track[tk].ptr += 2;
- return;
- }
+// if(byte == 0xF2)
+// {
+// CurrentPosition.track[tk].ptr += 2;
+// return;
+// }
- /*UI.PrintLn("@%X Track %u: %02X %02X",
- CurrentPosition.track[tk].ptr-1, (unsigned)tk, byte,
- TrackData[tk][CurrentPosition.track[tk].ptr]);*/
- uint8_t MidCh = byte & 0x0F, EvType = byte >> 4;
- MidCh += (uint8_t)current_device[tk];
- CurrentPosition.track[tk].status = byte;
+// /*UI.PrintLn("@%X Track %u: %02X %02X",
+// CurrentPosition.track[tk].ptr-1, (unsigned)tk, byte,
+// TrackData[tk][CurrentPosition.track[tk].ptr]);*/
+// uint8_t MidCh = byte & 0x0F, EvType = byte >> 4;
+// MidCh += (uint8_t)current_device[tk];
+// CurrentPosition.track[tk].status = byte;
- switch(EvType)
- {
- case 0x8: // Note off
- {
- uint8_t note = TrackData[tk][CurrentPosition.track[tk].ptr++];
- /*uint8_t vol=*/TrackData[tk][CurrentPosition.track[tk].ptr++];
- //if(MidCh != 9) note -= 12; // HACK
- realTime_NoteOff(MidCh, note);
- break;
- }
- case 0x9: // Note on
- {
- uint8_t note = TrackData[tk][CurrentPosition.track[tk].ptr++];
- uint8_t vol = TrackData[tk][CurrentPosition.track[tk].ptr++];
- //if(MidCh != 9) note -= 12; // HACK
- if(realTime_NoteOn(MidCh, note, vol))
- CurrentPosition.began = true;
- break;
- }
+// switch(EvType)
+// {
+// case 0x8: // Note off
+// {
+// uint8_t note = TrackData[tk][CurrentPosition.track[tk].ptr++];
+// /*uint8_t vol=*/TrackData[tk][CurrentPosition.track[tk].ptr++];
+// //if(MidCh != 9) note -= 12; // HACK
+// realTime_NoteOff(MidCh, note);
+// break;
+// }
+// case 0x9: // Note on
+// {
+// uint8_t note = TrackData[tk][CurrentPosition.track[tk].ptr++];
+// uint8_t vol = TrackData[tk][CurrentPosition.track[tk].ptr++];
+// //if(MidCh != 9) note -= 12; // HACK
+// if(realTime_NoteOn(MidCh, note, vol))
+// CurrentPosition.began = true;
+// break;
+// }
- case 0xA: // Note touch
- {
- uint8_t note = TrackData[tk][CurrentPosition.track[tk].ptr++];
- uint8_t vol = TrackData[tk][CurrentPosition.track[tk].ptr++];
- realTime_NoteAfterTouch(MidCh, note, vol);
- break;
- }
+// case 0xA: // Note touch
+// {
+// uint8_t note = TrackData[tk][CurrentPosition.track[tk].ptr++];
+// uint8_t vol = TrackData[tk][CurrentPosition.track[tk].ptr++];
+// realTime_NoteAfterTouch(MidCh, note, vol);
+// break;
+// }
- case 0xB: // Controller change
- {
- uint8_t ctrlno = TrackData[tk][CurrentPosition.track[tk].ptr++];
- uint8_t value = TrackData[tk][CurrentPosition.track[tk].ptr++];
+// case 0xB: // Controller change
+// {
+// uint8_t ctrlno = TrackData[tk][CurrentPosition.track[tk].ptr++];
+// uint8_t value = TrackData[tk][CurrentPosition.track[tk].ptr++];
- if((opl._parent->loopingIsEnabled != 0) && (ctrlno == 111) && !invalidLoop)
- {
- loopStart = true;
- loopStart_passed = true;
- break;
- }
+// if((m_setup.loopingIsEnabled) && (ctrlno == 111) && !invalidLoop)
+// {
+// loopStart = true;
+// loopStart_passed = true;
+// break;
+// }
- realTime_Controller(MidCh, ctrlno, value);
- break;
- }
+// realTime_Controller(MidCh, ctrlno, value);
+// break;
+// }
- case 0xC: // Patch change
- realTime_PatchChange(MidCh, TrackData[tk][CurrentPosition.track[tk].ptr++]);
- break;
+// case 0xC: // Patch change
+// realTime_PatchChange(MidCh, TrackData[tk][CurrentPosition.track[tk].ptr++]);
+// break;
- case 0xD: // Channel after-touch
- {
- // TODO: Verify, is this correct action?
- uint8_t vol = TrackData[tk][CurrentPosition.track[tk].ptr++];
- realTime_ChannelAfterTouch(MidCh, vol);
- break;
- }
+// case 0xD: // Channel after-touch
+// {
+// // TODO: Verify, is this correct action?
+// uint8_t vol = TrackData[tk][CurrentPosition.track[tk].ptr++];
+// realTime_ChannelAfterTouch(MidCh, vol);
+// break;
+// }
- case 0xE: // Wheel/pitch bend
- {
- uint8_t a = TrackData[tk][CurrentPosition.track[tk].ptr++];
- uint8_t b = TrackData[tk][CurrentPosition.track[tk].ptr++];
- realTime_PitchBend(MidCh, b, a);
- break;
- }
- }
-}
+// case 0xE: // Wheel/pitch bend
+// {
+// uint8_t a = TrackData[tk][CurrentPosition.track[tk].ptr++];
+// uint8_t b = TrackData[tk][CurrentPosition.track[tk].ptr++];
+// realTime_PitchBend(MidCh, b, a);
+// break;
+// }
+// }
+//}
void MIDIplay::HandleEvent(size_t tk, MIDIplay::MidiEvent &evt, int &status)
{
@@ -1680,7 +1721,7 @@ void MIDIplay::HandleEvent(size_t tk, MIDIplay::MidiEvent &evt, int &status)
if(evtype == MidiEvent::ST_MARKER)//Meta event
{
//Turn on/off Loop handling when loop is disabled
- if(opl._parent->loopingIsEnabled != 0)
+ if(m_setup.loopingIsEnabled)
{
/* Move this away from events handler */
for(size_t i = 0; i < data.size(); i++)
@@ -1775,8 +1816,8 @@ void MIDIplay::HandleEvent(size_t tk, MIDIplay::MidiEvent &evt, int &status)
{
uint8_t note = evt.data[0];
uint8_t vol = evt.data[1];
- if(realTime_NoteOn(midCh, note, vol))
- CurrentPosition.began = true;
+ /*if(*/ realTime_NoteOn(midCh, note, vol); /*)*/
+ //CurrentPosition.began = true;
break;
}
@@ -1793,7 +1834,7 @@ void MIDIplay::HandleEvent(size_t tk, MIDIplay::MidiEvent &evt, int &status)
uint8_t ctrlno = evt.data[0];
uint8_t value = evt.data[1];
- if((opl._parent->loopingIsEnabled != 0) && (ctrlno == 111) && !invalidLoop)
+ if((m_setup.loopingIsEnabled) && (ctrlno == 111) && !invalidLoop)
{
loopStart = true;
loopStart_passed = true;
@@ -2017,7 +2058,7 @@ void MIDIplay::KillOrEvacuate(size_t from_channel, AdlChannel::users_t::iterator
void MIDIplay::Panic()
{
- for(size_t chan = 0; chan < Ch.size(); chan++)
+ for(uint8_t chan = 0; chan < Ch.size(); chan++)
{
for(uint8_t note = 0; note < 128; note++)
realTime_NoteOff(chan, note);
diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp
index 316c8e1..4878233 100644
--- a/src/adlmidi_opl3.cpp
+++ b/src/adlmidi_opl3.cpp
@@ -406,7 +406,7 @@ void OPL3::ChangeVolumeRangesModel(ADLMIDI_VolumeModels volumeModel)
}
}
-void OPL3::Reset()
+void OPL3::Reset(unsigned long PCM_RATE)
{
#ifdef ADLMIDI_USE_DOSBOX_OPL
DBOPL::Handler emptyChip; //Constructors inside are will initialize necessary fields
@@ -445,9 +445,9 @@ void OPL3::Reset()
for(unsigned card = 0; card < NumCards; ++card)
{
#ifdef ADLMIDI_USE_DOSBOX_OPL
- cards[card].Init(_parent->PCM_RATE);
+ cards[card].Init(PCM_RATE);
#else
- OPL3_Reset(&cards[card], static_cast<Bit32u>(_parent->PCM_RATE));
+ OPL3_Reset(&cards[card], static_cast<Bit32u>(PCM_RATE));
#endif
for(unsigned a = 0; a < 18; ++a) Poke(card, 0xB0 + Channels[a], 0x00);
diff --git a/src/adlmidi_private.cpp b/src/adlmidi_private.cpp
index c888b18..04bb481 100644
--- a/src/adlmidi_private.cpp
+++ b/src/adlmidi_private.cpp
@@ -47,7 +47,7 @@ int adlRefreshNumCards(ADL_MIDIPlayer *device)
//For embedded bank
for(unsigned a = 0; a < 256; ++a)
{
- unsigned insno = banks[device->AdlBank][a];
+ unsigned insno = banks[play->m_setup.AdlBank][a];
if(insno == 198)
continue;
++n_total[a / 128];
@@ -57,13 +57,13 @@ int adlRefreshNumCards(ADL_MIDIPlayer *device)
}
}
- device->NumFourOps =
- (n_fourop[0] >= n_total[0] * 7 / 8) ? device->NumCards * 6
- : (n_fourop[0] < n_total[0] * 1 / 8) ? 0
- : (device->NumCards == 1 ? 1 : device->NumCards * 4);
- play->opl.NumFourOps = device->NumFourOps;
+ play->m_setup.NumFourOps =
+ (n_fourop[0] >= n_total[0] * 7 / 8) ? play->m_setup.NumCards * 6
+ : (n_fourop[0] < n_total[0] * 1 / 8) ? 0
+ : (play->m_setup.NumCards == 1 ? 1 : play->m_setup.NumCards * 4);
+ play->opl.NumFourOps = play->m_setup.NumFourOps;
- if(n_fourop[0] >= n_total[0] * 15 / 16 && device->NumFourOps == 0)
+ if(n_fourop[0] >= n_total[0] * 15 / 16 && play->m_setup.NumFourOps == 0)
{
ADLMIDI_ErrorString = "ERROR: You have selected a bank that consists almost exclusively of four-op patches.\n"
" The results (silence + much cpu load) would be probably\n"
diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp
index 451a8e6..d964e1e 100644
--- a/src/adlmidi_private.hpp
+++ b/src/adlmidi_private.hpp
@@ -156,7 +156,7 @@ public:
VOLUME_CMF,
VOLUME_DMX,
VOLUME_APOGEE,
- VOLUME_9X,
+ VOLUME_9X
} m_volumeScale;
OPL3();
@@ -181,30 +181,30 @@ public:
void Silence();
void updateFlags();
void ChangeVolumeRangesModel(ADLMIDI_VolumeModels volumeModel);
- void Reset();
+ void Reset(unsigned long PCM_RATE);
};
class MIDIplay
{
// Information about each track
- struct Position
- {
- bool began;
- char padding[7];
- double wait;
- struct TrackInfo
- {
- size_t ptr;
- uint64_t delay;
- int status;
- char padding2[4];
- TrackInfo(): ptr(0), delay(0), status(0) {}
- };
- std::vector<TrackInfo> track;
-
- Position(): began(false), wait(0.0l), track() { }
- } CurrentPosition, LoopBeginPosition, trackBeginPosition;
+ //struct Position
+ //{
+ // bool began;
+ // char padding[7];
+ // double wait;
+ // struct TrackInfo
+ // {
+ // size_t ptr;
+ // uint64_t delay;
+ // int status;
+ // char padding2[4];
+ // TrackInfo(): ptr(0), delay(0), status(0) {}
+ // };
+ // std::vector<TrackInfo> track;
+
+ // Position(): began(false), wait(0.0l), track() { }
+ //} CurrentPosition, LoopBeginPosition, trackBeginPosition;
std::map<std::string, uint64_t> devices;
std::map<uint64_t /*track*/, uint64_t /*channel begin index*/> current_device;
@@ -323,7 +323,7 @@ private:
T_SYSCOMSPOSPTR = 0xF2,//size == 2
T_SYSCOMSNGSEL = 0xF3,//size == 1
T_SYSEX2 = 0xF7,//size == len
- T_SPECIAL = 0xFF,
+ T_SPECIAL = 0xFF
};
enum SubTypes
{
@@ -348,7 +348,7 @@ private:
/* Non-standard, internal ADLMIDI usage only */
ST_LOOPSTART = 0xE1,//size == 0 <CUSTOM>
ST_LOOPEND = 0xE2,//size == 0 <CUSTOM>
- ST_RAWOPL = 0xE3,//size == 0 <CUSTOM>
+ ST_RAWOPL = 0xE3//size == 0 <CUSTOM>
};
//! Main type of event
uint8_t type;
@@ -390,6 +390,15 @@ private:
void sortEvents();
};
+ /**
+ * @brief Tempo maker entry. Used in the MIDI data building function only.
+ */
+ struct TempoMarker
+ {
+ uint64_t absPos;
+ fraction<uint64_t> tempo;
+ };
+
typedef std::list<MidiTrackPos> MidiTrackQueue;
// Information about each track
@@ -420,7 +429,7 @@ private:
std::vector<MidiTrackQueue > trackDataNew;
std::vector<int> trackDataNewStatus;
- void buildTrackData();
+ bool buildTrackData();
MidiEvent parseEvent(uint8_t **ptr, int &status);
public:
@@ -428,7 +437,6 @@ public:
~MIDIplay()
{}
- ADL_MIDIPlayer *config;
std::string musTitle;
fraction<uint64_t> InvDeltaTicks, Tempo;
bool trackStart,
@@ -440,13 +448,46 @@ public:
loopStart_hit /*loopStart entry was hited in previous tick*/;
char ____padding2[2];
OPL3 opl;
+
+ struct Setup
+ {
+ unsigned int AdlBank;
+ unsigned int NumFourOps;
+ unsigned int NumCards;
+ bool HighTremoloMode;
+ bool HighVibratoMode;
+ bool AdlPercussionMode;
+ bool LogarithmicVolumes;
+ int VolumeModel;
+ unsigned int SkipForward;
+ bool loopingIsEnabled;
+ bool ScaleModulators;
+
+ double delay;
+ double carry;
+
+ /* The lag between visual content and audio content equals */
+ /* the sum of these two buffers. */
+ double mindelay;
+ double maxdelay;
+
+ /* For internal usage */
+ ssize_t stored_samples; /* num of collected samples */
+ short backup_samples[1024]; /* Backup sample storage. */
+ ssize_t backup_samples_size; /* Backup sample storage. */
+ /* For internal usage */
+
+ unsigned long PCM_RATE;
+ } m_setup;
+
public:
static uint64_t ReadBEint(const void *buffer, size_t nbytes);
static uint64_t ReadLEint(const void *buffer, size_t nbytes);
uint64_t ReadVarLen(uint8_t **ptr);
- uint64_t ReadVarLen(size_t tk);
- uint64_t ReadVarLenEx(size_t tk, bool &ok);
+ //uint64_t ReadVarLen(size_t tk);
+ //uint64_t ReadVarLenEx(size_t tk, bool &ok);
+ uint64_t ReadVarLenEx(uint8_t **ptr, uint8_t *end, bool &ok);
/*
* A little class gives able to read filedata from disk and also from a memory segment
diff --git a/src/dbopl.h b/src/dbopl.h
index bbe40de..54384da 100644
--- a/src/dbopl.h
+++ b/src/dbopl.h
@@ -84,14 +84,14 @@ namespace DBOPL
sm3AMAM,
sm6Start,
sm2Percussion,
- sm3Percussion,
+ sm3Percussion
} SynthMode;
//Shifts for the values contained in chandata variable
enum
{
SHIFT_KSLBASE = 16,
- SHIFT_KEYCODE = 24,
+ SHIFT_KEYCODE = 24
};
struct Operator
@@ -103,7 +103,7 @@ namespace DBOPL
MASK_KSR = 0x10,
MASK_SUSTAIN = 0x20,
MASK_VIBRATO = 0x40,
- MASK_TREMOLO = 0x80,
+ MASK_TREMOLO = 0x80
};
typedef enum
@@ -112,7 +112,7 @@ namespace DBOPL
RELEASE,
SUSTAIN,
DECAY,
- ATTACK,
+ ATTACK
} State;
VolumeHandler volHandler;