/** * * Copyright (c) 2013-2015 Pascal Gauthier. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "PluginProcessor.h" #include "PluginEditor.h" #include "GlobalEditor.h" #include "ParamDialog.h" #include "SysexComm.h" #include "Dexed.h" #include "math.h" #include "DXLookNFeel.h" #include #include "msfa/fm_op_kernel.h" //============================================================================== DexedAudioProcessorEditor::DexedAudioProcessorEditor (DexedAudioProcessor* ownerFilter) : AudioProcessorEditor (ownerFilter), midiKeyboard (ownerFilter->keyboardState, MidiKeyboardComponent::horizontalKeyboard), cartManager(this) { LookAndFeel::setDefaultLookAndFeel(DXLookNFeel::getLookAndFeel()); setSize(866, ownerFilter->showKeyboard ? 674 : 581); processor = ownerFilter; background = DXLookNFeel::getLookAndFeel()->background; // OPERATORS addAndMakeVisible(&(operators[0])); operators[0].setBounds(2, 1, 287, 218); operators[0].bind(processor, 0); addAndMakeVisible(&(operators[1])); operators[1].setBounds(290, 1, 287, 218); operators[1].bind(processor, 1); addAndMakeVisible(&(operators[2])); operators[2].setBounds(578, 1, 287, 218); operators[2].bind(processor, 2); addAndMakeVisible(&(operators[3])); operators[3].setBounds(2, 219, 287, 218); operators[3].bind(processor, 3); addAndMakeVisible(&(operators[4])); operators[4].setBounds(290, 219, 287, 218); operators[4].bind(processor, 4); addAndMakeVisible(&(operators[5])); operators[5].setBounds(578, 219, 287, 218); operators[5].bind(processor, 5); // add the midi keyboard component.. addAndMakeVisible (&midiKeyboard); // The DX7 is a badass on the bass, keep it that way midiKeyboard.setLowestVisibleKey(24); midiKeyboard.setBounds(4, 581, getWidth() - 8, 90); addAndMakeVisible(&global); global.setBounds(2,436,864,144); global.bind(this); global.setMonoState(processor->isMonoMode()); rebuildProgramCombobox(); global.programs->addListener(this); addChildComponent(&cartManager); updateUI(); startTimer(100); } DexedAudioProcessorEditor::~DexedAudioProcessorEditor() { stopTimer(); processor->unbindUI(); } //============================================================================== void DexedAudioProcessorEditor::paint (Graphics& g) { g.setColour(background); g.fillRoundedRectangle(0.0f, 0.0f, (float) getWidth(), (float) getHeight(), 0); } void DexedAudioProcessorEditor::cartShow() { stopTimer(); cartManager.resetActiveSysex(); cartManager.setBounds(4, 2, 859, 576); cartManager.setVisible(true); cartManager.initialFocus(); } void DexedAudioProcessorEditor::loadCart(File file) { Cartridge cart; if ( cart.load(file) < 0 ) { AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Error", "Unable to open: " + file.getFullPathName()); return; } processor->loadCartridge(cart); rebuildProgramCombobox(); processor->setCurrentProgram(0); global.programs->setSelectedId(processor->getCurrentProgram()+1, dontSendNotification); processor->updateHostDisplay(); processor->activeFileCartridge = file; } void DexedAudioProcessorEditor::saveCart() { File startFileName = processor->activeFileCartridge.exists() ? processor->activeFileCartridge : processor->dexedCartDir; FileChooser fc ("Export DX sysex...", processor->dexedCartDir, "*.syx", 1); if ( fc.browseForFileToSave(true) ) { if ( ! processor->currentCart.saveVoice(fc.getResults().getReference(0)) ) { AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, "Error", "Unable to write: " + fc.getResults().getReference(0).getFullPathName()); } } } void DexedAudioProcessorEditor::parmShow() { int tp = processor->getEngineType(); AlertWindow window("","", AlertWindow::NoIcon, this); ParamDialog param; param.setColour(AlertWindow::backgroundColourId, Colour(0x32FFFFFF)); param.setDialogValues(processor->controllers, processor->sysexComm, tp, processor->showKeyboard); window.addCustomComponent(¶m); window.addButton("OK", 0); window.addButton("Cancel" ,1); if ( window.runModalLoop() != 0 ) return; bool ret = param.getDialogValues(processor->controllers, processor->sysexComm, &tp, &processor->showKeyboard); processor->setEngineType(tp); processor->savePreference(); setSize(866, processor->showKeyboard ? 674 : 581); midiKeyboard.repaint(); if ( ret == false ) { AlertWindow::showMessageBoxAsync(AlertWindow::WarningIcon, "Midi Interface", "Error opening midi ports"); } } void DexedAudioProcessorEditor::initProgram() { processor->resetToInitVoice(); } void DexedAudioProcessorEditor::comboBoxChanged (ComboBox* comboBoxThatHasChanged) { processor->setCurrentProgram(global.programs->getSelectedId()-1); processor->updateHostDisplay(); } void DexedAudioProcessorEditor::timerCallback() { if ( processor->forceRefreshUI ) { processor->forceRefreshUI = false; updateUI(); } if ( ! processor->peekVoiceStatus() ) return; for(int i=0;i<6;i++) { operators[i].updateGain(sqrt(processor->voiceStatus.amp[5 - i]) / 8196); // TODO: FUGLY !!!! change this sqrt nonsens operators[i].updateEnvPos(processor->voiceStatus.ampStep[5 - i]); } global.updatePitchPos(processor->voiceStatus.pitchStep); global.updateVu(processor->vuSignal); } void DexedAudioProcessorEditor::updateUI() { for(int i=0;ictrl.size();i++) { processor->ctrl[i]->updateComponent(); } for(int i=0;i<6;i++) { operators[i].updateDisplay(); } rebuildProgramCombobox(); global.updateDisplay(); } void DexedAudioProcessorEditor::rebuildProgramCombobox() { global.programs->clear(dontSendNotification); processor->currentCart.getProgramNames(processor->programNames); for(int i=0;igetNumPrograms();i++) { String id; id << (i+1) << ". " << processor->getProgramName(i); global.programs->addItem(id, i+1); } global.programs->setSelectedId(processor->getCurrentProgram()+1, dontSendNotification); String name = Cartridge::normalizePgmName((const char *) processor->data+145); cartManager.setActiveProgram(processor->getCurrentProgram(), name); if ( name != processor->getProgramName(processor->getCurrentProgram()) ) global.programs->setText("**. " + name, dontSendNotification); cartManager.resetActiveSysex(); } void DexedAudioProcessorEditor::storeProgram() { String currentName = Cartridge::normalizePgmName((const char *) processor->data+145); Cartridge destSysex = processor->currentCart; File *externalFile = NULL; bool activeCartridgeFound = processor->activeFileCartridge.exists(); while (true) { String msg; if ( externalFile == NULL ) { if ( activeCartridgeFound ) msg = "Store program to current (" + processor->activeFileCartridge.getFileName() + ") / new cartridge"; else msg = "Store program to current / new cartridge"; } else { msg = "Store program to " + externalFile->getFileName(); } AlertWindow dialog("Store Program", msg, AlertWindow::NoIcon, this); dialog.addTextEditor("Name", currentName, String("Name"), false); // TODO: fix the name length to 10 StringArray programs; destSysex.getProgramNames(programs); dialog.addComboBox("Dest", programs, "Program Destination"); if ( externalFile == NULL ) { StringArray saveAction; saveAction.add("Store program to DAW plugin song state"); saveAction.add("Store program and create a new copy of the .syx cartridge"); if ( activeCartridgeFound ) saveAction.add("Store program and overwrite current .syx cartridge"); dialog.addComboBox("SaveAction", saveAction, "Store Action"); } dialog.addButton("OK", 0, KeyPress(KeyPress::returnKey)); dialog.addButton("CANCEL", 1, KeyPress(KeyPress::escapeKey)); dialog.addButton("EXTERNAL FILE", 2, KeyPress()); int response = dialog.runModalLoop(); if ( response == 2 ) { FileChooser fc("Destination Sysex", processor->dexedCartDir, "*.syx;*.SYX;*.*", 1); if ( fc.browseForFileToOpen() ) { if ( externalFile != NULL ) delete externalFile; externalFile = new File(fc.getResults().getReference(0)); if ( destSysex.load(*externalFile) ) continue; AlertWindow::showMessageBoxAsync(AlertWindow::WarningIcon, "Read error", "Unable to read file"); } } if ( response == 0 ) { TextEditor *name = dialog.getTextEditor("Name"); ComboBox *dest = dialog.getComboBoxComponent("Dest"); int programNum = dest->getSelectedItemIndex(); String programName(name->getText()); if ( programName.length() > 10 ) { int toStrip = programName.length() - 10; programName = programName.dropLastCharacters(toStrip); } if ( externalFile == NULL ) { processor->currentCart.packProgram((uint8_t *) processor->data, programNum, programName); rebuildProgramCombobox(); processor->setCurrentProgram(programNum); processor->updateHostDisplay(); int action = dialog.getComboBoxComponent("SaveAction")->getSelectedItemIndex(); if ( action > 0 ) { File destination = processor->activeFileCartridge; if ( ! destination.exists() ) { FileChooser fc("Destination Sysex", processor->dexedCartDir, "*.syx", 1); if ( ! fc.browseForFileToSave(true) ) break; destination = fc.getResult(); } processor->currentCart.saveVoice(destination); processor->activeFileCartridge = destination; } } else { destSysex.packProgram((uint8_t *) processor->data, programNum, programName); if ( ! destSysex.saveVoice(*externalFile)) { AlertWindow::showMessageBoxAsync(AlertWindow::WarningIcon, "Write error", "Unable to write file"); } } } break; } if ( externalFile != NULL ) delete externalFile; cartManager.resetActiveSysex(); }