From 446486da6b37c52a89ec991f92d4826ce14c8be8 Mon Sep 17 00:00:00 2001 From: Frits Talbot Date: Mon, 25 Aug 2014 23:09:39 +0200 Subject: [PATCH] Delete leaking params that cause JUCE assertions to fail. Fix bad MidiMessage construction (JUCE assertion failure). Workaround for Cubase 7.5 invoking setCurrentProgram after setStateInformation and overwriting saved state with hardcoded preset. Add rudimentary versioning to get-/setStateInformation. --- Source/PluginProcessor.cpp | 71 +++++++++++++++++++++++++++++++++----- Source/PluginProcessor.h | 1 + 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index ea71510..91f5b7e 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -6,6 +6,7 @@ //============================================================================== JuceOplvstiAudioProcessor::JuceOplvstiAudioProcessor() + : i_program(-1) { // Initalize OPL velocity = false; @@ -380,6 +381,8 @@ void JuceOplvstiAudioProcessor::applyPitchBend() JuceOplvstiAudioProcessor::~JuceOplvstiAudioProcessor() { + for (int i = 0; i < params.size(); ++i) + delete params[i]; } //============================================================================== @@ -598,6 +601,9 @@ void JuceOplvstiAudioProcessor::updateGuiIfPresent() void JuceOplvstiAudioProcessor::setCurrentProgram (int index) { + if (i_program==index) + return; + i_program = index; std::vector &v_params = programs[getProgramName(index)]; for (unsigned int i = 0; i < params.size() && i < v_params.size(); i++) { @@ -634,7 +640,7 @@ void JuceOplvstiAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuf buffer.clear(0, 0, buffer.getNumSamples()); MidiBuffer::Iterator midi_buffer_iterator(midiMessages); - MidiMessage midi_message(0); + MidiMessage midi_message; int sample_number; while (midi_buffer_iterator.getNextEvent(midi_message,sample_number)) { if (midi_message.isNoteOn()) { @@ -678,9 +684,9 @@ void JuceOplvstiAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuf while (ch <= Hiopl::CHANNELS && n != active_notes[ch]) { ch += 1; } - Opl->KeyOff(ch); - active_notes[ch] = NO_NOTE; - } + Opl->KeyOff(ch); + active_notes[ch]=NO_NOTE; + } else if (midi_message.isPitchWheel()) { int bend = midi_message.getPitchWheelValue() - 0x2000; // range -8192 to 8191 // 1.05946309436 == (2^(1/1200))^100 == 1 semitone == 100 cents @@ -704,22 +710,71 @@ AudioProcessorEditor* JuceOplvstiAudioProcessor::createEditor() return gui; } +// FIXME: these two funcs and get-/setStateInformation should be replaced by a proper cross-platform archiving API, e.g. eos portable archive or boost text archive +template +void push(char *&cursor, T value) +{ + *reinterpret_cast(cursor) = value; + cursor+=sizeof(T); +} + +template +void pop(const char *&cursor, T &value) +{ + value=*reinterpret_cast(cursor); + cursor+=sizeof(T); +} + //============================================================================== void JuceOplvstiAudioProcessor::getStateInformation (MemoryBlock& destData) { - destData.ensureSize(sizeof(float) * getNumParameters()); + destData.ensureSize(sizeof(CURRENT_VERSION)+sizeof(i_program)+sizeof(float) * getNumParameters()); + + char *cursor = static_cast(destData.getData()); + + push(cursor, CURRENT_VERSION); + push(cursor, i_program); + for (int i = 0; i < getNumParameters(); i++) { float p = getParameter(i); - destData.copyFrom((void*)&p, i*sizeof(float), sizeof(float)); + push(cursor, p); } } void JuceOplvstiAudioProcessor::setStateInformation (const void* data, int sizeInBytes) { + if (sizeInBytes < sizeof(CURRENT_VERSION)) + return; + + const char *cursor = static_cast(data); + const char *end = cursor+sizeInBytes; + int version; + + pop(cursor, version); + + if (version == CURRENT_VERSION) + { + pop(cursor, i_program); + + const int parametersToLoad = std::min(static_cast(std::distance(cursor, end)) / sizeof(float), getNumParameters()); + + for (int i = 0; i < parametersToLoad; i++) + { + float p; + + pop(cursor, p); + setParameter(i, p); + } + + return; + } + float* fdata = (float*)data; - for (unsigned int i = 0; i < sizeInBytes / sizeof(float); i++) { + const int parametersToLoad = std::min(sizeInBytes / sizeof(float), getNumParameters()); + + for (int i = 0; i < parametersToLoad; i++) { setParameter(i, fdata[i]); - } + } } //============================================================================== diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index e3cac2f..c7a95b2 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -88,6 +88,7 @@ private: int i_program; bool velocity; static const int NO_NOTE=-1; + static const int CURRENT_VERSION = 0x09720100; // OPL2 v01.00 magic int active_notes[Hiopl::CHANNELS+1]; // keyed by channel float currentScaledBend;