ADLMIDI_EXPORT int adl_loadEmbeddedBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank, int num) { if(!device) return -1; #ifdef DISABLE_EMBEDDED_BANKS ADL_UNUSED(bank); ADL_UNUSED(num); MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); play->setErrorString("This build of libADLMIDI has no embedded banks. " "Please load banks by using adl_openBankFile() or " "adl_openBankData() functions instead of adl_loadEmbeddedBank()."); return -1; #else if(num < 0 || num >= maxAdlBanks()) return -1; OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); size_t id = it->first; for (unsigned i = 0; i < 128; ++i) { size_t insno = i + ((id & OPL3::PercussionTag) ? 128 : 0); size_t adlmeta = ::banks[num][insno]; it->second.ins[i] = adlinsdata2::from_adldata(::adlins[adlmeta]); } return 0; #endif }
ADLMIDI_EXPORT int adl_openData(ADL_MIDIPlayer *device, const void *mem, unsigned long size) { if(device) { MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER play->m_setup.tick_skip_samples_delay = 0; if(!play->LoadMIDI(mem, static_cast<size_t>(size))) { std::string err = play->getErrorString(); if(err.empty()) play->setErrorString("ADL MIDI: Can't load data from memory"); return -1; } else return 0; #else ADL_UNUSED(mem); ADL_UNUSED(size); play->setErrorString("ADLMIDI: MIDI Sequencer is not supported in this build of library!"); return -1; #endif //ADLMIDI_DISABLE_MIDI_SEQUENCER } ADLMIDI_ErrorString = "Can't load file: ADL MIDI is not initialized"; return -1; }
ADLMIDI_EXPORT void adl_setTempo(struct ADL_MIDIPlayer *device, double tempo) { #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device || (tempo <= 0.0)) return; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); play->m_sequencer.setTempo(tempo); #else ADL_UNUSED(device); ADL_UNUSED(tempo); #endif }
ADLMIDI_EXPORT double adl_tickEvents(struct ADL_MIDIPlayer *device, double seconds, double granulality) { #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return -1.0; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); return play->Tick(seconds, granulality); #else ADL_UNUSED(device); ADL_UNUSED(seconds); ADL_UNUSED(granulality); return -1.0; #endif }
ADLMIDI_EXPORT void adl_setRawEventHook(struct ADL_MIDIPlayer *device, ADL_RawEventHook rawEventHook, void *userData) { #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); play->m_sequencerInterface.onEvent = rawEventHook; play->m_sequencerInterface.onEvent_userData = userData; #else ADL_UNUSED(device); ADL_UNUSED(rawEventHook); ADL_UNUSED(userData); #endif }
ADLMIDI_EXPORT int adl_setBank(ADL_MIDIPlayer *device, int bank) { #ifdef DISABLE_EMBEDDED_BANKS ADL_UNUSED(bank); MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); play->setErrorString("This build of libADLMIDI has no embedded banks. " "Please load banks by using adl_openBankFile() or " "adl_openBankData() functions instead of adl_setBank()."); return -1; #else const uint32_t NumBanks = static_cast<uint32_t>(maxAdlBanks()); int32_t bankno = bank; if(bankno < 0) bankno = 0; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); if(static_cast<uint32_t>(bankno) >= NumBanks) { char errBuf[150]; snprintf(errBuf, 150, "Embedded bank number may only be 0..%u!\n", static_cast<unsigned int>(NumBanks - 1)); play->setErrorString(errBuf); return -1; } play->m_setup.bankId = static_cast<uint32_t>(bankno); play->m_synth.setEmbeddedBank(play->m_setup.bankId); play->applySetup(); return adlRefreshNumCards(device); #endif }
ADLMIDI_EXPORT int adl_openFile(ADL_MIDIPlayer *device, const char *filePath) { if(device) { MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER play->m_setup.tick_skip_samples_delay = 0; if(!play->LoadMIDI(filePath)) { std::string err = play->getErrorString(); if(err.empty()) play->setErrorString("ADL MIDI: Can't load file"); return -1; } else return 0; #else ADL_UNUSED(filePath); play->setErrorString("ADLMIDI: MIDI Sequencer is not supported in this build of library!"); return -1; #endif //ADLMIDI_DISABLE_MIDI_SEQUENCER } ADLMIDI_ErrorString = "Can't load file: ADL MIDI is not initialized"; return -1; }
ADLMIDI_EXPORT const char *adl_metaTrackTitle(struct ADL_MIDIPlayer *device, size_t index) { #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return ""; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); const std::vector<std::string> &titles = play->m_sequencer.getTrackTitles(); if(index >= titles.size()) return "INVALID"; return titles[index].c_str(); #else ADL_UNUSED(device); ADL_UNUSED(index); return "NOT SUPPORTED"; #endif }
ADLMIDI_EXPORT void adl_positionSeek(struct ADL_MIDIPlayer *device, double seconds) { #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(seconds < 0.0) return;//Seeking negative position is forbidden! :-P if(!device) return; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); play->realTime_panic(); play->m_setup.delay = play->m_sequencer.seek(seconds, play->m_setup.mindelay); play->m_setup.carry = 0.0; #else ADL_UNUSED(device); ADL_UNUSED(seconds); #endif }
ADLMIDI_EXPORT int adl_setTriggerHandler(struct ADL_MIDIPlayer *device, ADL_TriggerHandler handler, void *userData) { #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return -1; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); MidiSequencer &seq = play->m_sequencer; seq.setTriggerHandler(handler, userData); return 0; #else ADL_UNUSED(device); ADL_UNUSED(handler); ADL_UNUSED(userData); return -1; #endif }
ADLMIDI_EXPORT void adl_setLoopEnabled(ADL_MIDIPlayer *device, int loopEn) { if(!device) return; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER play->m_sequencer.setLoopEnabled(loopEn != 0); #else ADL_UNUSED(loopEn); #endif }
ADLMIDI_EXPORT int adl_setTrackOptions(struct ADL_MIDIPlayer *device, size_t trackNumber, unsigned trackOptions) { #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return -1; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); MidiSequencer &seq = play->m_sequencer; unsigned enableFlag = trackOptions & 3; trackOptions &= ~3u; // handle on/off/solo switch(enableFlag) { default: break; case ADLMIDI_TrackOption_On: case ADLMIDI_TrackOption_Off: if(!seq.setTrackEnabled(trackNumber, enableFlag == ADLMIDI_TrackOption_On)) return -1; break; case ADLMIDI_TrackOption_Solo: seq.setSoloTrack(trackNumber); break; } // handle others... if(trackOptions != 0) return -1; return 0; #else ADL_UNUSED(device); ADL_UNUSED(trackNumber); ADL_UNUSED(trackOptions); return -1; #endif }
ADLMIDI_EXPORT double adl_positionTell(struct ADL_MIDIPlayer *device) { #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return -1.0; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); return play->m_sequencer.tell(); #else ADL_UNUSED(device); return -1.0; #endif }
ADLMIDI_EXPORT size_t adl_metaMarkerCount(struct ADL_MIDIPlayer *device) { #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return 0; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); return play->m_sequencer.getMarkers().size(); #else ADL_UNUSED(device); return 0; #endif }
ADLMIDI_EXPORT const char *adl_metaMusicCopyright(struct ADL_MIDIPlayer *device) { #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return ""; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); return play->m_sequencer.getMusicCopyright().c_str(); #else ADL_UNUSED(device); return ""; #endif }
ADLMIDI_EXPORT void adl_positionRewind(struct ADL_MIDIPlayer *device) { #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); play->realTime_panic(); play->m_sequencer.rewind(); #else ADL_UNUSED(device); #endif }
ADLMIDI_EXPORT int adl_atEnd(struct ADL_MIDIPlayer *device) { #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return 1; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); return (int)play->m_sequencer.positionAtEnd(); #else ADL_UNUSED(device); return 1; #endif }
ADLMIDI_EXPORT Adl_MarkerEntry adl_metaMarker(struct ADL_MIDIPlayer *device, size_t index) { struct Adl_MarkerEntry marker; #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) { marker.label = "INVALID"; marker.pos_time = 0.0; marker.pos_ticks = 0; return marker; } MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); const std::vector<MidiSequencer::MIDI_MarkerEntry> &markers = play->m_sequencer.getMarkers(); if(index >= markers.size()) { marker.label = "INVALID"; marker.pos_time = 0.0; marker.pos_ticks = 0; return marker; } const MidiSequencer::MIDI_MarkerEntry &mk = markers[index]; marker.label = mk.label.c_str(); marker.pos_time = mk.pos_time; marker.pos_ticks = (unsigned long)mk.pos_ticks; #else ADL_UNUSED(device); ADL_UNUSED(index); marker.label = "NOT SUPPORTED"; marker.pos_time = 0.0; marker.pos_ticks = 0; #endif return marker; }
ADLMIDI_EXPORT int adl_setNumChips(ADL_MIDIPlayer *device, int numChips) { if(device == NULL) return -2; MidiPlayer *play = GET_MIDI_PLAYER(device); assert(play); #ifdef ADLMIDI_HW_OPL ADL_UNUSED(numChips); play->m_setup.numChips = 1; #else play->m_setup.numChips = static_cast<unsigned int>(numChips); #endif if(play->m_setup.numChips < 1 || play->m_setup.numChips > MaxChips) { play->setErrorString("number of chips may only be 1.." MaxChips_STR ".\n"); return -1; } play->m_synth.m_numChips = play->m_setup.numChips; play->partialReset(); return adlRefreshNumCards(device); }
ADLMIDI_EXPORT int adl_generateFormat(struct ADL_MIDIPlayer *device, int sampleCount, ADL_UInt8 *out_left, ADL_UInt8 *out_right, const ADLMIDI_AudioFormat *format) { #ifdef ADLMIDI_HW_OPL ADL_UNUSED(device); ADL_UNUSED(sampleCount); ADL_UNUSED(out_left); ADL_UNUSED(out_right); ADL_UNUSED(format); return 0; #else sampleCount -= sampleCount % 2; //Avoid even sample requests if(sampleCount < 0) return 0; if(!device) return 0; MidiPlayer *player = GET_MIDI_PLAYER(device); assert(player); MidiPlayer::Setup &setup = player->m_setup; ssize_t gotten_len = 0; ssize_t n_periodCountStereo = 512; int left = sampleCount; double delay = double(sampleCount) / double(setup.PCM_RATE); while(left > 0) { {//... const double eat_delay = delay < setup.maxdelay ? delay : setup.maxdelay; delay -= eat_delay; setup.carry += double(setup.PCM_RATE) * eat_delay; n_periodCountStereo = static_cast<ssize_t>(setup.carry); setup.carry -= double(n_periodCountStereo); { ssize_t leftSamples = left / 2; if(n_periodCountStereo > leftSamples) n_periodCountStereo = leftSamples; //! Count of stereo samples ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo; //! Total count of samples ssize_t in_generatedPhys = in_generatedStereo * 2; //! Unsigned total sample count //fill buffer with zeros int32_t *out_buf = player->m_outBuf; std::memset(out_buf, 0, static_cast<size_t>(in_generatedPhys) * sizeof(out_buf[0])); unsigned int chips = player->m_synth.m_numChips; if(chips == 1) player->m_synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo); else if(n_periodCountStereo > 0) { /* Generate data from every chip and mix result */ for(unsigned card = 0; card < chips; ++card) player->m_synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo); } /* Process it */ if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1) return 0; left -= (int)in_generatedPhys; gotten_len += (in_generatedPhys) /* - setup.stored_samples*/; } player->TickIterators(eat_delay); }//... } return static_cast<int>(gotten_len); #endif }
void OPN2::reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) { #if !defined(ADLMIDI_AUDIO_TICK_HANDLER) ADL_UNUSED(audioTickHandler); #endif clearChips(); m_insCache.clear(); m_regLFOSens.clear(); m_chips.resize(m_numChips, AdlMIDI_SPtr<OPNChipBase>()); for(size_t i = 0; i < m_chips.size(); i++) { OPNChipBase *chip; switch(emulator) { default: assert(false); abort(); #ifndef OPNMIDI_DISABLE_MAME_EMULATOR case OPNMIDI_EMU_MAME: chip = new MameOPN2; break; #endif #ifndef OPNMIDI_DISABLE_NUKED_EMULATOR case OPNMIDI_EMU_NUKED: chip = new NukedOPN2; break; #endif #ifndef OPNMIDI_DISABLE_GENS_EMULATOR case OPNMIDI_EMU_GENS: chip = new GensOPN2; break; #endif #ifndef OPNMIDI_DISABLE_GX_EMULATOR case OPNMIDI_EMU_GX: chip = new GXOPN2; break; #endif } m_chips[i].reset(chip); chip->setChipId((uint32_t)i); chip->setRate((uint32_t)PCM_RATE, 7670454); if(m_runAtPcmRate) chip->setRunningAtPcmRate(true); #if defined(ADLMIDI_AUDIO_TICK_HANDLER) chip->setAudioTickHandlerInstance(audioTickHandler); #endif } m_numChannels = m_numChips * 6; m_insCache.resize(m_numChannels, m_emptyInstrument.opn[0]); m_regLFOSens.resize(m_numChannels, 0); uint8_t regLFOSetup = (m_lfoEnable ? 8 : 0) | (m_lfoFrequency & 7); m_regLFOSetup = regLFOSetup; for(size_t card = 0; card < m_numChips; ++card) { writeReg(card, 0, 0x22, regLFOSetup);//push current LFO state writeReg(card, 0, 0x27, 0x00); //set Channel 3 normal mode writeReg(card, 0, 0x2B, 0x00); //Disable DAC //Shut up all channels writeReg(card, 0, 0x28, 0x00 ); //Note Off 0 channel writeReg(card, 0, 0x28, 0x01 ); //Note Off 1 channel writeReg(card, 0, 0x28, 0x02 ); //Note Off 2 channel writeReg(card, 0, 0x28, 0x04 ); //Note Off 3 channel writeReg(card, 0, 0x28, 0x05 ); //Note Off 4 channel writeReg(card, 0, 0x28, 0x06 ); //Note Off 5 channel } silenceAll(); }
ADLMIDI_EXPORT int adl_playFormat(ADL_MIDIPlayer *device, int sampleCount, ADL_UInt8 *out_left, ADL_UInt8 *out_right, const ADLMIDI_AudioFormat *format) { #if defined(ADLMIDI_DISABLE_MIDI_SEQUENCER) || defined(ADLMIDI_HW_OPL) ADL_UNUSED(device); ADL_UNUSED(sampleCount); ADL_UNUSED(out_left); ADL_UNUSED(out_right); ADL_UNUSED(format); return 0; #endif #if !defined(ADLMIDI_DISABLE_MIDI_SEQUENCER) && !defined(ADLMIDI_HW_OPL) sampleCount -= sampleCount % 2; //Avoid even sample requests if(sampleCount < 0) return 0; if(!device) return 0; MidiPlayer *player = GET_MIDI_PLAYER(device); assert(player); MidiPlayer::Setup &setup = player->m_setup; ssize_t gotten_len = 0; ssize_t n_periodCountStereo = 512; //ssize_t n_periodCountPhys = n_periodCountStereo * 2; int left = sampleCount; bool hasSkipped = setup.tick_skip_samples_delay > 0; while(left > 0) { {//... const double eat_delay = setup.delay < setup.maxdelay ? setup.delay : setup.maxdelay; if(hasSkipped) { size_t samples = setup.tick_skip_samples_delay > sampleCount ? sampleCount : setup.tick_skip_samples_delay; n_periodCountStereo = samples / 2; } else { setup.delay -= eat_delay; setup.carry += double(setup.PCM_RATE) * eat_delay; n_periodCountStereo = static_cast<ssize_t>(setup.carry); setup.carry -= double(n_periodCountStereo); } //if(setup.SkipForward > 0) // setup.SkipForward -= 1; //else { if((player->m_sequencer.positionAtEnd()) && (setup.delay <= 0.0)) break;//Stop to fetch samples at reaching the song end with disabled loop ssize_t leftSamples = left / 2; if(n_periodCountStereo > leftSamples) { setup.tick_skip_samples_delay = (n_periodCountStereo - leftSamples) * 2; n_periodCountStereo = leftSamples; } //! Count of stereo samples ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo; //! Total count of samples ssize_t in_generatedPhys = in_generatedStereo * 2; //! Unsigned total sample count //fill buffer with zeros int32_t *out_buf = player->m_outBuf; std::memset(out_buf, 0, static_cast<size_t>(in_generatedPhys) * sizeof(out_buf[0])); unsigned int chips = player->m_synth.m_numChips; if(chips == 1) { player->m_synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo); } else if(n_periodCountStereo > 0) { /* Generate data from every chip and mix result */ for(size_t card = 0; card < chips; ++card) player->m_synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo); } /* Process it */ if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1) return 0; left -= (int)in_generatedPhys; gotten_len += (in_generatedPhys) /* - setup.stored_samples*/; } if(hasSkipped) { setup.tick_skip_samples_delay -= n_periodCountStereo * 2; hasSkipped = setup.tick_skip_samples_delay > 0; } else setup.delay = player->Tick(eat_delay, setup.mindelay); }//... } return static_cast<int>(gotten_len); #endif //ADLMIDI_DISABLE_MIDI_SEQUENCER }