#ifndef UDO_MELSEQUENCINGPERSIST #define UDO_MELSEQUENCINGPERSIST ## /* Melodic sequencer persistence: saving/loading from files and database Web version This file is part of the SONICS UDO collection by Richard Knight 2021, 2022, 2024 License: GPL-2.0-or-later http://1bpm.net */ #include "/sequencing_melodic.udo" #include "/array_tools.udo" #include "/table_tools.udo" #include "/interop.udo" #include "/json.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, S, 0 Sjson = "{" index = 0 while (index < lenarray(gimel_fns)) do Sjson = strcat(Sjson, sprintf("\"%s\":%s,", gSmel_names[index], tab_serialise(gimel_fns[index]))) index += 1 od Sjson = strcat(Sjson, sprintf("\"state\":%s,", tab_serialise(gimel_state))) Sjson = strcat(Sjson, sprintf("\"details\":\"%s\",\"mel_number\":%d,\"seq_tempo\":%f,\"seq_swing\":%f}", gSmel_details, gimel_number, i(gkseq_tempo), i(gkseq_swing))) xout Sjson endop /* Set the current sequencing and progression state mel_setstate_json SJson SJson JSON string containing state data */ opcode mel_setstate_json, 0, S Sjson xin i_, gSmel_details, i_ json_parse Sjson, "details" i_, S_, gimel_number json_parse Sjson, "mel_number" i_, S_, itempo json_parse Sjson, "seq_tempo" i_, S_, iswing json_parse Sjson, "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 i_, Stringvalue, i_ json_parse Sjson, gSmel_names[index] iarray[] json_getnumericarray Stringvalue copya2ftab iarray, gimel_fns[index] index += 1 od i_, Stringvalue, i_ json_parse Sjson, "state" iarray[] json_getnumericarray Stringvalue copya2ftab iarray, gimel_state endop instr mel_savestate_fs prints sprintf("%s unsupported in web UDO\n", nstrstr(p1)) turnoff endin instr mel_loadstate_fs prints sprintf("%s unsupported in web UDO\n", nstrstr(p1)) turnoff endin /* 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 turnoff endin /* 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 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 mel_setstate_json(Sdata) 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 Sjson = mel_getstate_json() Sjson json_appendvalue Sjson, "cbid", icbid 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 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