Browse Source

update template

master
Nils 4 years ago
parent
commit
8c90857e9a
  1. 7
      template/engine/api.py
  2. 49
      template/engine/sampler_sf2.py
  3. 4
      template/engine/session.py
  4. 6
      template/helper.py
  5. 2
      template/qtgui/mainwindow.py
  6. 20
      template/qtgui/nsmclient.py
  7. 78
      template/start.py

7
template/engine/api.py

@ -130,6 +130,8 @@ class Callbacks(object):
def _setPlaybackTicks(self): def _setPlaybackTicks(self):
"""This gets called very very often. Any connected function needs to watch closely
for performance issues"""
ppqn = cbox.Transport.status().pos_ppqn ppqn = cbox.Transport.status().pos_ppqn
status = playbackStatus() status = playbackStatus()
for func in self.setPlaybackTicks: for func in self.setPlaybackTicks:
@ -146,6 +148,8 @@ class Callbacks(object):
This is deprecated. Append to _checkPlaybackStatusAndSendSignal which is checked by the This is deprecated. Append to _checkPlaybackStatusAndSendSignal which is checked by the
event loop. event loop.
""" """
raise NotImplementedError("this function was deprecated. use _checkPlaybackStatusAndSendSignal")
pass #only keep for the docstring and to keep the pattern. pass #only keep for the docstring and to keep the pattern.
def _checkPlaybackStatusAndSendSignal(self): def _checkPlaybackStatusAndSendSignal(self):
@ -286,6 +290,7 @@ def startEngine(nsmClient):
it takes after imports. it takes after imports.
""" """
logger.info("Starting template api engine")
assert session assert session
assert callbacks assert callbacks
@ -301,6 +306,8 @@ def startEngine(nsmClient):
callbacks._recordingModeChanged() #recording mode is in the save file. callbacks._recordingModeChanged() #recording mode is in the save file.
callbacks._historyChanged() #send initial undo status to the GUI, which will probably deactivate its undo/redo menu because it is empty. callbacks._historyChanged() #send initial undo status to the GUI, which will probably deactivate its undo/redo menu because it is empty.
logger.info("Template api engine started")
def _deprecated_updatePlayback(): def _deprecated_updatePlayback():
"""The only place in the program to update the cbox playback besides startEngine. """The only place in the program to update the cbox playback besides startEngine.

49
template/engine/sampler_sf2.py

