diff options
Diffstat (limited to 'site/udo/sequencing_melodic_persistence.udo')
-rwxr-xr-x | site/udo/sequencing_melodic_persistence.udo | 275 |
1 files changed, 275 insertions, 0 deletions
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
|