Skip to content

Commit

Permalink
Cherry pick
Browse files Browse the repository at this point in the history
  • Loading branch information
christofmuc committed Jan 15, 2021
1 parent 3a3ec70 commit 7f2e545
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 7 deletions.
1 change: 1 addition & 0 deletions The-Orm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ set(SOURCES
PatchNameDialog.cpp PatchNameDialog.h
PatchPerSynthList.cpp PatchPerSynthList.h
PatchView.cpp PatchView.h
ReceiveManualDumpWindow.cpp ReceiveManualDumpWindow.h
RecordingView.cpp RecordingView.h
RotaryWithLabel.cpp RotaryWithLabel.h
ScriptedQuery.cpp ScriptedQuery.h
Expand Down
67 changes: 61 additions & 6 deletions The-Orm/PatchView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
#include "GenericAdaptation.h" //TODO For the Python runtime. That should probably go to its own place, as Python now is used for more than the GenericAdaptation

#include <boost/format.hpp>
#include "PatchInterchangeFormat.h"
#include "Settings.h"
#include "ReceiveManualDumpWindow.h"

const char *kAllPatchesFilter = "All patches";
const char *kAllDataTypesFilter = "All types";
Expand Down Expand Up @@ -70,13 +73,19 @@ PatchView::PatchView(midikraft::PatchDatabase &database, std::vector<midikraft::
{ "fetchEditBuffer",{ 1, "Import edit buffer from synth", [this]() {
retrieveEditBuffer();
} } },
{ "loadsysEx", { 2, "Import sysex files from computer", [this]() {
{ "receiveManualDump",{ 2, "Receive manual dump", [this]() {
receiveManualDump();
} } },
{ "loadsysEx", { 3, "Import sysex files from computer", [this]() {
loadPatches();
} } },
{ "exportSysex", { 3, "Export into sysex files", [this]() {
{ "exportSysex", { 4, "Export into sysex files", [this]() {
exportPatches();
} } },
{ "showDiff", { 4, "Show patch comparison", [this]() {
{ "exportPIF", { 5, "Export into PIF", [this]() {
createPatchInterchangeFile();
} } },
{ "showDiff", { 6, "Show patch comparison", [this]() {
showPatchDiffDialog();
} } },
};
Expand Down Expand Up @@ -348,7 +357,7 @@ void PatchView::retrievePatches() {
auto device = std::dynamic_pointer_cast<midikraft::DiscoverableDevice>(activeSynth);
auto midiLocation = midikraft::Capability::hasCapability<midikraft::MidiLocationCapability>(activeSynth);
std::shared_ptr<ProgressHandlerWindow> progressWindow = std::make_shared<LibrarianProgressWindow>(librarian_);
if (activeSynth && device->wasDetected()) {
if (activeSynth /*&& device->wasDetected()*/) {
midikraft::MidiController::instance()->enableMidiInput(midiLocation->midiInput());
importDialog_ = std::make_unique<ImportFromSynthDialog>(activeSynth.get(),
[this, progressWindow, activeSynth, midiLocation](std::vector<MidiBankNumber> bankNo) {
Expand Down Expand Up @@ -504,6 +513,26 @@ class MergeManyPatchFiles : public ProgressHandlerWindow {
std::function<void(std::vector<midikraft::PatchHolder>)> finished_;
};

void PatchView::receiveManualDump() {
auto synthToReceiveFrom = UIModel::instance()->currentSynth_.smartSynth();

if (synthToReceiveFrom) {
// We need to start a listener thread, and display a waiting dialog box with an end button all the while...
ReceiveManualDumpWindow receiveDumpBox(UIModel::instance()->currentSynth_.smartSynth());

receiveDumpBox.runThread();

auto messagesReceived = receiveDumpBox.result();
if (messagesReceived.size() > 0) {
// Try to load via Librarian
auto patches = librarian_.loadSysexPatchesManualDump(synthToReceiveFrom, messagesReceived, automaticCategories_);
if (patches.size() > 0) {
mergeNewPatches(patches);
}
}
}
}

void PatchView::loadPatches() {
if (UIModel::currentSynth()) {
auto patches = librarian_.loadSysexPatchesFromDisk(UIModel::instance()->currentSynth_.smartSynth(), automaticCategories_);
Expand All @@ -523,6 +552,33 @@ void PatchView::exportPatches()
}
}

void PatchView::updateLastPath() {
if (lastPathForPIF_.empty()) {
// Read from settings
lastPathForPIF_ = Settings::instance().get("lastPatchInterchangePath", "");
if (lastPathForPIF_.empty()) {
// Default directory
lastPathForPIF_ = File::getSpecialLocation(File::userDocumentsDirectory).getFullPathName().toStdString();
}
}
}

void PatchView::createPatchInterchangeFile()
{
// If at least one synth is selected, build and run the query. Never run a query against all synths from this code
if (!advancedFilters_.synthFilters_.selectedCategories().empty()) {
loadPage(0, -1, [this](std::vector<midikraft::PatchHolder> patches) {
updateLastPath();
FileChooser pifChooser("Please enter the name of the Patch Interchange Format file to create...", File(lastPathForPIF_), "*.json");
if (pifChooser.browseForFileToSave(true)) {
midikraft::PatchInterchangeFormat::save(patches, pifChooser.getResult().getFullPathName().toStdString());
lastPathForPIF_ = pifChooser.getResult().getFullPathName().toStdString();
Settings::instance().set("lastPatchInterchangePath", lastPathForPIF_);
}
});
}
}

std::string PatchView::currentlySelectedSourceUUID() {
if (importList_.getSelectedItemIndex() > 0) {
std::string selectedItemText = importList_.getText().toStdString();
Expand Down Expand Up @@ -561,8 +617,7 @@ void PatchView::rebuildDataTypeFilterBox() {
for (size_t i = 0; i < dflc->dataTypeNames().size(); i++) {
auto typeName = dflc->dataTypeNames()[i];
if (typeName.canBeSent) {
typeNameList.add(typeName.name);
}
typeNameList.add(typeName.name);
}
advancedFilters_.dataTypeSelector_.addItemList(typeNameList, 1);
}
Expand Down
5 changes: 5 additions & 0 deletions The-Orm/PatchView.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ class PatchView : public Component,
void retrievePatches();

void loadPatches();
void receiveManualDump();
void exportPatches();
void updateLastPath();
void createPatchInterchangeFile();
std::string currentlySelectedSourceUUID();
void rebuildSynthFilters();
void rebuildImportFilterBox();
Expand Down Expand Up @@ -128,6 +131,8 @@ class PatchView : public Component,
midikraft::PatchHolder compareTarget_;

midikraft::PatchDatabase &database_;

std::string lastPathForPIF_;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PatchView)
};
Expand Down
45 changes: 45 additions & 0 deletions The-Orm/ReceiveManualDumpWindow.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
Copyright (c) 2021 Christof Ruch. All rights reserved.
Dual licensed: Distributed under Affero GPL license by default, an MIT license is available for purchase
*/

#include "ReceiveManualDumpWindow.h"

#include "MidiController.h"

#include "Capability.h"

ReceiveManualDumpWindow::ReceiveManualDumpWindow(std::shared_ptr<midikraft::Synth> synth) :
ThreadWithProgressWindow("Waiting for sysex messages from " + synth->getName() +"...", false, true, 1000, "Stop"), synth_(synth)
{
// Create a MIDI log view with a decent size
midiLog_ = std::make_unique<MidiLogView>(false, true);
midiLog_->setSize(800, 400);

// Add this as a custom component to our AlertWindow
getAlertWindow()->addCustomComponent(midiLog_.get());
}

void ReceiveManualDumpWindow::run()
{
// Determine which MIDI port to listen to
auto locationCap = midikraft::Capability::hasCapability<midikraft::MidiLocationCapability>(synth_);

auto incomingHandler = midikraft::MidiController::makeOneHandle();
midikraft::MidiController::instance()->addMessageHandler(incomingHandler, [this, locationCap](MidiInput *source, MidiMessage const &received) {
// Just capture all messages incoming from the devices' input port. That might be too many...
if (!locationCap || locationCap->midiInput() == source->getName()) {
midiLog_->addMessageToList(received, source->getName(), false);
receivedMessages_.push_back(received);
}
});

do {
} while (!threadShouldExit());
}

std::vector<juce::MidiMessage> ReceiveManualDumpWindow::result() const
{
return receivedMessages_;
}
30 changes: 30 additions & 0 deletions The-Orm/ReceiveManualDumpWindow.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
Copyright (c) 2021 Christof Ruch. All rights reserved.
Dual licensed: Distributed under Affero GPL license by default, an MIT license is available for purchase
*/

#pragma once

#include "JuceHeader.h"

#include "Synth.h"
#include "MidiLogView.h"


class ReceiveManualDumpWindow : public ThreadWithProgressWindow {
public:
ReceiveManualDumpWindow(std::shared_ptr<midikraft::Synth> synth);

virtual void run() override;

std::vector<MidiMessage> result() const;

private:
std::shared_ptr<midikraft::Synth> synth_;
std::unique_ptr<MidiLogView> midiLog_;

std::vector<MidiMessage> receivedMessages_;
};


2 changes: 1 addition & 1 deletion juce-widgets

0 comments on commit 7f2e545

Please sign in to comment.