diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/adlmidi.cpp | 211 | ||||
-rw-r--r-- | src/adlmidi_load.cpp | 118 | ||||
-rw-r--r-- | src/adlmidi_midiplay.cpp | 619 | ||||
-rw-r--r-- | src/adlmidi_opl3.cpp | 6 | ||||
-rw-r--r-- | src/adlmidi_private.cpp | 14 | ||||
-rw-r--r-- | src/adlmidi_private.hpp | 91 | ||||
-rw-r--r-- | src/dbopl.h | 8 |
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; |