diff --git a/MidiKraft b/MidiKraft index 8d4ee743..e3e42211 160000 --- a/MidiKraft +++ b/MidiKraft @@ -1 +1 @@ -Subproject commit 8d4ee7432a33822712f3a53f287719697576f8a9 +Subproject commit e3e42211194b0ff2a4115f130747a5f5aadca0f4 diff --git a/adaptations/Adaptation Programming Guide.md b/adaptations/Adaptation Programming Guide.md index bf94d3a7..b65e8c00 100644 --- a/adaptations/Adaptation Programming Guide.md +++ b/adaptations/Adaptation Programming Guide.md @@ -400,7 +400,8 @@ Additionally, when you have implement all three functions to enable the ProgramD def numberFromDump(message) -which will be used if present to detect the original program slot location stored in a program dump for archival purposes. +which will be used if present to detect the original program slot location stored in a program dump for archival purposes. This should return -1 in case +the message is not a program dump (but e.g. an edit buffer dump which has no number stored). ### Requesting a specific program at a specific memory position diff --git a/adaptations/AlesisAndromedaA6.py b/adaptations/AlesisAndromedaA6.py index f080faac..8b71d72b 100644 --- a/adaptations/AlesisAndromedaA6.py +++ b/adaptations/AlesisAndromedaA6.py @@ -106,8 +106,6 @@ def numberFromDump(message): bank = message[6] program = message[7] return bank * numberOfPatchesPerBank() + program - if isEditBufferDump(message): - return 0 raise Exception("Can only extract number from single program dumps") diff --git a/adaptations/BC_Kijimi.py b/adaptations/BC_Kijimi.py index 7fde00bb..81339d7d 100644 --- a/adaptations/BC_Kijimi.py +++ b/adaptations/BC_Kijimi.py @@ -108,8 +108,6 @@ def isDefaultName(patchName): def numberFromDump(message): - if isEditBufferDump(message): - return 0 if isSingleProgramDump(message): return message[3] * numberOfPatchesPerBank() + message[4] raise Exception("Only single program dumps have program numbers") diff --git a/adaptations/Behringer Deepmind 12.py b/adaptations/Behringer Deepmind 12.py index 68ff083d..ae5f2c02 100644 --- a/adaptations/Behringer Deepmind 12.py +++ b/adaptations/Behringer Deepmind 12.py @@ -91,8 +91,6 @@ def nameFromDump(message): def numberFromDump(message) -> int: if isSingleProgramDump(message): return message[8] * numberOfPatchesPerBank() + message[9] - elif isEditBufferDump(message): - return 0 return -1 diff --git a/adaptations/GenericEditBufferCapability.cpp b/adaptations/GenericEditBufferCapability.cpp index 6dd638cc..4b5fb2fe 100644 --- a/adaptations/GenericEditBufferCapability.cpp +++ b/adaptations/GenericEditBufferCapability.cpp @@ -108,6 +108,10 @@ namespace knobkraft { try { auto data = patch->data(); int c = me_->channel().toZeroBasedInt(); + if (c < 0) { + c = 0; + spdlog::warn("Channel is unknown in patchToSysex, defaulting to MIDI channel 1"); + } py::object result = me_->callMethod(kConvertToEditBuffer, c, data); std::vector byteData = GenericAdaptation::intVectorToByteVector(result.cast>()); return Sysex::vectorToMessages(byteData); diff --git a/adaptations/GenericProgramDumpCapability.cpp b/adaptations/GenericProgramDumpCapability.cpp index 7e7c1190..e8cc2b57 100644 --- a/adaptations/GenericProgramDumpCapability.cpp +++ b/adaptations/GenericProgramDumpCapability.cpp @@ -102,12 +102,21 @@ namespace knobkraft { MidiProgramNumber GenericProgramDumpCapability::getProgramNumber(const std::vector& message) const { + if (!isSingleProgramDump(message)) { + return MidiProgramNumber::invalidProgram(); + } py::gil_scoped_acquire acquire; if (me_->pythonModuleHasFunction("numberFromDump")) { try { auto vector = GenericAdaptation::midiMessagesToVector(message); py::object result = me_->callMethod(kNumberFromDump, vector); - return MidiProgramNumber::fromZeroBase(result.cast()); + int programNumberReturned = result.cast(); + if (programNumberReturned >= 0) { + return MidiProgramNumber::fromZeroBase(programNumberReturned); + } + else { + return MidiProgramNumber::invalidProgram(); + } } catch (py::error_already_set &ex) { me_->logAdaptationError(kNumberFromDump, ex); @@ -117,7 +126,7 @@ namespace knobkraft { me_->logAdaptationError(kNumberFromDump, ex); } } - return MidiProgramNumber::fromZeroBase(0); + return MidiProgramNumber::invalidProgram(); } std::vector GenericProgramDumpCapability::patchToProgramDumpSysex(std::shared_ptr patch, MidiProgramNumber programNumber) const @@ -127,6 +136,10 @@ namespace knobkraft { { auto data = patch->data(); int c = me_->channel().toZeroBasedInt(); + if (c < 0) { + spdlog::warn("unknown channel in patchToProgramDumpSysex, defaulting to MIDI channel 1"); + c = 0; + } int programNo = programNumber.toZeroBasedWithBank(); py::object result = me_->callMethod(kConvertToProgramDump, c, data, programNo); std::vector byteData = GenericAdaptation::intVectorToByteVector(result.cast>()); diff --git a/adaptations/Novation_AStation.py b/adaptations/Novation_AStation.py index 1abfc385..c68484a7 100644 --- a/adaptations/Novation_AStation.py +++ b/adaptations/Novation_AStation.py @@ -112,7 +112,7 @@ def isSingleProgramDump(message): def numberFromDump(message): if not isSingleProgramDump(message): - return 0 + return -1 bank = message[11] bank = bank - 1 if bank > 0 else 0 # some program patch have bank == 0 program = message[12] diff --git a/adaptations/Novation_Summit.py b/adaptations/Novation_Summit.py index 577444f3..14c8a29b 100644 --- a/adaptations/Novation_Summit.py +++ b/adaptations/Novation_Summit.py @@ -80,7 +80,7 @@ def isSingleProgramDump(message): def numberFromDump(message): if not isSingleProgramDump(message): - return 0 + return -1 bank = message[12] % 4 # Not more than 4 banks allowed program = message[13] % 128 # Maximum 128 programs per bank return bank * 128 + program diff --git a/adaptations/Novation_UltraNova.py b/adaptations/Novation_UltraNova.py index ea489f5d..76246baf 100644 --- a/adaptations/Novation_UltraNova.py +++ b/adaptations/Novation_UltraNova.py @@ -126,7 +126,7 @@ def isSingleProgramDump(message): def numberFromDump(message): if not isSingleProgramDump(message): - return 0 + return -1 bank = message[11] bank = bank - 1 if bank > 0 else 0 # some program patch have bank == 0 program = message[12] diff --git a/adaptations/YamahaRefaceDX.py b/adaptations/YamahaRefaceDX.py index 1a289cc7..a99a7dec 100644 --- a/adaptations/YamahaRefaceDX.py +++ b/adaptations/YamahaRefaceDX.py @@ -257,9 +257,7 @@ def friendlyProgramName(programNo): def numberFromDump(message): - if isEditBufferDump(message): - return 0 - elif isSingleProgramDump(message): + if isSingleProgramDump(message): # The program number is in the bulkprogramheader return message[10] raise Exception("Can only extract program number from SingleProgramDumps!") diff --git a/adaptations/roland/GenericRoland.py b/adaptations/roland/GenericRoland.py index 93453b2f..917210e0 100644 --- a/adaptations/roland/GenericRoland.py +++ b/adaptations/roland/GenericRoland.py @@ -551,7 +551,7 @@ def numberFromDump(self, message) -> int: model = self.model_from_message(message) if model is not None: return model.numberFromDump(message) - return 0 + return -1 @knobkraft_api def nameFromDump(self, message) -> str: diff --git a/adaptations/test_BC_Kijimi.py b/adaptations/test_BC_Kijimi.py index 41a5ec56..711dfaa2 100644 --- a/adaptations/test_BC_Kijimi.py +++ b/adaptations/test_BC_Kijimi.py @@ -30,7 +30,6 @@ def test_BC_Kijimi(): edit_buffer = convertToEditBuffer(0, patch_from_device_message) assert isEditBufferDump(edit_buffer) assert nameFromDump(edit_buffer) == "Kijimi tmp" - assert numberFromDump(edit_buffer) == 0 program_back = convertToProgramDump(0, edit_buffer, 1) assert isSingleProgramDump(program_back) assert numberFromDump(program_back) == 1