Browse Source

Can now choose variant in the gui. Auditioner also respects current variant

master
Nils 3 years ago
parent
commit
5eb7704a2f
  1. 30
      engine/api.py
  2. 29
      engine/instrument.py
  3. 75
      qtgui/auditioner.py
  4. 20
      qtgui/designer/mainwindow.py
  5. 32
      qtgui/designer/mainwindow.ui
  6. 34
      qtgui/instrument.py
  7. 56
      qtgui/mainwindow.py
  8. 166
      qtgui/selectedinstrumentcontroller.py

30
engine/api.py

@ -107,12 +107,10 @@ def startEngine(nsmClient):
for instrument in Instrument.allInstruments.values():
callbacks._instrumentStatusChanged(*instrument.idKey)
#loadSamples() #DEBUG
logger.info("Tembro api startEngine complete")
def loadSamples():
def loadAllInstrumentSamples():
"""Actually load all instrument samples"""
for instrument in Instrument.allInstruments.values():
callbacks._startLoadingSamples(*instrument.idKey)
@ -120,13 +118,37 @@ def loadSamples():
callbacks._instrumentStatusChanged(*instrument.idKey)
callbacks._dataChanged
def unloadInstrumentSamples(idkey:tuple):
print ("unloading is not implemented yet")
instrument = Instrument.allInstruments[idkey]
callbacks._instrumentStatusChanged(*instrument.idKey)
def loadInstrumentSamples(idkey:tuple):
"""Load one .sfz from a library."""
instrument = Instrument.allInstruments[idkey]
callbacks._startLoadingSamples(*instrument.idKey)
instrument.loadSamples()
callbacks._instrumentStatusChanged(*instrument.idKey)
callbacks._dataChanged
def chooseVariantByIndex(idkey:tuple, variantIndex:int):
"""Choose a variant of an already enabled instrument"""
libraryId, instrumentId = idkey
instrument = Instrument.allInstruments[idkey]
instrument.chooseVariantByIndex(variantIndex)
callbacks._instrumentStatusChanged(*instrument.idKey)
callbacks._dataChanged
def auditionerInstrument(idkey:tuple):
"""Load an indendepent instance of an instrument into the auditioner port"""
libraryId, instrumentId = idkey
originalInstrument = Instrument.allInstruments[idkey]
#It does not matter if the originalInstrument has its samples loaded or not. We just want the path
session.data.auditioner.loadInstrument(originalInstrument.tarFilePath, originalInstrument.defaultVariant)
if originalInstrument.currentVariant:
var = originalInstrument.currentVariant
else:
var = originalInstrument.defaultVariant
session.data.auditioner.loadInstrument(originalInstrument.tarFilePath, var)
callbacks._auditionerInstrumentChanged(libraryId, instrumentId)
def getAvailableAuditionerPorts()->dict:

29
engine/instrument.py