@ -53,8 +53,8 @@ class Sampler_sf2(Data):
self.patchlist = {} #bank:{program:name} self.patchlist = {} #bank:{program:name}
self.buffer_ignoreProgramChanges = ignoreProgramChanges self.buffer_ignoreProgramChanges = ignoreProgramChanges
self.midiInput = MidiInput(session=parentSession, portName="in") self.midiInput = MidiInput(session=parentSession, portName="in")
#Set libfluidsynth! to 16 output pairs. We prepared 32 jack ports in the session start. "soundfont" is our given name, in the line below. This is a prepared config which will be looked up by add_new_instrument #Set libfluidsynth! to 16 output pairs. We prepared 32 jack ports in the session start. "soundfont" is our given name, in the line below. This is a prepared config which will be looked up by add_new_instrument
cbox.Config.set("instrument:soundfont", "engine", "fluidsynth") cbox.Config.set("instrument:soundfont", "engine", "fluidsynth")
cbox.Config.set("instrument:soundfont", "output_pairs", 16) #this is not the same as session.py cbox.Config.set("io", "outputs", METADATA["cboxOutputs"]). It is yet another layer and those two need connections cbox.Config.set("instrument:soundfont", "output_pairs", 16) #this is not the same as session.py cbox.Config.set("io", "outputs", METADATA["cboxOutputs"]). It is yet another layer and those two need connections
@ -68,31 +68,38 @@ class Sampler_sf2(Data):
self.midiInput.scene.status().layers[0].set_ignore_program_changes(ignoreProgramChanges) self.midiInput.scene.status().layers[0].set_ignore_program_changes(ignoreProgramChanges)
assert self._ignoreProgramChanges == ignoreProgramChanges assert self._ignoreProgramChanges == ignoreProgramChanges
#Active patches is a dynamic value. Load the saved ones here, but do not save their state locally #Active patches is a dynamic value. Load the saved ones here, but do not save their state locally
try: try:
self.setActivePatches(activePatches) self.setActivePatches(activePatches)
except: except:
self._correctActivePatches() self._correctActivePatches()
#Create a dynamic pair of audio output ports and route all stereo pairs to our summing channel. #Create a dynamic pair of audio output ports and route all stereo pairs to our summing channel.
#This does _not_ need updating when loading another sf2 or changing instruments. #This does _not_ need updating when loading another sf2 or changing instruments.
lmixUuid = cbox.JackIO.create_audio_output('left_mix', "#1") #add "#1" as second parameter for auto-connection to system out 1
rmixUuid = cbox.JackIO.create_audio_output('right_mix', "#2") #add "#2" as second parameter for auto-connection to system out 2 assert not self.parentSession.standaloneMode is None
for i in range(16): if self.parentSession.standaloneMode:
lmixUuid = cbox.JackIO.create_audio_output('left_mix', "#1") #add "#1" as second parameter for auto-connection to system out 1
rmixUuid = cbox.JackIO.create_audio_output('right_mix', "#2") #add "#2" as second parameter for auto-connection to system out 2
else:
lmixUuid = cbox.JackIO.create_audio_output('left_mix')
rmixUuid = cbox.JackIO.create_audio_output('right_mix')
for i in range(16):
router = cbox.JackIO.create_audio_output_router(lmixUuid, rmixUuid) router = cbox.JackIO.create_audio_output_router(lmixUuid, rmixUuid)
router.set_gain(-3.0) router.set_gain(-3.0)
self.instrument.get_output_slot(i).rec_wet.attach(router) #output_slot is 0 based and means a pair self.instrument.get_output_slot(i).rec_wet.attach(router) #output_slot is 0 based and means a pair
#slot 17 is an error. cbox tells us there is only [1, 16], good. #slot 17 is an error. cbox tells us there is only [1, 16], good.
#Set port order. It is already correct because alphanumerial order, but explicit is better than implicit #Set port order. It is already correct because alphanumerial order, but explicit is better than implicit
for channelNumber in range(1,33): for channelNumber in range(1,33):
portname = f"{cbox.JackIO.status().client_name}:out_{channelNumber}" portname = f"{cbox.JackIO.status().client_name}:out_{channelNumber}"
try: try:
cbox.JackIO.Metadata.set_port_order(portname, channelNumber) cbox.JackIO.Metadata.set_port_order(portname, channelNumber)
except Exception as e: #No Jack Meta Data except Exception as e: #No Jack Meta Data
logger.error(e) logger.error(e)
#Also sort the mixing channels #Also sort the mixing channels
try: try:
portname = f"{cbox.JackIO.status().client_name}:left_mix" portname = f"{cbox.JackIO.status().client_name}:left_mix"
cbox.JackIO.Metadata.set_port_order(portname, 33) cbox.JackIO.Metadata.set_port_order(portname, 33)
@ -140,12 +147,12 @@ class Sampler_sf2(Data):
def loadSoundfont(self, filePath, defaultSoundfont=None): def loadSoundfont(self, filePath, defaultSoundfont=None):
"""defaultSoundfont is a special case. The path is not saved""" """defaultSoundfont is a special case. The path is not saved"""
logger.info(f"loading path: \"{filePath}\" defaultSoundfont parameter: {defaultSoundfont}") logger.info(f"loading path: \"{filePath}\" defaultSoundfont parameter: {defaultSoundfont}")
#Remove the old link, if present. We cannot unlink directly in loadSoundfont because it is quite possible that a user will try out another soundfont but decide not to save but close and reopen to get his old soundfont back. #Remove the old link, if present. We cannot unlink directly in loadSoundfont because it is quite possible that a user will try out another soundfont but decide not to save but close and reopen to get his old soundfont back.
if self.filePath and os.path.islink(self.filePath): if self.filePath and os.path.islink(self.filePath):
self._unlinkOnSave.append(self.filePath) self._unlinkOnSave.append(self.filePath)
#self.midiInput.scene.clear() do not call for the sf2 engine. Will kill our instrument. #self.midiInput.scene.clear() do not call for the sf2 engine. Will kill our instrument.
for stereoPair in range(16): #midi channels fluidsynth output . 0-15 for stereoPair in range(16): #midi channels fluidsynth output . 0-15
@ -161,7 +168,7 @@ class Sampler_sf2(Data):
else: else:
self.instrument.engine.load_soundfont(filePath) self.instrument.engine.load_soundfont(filePath)
self.filePath = filePath self.filePath = filePath
self.patchlist = self._convertPatches( self.instrument.engine.get_patches() ) self.patchlist = self._convertPatches( self.instrument.engine.get_patches() )
self._correctActivePatches() self._correctActivePatches()
return True, "" return True, ""
except Exception as e: #throws a general Exception if not a good file except Exception as e: #throws a general Exception if not a good file
@ -177,7 +184,7 @@ class Sampler_sf2(Data):
change cbox here and now.""" change cbox here and now."""
if not self.patchlist: if not self.patchlist:
self.patchlist = self._convertPatches( self.instrument.engine.get_patches() ) #try again self.patchlist = self._convertPatches( self.instrument.engine.get_patches() ) #try again
if not self.patchlist: raise ValueError("No programs in this sound font") if not self.patchlist: raise ValueError("No programs in this sound font")
for channel, (value, name) in self.instrument.engine.status().patch.items(): #channel is base 1 for channel, (value, name) in self.instrument.engine.status().patch.items(): #channel is base 1
program = value & 127 program = value & 127
@ -192,7 +199,7 @@ class Sampler_sf2(Data):
logger.info(METADATA["name"] + f": Channel {channel} Old bank/program not possible in new soundfont. Switching to first available program.") logger.info(METADATA["name"] + f": Channel {channel} Old bank/program not possible in new soundfont. Switching to first available program.")
self.setPatch(channel, youchoose_bank, youchoose_program) self.setPatch(channel, youchoose_bank, youchoose_program)
break #inner loop. one instrument is enough. break #inner loop. one instrument is enough.
def activePatches(self): def activePatches(self):
@ -203,7 +210,7 @@ class Sampler_sf2(Data):
Takes the current bank into consideration Takes the current bank into consideration
""" """
result = {} result = {}
for channel, (value, name) in self.instrument.engine.status().patch.items(): for channel, (value, name) in self.instrument.engine.status().patch.items():
program = value & 127 program = value & 127
bank = value >> 7 bank = value >> 7
@ -218,7 +225,7 @@ class Sampler_sf2(Data):
self.setPatch(channel, bank, program) self.setPatch(channel, bank, program)
def setPatch(self, channel, bank, program): def setPatch(self, channel, bank, program):
"""An input error happens not often, but can happen if the saved data mismatches the """An input error happens not often, but can happen if the saved data mismatches the
soundfont. This happens on manual save file change or soundfont change (version update?) soundfont. This happens on manual save file change or soundfont change (version update?)
between program runs. between program runs.
We assume self.patchlist is up to date.""" We assume self.patchlist is up to date."""
@ -246,7 +253,7 @@ class Sampler_sf2(Data):
portnameR = f"{cbox.JackIO.status().client_name}:out_{chanR}" portnameR = f"{cbox.JackIO.status().client_name}:out_{chanR}"
#Use the instrument name as port name: 03-L:Violin #Use the instrument name as port name: 03-L:Violin
try: try:
cbox.JackIO.Metadata.set_pretty_name(portnameL, f"{str(channel).zfill(2)}-L : {name}") cbox.JackIO.Metadata.set_pretty_name(portnameL, f"{str(channel).zfill(2)}-L : {name}")
cbox.JackIO.Metadata.set_pretty_name(portnameR, f"{str(channel).zfill(2)}-R : {name}") cbox.JackIO.Metadata.set_pretty_name(portnameR, f"{str(channel).zfill(2)}-R : {name}")
except Exception as e: #No Jack Meta Data except Exception as e: #No Jack Meta Data

