You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

101 lines
4.2 KiB

#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2022, 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")
from typing import Dict
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 *
import template.engine.ly2cbox as ly2cbox
#New callbacks
class ClientCallbacks(Callbacks): #inherits from the templates api callbacks
def __init__(self):
super().__init__()
#Inject our derived Callbacks into the parent module
template.engine.api.callbacks = ClientCallbacks()
from template.engine.api import callbacks
playTestSignals:Dict[int, bytes] = {} #channel:cboxPatternBytes patterns are defined in startEngine because we obviously need to wait for cbox to be ready.
_templateStartEngine = startEngine
def startEngine(nsmClient, additionalData:dict={}): # type: ignore
_templateStartEngine(nsmClient, additionalData)
#Populate Channel Activity and Channel Instrument Changes midi callbacks
_registerMidiCallbacks()
global playTestSignals
playTestSignals = {channel : ly2cbox.pattern("c'16 g c", channel) for channel in range(1, 17)}
#Send initial Data etc.
logger.info("Sending initial callbacks to GUI")
callbacks._soundfontChanged()
callbacks._ignoreProgramChangesChanged()
#Maybe autoconnect the mixer.
if session.standaloneMode and additionalData["autoconnectMixer"]: #this is only for startup.
connectMixerToSystemPorts()
logger.info("Fluajho api startEngine complete")
def _registerMidiCallbacks():
"""This needs to be a function to delay execution until we have a session and nsm loaded
our data."""
from template.engine.input_midi import MidiProcessor
def _NoteOn(timestamp, channel, m_note, m_velocity):
callbacks._channelActivity(channel+1)
def _controlChange(timestamp, channel, cc_type, m_value):
"""Includes Bank Change, which is a CC.
Jack-Keyboard and other programs send this even if only a program changed. This will
trigger our GUI to update the whole channel as well, but technically we don't react to
an individual program change here.
"""
if cc_type == MidiProcessor.CC_BANKCHANGE_COARSE or cc_type == MidiProcessor.CC_BANKCHANGE_FINE:
callbacks._channelChanged(channel+1)
def _programChange(timestamp, channel, value):
"""The callbacks receiver will fetch the new program values on its own"""
callbacks._channelChanged(channel+1)
session.data.midiInput.midiProcessor.register_NoteOn(_NoteOn)
session.data.midiInput.midiProcessor.register_CC(_controlChange)
session.data.midiInput.midiProcessor.register_ProgramChange(_programChange)
def connectMixerToSystemPorts():
session.data.connectMixerToSystemPorts()
#Sampler
def playTestSignal(channel:int):
"""Channel 1-16
Play a short test chime to verify that sound is working and to see how the instrument sounds"""
#patterns are defined in startEngine because we obviously need to wait for cbox to be ready.
if channel <1 or channel > 16:
raise ValueError(f"Midi Channel must be between 1 and 16 inclusive. Yours is {channel}")
callbacks._channelActivity(channel)
session.data.midiInput.scene.play_pattern(playTestSignals[channel], 150.0, id=channel) #If there is already an adhoc pattern with a given non-zero id, stop it and release all the pending notes. Retry until all the notes are released.