#! /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 Modules
from typing import List , Set , Dict , Tuple
#Third Party Modules
from calfbox import cbox
#Template Modules
import template . engine . api #we need direct access to the module to inject data in the provided structures. but we also need the functions directly. next line:
from template . engine . api import *
#Our Modules
from engine . instrument import Instrument
#New callbacks
class ClientCallbacks ( Callbacks ) : #inherits from the templates api callbacks
def __init__ ( self ) :
super ( ) . __init__ ( )
self . tempCallback = [ ]
self . instrumentListMetadata = [ ]
self . startLoadingSamples = [ ]
self . instrumentStatusChanged = [ ]
self . auditionerInstrumentChanged = [ ]
def _tempCallback ( self ) :
""" Just for copy paste during development """
export = session . data . export ( )
for func in self . tempCallback :
func ( export )
callbacks . _dataChanged ( )
def _instrumentListMetadata ( self ) :
""" All libraries with all instruments as meta-data dicts. Hirarchy.
A dict of dicts .
Will be sent once on program start . Does not wait until actual samples are loaded
but as soon as all data is parsed . """
export = session . data . exportMetadata ( )
for func in self . instrumentListMetadata :
func ( export )
def _instrumentStatusChanged ( self , libraryId : int , instrumentId : int ) :
""" For example the current variant changed """
export = session . data . libraries [ libraryId ] . instruments [ instrumentId ] . exportStatus ( )
for func in self . instrumentStatusChanged :
func ( export )
callbacks . _dataChanged ( )
def _startLoadingSamples ( self , libraryId : int , instrumentId : int ) :
""" The sample loading of this instrument has started.
Start flashing an LED or so .
The end of loading is signaled by a statusChange callback with the current variant included
"""
key = ( libraryId , instrumentId )
for func in self . startLoadingSamples :
func ( key )
def _auditionerInstrumentChanged ( self , libraryId : int , instrumentId : int ) :
""" We just send the key. It is assumed that the receiver already has a key:metadata database """
export = session . data . libraries [ libraryId ] . instruments [ instrumentId ] . exportMetadata ( )
for func in self . auditionerInstrumentChanged :
func ( export )
#Inject our derived Callbacks into the parent module
template . engine . api . callbacks = ClientCallbacks ( )
from template . engine . api import callbacks
_templateStartEngine = startEngine
def startEngine ( nsmClient ) :
_templateStartEngine ( nsmClient ) #loads save files or creates empty structure.
#Send initial Callbacks to create the first GUI state.
#The order of initial callbacks must not change to avoid GUI problems.
#For example it is important that the tracks get created first and only then the number of measures
logger . info ( " Sending initial callbacks to GUI " )
callbacks . _instrumentListMetadata ( ) #Relatively quick. Happens only once in the program
#One round of status updates for all instruments. Still no samples loaded, but we saved the status of each with our own data.
for instrument in Instrument . allInstruments . values ( ) :
callbacks . _instrumentStatusChanged ( * instrument . idKey )
#loadSamples() #DEBUG
logger . info ( " Tembro api startEngine complete " )
def loadSamples ( ) :
""" Actually load all instrument samples """
for instrument in Instrument . allInstruments . values ( ) :
callbacks . _startLoadingSamples ( * instrument . idKey )
instrument . loadSamples ( )
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 )
callbacks . _auditionerInstrumentChanged ( libraryId , instrumentId )
def getAvailableAuditionerPorts ( ) - > dict :
""" Fetches a new port list each time it is called. No cache. """
return session . data . auditioner . getAvailablePorts ( )
def connectAuditionerPort ( externalPort : str ) :
""" externalPort is in the Client:Port JACK format.
If externalPort evaluates to False it will disconnect any port . """
session . data . auditioner . connectMidiInputPort ( externalPort )