4
template/engine/session.py

@ -51,7 +51,7 @@ class Session(object):
self.recordingEnabled = False #MidiInput callbacks can use this to prevent/allow data creation. Handled via api callback. Saved. self.recordingEnabled = False #MidiInput callbacks can use this to prevent/allow data creation. Handled via api callback. Saved.
self.eventLoop = None # added in api.startEngine self.eventLoop = None # added in api.startEngine
self.data = None #nsm_openOrNewCallback self.data = None #nsm_openOrNewCallback
self.standaloneMode = None #fake NSM single server for LaborejoSoftwareSuite programs or not. Set in nsm_openOrNewCallback
def addSessionPrefix(self, jsonDataAsString:str): def addSessionPrefix(self, jsonDataAsString:str):
"""During load the current session prefix gets added. Turning pseudo-relative paths into """During load the current session prefix gets added. Turning pseudo-relative paths into
@ -103,6 +103,8 @@ class Session(object):
self.sessionPrefix = ourPath #if we want to save and load resources they need to be in the session dir. We never load from outside, the scheme is always "import first, load local file" self.sessionPrefix = ourPath #if we want to save and load resources they need to be in the session dir. We never load from outside, the scheme is always "import first, load local file"
self.absoluteJsonFilePath = os.path.join(ourPath, "save." + METADATA["shortName"] + ".json") self.absoluteJsonFilePath = os.path.join(ourPath, "save." + METADATA["shortName"] + ".json")
self.standaloneMode = sessionName == "NOT-A-SESSION"
try: try:
self.data = self.openFromJson(self.absoluteJsonFilePath) self.data = self.openFromJson(self.absoluteJsonFilePath)
except FileNotFoundError: except FileNotFoundError:

6
template/helper.py

@ -95,4 +95,10 @@ def whoCalled():
print() print()
def provokecrash():
"""Obviously for testing"""
import ctypes
p = ctypes.pointer(ctypes.c_char.from_address(5))
p[0] = b'x'

2
template/qtgui/mainwindow.py

@ -186,7 +186,7 @@ class MainWindow(QtWidgets.QMainWindow):
if not settings.contains("showAboutDialog"): if not settings.contains("showAboutDialog"):
settings.setValue("showAboutDialog", METADATA["showAboutDialogFirstStart"]) settings.setValue("showAboutDialog", METADATA["showAboutDialogFirstStart"])
self.about = About(mainWindow=self) self.about = About(mainWindow=self) #This does not show, it only creates. Showing is decided in self.start
self.ui.menubar.setNativeMenuBar(False) #Force a real menu bar. Qt on wayland will not display it otherwise. self.ui.menubar.setNativeMenuBar(False) #Force a real menu bar. Qt on wayland will not display it otherwise.
self.menu = Menu(mainWindow=self) #needs the about dialog, save file and the api.session ready. self.menu = Menu(mainWindow=self) #needs the about dialog, save file and the api.session ready.

20
template/qtgui/nsmclient.py

@ -548,18 +548,14 @@ class NSMClient(object):
"""If you want a very strict client you can block any non-NSM quit-attempts, like ignoring a """If you want a very strict client you can block any non-NSM quit-attempts, like ignoring a
qt closeEvent, and instead send the NSM Server a request to close this client. qt closeEvent, and instead send the NSM Server a request to close this client.
This method is a shortcut to do just that. This method is a shortcut to do just that.
"""
Using this method will not result in a NSM-"client died unexpectedly" message that usually logger.info("Sending SIGTERM to ourselves to trigger the exit callback.")
happens a client quits on its own. This message is harmless but may confuse a user.""" #if "server-control" in self.serverFeatures:
# message = _OutgoingMessage("/nsm/server/stop")
logger.info("instructing the NSM-Server to send SIGTERM to ourselves.") # message.add_arg("{}".format(self.ourClientId))
if "server-control" in self.serverFeatures: # self.sock.sendto(message.build(), self.nsmOSCUrl)
message = _OutgoingMessage("/nsm/server/stop") #else:
message.add_arg("{}".format(self.ourClientId)) kill(getpid(), SIGTERM) #this calls the exit callback
self.sock.sendto(message.build(), self.nsmOSCUrl)
else:
logger.warning("...but the NSM-Server does not support server control. Quitting on our own. Server only supports: {}".format(self.serverFeatures))
kill(getpid(), SIGTERM) #this calls the exit callback but nsm will output something like "client died unexpectedly."
def serverSendSaveToSelf(self): def serverSendSaveToSelf(self):
"""Some clients want to offer a manual Save function, mostly for psychological reasons. """Some clients want to offer a manual Save function, mostly for psychological reasons.