@ -100,7 +100,7 @@ class Instrument(object):
self.midiInputPortName = metadata["name"]
self.variants = metadata["variants"].split(",")
self.defaultVariant = metadata["defaultVariant"]
self.enabled = True #means loaded.
self.enabled = False #means loaded.
#Calfbox. The JACK ports are constructed without samples at first.
@ -149,6 +149,7 @@ class Instrument(object):
#Dynamic data
result["currentVariant"] = self.currentVariant # str
result["currentVariantWithoutSfzExtension"] = self.currentVariant.rstrip(".sfz") if self.currentVariant else ""# str
result["state"] = self.enabled #bool
return result
@ -161,29 +162,51 @@ class Instrument(object):
Please note that we don't add the default variant here. It is only important for the
external world to know what the current variant is. Which is handled by self.exportStatus()
"""
parentMetadata = self.parentLibrary.config["library"]
result = {}
result["id"] = self.metadata["id"] #int
result["id-key"] = self.idKey # tuple (int, int) redundancy for convenience.
result["name"] = self.metadata["name"] #str
result["description"] = self.metadata["description"] #str
result["variants"] = self.variants #list of str
result["variantsWithoutSfzExtension"] = [var.rstrip(".sfz") for var in self.variants] #list of str
result["defaultVariant"] = self.metadata["defaultVariant"] #str
result["defaultVariantWithoutSfzExtension"] = self.metadata["defaultVariant"].rstrip(".sfz") #str
result["tags"] = self.metadata["tags"].split(",") # list of str
#Optional Tags.
result["license"] = self.metadata["license"] if "license" in self.metadata else "" #str
result["vendor"] = self.metadata["vendor"] if "vendor" in self.metadata else "" #str
result["group"] = self.metadata["group"] if "group" in self.metadata else "" #str
#While license replaces the library license, vendor is an addition:
if "license" in self.metadata:
result["license"] = self.metadata["license"]
else:
result["license"] = parentMetadata["license"]
if "vendor" in self.metadata:
result["vendor"] = parentMetadata["vendor"] + "\n\n" + self.metadata["vendor"]
else:
result["vendor"] = parentMetadata["vendor"]
return result
def loadSamples(self):
"""Instrument is constructed without loading the sample data. But the JACK Port and
all Python objects exist. The API can instruct the loading when everything is ready,
so that the callbacks can receive load-progress messages"""
self.enable()
if self.startVariantSfzFilename:
self.chooseVariant(self.startVariantSfzFilename)
else:
self.chooseVariant(self.metadata["defaultVariant"])
def chooseVariantByIndex(self, index:int):
"""The variant list is static. Instead of a name we can just choose by index.
This is convenient for functions that choose the variant by a list index"""
variantSfzFileName = self.variants[index]
self.chooseVariant(variantSfzFileName)
def chooseVariant(self, variantSfzFileName:str):
"""load_patch_from_tar is blocking. This function will return when the instrument is ready
to play.

75
qtgui/auditioner.py

