From 6bd4590a54c98c2149607f8bb4e09449b7615d2e Mon Sep 17 00:00:00 2001 From: jens Date: Wed, 3 May 2023 17:59:08 +0200 Subject: [PATCH] - added legacy (< v1.0.0) import for patches - added legacy (< v1.0.0) import for banks --- Source/JaySynthAudioProcessorEditor.cpp | 8 +- Source/PluginProcessor.cpp | 379 +++++++++++++----------- Source/PluginProcessor.h | 21 +- 3 files changed, 230 insertions(+), 178 deletions(-) diff --git a/Source/JaySynthAudioProcessorEditor.cpp b/Source/JaySynthAudioProcessorEditor.cpp index 87166c2..ee236e4 100644 --- a/Source/JaySynthAudioProcessorEditor.cpp +++ b/Source/JaySynthAudioProcessorEditor.cpp @@ -4938,7 +4938,7 @@ void JaySynthAudioProcessorEditor::buttonClicked (Button* buttonThatWasClicked) if (fc.browseForFileToOpen()) { File const &file = fc.getResult(); - getProcessor()->loadBank(file); + getProcessor()->loadBankFromFile(file); m_fileChooserDirectory = file; } } @@ -4949,7 +4949,7 @@ void JaySynthAudioProcessorEditor::buttonClicked (Button* buttonThatWasClicked) if (fc.browseForFileToSave(true)) { File const &file = fc.getResult(); - getProcessor()->saveBank(file); + getProcessor()->saveBankToFile(file); m_fileChooserDirectory = file; } } @@ -4960,7 +4960,7 @@ void JaySynthAudioProcessorEditor::buttonClicked (Button* buttonThatWasClicked) if (fc.browseForFileToOpen()) { File const &file = fc.getResult(); - getProcessor()->loadPatch(file, 0); + getProcessor()->loadPatchFromFile(file, 0); m_fileChooserDirectory = file; } } @@ -4971,7 +4971,7 @@ void JaySynthAudioProcessorEditor::buttonClicked (Button* buttonThatWasClicked) if (fc.browseForFileToSave(true)) { File const &file = fc.getResult(); - getProcessor()->savePatch(file, 0); + getProcessor()->savePatchToFile(file, 0); m_fileChooserDirectory = file; } } diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 0a8b5d9..ef9d28a 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -705,7 +705,7 @@ void JaySynthAudioProcessor::commitEditBuffer() } } -void JaySynthAudioProcessor::patch2xml(XmlElement *xml, JaySynthSound const *patch) +void JaySynthAudioProcessor::patchEncodeXml(XmlElement *xml, JaySynthSound const *patch) { XmlElement *xml_patch = xml->createNewChildElement("Patch"); xml_patch->setAttribute ("NAME", patch->getName()); @@ -717,7 +717,7 @@ void JaySynthAudioProcessor::patch2xml(XmlElement *xml, JaySynthSound const *pat patch->getMidiCC()->exportXML(xml_patch); } -void JaySynthAudioProcessor::xml2patch(const XmlElement *xml, JaySynthSound *patch) +void JaySynthAudioProcessor::patchDecodeXml(const XmlElement *xml, JaySynthSound *patch) { // ok, now pull out our parameters.. patch->setName(xml->getStringAttribute("NAME")); @@ -737,7 +737,7 @@ void JaySynthAudioProcessor::xml2patch(const XmlElement *xml, JaySynthSound *pat } -void JaySynthAudioProcessor::bank2xml(XmlElement *xml) +void JaySynthAudioProcessor::bankEncodeXml(XmlElement *xml) { XmlElement *xml_bank = xml->createNewChildElement("Bank"); for (int i=0; i < NUM_PROGRAMS; i++) @@ -745,11 +745,11 @@ void JaySynthAudioProcessor::bank2xml(XmlElement *xml) XmlElement *xml_program = xml_bank->createNewChildElement (String("Program_") + String(i)); JaySynthSound *pPatch = &patches[i]; xml_program->setAttribute ("ID", i); - patch2xml(xml_program, pPatch); + patchEncodeXml(xml_program, pPatch); } } -void JaySynthAudioProcessor::xml2bank(const XmlElement *_xml) +void JaySynthAudioProcessor::bankDecodeXml(const XmlElement *_xml) { XmlElement *xml = (XmlElement*)_xml; while(xml) @@ -766,7 +766,7 @@ void JaySynthAudioProcessor::xml2bank(const XmlElement *_xml) if (xml2->hasTagName ("Patch")) { // Read patch - xml2patch(xml2, pPatch); + patchDecodeXml(xml2, pPatch); } } xml = xml->getNextElement(); @@ -779,7 +779,7 @@ void JaySynthAudioProcessor::getStateInformation (MemoryBlock& destData) // Create an outer XML element.. ScopedPointer xml = new XmlElement("JSynth"); - bank2xml(xml); + bankEncodeXml(xml); setCurrentProgram(getCurrentProgram()); @@ -793,152 +793,7 @@ void JaySynthAudioProcessor::getStateInformation (MemoryBlock& destData) outputStream.flush(); } -void JaySynthAudioProcessor::setStateInformation (const void* data, int sizeInBytes) -{ - ScopedPointer pUncompressedData = new char[8192*1024]; - - MemoryInputStream inputStream(data, sizeInBytes, false); - GZIPDecompressorInputStream GZIPDec(inputStream); - int uncompressedSize = GZIPDec.read(pUncompressedData, 8192*1024); - - void* pData = (void *)data; - int size = sizeInBytes; - if (uncompressedSize) - { - pData = (void *)pUncompressedData; - size = uncompressedSize; - } - - ScopedPointer xml = getXmlFromBinary(pData, size); - if (xml != 0) - { - if (xml->hasTagName ("JSynth")) - { - XmlElement *xml2 = xml->getFirstChildElement(); - if (xml2->hasTagName ("Bank")) - { - XmlElement *xml3 = xml2->getFirstChildElement(); - xml2bank(xml3); - } - } - setCurrentProgram(getCurrentProgram()); - } -} - -void JaySynthAudioProcessor::getCurrentProgramStateInformation (MemoryBlock& destData) -{ - // You should use this method to store your parameters in the memory block. - // You could do that either as raw data, or use the XML or ValueTree classes - // as intermediaries to make it easy to save and load complex data. - // You should use this method to store your parameters in the memory block. - // Here's an example of how you can use XML to make it easy and more robust: - - commitEditBuffer(); - - MemoryOutputStream outputStream (destData, false); - MemoryBlock tmpBlock(2*65536, /*initialiseToZero*/true); - GZIPCompressorOutputStream GZIPEnc(&outputStream, /*compressionLevel*/0, /*deleteDestStreamWhenDestroyed*/false, /*windowBits*/0); - - // Create an outer XML element.. - ScopedPointer xml = new XmlElement("JSynth"); - patch2xml(xml, currpatch); - - setCurrentProgram(getCurrentProgram()); - - // then use this helper function to stuff it into the binary blob and return it.. - copyXmlToBinary (*xml, tmpBlock); - GZIPEnc.write(tmpBlock.getData(), tmpBlock.getSize()); -} - -void JaySynthAudioProcessor::setCurrentProgramStateInformation (const void* data, int sizeInBytes) -{ - // You should use this method to restore your parameters from this memory block, - // whose contents will have been created by the getStateInformation() call. - int i, uncompressedSize; - synth_float_t value; - ScopedPointer xmlState = NULL; - void* pData; - int size; - - ScopedPointer pUncompressedData; - pUncompressedData = new char[2*65536]; - - MemoryInputStream inputStream(data, sizeInBytes, false); - GZIPDecompressorInputStream GZIPDec(inputStream); - uncompressedSize = GZIPDec.read(pUncompressedData, 2*65536); - - pData = (void *)data; - size = sizeInBytes; - if (uncompressedSize) - { - pData = (void *)pUncompressedData; - size = uncompressedSize; - } - xmlState = getXmlFromBinary(pData, size); - - if (xmlState != 0) - { - xml2patch(xmlState, currpatch); - setCurrentProgram(getCurrentProgram()); - } -} - -void JaySynthAudioProcessor::loadPatch (const File &file, int index) -{ - String ext = file.getFileExtension(); - if (String(".fxp") == ext) - { - MemoryBlock mem; - file.loadFileAsData(mem); - fxProgram *program = (fxProgram*)mem.getData(); - if (String((const char*)&program->chunkMagic) == String(cMagic)) - { - bool is_regular = String((const char*)&program->fxMagic) == String(fMagic); - bool is_opaque = String((const char*)&program->fxMagic) == String(chunkPresetMagic); - if (is_opaque) - { - uint32_t size = ByteOrder::swap((uint32_t)program->content.data.size); - setCurrentProgramStateInformation(program->content.data.chunk, (int)size); - } - } - } - else if (String(".xmp") == ext) - { - ScopedPointer xml = XmlDocument::parse(file); - if (xml->hasTagName ("JSynth")) - { - XmlElement *xml2 = xml->getFirstChildElement(); - if (xml2->hasTagName ("Patch")) - { - xml2patch(xml2, currpatch); - setCurrentProgram(getCurrentProgram()); - } - } - } -} - -void JaySynthAudioProcessor::savePatch (const File &file, int index) -{ - String ext = file.getFileExtension(); - if (String(".fxp") == ext) - { - // ToDo: implement fxp save - } - else if (String(".xmp") == ext) - { - commitEditBuffer(); - - // Create an outer XML element.. - ScopedPointer xml = new XmlElement("JSynth"); - patch2xml(xml, currpatch); - - // Write XML to file - xml->writeToFile (/*const File &destinationFile*/file, /*dtdToUse*/""); - } -} - -//#include -void JaySynthAudioProcessor::loadBank (const File &file) +void JaySynthAudioProcessor::loadBankFromFile (const File &file) { String ext = file.getFileExtension(); if (String(".fxb") == ext) @@ -960,20 +815,176 @@ void JaySynthAudioProcessor::loadBank (const File &file) else if (String(".xmb") == ext) { ScopedPointer xml = XmlDocument::parse(file); - if (xml->hasTagName ("JSynth")) - { - const XmlElement *xml2 = xml->getFirstChildElement(); - if (xml2->hasTagName ("Bank")) - { - const XmlElement *xml3 = xml2->getFirstChildElement(); - xml2bank(xml3); - setCurrentProgram(getCurrentProgram()); - } - } + bankImportXml(xml); } } -void JaySynthAudioProcessor::saveBank (const File &file) +void JaySynthAudioProcessor::bankImportXml (const XmlElement *xml) +{ + if (xml != 0) + { + if (xml->hasTagName ("JSynth")) + { + XmlElement *xml2 = xml->getFirstChildElement(); + if (xml2->hasTagName ("Bank")) + { + XmlElement *xml3 = xml2->getFirstChildElement(); + bankDecodeXml(xml3); + } + } + else + { + // Legacy + if (xml->hasTagName ("JSYNTH_BANK")) + { + XmlElement *xml2 = xml->getFirstChildElement(); + bankImportXml_legacy(*xml2); + + } + } + setCurrentProgram(getCurrentProgram()); + } +} + +void JaySynthAudioProcessor::setStateInformation (const void* data, int sizeInBytes) +{ + ScopedPointer pUncompressedData = new char[8192*1024]; + + MemoryInputStream inputStream(data, sizeInBytes, false); + GZIPDecompressorInputStream GZIPDec(inputStream); + int uncompressedSize = GZIPDec.read(pUncompressedData, 8192*1024); + + void* pData = (void *)data; + int size = sizeInBytes; + if (uncompressedSize) + { + pData = (void *)pUncompressedData; + size = uncompressedSize; + } + + ScopedPointer xml = getXmlFromBinary(pData, size); + bankImportXml(xml); +} + +void JaySynthAudioProcessor::getCurrentProgramStateInformation (MemoryBlock& destData) +{ + // You should use this method to store your parameters in the memory block. + // You could do that either as raw data, or use the XML or ValueTree classes + // as intermediaries to make it easy to save and load complex data. + // You should use this method to store your parameters in the memory block. + // Here's an example of how you can use XML to make it easy and more robust: + + commitEditBuffer(); + + MemoryOutputStream outputStream (destData, false); + MemoryBlock tmpBlock(2*65536, /*initialiseToZero*/true); + GZIPCompressorOutputStream GZIPEnc(&outputStream, /*compressionLevel*/0, /*deleteDestStreamWhenDestroyed*/false, /*windowBits*/0); + + // Create an outer XML element.. + ScopedPointer xml = new XmlElement("JSynth"); + patchEncodeXml(xml, currpatch); + + setCurrentProgram(getCurrentProgram()); + + // then use this helper function to stuff it into the binary blob and return it.. + copyXmlToBinary (*xml, tmpBlock); + GZIPEnc.write(tmpBlock.getData(), tmpBlock.getSize()); +} + +void JaySynthAudioProcessor::loadPatchFromFile (const File &file, int index) +{ + String ext = file.getFileExtension(); + if (String(".fxp") == ext) + { + MemoryBlock mem; + file.loadFileAsData(mem); + fxProgram *program = (fxProgram*)mem.getData(); + if (String((const char*)&program->chunkMagic) == String(cMagic)) + { + bool is_regular = String((const char*)&program->fxMagic) == String(fMagic); + bool is_opaque = String((const char*)&program->fxMagic) == String(chunkPresetMagic); + if (is_opaque) + { + uint32_t size = ByteOrder::swap((uint32_t)program->content.data.size); + setCurrentProgramStateInformation(program->content.data.chunk, (int)size); + } + } + } + else if (String(".xmp") == ext) + { + ScopedPointer xml = XmlDocument::parse(file); + patchImportXml(xml, currpatch); + } +} + +void JaySynthAudioProcessor::patchImportXml (const XmlElement *xml, JaySynthSound *patch) +{ + if (xml->hasTagName ("JSynth")) + { + XmlElement *xml2 = xml->getFirstChildElement(); + if (xml2->hasTagName ("Patch")) + { + patchDecodeXml(xml2, patch); + } + } + else if (xml->hasTagName ("JSYNTH_PATCH")) + { + patchImportXml_legacy(*xml, patch); + } + setCurrentProgram(getCurrentProgram()); +} + +void JaySynthAudioProcessor::setCurrentProgramStateInformation (const void* data, int sizeInBytes) +{ + // You should use this method to restore your parameters from this memory block, + // whose contents will have been created by the getStateInformation() call. + int i, uncompressedSize; + synth_float_t value; + void* pData; + int size; + + ScopedPointer pUncompressedData; + pUncompressedData = new char[2*65536]; + + MemoryInputStream inputStream(data, sizeInBytes, false); + GZIPDecompressorInputStream GZIPDec(inputStream); + uncompressedSize = GZIPDec.read(pUncompressedData, 2*65536); + + pData = (void *)data; + size = sizeInBytes; + if (uncompressedSize) + { + pData = (void *)pUncompressedData; + size = uncompressedSize; + } + ScopedPointer xml = getXmlFromBinary(pData, size); + if (xml) + { + patchImportXml(xml, currpatch); + } +} + +void JaySynthAudioProcessor::savePatchToFile (const File &file, int index) +{ + String ext = file.getFileExtension(); + if (String(".fxp") == ext) + { + // ToDo: implement fxp save + } + else if (String(".xmp") == ext) + { + commitEditBuffer(); + + // Create an outer XML element.. + ScopedPointer xml = new XmlElement("JSynth"); + patchEncodeXml(xml, currpatch); + + // Write XML to file + xml->writeToFile (/*const File &destinationFile*/file, /*dtdToUse*/""); + } +} + +void JaySynthAudioProcessor::saveBankToFile (const File &file) { String ext = file.getFileExtension(); if (String(".fxb") == ext) @@ -986,13 +997,49 @@ void JaySynthAudioProcessor::saveBank (const File &file) // Create an outer XML element.. ScopedPointer xml = new XmlElement("JSynth"); - bank2xml(xml); + bankEncodeXml(xml); // Write XML to file xml->writeToFile (/*const File &destinationFile*/file, /*dtdToUse*/""); } } - +void JaySynthAudioProcessor::patchImportXml_legacy(const XmlElement& xml, JaySynthSound *patch) +{ + // ok, now pull out our parameters.. + patch->setName(xml.getStringAttribute("NAME")); + for (int i=0; i < SYNTH_NUM_PARAMS; i++) + { + synth_float_t value = (synth_float_t) xml.getDoubleAttribute (getParameterNameXML(i), patch->getParameter(i)); + if (i==SYNTH_PARAM_TUNE) + { + if (value > 400.0) + { + value = 1200*log(value/440)/log(2.0); + } + } + patch->setParameter(i, value); + } + ((JaySynthMidiCC*)patch->getMidiCC())->importXML(&xml); +} + +void JaySynthAudioProcessor::bankImportXml_legacy(const XmlElement& xml) +{ + // make sure that it's actually our type of XML object.. + XmlElement *pXML = (XmlElement*)&xml; + + while(pXML) + { + int progID = pXML->getIntAttribute("ID"); + if (progID >= NUM_PROGRAMS) + break; + + JaySynthSound *pPatch = &patches[progID]; + patchImportXml_legacy(*pXML, pPatch); + ((JaySynthMidiCC*)pPatch->getMidiCC())->importXML(pXML); + pXML = pXML->getNextElement(); + } +} + //============================================================================== // This creates new instances of the plugin.. AudioProcessor* JUCE_CALLTYPE createPluginFilter() diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 9911824..a8a2742 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -207,11 +207,11 @@ public: XmlElement* getXmlFromBinary (const void* data, const int sizeInBytes); const String getParameterNameXML (int index); - void patch2xml(XmlElement *xml, JaySynthSound const *patch); - void xml2patch(const XmlElement *xml, JaySynthSound *patch); + void patchEncodeXml(XmlElement *xml, JaySynthSound const *patch); + void patchDecodeXml(const XmlElement *xml, JaySynthSound *patch); - void bank2xml(XmlElement *xml); - void xml2bank(const XmlElement *xml); + void bankEncodeXml(XmlElement *xml); + void bankDecodeXml(const XmlElement *xml); void getCurrentProgramStateInformation (MemoryBlock& destData); void setCurrentProgramStateInformation (const void* data, int sizeInBytes); @@ -219,10 +219,15 @@ public: void getStateInformation (MemoryBlock& destData); void setStateInformation (const void* data, int sizeInBytes); - void loadPatch (const File &file, int index); - void savePatch (const File &file, int index); - void loadBank (const File &file); - void saveBank (const File &file); + void loadPatchFromFile (const File &file, int index); + void savePatchToFile (const File &file, int index); + void loadBankFromFile (const File &file); + void saveBankToFile (const File &file); + + void patchImportXml_legacy(const XmlElement& xml, JaySynthSound *patch); + void bankImportXml_legacy(const XmlElement& xml); + void bankImportXml (const XmlElement *xml); + void patchImportXml (const XmlElement *xml, JaySynthSound *patch); void commitEditBuffer(); //==============================================================================