78
template/start.py

@ -83,13 +83,13 @@ try:
compiledVersion = True compiledVersion = True
logger.info("Compiled prefix found: {}".format(prefix)) logger.info("Compiled prefix found: {}".format(prefix))
except ModuleNotFoundError as e: except ModuleNotFoundError as e:
compiledVersion = False compiledVersion = False
logger.info("Compiled version: {}".format(compiledVersion)) logger.info("Compiled version: {}".format(compiledVersion))
cboxSharedObjectVersionedName = "lib"+METADATA["shortName"]+".so." + METADATA["version"] cboxSharedObjectVersionedName = "lib"+METADATA["shortName"]+".so." + METADATA["version"]
if compiledVersion: if compiledVersion:
PATHS={ #this gets imported PATHS={ #this gets imported
"root": "", "root": "",
"bin": os.path.join(prefix, "bin"), "bin": os.path.join(prefix, "bin"),
@ -98,26 +98,26 @@ if compiledVersion:
"share": os.path.join(prefix, "share", METADATA["shortName"]), "share": os.path.join(prefix, "share", METADATA["shortName"]),
"templateShare": os.path.join(prefix, "share", METADATA["shortName"], "template"), "templateShare": os.path.join(prefix, "share", METADATA["shortName"], "template"),
#"lib": os.path.join(prefix, "lib", METADATA["shortName"]), #cbox is found via the PYTHONPATH #"lib": os.path.join(prefix, "lib", METADATA["shortName"]), #cbox is found via the PYTHONPATH
} }
cboxSharedObjectPath = os.path.join(prefix, "lib", METADATA["shortName"], cboxSharedObjectVersionedName) cboxSharedObjectPath = os.path.join(prefix, "lib", METADATA["shortName"], cboxSharedObjectVersionedName)
_root = os.path.dirname(__file__) _root = os.path.dirname(__file__)
_root = os.path.abspath(os.path.join(_root, "..")) _root = os.path.abspath(os.path.join(_root, ".."))
fallback_cboxSharedObjectPath = os.path.join(_root, "site-packages", cboxSharedObjectVersionedName) fallback_cboxSharedObjectPath = os.path.join(_root, "site-packages", cboxSharedObjectVersionedName)
#Local version has higher priority #Local version has higher priority
if os.path.exists(fallback_cboxSharedObjectPath): #we are not yet installed, look in the source site-packages dir if os.path.exists(fallback_cboxSharedObjectPath): #we are not yet installed, look in the source site-packages dir
os.environ["CALFBOXLIBABSPATH"] = fallback_cboxSharedObjectPath os.environ["CALFBOXLIBABSPATH"] = fallback_cboxSharedObjectPath
elif os.path.exists(cboxSharedObjectPath): #we are installed elif os.path.exists(cboxSharedObjectPath): #we are installed
os.environ["CALFBOXLIBABSPATH"] = cboxSharedObjectPath os.environ["CALFBOXLIBABSPATH"] = cboxSharedObjectPath
else: else:
pass pass
#no support for system-wide cbox in compiled mode. Error handling at the bottom of the file #no support for system-wide cbox in compiled mode. Error handling at the bottom of the file
else: else:
_root = os.path.dirname(__file__) _root = os.path.dirname(__file__)
_root = os.path.abspath(os.path.join(_root, "..")) _root = os.path.abspath(os.path.join(_root, ".."))
@ -128,16 +128,16 @@ else:
"desktopfile": os.path.join(_root, "desktop", "desktop.desktop"), #not ~/Desktop but our desktop file "desktopfile": os.path.join(_root, "desktop", "desktop.desktop"), #not ~/Desktop but our desktop file
"share": os.path.join(_root, "engine", "resources"), "share": os.path.join(_root, "engine", "resources"),
"templateShare": os.path.join(_root, "template", "engine", "resources"), "templateShare": os.path.join(_root, "template", "engine", "resources"),
#"lib": "", #use only system paths #"lib": "", #use only system paths
} }
if os.path.exists (os.path.join(_root, "site-packages", cboxSharedObjectVersionedName)): if os.path.exists (os.path.join(_root, "site-packages", cboxSharedObjectVersionedName)):
os.environ["CALFBOXLIBABSPATH"] = os.path.join(_root, "site-packages", cboxSharedObjectVersionedName) os.environ["CALFBOXLIBABSPATH"] = os.path.join(_root, "site-packages", cboxSharedObjectVersionedName)
#else use system-wide. #else use system-wide.
if os.path.exists (os.path.join(_root, "site-packages", "calfbox", "cbox.py")): if os.path.exists (os.path.join(_root, "site-packages", "calfbox", "cbox.py")):
#add to the front to have higher priority than system site-packages #add to the front to have higher priority than system site-packages
logger.info("Will attempt to start with local calfbox python module: {}".format(os.path.join(_root, "site-packages", "calfbox", "cbox.py"))) logger.info("Will attempt to start with local calfbox python module: {}".format(os.path.join(_root, "site-packages", "calfbox", "cbox.py")))
sys.path.insert(0, os.path.join(os.path.join(_root, "site-packages"))) sys.path.insert(0, os.path.join(os.path.join(_root, "site-packages")))
#else try to use system-wide calfbox. Check for this and if the .so exists at the end of this file. #else try to use system-wide calfbox. Check for this and if the .so exists at the end of this file.
@ -147,7 +147,7 @@ logger.info("PATHS: {}".format(PATHS))
QtGui.QGuiApplication.setDesktopSettingsAware(False) #We need our own font so the user interface stays predictable QtGui.QGuiApplication.setDesktopSettingsAware(False) #We need our own font so the user interface stays predictable
QtGui.QGuiApplication.setDesktopFileName(PATHS["desktopfile"]) QtGui.QGuiApplication.setDesktopFileName(PATHS["desktopfile"])
qtApp = QApplication(sys.argv) qtApp = QApplication(sys.argv)
setPaletteAndFont(qtApp) setPaletteAndFont(qtApp)
def exitWithMessage(message:str): def exitWithMessage(message:str):
@ -157,7 +157,7 @@ def exitWithMessage(message:str):
else: else:
from PyQt5.QtWidgets import QMessageBox from PyQt5.QtWidgets import QMessageBox
#This is the start file for the Qt client so we know at least that Qt is installed and use that for a warning. #This is the start file for the Qt client so we know at least that Qt is installed and use that for a warning.
QMessageBox.critical(qtApp.desktop(), title, message) QMessageBox.critical(qtApp.desktop(), title, message)
sys.exit(title + ": " + message) sys.exit(title + ": " + message)
def setProcessName(executableName): def setProcessName(executableName):
@ -180,7 +180,7 @@ def setProcessName(executableName):
libpthread_path = ctypes.util.find_library("pthread") libpthread_path = ctypes.util.find_library("pthread")
if not libpthread_path: if not libpthread_path:
return return
libpthread = ctypes.CDLL(libpthread_path) libpthread = ctypes.CDLL(libpthread_path)
if hasattr(libpthread, "pthread_setname_np"): if hasattr(libpthread, "pthread_setname_np"):
_pthread_setname_np = libpthread.pthread_setname_np _pthread_setname_np = libpthread.pthread_setname_np
@ -194,7 +194,7 @@ def setProcessName(executableName):
if _pthread_setname_np is None: if _pthread_setname_np is None:
return return
_pthread_setname_np(_pthread_self(), executableName.encode()) _pthread_setname_np(_pthread_self(), executableName.encode())
def checkNsmOrExit(prettyName): def checkNsmOrExit(prettyName):
@ -204,17 +204,17 @@ def checkNsmOrExit(prettyName):
import sys import sys
from os import getenv from os import getenv
if not getenv("NSM_URL"): #NSMClient checks for this itself but we can anticipate an error and inform the user. if not getenv("NSM_URL"): #NSMClient checks for this itself but we can anticipate an error and inform the user.
path = ChooseSessionDirectory(qtApp).path #ChooseSessionDirectory is calling exec. We can't call qtapp.exec_ because that blocks forever, even after quitting the window. path = ChooseSessionDirectory(qtApp).path #ChooseSessionDirectory is calling exec. We can't call qtapp.exec_ because that blocks forever, even after quitting the window.
#qSessionDirApp.quit() #qSessionDirApp.quit()
#del qSessionDirApp #del qSessionDirApp
#path = "/tmp" #path = "/tmp"
if path: if path:
startPseudoNSMServer(path) startPseudoNSMServer(path)
else: else:
sys.exit() sys.exit()
#message = f"""Please start {prettyName} only through the New Session Manager (NSM) or use the --save command line parameter.""" #message = f"""Please start {prettyName} only through the New Session Manager (NSM) or use the --save command line parameter."""
#exitWithMessage(message) #exitWithMessage(message)
@ -281,14 +281,14 @@ def profiler(*pargs, **kwds):
#Catch Exceptions even if PyQt crashes. #Catch Exceptions even if PyQt crashes.
import sys import sys
sys._excepthook = sys.excepthook sys._excepthook = sys.excepthook
def exception_hook(exctype, value, traceback): def exception_hook(exctype, value, traceback):
"""This hook purely exists to call sys.exit(1) even on a Qt crash """This hook purely exists to call sys.exit(1) even on a Qt crash
so that atexit gets triggered""" so that atexit gets triggered"""
#print(exctype, value, traceback) #print(exctype, value, traceback)
logger.error("Caught crash in execpthook. Trying too execute atexit anyway") logger.error("Caught crash in execpthook. Trying too execute atexit anyway")
sys._excepthook(exctype, value, traceback) sys._excepthook(exctype, value, traceback)
sys.exit(1) sys.exit(1)
sys.excepthook = exception_hook sys.excepthook = exception_hook
@ -340,13 +340,13 @@ if args.mute:
#Make sure calfbox is available. #Make sure calfbox is available.
if "CALFBOXLIBABSPATH" in os.environ: if "CALFBOXLIBABSPATH" in os.environ:
logger.info("Looking for calfbox shared library in absolute path: {}".format(os.environ["CALFBOXLIBABSPATH"])) logger.info("Looking for calfbox shared library in absolute path: {}".format(os.environ["CALFBOXLIBABSPATH"]))
else: else:
logger.info("Looking for calfbox shared library systemwide through ctypes.util.find_library") logger.info("Looking for calfbox shared library systemwide through ctypes.util.find_library")
try: try:
from calfbox import cbox from calfbox import cbox
logger.info("{}: using cbox python module from {} . Local version has higher priority than system wide.".format(METADATA["name"], os.path.abspath(cbox.__file__))) logger.info("{}: using cbox python module from {} . Local version has higher priority than system wide.".format(METADATA["name"], os.path.abspath(cbox.__file__)))
except Exception as e: except Exception as e:
print (e) print (e)
@ -355,8 +355,14 @@ except Exception as e:
print (sys.modules["calfbox"], "->", os.path.abspath(sys.modules["calfbox"].__file__)) print (sys.modules["calfbox"], "->", os.path.abspath(sys.modules["calfbox"].__file__))
else: else:
print ("calfbox python module is not in sys.modules. This means it truly can't be found or you forgot --mute") print ("calfbox python module is not in sys.modules. This means it truly can't be found or you forgot --mute")
print ("sys.path start and tail:", sys.path[0:5], sys.path[-1]) print ("sys.path start and tail:", sys.path[0:5], sys.path[-1])
exitWithMessage("Calfbox module could not be loaded") exitWithMessage("Calfbox module could not be loaded")
#Capture Ctlr+C / SIGINT and let @atexit handle the rest.
import signal
import sys
def signal_handler(sig, frame):
sys.exit(0) #atexit will trigger
signal.signal(signal.SIGINT, signal_handler)

Loading…
Cancel
Save