From 9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22 Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 13 Apr 2025 18:48:02 +0100 Subject: initial --- site/udo/sequencing_melodic_persistence.udo | 275 ++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100755 site/udo/sequencing_melodic_persistence.udo (limited to 'site/udo/sequencing_melodic_persistence.udo') diff --git a/site/udo/sequencing_melodic_persistence.udo b/site/udo/sequencing_melodic_persistence.udo new file mode 100755 index 0000000..0709832 --- /dev/null +++ b/site/udo/sequencing_melodic_persistence.udo @@ -0,0 +1,275 @@ +#ifndef UDO_MELSEQUENCINGPERSIST +#define UDO_MELSEQUENCINGPERSIST ## +/* + Melodic sequencer persistence: saving/loading from files and database + Requires JSON opcodes + + This file is part of the SONICS UDO collection by Richard Knight 2021, 2022 + License: GPL-2.0-or-later + http://1bpm.net +*/ + +#include "pgdb.udo" +#include "sequencing_melodic.udo" +#include "array_tools.udo" +#include "interop.udo" + + +/* + Get the current state as a JSON object + + iJson mel_getstate_json + + iJson the JSON object containing current sequencing and progression data + +*/ +opcode mel_getstate_json, i, 0 + iJson jsoninit + index = 0 + while (index < lenarray(gimel_fns)) do + iarray[] tab2array gimel_fns[index] + jsoninsertval iJson, gSmel_names[index], iarray + index += 1 + od + iarray[] tab2array gimel_state + jsoninsertval iJson, "state", iarray + jsoninsertval iJson, "details", gSmel_details + jsoninsertval iJson, "mel_number", gimel_number + jsoninsertval iJson, "seq_tempo", i(gkseq_tempo) + jsoninsertval iJson, "seq_swing", i(gkseq_swing) + xout iJson +endop + + +/* + Set the current sequencing and progression state + + mel_setstate_json iJson + + iJson JSON object containing state data + +*/ +opcode mel_setstate_json, 0, i + iJson xin + + gSmel_details jsongetval iJson, "details" + gimel_number jsongetval iJson, "mel_number" + itempo jsongetval iJson, "seq_tempo" + iswing jsongetval iJson, "seq_swing" + +#ifdef MEL_INITTIME + gkseq_tempo init itempo + gkseq_swing init iswing +#end + + ; if data to be loaded has more progression items than ftables, free and generate again + if (gimel_number > ftlen(gimel_fns[0])) then + index = 0 + while (index < lenarray(gimel_fns)) do + ftfree gimel_fns[index], 0 + gimel_fns[index] = ftgen(0, 0, -gimel_number, -7, 0) + od + endif + + + index = 0 + while (index < lenarray(gimel_fns)) do + iJsonSub jsonget iJson, gSmel_names[index] + iarray[] jsonarrval iJsonSub + copya2ftab iarray, gimel_fns[index] + jsondestroy iJsonSub + index += 1 + od + + + iJsonSub jsonget iJson, "state" + iarray[] jsonarrval iJsonSub + copya2ftab iarray, gimel_state + jsondestroy(iJsonSub) + +endop + + + +/* + Save the sequencing and progression state to a file + + p4 path to save file to + p5 optional callback ID for host interop; sent on completion +*/ +instr mel_savestate_fs + Spath = p4 + icbid = p5 + iJson = mel_getstate_json() + jsondump(iJson, Spath) + jsondestroy(iJson) + if (icbid != 0) then + schedule("io_callback", 0, 1, icbid) + endif + turnoff +endin + + + +opcode mel_loadstate_fs, 0, S + Spath xin + iJson jsonload Spath + mel_setstate_json(iJson) + jsondestroy(iJson) +endop +/* + Load the sequencing and progression state from a file + + p4 path to load data from + p5 optional callback ID for host interop; sent on completion +*/ +instr mel_loadstate_fs + Spath = p4 + icbid = p5 + mel_loadstate_fs Spath + if (icbid != 0) then + schedule("io_callback", 0, 1, icbid) + endif + schedule("mel_futures_refresh", 0, 1) + turnoff +endin + + + +opcode mel_savestate_db, 0, S + Sname xin + iJson = mel_getstate_json() + pgdb_json_save Sname, "melsys", iJson + jsondestroy(iJson) +endop +/* + Save the sequencing and progression state to database + + p4 reference name in database + p5 optional callback ID for host interop; sent on completion +*/ +instr mel_savestate_db + Sname = p4 + icbid = p5 + mel_savestate_db Sname + if (icbid != 0) then + schedule("io_callback", 0, 1, icbid) + endif + turnoff +endin + + + +opcode mel_loadstate_db, 0, S + Sname xin + iJson pgdb_json_load Sname, "melsys" + mel_setstate_json(iJson) + jsondestroy(iJson) +endop +/* + Load the sequencing and progression state from database + + p4 reference name in database + p5 optional callback ID for host interop; sent on completion +*/ +instr mel_loadstate_db + Sname = p4 + icbid = p5 + mel_loadstate_db Sname + if (icbid != 0) then + schedule("io_callback", 0, 1, icbid) + endif + schedule("mel_futures_refresh", 0, 1) + turnoff +endin + + + +/* + Load the sequencing and progression state from a string channel + + p4 channel name containing string representation of JSON + p5 optional callback ID for host interop; sent on completion +*/ +instr mel_loadstate_channel + Schannel = p4 + icbid = p5 + Sdata chnget Schannel + iJson jsonloads Sdata + mel_setstate_json(iJson) + jsondestroy(iJson) + if (icbid != 0) then + schedule("io_callback", 0, 1, icbid) + endif + schedule("mel_futures_refresh", 0, 1) + turnoff +endin + + +/* + Just get state: interop host handles persistence + p4 callback ID to send data with/to +*/ +instr mel_getstate_string + icbid = p4 + iJson = mel_getstate_json() + jsoninsertval iJson, "cbid", icbid + Sjson = jsondumps(iJson, 0) + io_sendstring("callback", Sjson) + turnoff +endin + + +/* + Get an array of the known mel states from database + Sdata[] mel_liststates_db + + Sdata[] the state names +*/ +opcode mel_liststates_db, S[], 0 + Sresult[][] dbarray gidb, "SELECT name FROM savejson WHERE unit = 'melsys'" + ilen = lenarray(Sresult) + Sdata[] init ilen + index = 0 + while (index < ilen) do + Sdata[index] = Sresult[index][0] + index += 1 + od + xout Sdata +endop + + +/* + Get a list of mel states from database and return to host with the specified callback ID + + p4 callback ID +*/ +instr mel_liststates_db + icbid = p4 + iJson = jsoninit() + jsoninsertval(iJson, "cbid", icbid) + jsoninsertval(iJson, "states", mel_liststates_db()) + io_sendstring("callback", jsondumps(iJson, 0)) + turnoff +endin + + +; if MEL_INITPATH or MEL_INITDB is set, load the specified progression data accordingly +#ifdef MEL_HASINIT +instr _mel_persistence_init +#ifdef MEL_INITPATH + subinstrinit "mel_loadstate_fs", "$MEL_INITPATH" +#end +#ifdef MEL_INITDB + ;mel_loadstate_db "$MEL_INITDB" + subinstrinit "mel_loadstate_db", "$MEL_INITDB" +#end + alwayson "_mel_manager" + turnoff +endin +schedule "_mel_persistence_init", 0, 60 + +; end MEL_HASINIT +#end + +#end -- cgit v1.2.3