1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
from time import sleep
from signal import SIGKILL
from os import getpid, kill
if __name__ == "__main__":
import argparse, os
parser = argparse.ArgumentParser(description="Laborejo Qt")
parser.add_argument('infiles', help="One or more lbjs or lbj files to load.", nargs="*")
parser.add_argument("-n", "--new", help="Start with an empty file (additionally to loaded files)", action="store_true")
parser.add_argument("-c", "--config", help="The configuration dir for user scripts, templates and configs etc. Default=~/.laborejo/", type=str)
parser.add_argument("-g", "--geometry", help="Start with a window geometry 'width x height' or 'width x height + leftCorner + rightCorner'. Example A: 1024x768 Example B: 1920x1080+0+0", type=str, default=None)
parser.add_argument("-m", "--mute", help ="Don't start the audio/midi engine. You need this for playback but it can be turned off if you don't want JACK or for performance reasons", action="store_true")
parser.add_argument("-j", "--jack", help ="Start with active JACK Mode instead of internal sampler mode. Can be toggled at any time in the program again.", action="store_true")
parser.add_argument("-i", "--midiin", help="Jack Midi input port for note insert. No ALSA. Example: jack-keyboad:midi_out . Default: as sepcified in config file.", type=str, default=None)
parser.add_argument("-l", "--lonely", help ="Don't connect any jack ports, not even a given jack midi port --midiin. Use this if you restore your jack connections with an external tool. This is not needed for Non-Session-Manager support.", action="store_true")
parser.add_argument("-s", "--soundfont", help="A path to an alternative .sf2 soundfont to be used by the internal midi sampler. Example /usr/share/soundfonts/fluidr3/FluidR3GM.SF2", type=str, default=None)
args = parser.parse_args()
#initialize the GUI. We do this after parse init
#because if it were just --help we don't need to start the whole Qt chain.
import laborejoqt
from laborejoqt import laborejoqtnsmclient as nsmclient #laborejoqtnsmclient.py is a local file.
"""
If Laborejo was started through the non-session manager this means
nsmclient.states.nsmUrl is True.
We use this information to change some functions in the program.
Many parser arguments will be ignored. We automatically assume
NSM means Jack is working as well.
"""
if args.config:
p = os.path.realpath(args.config) + "/"
print ("Starting Laborejo-Qt with config directory", p)
laborejoqt.api._getSession().configdir = p
laborejoqt.config.JACKMODE = bool(nsmclient.states.nsmUrl) or args.jack
laborejoqt.main = laborejoqt.StartQT4(geometry = args.geometry, nonSessionManager = nsmclient.states.nsmUrl)
if (laborejoqt.config.JACK and not args.mute) or nsmclient.states.nsmUrl:
midiInTimer = laborejoqt.QtCore.QTimer()
midiInTimer.start(laborejoqt.config.MIDI_TIMER) #50ms default
if nsmclient.states.nsmUrl:
#Initialize the session handler:
##after we have the functions from laborejoqt.main
##but before init calfbox since we need the unique session id to load/save files and create jack ports
capabilities = {
"switch" : False, #client is capable of responding to multiple `open` messages without restarting
"dirty" : True, #client knows when it has unsaved changes
"progress" : False, #client can send progress updates during time-consuming operations
"message" : False, #client can send textual status updates
"optional-gui" : True, #client has an optional GUI
}
requiredFunctions = {
"function_open" : laborejoqt.main.nsmLoad, #Accept two parameters. Return two values. A bool and a status string. Otherwise you'll get a message that does not help at all: "Exception TypeError: "'NoneType' object is not iterable" in 'liblo._callback' ignored"
"function_save" : laborejoqt.main.nsmSave, #Accept one parameter. Return two values. A bool and a status string. Otherwise you'll get a message that does not help at all: "Exception TypeError: "'NoneType' object is not iterable" in 'liblo._callback' ignored"
}
def quitty():
try:
laborejoqt.api.calfboxShutdown()
except:
pass
try:
midiInTimer.stop()
except:
pass
kill(getpid(), SIGKILL) #Killing Blow, if those above fail.
optionalFunctions = {
"function_quit" : quitty, #Accept zero parameters. Return True or False
"function_showGui" : laborejoqt.main.show, #Accept zero parameters. Return True or False
"function_hideGui" : laborejoqt.main.hide, #Accept zero parameters. Return True or False
}
laborejoqt.main.session.ourNsmClient, nsmReturnedTimerFunction = nsmclient.init(
prettyName = "LaborejoQt",
capabilities = capabilities,
requiredFunctions = requiredFunctions,
optionalFunctions = optionalFunctions,
sleepValueMs = 0) #no additional sleeps. The qt timer takes care of that
#Now start the timer. Hopefully that gives us nsmClientId from nsmLoad() before we init cbox
laborejoqt.QtCore.QObject.connect(midiInTimer, laborejoqt.QtCore.SIGNAL("timeout()"), nsmReturnedTimerFunction)
if nsmclient.states.nsmUrl:
#The qt timer starts only when we call laborejoqt.app.exec_(), which starts the event loop.
#We need the nsmLoad() function for nsmClientId. Call the osc query manually until we get something.
while not laborejoqt.main.session.nsmClientId:
nsmReturnedTimerFunction()
sleep(0.3)
laborejoqt.api.calfboxInit(None, autoconnect = False, clientName = laborejoqt.main.session.nsmClientId) #If soundfont is none it falls back to a small default GM provided within the Laborejo source tree
elif laborejoqt.config.JACK and not args.mute:
midiInPort = args.midiin if args.midiin else laborejoqt.config.midiinport
laborejoqt.api.calfboxInit(
args.soundfont, #If soundfont is none it falls back to a small default GM provided within the Laborejo source tree
autoconnect=not args.lonely,
midiInPort = midiInPort)
if laborejoqt.api.cboxSmfCompatibleModule: #started succesfully?
laborejoqt.main.session.playbackEngine = True
laborejoqt.QtCore.QObject.connect(midiInTimer, laborejoqt.QtCore.SIGNAL("timeout()"), laborejoqt.api.calfboxProcessor)
laborejoqt.main.createMidiShortcuts()
laborejoqt.api.calfboxSetTransportKeepRolling(laborejoqt.config.TRANSPORT_KEEP_ROLLING) #live update.
else:
laborejoqt.main.session.playbackEngine = False
if nsmclient.states.nsmUrl:
raise RuntimeError("You tried to run Laborejo-Qt in NSM mode but the playback engine could not be started. You need JACK started and calfbox/calfbox python module installed for session management")
laborejoqt.listener.main = laborejoqt.main #We need this before initializing the listeners below. This is also the reason why we can't move this code into the listener module.
laborejoqt.listener.init() #Connect the listeners with the backend.
#load command line files. A new empty file can also be opened, does not conflict with loading files.
if args.infiles and not nsmclient.states.nsmUrl:
lbjsScoreFiles = [x for x in args.infiles if x.endswith(".lbjs")]
lbjCollectionFiles = [x for x in args.infiles if x.endswith(".lbj")]
if lbjsScoreFiles:
laborejoqt.main.load(lbjsScoreFiles)
if lbjCollectionFiles:
laborejoqt.main.loadCollection(lbjCollectionFiles)
if args.new and not nsmclient.states.nsmUrl:
laborejoqt.api.new()
#else it is just an empty program start
if not nsmclient.states.nsmUrl:
from atexit import register
register(laborejoqt.api.calfboxShutdown) #On Exit shut down the jack client properly. Even if started with -m this will not fail. There is a "try" inside.
#else:
#NSM has its own exit signal. We will use that instead.
laborejoqt.api.jackMidiInToggleMute(boolean = False)
if nsmclient.states.nsmUrl:
laborejoqt.QtCore.QTimer.singleShot(0, laborejoqt.main.nsmActuallyLoadFirstFiles)
laborejoqt.app.exec_()
|