diff options
Diffstat (limited to 'site/udo/twigs/twigs.udo')
-rwxr-xr-x | site/udo/twigs/twigs.udo | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/site/udo/twigs/twigs.udo b/site/udo/twigs/twigs.udo new file mode 100755 index 0000000..a4bda3f --- /dev/null +++ b/site/udo/twigs/twigs.udo @@ -0,0 +1,444 @@ +#ifndef UDO_TWIGS
+#define UDO_TWIGS ##
+/*
+ Twigs
+ Spectral transformer
+
+ This file is part of the SONICS UDO collection by Richard Knight 2024, 2025
+ License: GPL-2.0-or-later
+ http://1bpm.net
+*/
+
+#include "/pvs_fulltabproc.udo"
+#include "/host_platform.udo"
+#include "/lagdetect.udo"
+#include "/interop.udo"
+
+gitwgs_bufferL = -1
+gitwgs_bufferR = -1
+gitwgs_tpvfHandleL = -1
+gitwgs_tpvfHandleR = -1
+gitwgs_channels = -1
+gitwgs_userstopped = 0
+gitwgs_fnbinselection = -1
+gitwgs_fnbintimeselection = -1
+
+#include "/twigs/checkpointing.udo"
+
+opcode twgs_getselectionindexes, ii, i
+ indexbin xin
+ ibins = ftlen(gitwgs_fnbinselection)
+ itablen = ftlen(tab_i(2, gitwgs_tpvfHandleL))
+ iframes = itablen / ibins
+ istartindex = (round(tab_i(indexbin, gitwgs_fnbintimeselection) * iframes) * ibins) + indexbin
+ iendindex = (round(tab_i(indexbin + ibins, gitwgs_fnbintimeselection) * iframes) * ibins) + indexbin
+ if (iendindex > itablen) then
+ iendindex = itablen
+ endif
+
+;print tab_i(indexbin, gitwgs_fnbintimeselection)
+;print istartindex
+;print tab_i(indexbin + ibins, gitwgs_fnbintimeselection)
+;print iendindex
+ xout istartindex, iendindex
+endop
+
+opcode twgs_failresponse, S, ij
+ icbid, istatus xin
+ xout sprintf("{\"cbid\":%d,\"status\":%d}", icbid, istatus)
+endop
+
+
+opcode twgs_refreshviewresponse, S, i
+ icbid xin
+ ifnampL tab_i 2, gitwgs_tpvfHandleL
+ ifnfreqL tab_i 3, gitwgs_tpvfHandleL
+ iduration tab_i 4, gitwgs_tpvfHandleL
+ if (gitwgs_channels == 2) then
+ ifnampR tab_i 2, gitwgs_tpvfHandleR
+ ifnfreqR tab_i 3, gitwgs_tpvfHandleR
+ else
+ ifnampR = -1
+ ifnfreqR = -1
+ endif
+ xout sprintf("{\"cbid\":%d,\"status\":1,\"tables\":[%d,%d,%d,%d],\"duration\":%f,\"undolevel\":%d}", icbid, ifnampL, ifnfreqL, ifnampR, ifnfreqR, iduration, gitwgs_checkpointstate)
+endop
+
+
+opcode twgs_clearbuffers, 0, pp
+ ihandles, ibuffers xin
+ if (ibuffers == 1) then
+ if (gitwgs_bufferL > 0 && ftexists(gitwgs_bufferL) == 1) then
+ ftfree gitwgs_bufferL, 0
+ gitwgs_bufferL = -1
+ endif
+ if (gitwgs_bufferR > 0 && ftexists(gitwgs_bufferR) == 1) then
+ ftfree gitwgs_bufferR, 0
+ gitwgs_bufferR = -1
+ endif
+ endif
+
+ if (ihandles == 1) then
+ if (gitwgs_tpvfHandleL > 0 && ftexists(gitwgs_tpvfHandleL) == 1) then
+ ftfree gitwgs_tpvfHandleL, 0
+ gitwgs_tpvfHandleL = -1
+ endif
+ if (gitwgs_tpvfHandleR > 0 && ftexists(gitwgs_tpvfHandleR) == 1) then
+ ftfree gitwgs_tpvfHandleR, 0
+ gitwgs_tpvfHandleR = -1
+ endif
+ gitwgs_channels = -1
+ endif
+endop
+
+opcode twgs_loadfile, ik, Sjj
+ Spath, ifftsize, ifftdecimation xin
+ kdone init 0
+ if (filevalid(Spath) != 1) then
+ iresponse = -1
+ goto complete
+ endif
+
+ ifilesr = filesr(Spath)
+ ifilechannels = filenchnls(Spath)
+ ilens = filelen(Spath)
+ ilen = round(ilens * ifilesr)
+
+ if (ilen >= gihost_max32bitftlen || ilens * sr >= gihost_max32bitftlen) then ; limitation with WASM Csound build at the moment
+ iresponse = -2
+ goto complete
+ endif
+
+ gitwgs_channels = ifilechannels
+ twgs_clearbuffers()
+ twgs_checkpoint_clear()
+
+ gitwgs_bufferL = ftgen(0, 0, -ilen, 1, Spath, 0, 0, 1)
+ if (gitwgs_channels == 2) then
+ gitwgs_bufferR = ftgen(0, 0, -ilen, 1, Spath, 0, 0, 2)
+ imono = 0
+ else
+ imono = 1
+ endif
+
+ if (sr != ifilesr) then ; different sr causes issues in table reading opcodes, convert..
+ inewlen = ilens * sr
+ ifnnewL ftgen 0, 0, -inewlen, -2, 0
+ if (imono == 0) then
+ ifnnewR ftgen 0, 0, -inewlen, -2, 0
+ endif
+ ktimek timeinstk
+ ikcycles = ilens * kr
+ if (ktimek == 1) then
+ kcount = 0
+ while (kcount < ikcycles) do
+ aposw linseg 0, ilens, inewlen - 1
+ aposr linseg 0, ilens, ilen - 1
+ asig table3 aposr, gitwgs_bufferL
+ tablew asig, aposw, ifnnewL
+ if (imono == 0) then
+ asig table3 aposr, gitwgs_bufferR
+ tablew asig, aposw, ifnnewR
+ endif
+ kcount += 1
+ od
+ else
+ kdone = 1
+ endif
+
+ ftfree gitwgs_bufferL, 1
+ gitwgs_bufferL = ifnnewL
+ if (imono == 0) then
+ ftfree gitwgs_bufferR, 1
+ gitwgs_bufferR = ifnnewR
+ endif
+ else
+ kdone = 1
+ endif
+
+ iresponse = 1
+complete:
+ xout iresponse, kdone
+endop
+
+
+#include "/twigs/transforms.udo"
+
+
+instr twgs_undo
+ icbid = p4
+
+ istatus twgs_undo
+ if (istatus < 0) then
+ Sresponse = twgs_failresponse(icbid)
+ else
+ Sresponse = twgs_refreshviewresponse(icbid)
+ endif
+
+ io_sendstring("callback", Sresponse)
+ turnoff
+endin
+
+
+instr twgs_stop
+ gitwgs_userstopped = 1
+ turnoff2 "twgs_play", 0, 1
+ turnoff
+endin
+
+instr twgs_playcomplete_response
+ icbid = p4
+ istatus = 0
+ if (gitwgs_userstopped == 1) then
+ istatus = 3
+ endif
+ io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":%d}", icbid, istatus))
+ turnoff
+endin
+
+instr twgs_playlag_response
+ icbid = p4
+ turnoff2 "twgs_play", 0, 0
+ io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":-1}", icbid))
+ turnoff
+endin
+
+instr twgs_play
+ icbid = p4
+ iplaytype = p5 ; 0 = from analysis, 1 = from buffer
+ iselectedonly = p6
+ istart = p7
+ iend = p8
+ iresynthtype = p9 ; 0 = pvsynth, 1 = pvsadsyn
+ gitwgs_userstopped = 0
+ io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":1}", icbid))
+
+ ilen = tab_i(4, gitwgs_tpvfHandleL)
+ p3 = ilen * (iend - istart)
+
+ if (iplaytype == 0) then
+ if (iselectedonly == 1) then
+ ibinselection = gitwgs_fnbinselection
+ else
+ ibinselection = -1
+ endif
+
+ istartframe = tpvf_framecount(gitwgs_tpvfHandleL) * istart
+ aL, k_ tpvf_resynth gitwgs_tpvfHandleL, ibinselection, iresynthtype, 0, istartframe
+ aL dcblock aL
+ if (gitwgs_channels == 2) then
+ aR, k_ tpvf_resynth gitwgs_tpvfHandleR, ibinselection, iresynthtype, istartframe
+ aR dcblock aR
+ else
+ aR = aL
+ endif
+ else
+ apos lphasor 1
+ apos += (istart * ftlen(gitwgs_bufferL))
+ aL table3 apos, gitwgs_bufferL
+ if (gitwgs_channels == 2) then
+ aR table3 apos, gitwgs_bufferR
+ else
+ aR = aL
+ endif
+ endif
+
+ kpos linseg istart, p3, iend
+ chnset kpos, "twgs_playposratio"
+
+ klagging lagdetect 1.1
+ if (klagging == 1) then
+ schedulek("twgs_playlag_response", 0, 1, icbid)
+ endif
+
+ kreleasing init 0
+ ktimek timeinstk
+ iduration = (p3 * kr) ;+ (iextracycles / sr)
+ krelease release
+ if (kreleasing == 0 && (krelease == 1 || ktimek >= iduration)) then
+ kreleasing = 1
+ schedulek("twgs_playcomplete_response", 0, 1, icbid)
+ turnoff
+ endif
+ outs aL, aR
+endin
+
+
+instr twgs_resynth_response
+ icbid = p4
+ io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":1}", icbid))
+ turnoff
+endin
+
+instr twgs_resynth
+ icbid = p4
+ Snext = strget(p5)
+ iresynthtype = p6 ; 0 = pvsynth, 1 = pvsadsyn
+ p3 = 3600
+ io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":5}", icbid))
+ twgs_clearbuffers(0, 1)
+ kdone init 0
+ gitwgs_bufferL, kdoneL tpvf_resynth_offline gitwgs_tpvfHandleL, iresynthtype
+ if (gitwgs_channels == 2) then
+ gitwgs_bufferR, kdoneR tpvf_resynth_offline gitwgs_tpvfHandleR, iresynthtype
+ else
+ kdoneR init 1
+ endif
+ if (kdoneL == 1 && kdoneR == 1) then
+ schedulek(Snext, 0, 1, icbid, 1)
+ turnoff
+ endif
+endin
+
+instr twgs_getbuffers
+ icbid = p4
+ if (gitwgs_channels == 2) then
+ Stables = sprintf("[%d,%d]", gitwgs_bufferL, gitwgs_bufferR)
+ else
+ Stables = sprintf("[%d]", gitwgs_bufferL)
+ endif
+ io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":1,\"tables\":%s}", icbid, Stables))
+ turnoff
+endin
+
+
+instr twgs_savefile_response
+ icbid = p4
+ Spath = p5
+ io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":1,\"path\":\"%s\"}", icbid, Spath))
+ turnoff
+endin
+
+
+instr twgs_savefile
+ icbid = p4
+ Spath = strget(p5)
+
+ ktimek timeinstk
+ idurations = ftlen(gitwgs_bufferL) / sr
+ ikcycles = idurations * kr
+ if (ktimek == 1) then
+ kcount init 0
+ while (kcount < ikcycles) do
+ apos lphasor 1
+ aL table apos, gitwgs_bufferR
+ if (gitwgs_channels == 1) then
+ fout Spath, 14, aL
+ else
+ aR table3 apos, gitwgs_bufferL
+ fout Spath, 14, aL, aR
+ endif
+ kcount += 1
+ od
+ else
+ schedulek("twgs_savefile_response", 0, 1, icbid, Spath)
+ turnoff
+ endif
+endin
+
+
+
+instr twgs_loadfilecomplete_response
+ icbid = p4
+ ifftsize tab_i 0, gitwgs_tpvfHandleL
+ ifftdecimation tab_i 1, gitwgs_tpvfHandleL
+ ifnampL tab_i 2, gitwgs_tpvfHandleL
+ ifnfreqL tab_i 3, gitwgs_tpvfHandleL
+ iduration tab_i 4, gitwgs_tpvfHandleL
+ if (gitwgs_channels == 2) then
+ ifnampR tab_i 2, gitwgs_tpvfHandleR
+ ifnfreqR tab_i 3, gitwgs_tpvfHandleR
+ else
+ ifnampR = -1
+ ifnfreqR = -1
+ endif
+
+ Sresponse = sprintf("{\"cbid\":%d,\"status\":1,\"channels\":%d,\"tables\":[%d,%d,%d,%d],\"bins\":%d,\"binseltab\":%d,\"bintimeseltab\":%d,\"duration\":%f,\"undolevel\":%d,\"fftdecim\":%d,\"sr\":%d}", icbid, gitwgs_channels, ifnampL, ifnfreqL, ifnampR, ifnfreqR, ifftsize / 2, gitwgs_fnbinselection, gitwgs_fnbintimeselection, iduration, gitwgs_checkpointstate, ifftdecimation, sr)
+ io_sendstring("callback", Sresponse)
+ turnoff
+endin
+
+instr twgs_loadfile_analysis
+ icbid = p4
+ ifftsize = p5
+ ifftdecimation = p6
+
+ itablen = tpvf_tablen(ftlen(gitwgs_bufferL), ifftsize, ifftdecimation)
+ if (itablen >= gihost_max32bitftlen) then
+ io_sendstring("callback", twgs_failresponse(icbid, -2))
+ turnoff
+ endif
+
+ kdoneL, gitwgs_tpvfHandleL tpvf_analyse gitwgs_bufferL, ifftsize, ifftdecimation
+ ftfree gitwgs_bufferL, 1
+ if (gitwgs_channels == 2) then
+ kdoneR, gitwgs_tpvfHandleR tpvf_analyse gitwgs_bufferR, ifftsize, ifftdecimation
+ ftfree gitwgs_bufferR, 1
+ else
+ istatusR = 1
+ kdoneR init 1
+ endif
+
+ if (gitwgs_fnbinselection > 0) then
+ ftfree gitwgs_fnbinselection, 0
+ endif
+ gitwgs_fnbinselection ftgen 0, 0, -(ifftsize / 2), -2, 0
+
+ if (gitwgs_fnbintimeselection > 0) then
+ ftfree gitwgs_fnbintimeselection, 0
+ endif
+ gitwgs_fnbintimeselection ftgen 0, 0, -ifftsize, -2, 0
+
+ if (kdoneL == 1 && kdoneR == 1) then
+ schedule("twgs_loadfilecomplete_response", 0, 1, icbid)
+ turnoff
+ endif
+endin
+
+
+instr twgs_loadftable
+ icbid = p4
+ ifftsize = p5
+ ifftdecimation = p6
+ ifnL = p7
+ ifnR = p8
+ iclearaudiobuffers = p9
+
+ if (ifnL <= 0 || ftexists(ifnL) == 0 || (ifnR > 0 && ftexists(ifnR) == 0)) then
+ io_sendstring("callback", twgs_failresponse(icbid, -1))
+ turnoff
+ endif
+
+ twgs_clearbuffers(1, iclearaudiobuffers)
+ twgs_checkpoint_clear()
+
+ gitwgs_bufferL = ifnL
+ if (ifnR > 0) then
+ gitwgs_bufferR = ifnR
+ gitwgs_channels = 2
+ else
+ gitwgs_channels = 1
+ endif
+
+ schedule("twgs_loadfile_analysis", 0, 1, icbid, ifftsize, ifftdecimation)
+ turnoff
+endin
+
+instr twgs_loadfile
+ icbid = p4
+ Spath = strget(p5)
+ ifftsize = p6
+ ifftdecimation = p7
+ istatus, kdone twgs_loadfile Spath
+ if (istatus < 0) then
+ io_sendstring("callback", twgs_failresponse(icbid, istatus))
+ turnoff
+ else
+ if (kdone == 1) then
+ schedulek("twgs_loadfile_analysis", 0, 1, icbid, ifftsize, ifftdecimation)
+ turnoff
+ endif
+ endif
+endin
+
+#end
|