Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 88 additions & 7 deletions zyngine/zynthian_state_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1087,7 +1087,7 @@ def save_snapshot(self, fpath, extra_data=None):
self.end_busy("save snapshot")
return True

def load_snapshot(self, fpath, load_chains=True, load_sequences=True, merge=False):
def load_snapshot(self, fpath, load_chains=True, load_sequences=True, load_ctrldev=False, merge=False):
"""Loads a snapshot from file

fpath : Full path and filename of snapshot file
Expand Down Expand Up @@ -1217,7 +1217,7 @@ def load_snapshot(self, fpath, load_chains=True, load_sequences=True, merge=Fals
zs3 = self.sanitize_zs3_from_json(state["zs3"])
if not merge:
self.zs3 = zs3
self.load_zs3(zs3["zs3-0"], autoconnect=False)
self.load_zs3(zs3["zs3-0"], autoconnect=False, load_ctrldev=load_ctrldev)
try:
mute |= self.zs3["zs3-0"]["mixer"]["chan_16"]["mute"]
except:
Expand All @@ -1240,6 +1240,12 @@ def load_snapshot(self, fpath, load_chains=True, load_sequences=True, merge=Fals
for proc in self.chain_manager.processors.values():
proc.set_midi_autolearn(True)

if load_ctrldev and not load_chains:
zs3 = self.sanitize_zs3_from_json(state["zs3"])
if not merge:
self.zs3 = zs3
self.load_ctrldev(zs3["zs3-0"])

# Save last snapshot info and get snapshot's program number
self.last_snapshot_count += 1
if basename(fpath) != "last_state.zss":
Expand Down Expand Up @@ -1337,7 +1343,7 @@ def save_last_state_snapshot(self):

def load_last_state_snapshot(self):
if isfile(self.last_state_snapshot_fpath):
return self.load_snapshot(self.last_state_snapshot_fpath)
return self.load_snapshot(self.last_state_snapshot_fpath, load_ctrldev=True)

def delete_last_state_snapshot(self):
try:
Expand Down Expand Up @@ -1377,7 +1383,7 @@ def toggle_zs3_chain_restore_flag(self, zs3_id, chain_id):
except:
tstate["restore"] = False

def load_zs3(self, zs3_id, autoconnect=True):
def load_zs3(self, zs3_id, autoconnect=True, load_ctrldev=False):
"""Restore a ZS3

zs3_id : ID of ZS3 to restore or zs3 dict
Expand Down Expand Up @@ -1533,7 +1539,7 @@ def load_zs3(self, zs3_id, autoconnect=True):

if "midi_capture" in zs3_state:
self.set_busy_details("restoring midi capture state")
self.set_midi_capture_state(zs3_state['midi_capture'])
self.set_midi_capture_state(zs3_state['midi_capture'], load_ctrldev=load_ctrldev)

if "global" in zs3_state:
if "midi_transpose" in zs3_state["global"]:
Expand Down Expand Up @@ -1570,6 +1576,78 @@ def load_zs3(self, zs3_id, autoconnect=True):
zynautoconnect.request_audio_connect(True)
return True

def load_ctrldev(self, zs3_id, autoconnect=True, load_ctrldev=True):
"""Restore ctrldev from a zs3

zs3_id : ID of ZS3 to restore or zs3 dict
Returns : True on success
"""

if isinstance(zs3_id, str):
# Try loading exact match
try:
zs3_state = self.zs3[zs3_id]
except:
# else ignore MIDI channel => try loading "program change" match
try:
zs3_id = f"*/{zs3_id.split('/')[1]}"
zs3_state = self.zs3[zs3_id]
except:
logging.info(f"Not found ZS3 matching '{zs3_id}'")
return False
else:
try:
zs3_state = zs3_id
zs3_id = self.last_zs3_id
if zs3_id is None:
zs3_id = "zs3-0"
except:
zs3_id = "zs3-0"

if "midi_capture" in zs3_state:
self.set_busy_details("restoring midi capture state")
"""Set midi input (capture) state: flags, chain routing, etc.

mcstate : dictionary with state. None for reset state to defaults.
"""
mcstate = zs3_state['midi_capture']
if mcstate:
ctrldev_state_drivers = {}
for uid, state in mcstate.items():
#logging.debug(f"MCSTATE {uid} => {state}")
izmip = zynautoconnect.get_midi_in_devid_by_uid(uid, zynthian_gui_config.midi_usb_by_port)
if izmip is None:
continue
zynautoconnect.update_midi_in_dev_mode(izmip)
try:
# TODO: Use ctrldev_driver=None to disable driver
if state["disable_ctrldev"]:
self.ctrldev_manager.unload_driver(izmip, True)
else:
self.ctrldev_manager.load_driver(izmip, state["ctrldev_driver"])
except:
pass
try:
ctrldev_state_drivers[uid] = state["ctrldev_state"]
except:
pass

