1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
|
#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
|