From 9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22 Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 13 Apr 2025 18:48:02 +0100 Subject: initial --- site/udo/scss/persistence.udo | 366 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100755 site/udo/scss/persistence.udo (limited to 'site/udo/scss/persistence.udo') diff --git a/site/udo/scss/persistence.udo b/site/udo/scss/persistence.udo new file mode 100755 index 0000000..075b06a --- /dev/null +++ b/site/udo/scss/persistence.udo @@ -0,0 +1,366 @@ +#ifndef UDO_SCSS_PERSISTENCE +#define UDO_SCSS_PERSISTENCE ## +/* + SONICS Category Sequencer System + Persistence: saving and loading state to database and FS + + Designed for use with an API host to/from which callbacks and JSON states can be exchanged + + Requires JSON opcodes + https://git.1bpm.net/csound-json + + This file is part of the SONICS UDO collection by Richard Knight 2022 + License: GPL-2.0-or-later + http://1bpm.net +*/ +#include "sequencing_melodic_persistence.udo" +#include "table_tools.udo" +#include "pgdb.udo" + +opcode scss_json2tab, 0, ii + iJson, ifn xin + if (jsontype(iJson) == 4) then + iarray[] jsonarrval iJson + copya2ftab iarray, ifn + endif +endop + +opcode scss_json2tab, 0, iiS + iJsonTop, ifn, Skey xin + iJson = jsonget(iJsonTop, Skey) + scss_json2tab(iJson, ifn) + jsondestroy(iJson) +endop + +opcode scss_tabarr2json, 0, iSi[][] + iJson, Srelname, ifns[][] xin + iJarrTop = jsonloads("[]") + index = 0 + while (index < lenarray(ifns, 1)) do + iJarrSub = jsonloads("[]") + index2 = 0 + while (index2 < lenarray(ifns, 2)) do + iJtable = jsonloads(tab_serialise(ifns[index][index2])) + jsonptradd iJarrSub, sprintf("/%d", jsonsize(iJarrSub)), iJtable + index2 += 1 + od + index += 1 + jsonptradd iJarrTop, sprintf("/%d", jsonsize(iJarrTop)), iJarrSub + jsondestroy(iJarrSub) + od + jsoninsert iJson, Srelname, iJarrTop + jsondestroy(iJarrTop) +endop + + +opcode scss_json2tabarr, i[][], iSi[][] + iJsonTop, Srelname, ifns[][] xin + iJson = jsonget(iJsonTop, Srelname) + isize = jsonsize(iJson) + index = 0 + while (index < isize) do + iJsonSub = jsonget(iJson, index) + isize2 = jsonsize(iJsonSub) + index2 = 0 + while (index2 < isize2) do + iJtable = jsonget(iJsonSub, index2) + + iarray[] jsonarrval iJsonSub + copya2ftab iarray, ifns[index][index2] + ;tab_unserialise(jsondumps(iJtable, 0), ifns[index][index2]) + jsondestroy(iJtable) + index2 += 1 + od + jsondestroy(iJsonSub) + index += 1 + od + jsondestroy(iJson) + xout ifns +endop + + +/* + Set parameters based on a JSON object with key as channel name and value as channel value to be set + + scss_setparamstate iJsonInput + + iJsonInput JSON object of channel values +*/ +opcode scss_setparamstate, 0, i + iJsonInput xin + Skeys[] jsonkeys iJsonInput + index = 0 + while (index < lenarray(Skeys)) do + Sparam = Skeys[index] + chnset jsongetval:i(iJsonInput, Sparam), Sparam + index += 1 + od +endop + + + +/* + Get parameters from a SCSS definition JSON object and append current values to iJsonOutput using channel prefix Sprefix + + _scss_getparams iJsonInput, iJsonOutput, Sprefix + + iJsonInput object to evaluate; should have an array with key "parameters" featuring objects which have a key "name" specifying parameter name + iJsonOutput output object to add values to (key is channel name, value is current value) + Sprefix parameter prefix to use for channel name +*/ +opcode _scss_getparams, 0, iiS + iJsonInput, iJsonOutput, Sprefix xin + SparameterPointer = "/parameters" + if (jsonptrhas(iJsonInput, SparameterPointer) == 1) then + iJsonParameters = jsonptr(iJsonInput, SparameterPointer) + iparamsize = jsonsize(iJsonParameters) + indexparam = 0 + while (indexparam < iparamsize) do + SparamName jsonptrval iJsonParameters, sprintf("/%d/name", indexparam) + Sparam = sprintf("%s_%s", Sprefix, SparamName) + jsoninsertval iJsonOutput, Sparam, chnget:i(Sparam) + indexparam += 1 + od + jsondestroy(iJsonParameters) + endif +endop + + +/* + Get all registered parameters in giscss_stateJson, and get current channel values, + returning an object with key as channel name and value as channel value + + iJsonOutput scss_getparamstate + + iJsonOutput JSON object of channel values +*/ +opcode scss_getparamstate, i, 0 + iJsonOutput = jsoninit() + + + ; global parameters + _scss_getparams(giscss_stateJson, iJsonOutput, "scss") + + ; categories + iJsonCategories = jsonptr(giscss_stateJson, "/categories") + icatnum = jsonsize(iJsonCategories) + jsondestroy(iJsonCategories) + index = 0 + while (index < icatnum) do + iJsonCategory = jsonptr(giscss_stateJson, sprintf("/categories/%d", index)) + Scategory jsonptrval iJsonCategory, "/name" + + ; category parameters + _scss_getparams(iJsonCategory, iJsonOutput, Scategory) + + ; items/instruments + iJsonItems = jsonptr(iJsonCategory, "/items") + iinstrnum = jsonsize(iJsonItems) + indexItem = 0 + while (indexItem < iinstrnum) do + iJsonItem = jsonptr(iJsonItems, sprintf("/%d", indexItem)) + Sinstrument = jsongetval(iJsonItem, "name") + _scss_getparams(iJsonItem, iJsonOutput, Sinstrument) + jsondestroy(iJsonItem) + indexItem += 1 + od + jsondestroy(iJsonItems) + jsondestroy(iJsonCategory) + index += 1 + od + xout iJsonOutput +endop + + + +/* + Get sequencing state as JSON object + + iJsonSeq scss_getseqstate + + iJsonSeq object of sequencing data +*/ +opcode scss_getseqstate, i, 0 + iJsonSeq = jsoninit() + scss_tabarr2json(iJsonSeq, "giscss_stfn_trig", giscss_stfn_trig) + scss_tabarr2json(iJsonSeq, "giscss_stfn_dur", giscss_stfn_dur) + scss_tabarr2json(iJsonSeq, "giscss_stfn_params", giscss_stfn_params) + + Skeys[] fillarray "giscss_st_size", "giscss_st_slots", "giscss_st_paramnumber" ; giscss_stfn_temp", "giscss_stfn_param_temp" + ivalues[] fillarray giscss_st_size, giscss_st_slots, giscss_st_paramnumber ; giscss_stfn_temp giscss_stfn_param_temp + jsoninsertval(iJsonSeq, Skeys, ivalues) + xout iJsonSeq +endop + + + +/* + Set sequencing state from JSON object + + scss_setseqstate iJsonSeq + + iJsonSeq object of sequencing data +*/ +opcode scss_setseqstate, 0, i + iJsonSeq xin + + giscss_stfn_trig scss_json2tabarr iJsonSeq, "giscss_stfn_trig", giscss_stfn_trig + giscss_stfn_dur scss_json2tabarr iJsonSeq, "giscss_stfn_dur", giscss_stfn_dur + giscss_stfn_params scss_json2tabarr iJsonSeq, "giscss_stfn_params", giscss_stfn_params + + giscss_st_size = jsongetval:i(iJsonSeq, "giscss_st_size") + giscss_st_slots = jsongetval:i(iJsonSeq, "giscss_st_slots") + giscss_st_paramnumber = jsongetval:i(iJsonSeq, "giscss_st_paramnumber") +endop + + + +opcode scss_getstate, i, ppppp + igetsequencing, igetparameters, igetmelstate, igetinstrstate, igetcatenabled xin + + iJson = jsoninit() + + if (igetsequencing == 1) then + iJsonSequencing = scss_getseqstate() + jsoninsert(iJson, "sequencing", iJsonSequencing) + jsondestroy(iJsonSequencing) + endif + + if (igetparameters == 1) then + iJsonParameters = scss_getparamstate() + jsoninsert(iJson, "parameters", iJsonParameters) + jsondestroy(iJsonParameters) + endif + + if (igetmelstate == 1) then + iJsonMelstate = mel_getstate_json() + jsoninsert(iJson, "melstate", iJsonMelstate) + jsondestroy(iJsonMelstate) + endif + + + if (igetinstrstate == 1) then + iJinstrState = jsonloads(tab_serialise(giscss_instrState)) + jsoninsert(iJson, "giscss_instrState", iJinstrState) + jsondestroy(iJinstrState) + endif + + if (igetcatenabled == 1) then + iJcatEnabled = jsonloads(tab_serialise(giscss_catEnabled)) + jsoninsert(iJson, "giscss_catEnabled", iJcatEnabled) + jsondestroy(iJcatEnabled) + endif + + xout iJson +endop + + + +opcode scss_setstate, 0, ippppp + iJson, isetsequencing, isetparameters, isetmelstate, isetinstrstate, isetcatenabled xin + + if (isetsequencing == 1 && jsonptrhas(iJson, "/sequencing") == 1) then + iJsonSequencing = jsonget(iJson, "sequencing") + scss_setseqstate(iJsonSequencing) + jsondestroy(iJsonSequencing) + endif + + if (isetparameters == 1 && jsonptrhas(iJson, "/parameters") == 1) then + iJsonParameters = jsonget(iJson, "parameters") + scss_setparamstate(iJsonParameters) + jsondestroy(iJsonParameters) + endif + + if (isetmelstate == 1 && jsonptrhas(iJson, "/melstate") == 1) then + iJsonMelstate = jsonget(iJson, "melstate") + mel_setstate_json(iJsonMelstate) + jsondestroy(iJsonMelstate) + endif + + if (isetinstrstate == 1 && jsonptrhas(iJson, "/giscss_instrState") == 1) then + iJinstrState = jsonget(iJson, "giscss_instrState") + endif + + if (isetcatenabled == 1 && jsonptrhas(iJson, "/giscss_catEnabled") == 1) then + iJcatEnabled = jsonget(iJson, "giscss_catEnabled") + endif + +endop + + + +/* + Get the current values of all registered parameters, returning callback ID to host and an object with key "parameters" + containing keys as the channel names and values as the channel values + + p4 callback ID +*/ +instr scss_getparamstate + icbid = p4 + iJson = jsoninit() + iJsonState = scss_getparamstate() + jsoninsert iJson, "parameters", iJsonState + jsoninsertval iJson, "cbid", icbid + jsoninsertval iJson, "status", "complete" + io_sendstring("callback", jsondumps(iJson, 0)) + jsondestroy(iJsonState) + jsondestroy(iJson) + turnoff +endin + + + +/* + Save state to database + + p4 callback ID + p5 reference name of the state to save; blank is accepted and saves as SCSS_NAME +*/ +instr scss_savestate_db + icbid = p4 + Sreference = strcat("$SCSS_NAME||", strget(p5)) + + ; save state values + iJsonState = scss_getstate() + Squery = sprintf("DELETE FROM savejson WHERE name = '%s' AND unit = 'scss_state'; INSERT INTO savejson (name, data, unit, created) VALUES ('%s', '%s', 'scss_state', current_timestamp)",\ + Sreference, Sreference, jsondumps(iJsonState, 0)\ + ) + dbexec gidb, Squery + jsondestroy(iJsonState) + + + ; return callback ID to host + iJson = jsoninit() + jsoninsertval iJson, "cbid", icbid + jsoninsertval iJson, "status", "complete" + io_sendstring("callback", jsondumps(iJson, 0)) + turnoff +endin + + + + +/* + Load parameter state from database, returning JSON to host as in the instrument scss_getparamstate + + p4 callback ID + p5 reference name of the state to load; blank is accepted and loads as SCSS_NAME +*/ +instr scss_loadstate_db + icbid = p4 + Sreference = strcat("$SCSS_NAME||", strget(p5)) + + ; load parameter values + Squery = sprintf("SELECT data::text FROM savejson WHERE unit = 'scss_state' AND name = '%s'", Sreference) + Sresult dbscalar gidb, Squery + iJson = jsonloads(Sresult) + scss_setstate(iJson) + jsondestroy(iJson) + + ; returns state data and callback ID to host + schedule("scss_getparamstate", 0, 1, icbid) + turnoff +endin + + +#end -- cgit v1.2.3