self.ctrldev_manager.set_state_drivers(ctrldev_state_drivers)

else:
zynautoconnect.reset_midi_in_dev_all()


if zs3_id != 'zs3-0':
self.last_zs3_id = zs3_id
#self.zs3['zs3-0'] = self.zs3[zs3_id].copy()
zynsigman.send(zynsigman.S_STATE_MAN, self.SS_LOAD_ZS3, zs3_id=zs3_id)

if autoconnect:
zynautoconnect.request_midi_connect(True)
zynautoconnect.request_audio_connect(True)
return True

def get_next_zs3_index(self):
used_indexes = []
for zid, state in self.zs3.items():
Expand Down Expand Up @@ -1951,7 +2029,7 @@ def get_midi_capture_state(self):

return mcstate

def set_midi_capture_state(self, mcstate=None):
def set_midi_capture_state(self, mcstate=None, load_ctrldev=False):
"""Set midi input (capture) state: flags, chain routing, etc.

mcstate : dictionary with state. None for reset state to defaults.
Expand Down Expand Up @@ -1984,8 +2062,11 @@ def set_midi_capture_state(self, mcstate=None):
# TODO: Use ctrldev_driver=None to disable driver
if state["disable_ctrldev"]:
self.ctrldev_manager.unload_driver(izmip, True)
else:
elif load_ctrldev:
self.ctrldev_manager.load_driver(izmip, state["ctrldev_driver"])
else:
pass
# self.ctrldev_manager.load_driver(izmip, state["ctrldev_driver"])
except:
pass
try:
Expand Down
10 changes: 10 additions & 0 deletions zyngui/zynthian_gui_snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ def show_options(self, i, restrict_options):
"Load Replace Chains": [param, ["Load chains from snapshot, replacing current state.", "snapshot_chains.png"]],
"Load Merge Chains": [param, ["Load chains from snapshot, merging with current state.", "snapshot_chains.png"]],
"Load Replace Sequences": [param, ["Load sequences from snapshot, replacing current state", "snapshot_sequences.png"]],
"Load MIDI device drivers": [param, ["Load MIDI device drivers from snapshot, replacing current drivers", "midi_input.png"]],
"Save Overwriting": [param, ["Save current state, overwriting this snapshot.", "snapshot_overwrite.png"]]
}
budir = dirname(fpath) + "/.backup"
Expand Down Expand Up @@ -327,6 +328,9 @@ def options_cb(self, option, param):
elif option == "Load Replace Sequences":
# self.zyngui.show_confirm("Loading sequences from '%s' will destroy current sequences..." % (fname), self.load_snapshot_sequences, fpath)
self.load_snapshot_sequences(fpath)
elif option == "Load MIDI device drivers":
# self.zyngui.show_confirm("Loading ctrldev drivers from '%s' will destroy current drivers..." % (fname), self.load_snapshot_ctrldev, fpath)
self.load_snapshot_ctrldev(fpath)
elif option == "Save Overwriting":
# self.zyngui.show_confirm("Do you really want to overwrite '%s'?" % (fname), self.save_snapshot, fpath)
self.save_snapshot(fpath)
Expand Down Expand Up @@ -367,6 +371,12 @@ def load_snapshot_sequences(self, fpath):
self.sm.load_snapshot(fpath, load_chains=False)
self.zyngui.show_screen('zynpad', hmode=self.zyngui.SCREEN_HMODE_RESET)

def load_snapshot_ctrldev(self, fpath):
if self.is_not_empty_snapshot() and fpath != self.sm.last_state_snapshot_fpath:
self.sm.save_last_state_snapshot()
self.sm.load_snapshot(fpath, load_chains=False, load_sequences=False, load_ctrldev=True)
self.zyngui.show_screen('audio_mixer', hmode=self.zyngui.SCREEN_HMODE_RESET)

def restore_backup_cb(self, fname, fpath):
logging.debug("Restoring snapshot backup '{}'".format(fname))
self.load_snapshot(fpath)
Expand Down
3 changes: 1 addition & 2 deletions zynthian_headless.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ def __init__(self):
self.chain_manager = self.state_manager.chain_manager

if zynthian_gui_config.restore_last_state:
snapshot_loaded = self.state_manager.load_snapshot(
"/zynthian/zynthian-my-data/snapshots/last_state.zss")
snapshot_loaded = self.state_manager.load_last_state_snapshot()

self.state_manager.init_midi()
self.state_manager.init_midi_services()
Expand Down