@ -0,0 +1,75 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2021, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This file is part of the Laborejo Software Suite ( https://www.laborejo.org ),
This application 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, see <http://www.gnu.org/licenses/>.
"""
import logging; logging.info("import {}".format(__file__))
#Standard Library Modules
#Third Party Modules
from PyQt5 import QtWidgets, QtCore, QtGui
#Template Modules
#Our modules
import engine.api as api
class AuditionerMidiInputComboController(object):
def __init__(self, parentMainWindow):
self.parentMainWindow = parentMainWindow
self.comboBox = parentMainWindow.ui.auditionerMidiInputComboBox
self.wholePanel = parentMainWindow.ui.auditionerWidget
self.currentInstrumentLabel = parentMainWindow.ui.auditionerCurrentInstrument_label
self.currentInstrumentLabel.setText("")
#if not api.isStandaloneMode():
#self.wholePanel.hide()
#return
self.wholePanel.show() #explicit is better than implicit
self.originalShowPopup = self.comboBox.showPopup
self.comboBox.showPopup = self.showPopup
self.comboBox.activated.connect(self._newPortChosen)
api.callbacks.auditionerInstrumentChanged.append(self.callback_auditionerInstrumentChanged)
def callback_auditionerInstrumentChanged(self, exportMetadata:dict):
key = exportMetadata["id-key"]
t = f"➜ [{key[0]}-{key[1]}] {exportMetadata['name']}"
self.currentInstrumentLabel.setText(t)
def _newPortChosen(self, index:int):
assert self.comboBox.currentIndex() == index
api.connectAuditionerPort(self.comboBox.currentText())
def showPopup(self):
"""When the combobox is opened quickly update the port list before showing it"""
self._fill()
self.originalShowPopup()
def _fill(self):
self.comboBox.clear()
availablePorts = api.getAvailableAuditionerPorts()
self.comboBox.addItem("") # Not only a more visible seaparator than the Qt one, but also doubles as "disconnect"
self.comboBox.addItems(availablePorts["hardware"])
#self.comboBox.insertSeparator(len(availablePorts["hardware"])+1)
self.comboBox.addItem("") # Not only a more visible seaparator than the Qt one, but also doubles as "disconnect"
self.comboBox.addItems(availablePorts["software"])

20
qtgui/designer/mainwindow.py

@ -77,8 +77,21 @@ class Ui_MainWindow(object):
self.details_scrollArea.setWidgetResizable(True)
self.details_scrollArea.setObjectName("details_scrollArea")
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 545, 158))
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 598, 158))
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
self.formLayout = QtWidgets.QFormLayout(self.scrollAreaWidgetContents)
self.formLayout.setObjectName("formLayout")
self.variant_label = QtWidgets.QLabel(self.scrollAreaWidgetContents)
self.variant_label.setObjectName("variant_label")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.variant_label)
self.variants_comboBox = QtWidgets.QComboBox(self.scrollAreaWidgetContents)
self.variants_comboBox.setObjectName("variants_comboBox")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.variants_comboBox)
self.info_label = QtWidgets.QLabel(self.scrollAreaWidgetContents)
self.info_label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
self.info_label.setWordWrap(True)
self.info_label.setObjectName("info_label")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.info_label)
self.details_scrollArea.setWidget(self.scrollAreaWidgetContents)
self.verticalLayout_3.addWidget(self.details_scrollArea)
self.verticalLayout.addWidget(self.splitter_2)
@ -90,8 +103,6 @@ class Ui_MainWindow(object):
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.actionRofl = QtWidgets.QAction(MainWindow)
self.actionRofl.setObjectName("actionRofl")
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
@ -108,4 +119,5 @@ class Ui_MainWindow(object):
self.instruments_treeWidget.headerItem().setText(3, _translate("MainWindow", "Variant"))
self.instruments_treeWidget.headerItem().setText(4, _translate("MainWindow", "Tags"))
self.details_groupBox.setTitle(_translate("MainWindow", "NamePlaceholder"))
self.actionRofl.setText(_translate("MainWindow", "Rofl!"))
self.variant_label.setText(_translate("MainWindow", "Variants"))
self.info_label.setText(_translate("MainWindow", "TextLabel"))

32
qtgui/designer/mainwindow.ui

@ -191,10 +191,35 @@
<rect>
<x>0</x>
<y>0</y>
<width>545</width>
<width>598</width>
<height>158</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="variant_label">
<property name="text">
<string>Variants</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="variants_comboBox"/>
</item>
<item row="1" column="1">
<widget class="QLabel" name="info_label">
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
@ -216,11 +241,6 @@
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionRofl">
<property name="text">
<string>Rofl!</string>
</property>
</action>
</widget>
<resources/>
<connections/>

34
qtgui/instrument.py

@ -69,7 +69,7 @@ class InstrumentTreeController(object):
self.treeWidget.header().setSortIndicator(0,0)
self.treeWidget.itemDoubleClicked.connect(self.itemDoubleClicked)
#self.treeWidget.itemSelectionChanged = self.itemSelectionChanged
self.treeWidget.itemSelectionChanged.connect(self.itemSelectionChanged)
self.sortByColumnValue = 1 #by instrId
self.sortDescendingValue = 0 # Qt::SortOrder which is 0 for ascending and 1 for descending
@ -79,6 +79,18 @@ class InstrumentTreeController(object):
api.callbacks.instrumentStatusChanged.append(self.react_instrumentStatusChanged)
def itemSelectionChanged(self):
"""Only one instrument can be selected at the same time.
This function mostly informs other widgets that a different instrument was selected
"""
selItems = self.treeWidget.selectedItems()
assert len(selItems) == 1, selItems #because our selection is set to single
item = selItems[0]
if type(item) is GuiInstrument:
self.parentMainWindow.selectedInstrumentController.instrumentChanged(item.idkey)
else:
self.parentMainWindow.selectedInstrumentController.directLibrary(item.idkey)
def itemDoubleClicked(self, item:QtWidgets.QTreeWidgetItem, column:int):
if type(item) is GuiInstrument:
api.auditionerInstrument(item.idkey)
@ -198,10 +210,12 @@ class GuiLibrary(QtWidgets.QTreeWidgetItem):
def __init__(self, parentTreeController, libraryDict):
super().__init__([], type=1000) #type 0 is default qt type. 1000 is subclassed user type)
self.idkey = (libraryDict["id"], 0) #fake it for compatibility
#No dynamic data here. Everything gets created once.
self.setText(COLUMNS.index("id-key"), str(libraryDict["id"]))
self.setText(COLUMNS.index("name"), str(libraryDict["name"]))
self.setText(COLUMNS.index("tags"), str(libraryDict["description"]))
self.setText(COLUMNS.index("tags"), str(libraryDict["description"])[:42]+"")
class GuiInstrument(QtWidgets.QTreeWidgetItem):
@ -243,16 +257,24 @@ class GuiInstrument(QtWidgets.QTreeWidgetItem):
self.toggleSwitch = ToggleSwitch()
self.toggleSwitch.setAutoFillBackground(True) #otherwise conflicts with setItemWidget
self.toggleSwitch.toggled.connect(lambda c: print('toggled', c))
self.toggleSwitch.clicked.connect(lambda c: print('clicked', c))
self.toggleSwitch.pressed.connect(lambda: print('pressed'))
self.toggleSwitch.released.connect(lambda: print('released'))
#self.toggleSwitch.toggled.connect(lambda c: print('toggled', c)) #triggered by engine callback as well
self.toggleSwitch.clicked.connect(self.instrumentSwitchOnViaGui)
#self.toggleSwitch.pressed.connect(lambda: print('pressed')) #literal mouse down.
#self.toggleSwitch.released.connect(lambda: print('released'))
#We cannot add the ToggleSwitch Widget here.
#It must be inserted after self was added to the Tree. Use self.injectToggleSwitch from parent
def instrumentSwitchOnViaGui(self, state):
"""Only GUI clicks. Does not react to the engine callback that switches on instruments. For
example one that arrives through "load group" or "load all" """
if state:
api.loadInstrumentSamples(self.idkey)
else:
api.unloadInstrumentSamples(self.idkey)
def updateStatus(self, instrumentStatus:dict):
variantColumnIndex = self.columns.index("loaded")
self.currentVariant = instrumentStatus["currentVariant"]

56
qtgui/mainwindow.py

@ -35,7 +35,8 @@ from template.qtgui.about import About
import engine.api as api
from .instrument import InstrumentTreeController
from .auditioner import AuditionerMidiInputComboController
from .selectedinstrumentcontroller import SelectedInstrumentController
class MainWindow(TemplateMainWindow):
@ -55,6 +56,7 @@ class MainWindow(TemplateMainWindow):
#Do not start them all with "You can..." or "...that you can", in response to the Did you know? title.
#We use injection into the class and not a parameter because this dialog gets shown by creating an object. We can't give the parameters when this is shown via the mainWindow menu.
About.didYouKnow = [
QtCore.QCoreApplication.translate("About", "Double click an instrument to load it into the special Auditioner slot."),
QtCore.QCoreApplication.translate("About", "There is no way to load your own instruments into this program. If you create your own instruments and would like them to be included please contact the developers for a collaboration.")
] + About.didYouKnow
@ -62,12 +64,17 @@ class MainWindow(TemplateMainWindow):
#make the search bar smaller
self.ui.search_groupBox.setMinimumSize(30, 1)
self.ui.splitter_2.setSizes([1,1])
self.ui.splitter_2.setSizes([1,1]) #just a forced update
#Make the description field at least a bit visible
self.ui.details_groupBox.setMinimumSize(1, 50)
self.ui.splitter.setSizes([1,1]) #just a forced update
self.setupMenu()
self.auditionerMidiInputComboController = AuditionerMidiInputComboController(parentMainWindow=self)
self.instrumentTreeController = InstrumentTreeController(parentMainWindow=self)
self.selectedInstrumentController = SelectedInstrumentController(parentMainWindow=self)
self.start() #This shows the GUI, or not, depends on the NSM gui save setting. We need to call that after the menu, otherwise the about dialog will block and then we get new menu entries, which looks strange.
@ -77,53 +84,10 @@ class MainWindow(TemplateMainWindow):
#New menu entries and template-menu overrides
#self.menu.connectMenuEntry("actionAbout", lambda: print("About Dialog Menu deactivated")) #deactivates the original function
self.menu.addMenuEntry("menuEdit", "actionNils", "Nils", lambda: print("Merle"))
self.menu.addMenuEntry("menuEdit", "actionLoadSamples", "LoadSamples", api.loadSamples)
self.menu.addMenuEntry("menuEdit", "actionLoadSamples", "Load all Instrument Samples", api.loadAllInstrumentSamples)
#self.menu.connectMenuEntry("actionNils", lambda: print("Override"))
def zoom(self, scaleFactor:float):
pass
def stretchXCoordinates(self, factor):
pass
class AuditionerMidiInputComboController(object):
def __init__(self, parentMainWindow):
self.parentMainWindow = parentMainWindow
self.comboBox = parentMainWindow.ui.auditionerMidiInputComboBox
self.wholePanel = parentMainWindow.ui.auditionerWidget
self.currentInstrumentLabel = parentMainWindow.ui.auditionerCurrentInstrument_label
self.currentInstrumentLabel.setText("")
#if not api.isStandaloneMode():
#self.wholePanel.hide()
#return
self.wholePanel.show() #explicit is better than implicit
self.originalShowPopup = self.comboBox.showPopup
self.comboBox.showPopup = self.showPopup
self.comboBox.activated.connect(self._newPortChosen)
api.callbacks.auditionerInstrumentChanged.append(self.callback_auditionerInstrumentChanged)
def callback_auditionerInstrumentChanged(self, exportMetadata:dict):
key = exportMetadata["id-key"]
t = f"➜ [{key[0]}-{key[1]}] {exportMetadata['name']}"
self.currentInstrumentLabel.setText(t)
def _newPortChosen(self, index:int):
assert self.comboBox.currentIndex() == index
api.connectAuditionerPort(self.comboBox.currentText())
def showPopup(self):
"""When the combobox is opened quickly update the port list before showing it"""
self._fill()
self.originalShowPopup()
def _fill(self):
self.comboBox.clear()
availablePorts = api.getAvailableAuditionerPorts()
self.comboBox.addItems(availablePorts["hardware"])
#self.comboBox.insertSeparator(len(availablePorts["hardware"])+1)
self.comboBox.addItem("") # Not only a more visible seaparator than the Qt one, but also doubles as "disconnect"
self.comboBox.addItems(availablePorts["software"])

166
qtgui/selectedinstrumentcontroller.py

@ -0,0 +1,166 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2021, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This file is part of the Laborejo Software Suite ( https://www.laborejo.org ),
This application 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, see <http://www.gnu.org/licenses/>.
"""
import logging; logger = logging.getLogger(__name__); logger.info("import")
#Standard Library
#Third Party
from PyQt5 import QtCore, QtGui, QtWidgets
#Our Qt
#Engine
import engine.api as api
class SelectedInstrumentController(object):
"""Not a qt class. We externally control a collection of widgets.
There is only one set of widgets. We change their contents dynamically.
"""
def __init__(self, parentMainWindow):
self.parentMainWindow = parentMainWindow
self.currentIdKey = None
self.engineData = {} # id-key tuple : engine library metadata dict.
self.statusUpdates = {} # same as engineData, but with incremental status updates. One is guranteed to exist at startup
#Our Widgets
self.ui = parentMainWindow.ui
self.ui.details_groupBox.setTitle("")
self.ui.details_scrollArea.hide() #until the first instrument was selected
self.ui.variants_comboBox.activated.connect(self._newVariantChosen)
#Callbacks
api.callbacks.instrumentListMetadata.append(self.react_initialInstrumentList)
api.callbacks.instrumentStatusChanged.append(self.react_instrumentStatusChanged)
def directLibrary(self, idkey:tuple):
"""User clicked on a library treeItem"""
libraryId, instrumentId = idkey
self.currentIdKey = None
self.ui.details_scrollArea.show()
self.ui.variants_comboBox.hide()
self.ui.variant_label.hide()
metadata = self.engineData[libraryId]["library"]
self.ui.details_groupBox.setTitle(metadata["name"])
self.ui.info_label.setText(self._metadataToDescriptionLabel(metadata))
def _metadataToDescriptionLabel(self, metadata:dict)->str:
"""Can work with instruments and libraries alike"""
if "variants" in metadata: #this is an instrument
fullText = metadata["description"] + "\n\nVendor: " + metadata["vendor"] + "\n\nLicense: " + metadata["license"]
else:
fullText = metadata["description"] + "\n\nVendor: " + metadata["vendor"]
return fullText
def _newVariantChosen(self, index:int):
"""User chose a new variant through the combo box"""
assert self.ui.variants_comboBox.currentIndex() == index
assert self.currentIdKey
api.chooseVariantByIndex(self.currentIdKey, index)
def instrumentChanged(self, idkey:tuple):
"""This is a GUI-internal function. The user selected a different instrument from
the list. Single click, arrow keys etc.
We combine static metadata, which we saved ourselves, with the current instrument status
(e.g. which variant was chosen).
"""
libraryId, instrumentId = idkey
self.currentIdKey = idkey
self.ui.details_scrollArea.show()
#Static
instrumentData = self.engineData[libraryId][instrumentId]
self.ui.details_groupBox.setTitle(instrumentData["name"])
self.ui.variant_label.show()
self.ui.variants_comboBox.show()
self.ui.variants_comboBox.clear()
self.ui.variants_comboBox.addItems(instrumentData["variantsWithoutSfzExtension"])
self.ui.info_label.setText(self._metadataToDescriptionLabel(instrumentData))
#Dynamic
self.react_instrumentStatusChanged(self.statusUpdates[libraryId][instrumentId])
def react_instrumentStatusChanged(self, instrumentStatus:dict):
"""Callback from the api. Has nothing to do with any GUI state or selection.
Data:
#Static ids
result["id"] = self.metadata["id"]
result["id-key"] = self.idKey #redundancy for convenience.
#Dynamic data
result["currentVariant"] = self.currentVariant # str
result["state"] = self.enabled #bool
"""
idkey = instrumentStatus["id-key"]
libraryId, instrumentId = idkey
if not libraryId in self.statusUpdates:
self.statusUpdates[libraryId] = {} #empty library. status dict
self.statusUpdates[libraryId][instrumentId] = instrumentStatus #create or overwrite / keep up to date
loadState = instrumentStatus["state"]
instrumentData = self.engineData[libraryId][instrumentId]
instrumentStatus = self.statusUpdates[libraryId][instrumentId]
if loadState: #None if not loaded
self.ui.variants_comboBox.setEnabled(True)
currentVariantIndex = instrumentData["variantsWithoutSfzExtension"].index(instrumentStatus["currentVariantWithoutSfzExtension"])
self.ui.variants_comboBox.setCurrentIndex(currentVariantIndex)
else:
self.ui.variants_comboBox.setEnabled(False)
defaultVariantIndex = instrumentData["variantsWithoutSfzExtension"].index(instrumentData["defaultVariantWithoutSfzExtension"])
self.ui.variants_comboBox.setCurrentIndex(defaultVariantIndex)
def react_initialInstrumentList(self, data:dict):
"""For data form see docstring of instrument.py buildTree()
Summary:
libraryid : dict ->
instrumentid : metadatadict
Dict-Keys are always the same. Some always have data, some can be empty.
We receive this once at program start and build our permanent GUI widgets from it.
The additional status update callback for dynamic data is handled in
self.react_instrumentStatusChanged
"""
self.engineData = data
Loading…
Cancel
Save