From 9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22 Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 13 Apr 2025 18:48:02 +0100 Subject: initial --- site/udo/twist/twist.udo | 1304 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1304 insertions(+) create mode 100755 site/udo/twist/twist.udo (limited to 'site/udo/twist/twist.udo') diff --git a/site/udo/twist/twist.udo b/site/udo/twist/twist.udo new file mode 100755 index 0000000..34fa7cb --- /dev/null +++ b/site/udo/twist/twist.udo @@ -0,0 +1,1304 @@ +#ifndef UDO_TWIST +#define UDO_TWIST ## +/* + Twist + Waveform editor and transformer + + This file is part of the SONICS UDO collection by Richard Knight 2024 + License: GPL-2.0-or-later + http://1bpm.net +*/ + + +#include "/table_tools.udo" +#include "/host_platform.udo" +#include "/wavetables.udo" +#include "/interop.udo" +#include "/bussing.udo" +#include "/chop.udo" +#include "/transient_detect.udo" + +#ifdef TWST_FAILONLAG +#include "/lagdetect.udo" +#end + +gitwst_userstopped = 0 +imaxinstances = 16 +gitwst_instanceindex = 0 +gitwst_channels[] init imaxinstances +gitwst_duration[] init imaxinstances +gitwst_bufferL[] init imaxinstances +gitwst_bufferR[] init imaxinstances + +gitwst_copyBufferL = 0 +gitwst_copyBufferR = 0 + +gitwst_tf_state[] init 7 + +#include "/twist/checkpointing.udo" + +opcode twst_clearbuffers, 0, jj + ibufferL, ibufferR xin + ibufferL = (ibufferL == -1) ? gitwst_bufferL[gitwst_instanceindex] : ibufferL + ibufferR = (ibufferR == -1) ? gitwst_bufferR[gitwst_instanceindex] : ibufferR + + if (ibufferL > 0 && ftexists(ibufferL) == 1) then + ftfree ibufferL, 1 + endif + if (ibufferR > 0 && ftexists(ibufferR) == 1) then + ftfree ibufferR, 1 + endif +endop + +opcode twst_samplestoratio, ii, iij + istart, iend, instanceindex xin + instanceindex = (instanceindex == -1) ? gitwst_instanceindex : instanceindex + itotallen = ftlen(gitwst_bufferL[instanceindex]) + if (istart > 1 && iend > 1) then + istart /= itotallen + iend /= itotallen + endif + xout istart, iend +endop + +opcode twst_getstartend, iii, iij + istart, iend, instanceindex xin + instanceindex = (instanceindex == -1) ? gitwst_instanceindex : instanceindex + itotallen = ftlen(gitwst_bufferL[instanceindex]) + if (istart <= 1 && iend <= 1) then + istart *= itotallen + iend *= itotallen + ilen = int(iend - istart) + istart = int(istart) + iend = int(iend) + else + istart = max(0, istart) + iend = min(itotallen, iend) + ilen = iend - istart + endif + xout istart, ilen, iend +endop + +opcode twst_getstartend, ii, iij + istart, iend, instanceindex xin + istart, ilen, iend twst_getstartend istart, iend, instanceindex + xout istart, ilen +endop + +#include "/twist/transform_api.udo" + +opcode twst_createoverviewsextra, S, iSjjjp + icbid, Sextra, iselstart, iselend, instanceindex, istatus xin + instanceindex = (instanceindex == -1) ? gitwst_instanceindex : instanceindex + + iduration = ftlen(gitwst_bufferL[instanceindex]) / ftsr(gitwst_bufferL[instanceindex]) + if (qnan(iduration) == 1) then + iduration = 1 + endif + gitwst_duration[instanceindex] = iduration + Sresponse = sprintf("{\"cbid\":%d,\"status\":%d,\"waveL\":%d,\"duration\":%f,\"undolevel\":%d", icbid, istatus, gitwst_bufferL[instanceindex], iduration, gitwst_checkpointstate[instanceindex]) + if (gitwst_channels[instanceindex] == 2) then + Sresponse = strcat(Sresponse, sprintf(",\"waveR\":%d", gitwst_bufferR[instanceindex])) + endif + + if (iselstart != -1 && iselend != -1) then + iselstart, iselend twst_samplestoratio iselstart, iselend, instanceindex + Sresponse = strcat(Sresponse, sprintf(",\"selstart\":%f,\"selend\":%f", iselstart, iselend)) + endif + + if (strcmp(Sextra, "") != 0) then + Sresponse = strcat(Sresponse, strcat(",", Sextra)) + endif + + xout strcat(Sresponse, "}") +endop + +opcode twst_createoverviews, S, ijjp + icbid, iselstart, iselend, istatus xin + Sresponse twst_createoverviewsextra icbid, "", iselstart, iselend, -1, istatus + xout Sresponse +endop + + +opcode twst_failresponse, S, ij + icbid, istatus xin + xout sprintf("{\"cbid\":%d,\"status\":%d}", icbid, istatus) +endop + +instr twst_successresponse + icbid = p4 + io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":1}", icbid)) + turnoff +endin + +instr twst_checkalive + icbid = p4 + io_sendstring("callback", sprintf("{\"cbid\": %d}", icbid)) + turnoff +endin + +opcode twst_setapplymode, aa, iaaaa + iuniqueid, aLorig, aRorig, aLnew, aRnew xin + kapplymode chnget sprintf("applymode%d", iuniqueid) + kdry chnget sprintf("applymodedry%d", iuniqueid) + kwet chnget sprintf("applymodewet%d", iuniqueid) + khpf chnget sprintf("applymodehpf%d", iuniqueid) + klpf chnget sprintf("applymodelpf%d", iuniqueid) + + ; applymode 0 is replace + if (kapplymode == 1) then ; mix + aLnew = (aLorig * kdry) + (aLnew * kwet) + aRnew = (aRorig * kdry) + (aRnew * kwet) + elseif (kapplymode == 2) then ; modulate + aLnew = aLorig * aLnew + aRnew = aRorig * aRnew + elseif (kapplymode == 3) then ; demodulate + aLnew = tanh(aLorig / aLnew) + aRnew = tanh(aRorig / aRnew) + elseif (kapplymode == 4) then ; filter mix + kbw = klpf - khpf + kfreq = khpf + (kbw / 2) + aLbp butterbp aLnew, kfreq, kbw + aLbr butterbr aLorig, kfreq, kbw + aRbp butterbp aRnew, kfreq, kbw + aRbr butterbr aRorig, kfreq, kbw + aLnew = aLbp + aLbr + aRnew = aRbp + aRbr + endif + xout aLnew, aRnew +endop + + +opcode twst_playback, iaaiiiii, iiiSiioooOPo + istart, iend, ichannel, Stransform, ioffline, iautomating, icrossfadein, icrossfadeout, iuniqueid xin + itransforming = strcmp(Stransform, "") + if (istart == iend) then + istart = istart + iend = 1 + endif + + istatus = 1 + itfi = (strcmp(strsub(Stransform, 5, 8), "tfi") == 0) ? 1 : 0 + ibuflen = ftlen(gitwst_bufferL[gitwst_instanceindex]) + istartsamp = ibuflen * istart + iendsamp = ibuflen * iend + iendsampw = iendsamp + ilensamp = iendsamp - istartsamp + iextracycles = 0 + idurations = ilensamp / ftsr(gitwst_bufferL[gitwst_instanceindex]) + p3 = idurations + icrossfadeins = idurations * icrossfadein + icrossfadeouts = idurations * icrossfadeout + + ileft = 1 + iright = 1 + if (ichannel == 0 || gitwst_channels[gitwst_instanceindex] == 1) then + iright = 0 + elseif (ichannel == 1 && gitwst_channels[gitwst_instanceindex] == 2) then + ileft = 0 + endif + + if (ioffline == 1) then + idelaysamples = gitwst_tf_state[5] + if (idelaysamples > 0) then + idelays = idelaysamples / sr + iextracycles = round(kr * idelays) + else + idelays = 0 + endif + else + idelaysamples = 0 + iextracycles = 0 + idelays = 0 + endif + + gitwst_tf_state[0] = ileft + gitwst_tf_state[1] = iright + gitwst_tf_state[2] = istartsamp + gitwst_tf_state[3] = iendsamp + gitwst_tf_state[5] = 0 ; latency for fft processing etc + gitwst_tf_state[6] = ioffline + + aL init 0 + aR init 0 + ifnL = gitwst_bufferL[gitwst_instanceindex] + ifnR = gitwst_bufferR[gitwst_instanceindex] + ifnTargetL = gitwst_bufferL[gitwst_instanceindex] + ifnTargetR = gitwst_bufferR[gitwst_instanceindex] + + if (itfi == 1) then + idocut = 0 + if (istart != 0 && iend != 1) then + idocut = 1 + endif + + ; only 4 pfields in subinstr allowed + gitwst_tf_state[4] = idocut + aoutL, aoutR subinstr Stransform, iuniqueid + ; aoutL, aoutR twst_setapplymode iuniqueid, aL, aR, aoutL, aoutR ; no applymode for tfi + if (iautomating == 1) then + a_ subinstr "twst_automaterun" + endif + + if (ioffline == 1) then + itargetlen = int(p3 * sr) + iextracycles += (p3 * kr) + iendsampw = istartsamp + itargetlen + + if (p3 != idurations) then + inewlen = (ftlen(gitwst_bufferL[gitwst_instanceindex]) - ilensamp) + itargetlen + if (inewlen >= gihost_max32bitftlen) then ; limitation with WASM Csound build at the moment + istatus = -2 + goto complete + endif + + ifnTargetL ftgen 0, 0, -inewlen, -2, 0 + ifnTargetR ftgen 0, 0, -inewlen, -2, 0 + + if (istartsamp != 0) then ; copy part before commit + indexr = 0 + indexw = 0 + while (indexw < istartsamp - 1) do + if (ileft == 1) then + tabw_i tab_i(indexr, gitwst_bufferL[gitwst_instanceindex]), indexw, ifnTargetL + endif + if (iright == 1) then + tabw_i tab_i(indexr, gitwst_bufferR[gitwst_instanceindex]), indexw, ifnTargetR + endif + indexr += 1 + indexw += 1 + od + +/* aliasing from ftslice??? + if (ileft == 1) then + ftslicei gitwst_bufferL[gitwst_instanceindex], ifnTargetL, 0, istartsamp, 1 + endif + if (iright == 1) then + ftslicei gitwst_bufferR[gitwst_instanceindex], ifnTargetR, 0, istartsamp, 1 + endif +*/ + endif + + if (iendsampw < ftlen(ifnTargetL)) then ; copy part after commit + indexr = iendsamp + 1 + indexw = iendsampw + 1 + while (indexw < inewlen - 1) do + if (ileft == 1) then + tabw_i tab_i(indexr, gitwst_bufferL[gitwst_instanceindex]), indexw, ifnTargetL + endif + if (iright == 1) then + tabw_i tab_i(indexr, gitwst_bufferR[gitwst_instanceindex]), indexw, ifnTargetR + endif + indexr += 1 + indexw += 1 + od + endif + else + inewlen = ibuflen + endif + endif + idurations = p3 + + else ; is not tfi + inewlen = ibuflen ;ilensamp + aposr linseg istartsamp, idurations, iendsampw ;iendsamp + + if (ileft == 1) then + aL table3 aposr, ifnL + endif + if (iright == 1) then + aR table3 aposr, ifnR + endif + + if (itransforming == 1) then + if (iautomating == 1) then + a_ subinstr "twst_automaterun" + endif + chnset aL, "twstfeedL" + chnset aR, "twstfeedR" + aoutL, aoutR subinstr Stransform, iuniqueid + aoutL, aoutR twst_setapplymode iuniqueid, aL, aR, aoutL, aoutR + else + aoutL = aL + aoutR = aR + endif + endif ; end not tfi + + if (ioffline == 0) then + chnset -1, "twst_tfplayposratio" + kplayposratio chnget "twst_tfplayposratio" + if (kplayposratio >= 0) then + chnset (kplayposratio * (iend - istart)) + istart, "twst_playposratio" + else + ktimeenv linseg istart, p3, iend + chnset ktimeenv, "twst_playposratio" + endif + endif + + + if ((icrossfadein != 0 || icrossfadeout != 0) && (icrossfadein + icrossfadeout) < 1) then + icrossfadeins = max(0.0000001, icrossfadeins) ; god damn times can't seem to be 0 in linseg + icrossfademids = idurations - (icrossfadeins + icrossfadeouts) + icrossfademids = max(0.0000001, icrossfademids) + icrossfadeouts = max(0.0000001, icrossfadeouts) + + if (itfi == 1) then + imidsamp1 = istartsamp + (icrossfadeins * sr) + imidsamp2 = iendsamp - (icrossfadeouts * sr) + if (idelays != 0) then + aposr linseg istartsamp, idelays, istartsamp, icrossfadeins, imidsamp1, icrossfademids, imidsamp2, icrossfadeouts, iendsamp + else + aposr linseg istartsamp, icrossfadeins, imidsamp1, icrossfademids, imidsamp2, icrossfadeouts, iendsamp + endif + if (ileft == 1) then + aL table3 aposr, ifnL + endif + if (iright = 1) then + aR table3 aposr, ifnR + endif + + endif + + if (idelays != 0) then + acrossfade linseg 0, idelays, 0, icrossfadeins, 1, icrossfademids, 1, icrossfadeouts, 0 + else + acrossfade linseg 0, icrossfadeins, 1, icrossfademids, 1, icrossfadeouts, 0 + endif + + if (ileft == 1) then + aoutL = (aL * (1 - acrossfade)) + (aoutL * acrossfade) + endif + if (iright == 1) then + aoutR = (aR * (1 - acrossfade)) + (aoutR * acrossfade) + endif + endif + + if (chnget:i("twst_dcblockoutputs") == 1) then + aoutL dcblock2 aoutL + aoutR dcblock2 aoutR + endif + + if (chnget:i("twst_tanhoutputs") == 1) then + aoutL tanh aoutL + aoutR tanh aoutR + endif + + anull init 0 + if (ioffline == 1) then + if (itfi == 1) then + iendsampw = (idurations * sr) + istartsamp + endif + + if (idelays != 0) then + aposw linseg istartsamp, idelays, istartsamp, idurations, iendsampw + else + aposw linseg istartsamp, idurations, iendsampw + endif + + if (ileft == 1) then + tablew aoutL, aposw, ifnTargetL + endif + if (iright == 1) then + tablew aoutR, aposw, ifnTargetR + endif + amonitorL = anull + amonitorR = anull + else + amonitorL = aoutL + if (gitwst_channels[gitwst_instanceindex] == 1) then + amonitorR = amonitorL + else + amonitorR = aoutR + endif + endif + + inewlen = ftlen((ifnTargetL > 0) ? ifnTargetL : ifnTargetR) + +complete: + xout istatus, amonitorL, amonitorR, ifnTargetL, ifnTargetR, iextracycles, istartsamp / inewlen, iendsampw / inewlen +endop + + + +instr twst_setinstance + icbid = p4 + gitwst_instanceindex = p5 + io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":1}", icbid)) + turnoff +endin + +opcode twst_copy, k, opjj + istart, iend, ichannel, instanceindex xin + instanceindex = (instanceindex == -1) ? gitwst_instanceindex : instanceindex + + istart, ilen, iend twst_getstartend istart, iend + + twst_clearbuffers(gitwst_copyBufferL, gitwst_copyBufferR) + gitwst_copyBufferL = -1 + gitwst_copyBufferR = -1 + + if (gitwst_channels[instanceindex] == 2 && ichannel == -1) then + kdone, gitwst_copyBufferL, gitwst_copyBufferR chop_copyk istart, ilen, gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex] + elseif (ichannel == 1) then + kdone, gitwst_copyBufferR, i_ chop_copyk istart, ilen, gitwst_bufferR[instanceindex] + else + kdone, gitwst_copyBufferL, i_ chop_copyk istart, ilen, gitwst_bufferL[instanceindex] + endif + xout kdone +endop + +instr twst_copy + icbid = p4 + istart = p5 + iend = p6 + ichannel = p7 + inocheckpoint = p8 + + kdone twst_copy istart, iend, ichannel + if (kdone == 1) then + schedulek("twst_successresponse", 0, 1, icbid) + turnoff + endif +endin + + +opcode twst_trim, k, opjj + istart, iend, ichannel, instanceindex xin + instanceindex = (instanceindex == -1) ? gitwst_instanceindex : instanceindex + istart, ilen, iend twst_getstartend istart, iend + + kdone init 0 + kdone, gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex] chop_trimk istart, ilen, gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex] + xout kdone +endop + +instr twst_trim + icbid = p4 + istart = p5 + iend = p6 + ichannel = p7 + inocheckpoint = p8 + + if (inocheckpoint == 0) then + twst_checkpoint() + endif + + kdone twst_trim istart, iend, ichannel + if (kdone == 1) then + schedulek("twst_overviews_response", 0, 1, icbid, 0, 1) + turnoff + endif +endin + + +opcode twst_cut, ki, opjj + istart, iend, ichannel, instanceindex xin + instanceindex = (instanceindex == -1) ? gitwst_instanceindex : instanceindex + istart, ilen, iend twst_getstartend istart, iend + + twst_clearbuffers(gitwst_copyBufferL, gitwst_copyBufferR) + gitwst_copyBufferL = -1 + gitwst_copyBufferR = -1 + kdone init 0 + + if (gitwst_channels[instanceindex] == 2) then + if (ichannel == -1) then + kdone, gitwst_copyBufferL, gitwst_copyBufferR, gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex] chop_cutk istart, ilen, gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex] + elseif (ichannel == 0) then + kdone1, gitwst_copyBufferL, i_ chop_copyk istart, ilen, gitwst_bufferL[instanceindex] + kdone chop_setsilencek istart, ilen, gitwst_bufferL[instanceindex], -1, kdone1 + elseif (ichannel == 1) then + kdone1, gitwst_copyBufferR, i_ chop_copyk istart, ilen, gitwst_bufferR[instanceindex] + kdone chop_setsilencek istart, ilen, gitwst_bufferR[instanceindex], -1, kdone1 + endif + else + kdone, gitwst_copyBufferL, i_, gitwst_bufferL[instanceindex], i_ chop_cutk istart, ilen, gitwst_bufferL[instanceindex] + endif + + inewlen = ftlen(gitwst_bufferL[instanceindex]) + xout kdone, istart / inewlen +endop + + + +instr twst_overviews_response + icbid = p4 + iselstart = p5 + iselend = p6 + io_sendstring("callback", twst_createoverviews(icbid, iselstart, iselend)) + turnoff +endin + +instr twst_cut + icbid = p4 + istart = p5 + iend = p6 + ichannel = p7 + inocheckpoint = p8 + + if (inocheckpoint == 0) then + twst_checkpoint() + endif + + kdone, istart twst_cut istart, iend, ichannel + if (kdone == 1) then + schedulek("twst_overviews_response", 0, 1, icbid, istart, istart) + turnoff + endif +endin + + +opcode twst_delete, ki, opjj + istart, iend, ichannel, instanceindex xin + instanceindex = (instanceindex == -1) ? gitwst_instanceindex : instanceindex + istart, ilen, iend twst_getstartend istart, iend + kdone init 0 + + if (gitwst_channels[instanceindex] == 2) then + if (ichannel == -1) then + kdone, gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex] chop_deletek istart, ilen, gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex] + elseif (ichannel == 0) then + kdone chop_setsilencek istart, ilen, gitwst_bufferL[instanceindex] + elseif (ichannel == 1) then + kdone chop_setsilencek istart, ilen, gitwst_bufferR[instanceindex] + endif + else + kdone, gitwst_bufferL[instanceindex], i_ chop_deletek istart, ilen, gitwst_bufferL[instanceindex] + endif + + inewlen = ftlen(gitwst_bufferL[instanceindex]) + xout kdone, istart / inewlen +endop + + +instr twst_delete + icbid = p4 + istart = p5 + iend = p6 + ichannel = p7 + inocheckpoint = p8 + + if (inocheckpoint == 0) then + twst_checkpoint() + endif + + kdone, istart twst_delete istart, iend, ichannel + if (kdone == 1) then + schedulek("twst_overviews_response", 0, 1, icbid, istart, istart) + turnoff + endif +endin + +opcode twst_trypaste, ikii, ojjpo + istart, ichannel, instanceindex, inumber, imix xin + instanceindex = (instanceindex == -1) ? gitwst_instanceindex : instanceindex + istart, ilen, iend twst_getstartend istart, 1 + inewlen = ftlen(gitwst_bufferL[instanceindex]) + (ftlen(gitwst_copyBufferL) * inumber) + + if (inewlen >= gihost_max32bitftlen) then ; limitation with WASM Csound build at the moment + iresponse = -2 + goto complete + elseif (gitwst_copyBufferL < 1 && gitwst_copyBufferR < 1) then + iresponse = -1 + goto complete + endif + + kdone init 0 + if (gitwst_channels[instanceindex] == 1) then + kdone, gitwst_bufferL[instanceindex], i_, ipastelen chop_pastek gitwst_copyBufferL, -1, gitwst_bufferL[instanceindex], -1, istart, inumber, imix + elseif (gitwst_copyBufferR > 0 && ichannel == -1) then + kdone, gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex], ipastelen chop_pastek gitwst_copyBufferL, gitwst_copyBufferR, gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex], istart, inumber, imix + elseif (ichannel == 0) then + isrc = (gitwst_copyBufferL > 0) ? gitwst_copyBufferL : gitwst_copyBufferR + kdone1, gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex], ipastelen chop_pastek isrc, isrc, gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex], istart, inumber, imix + kdone chop_setsilencek istart, ilen, gitwst_bufferR[instanceindex], -1, kdone1 + elseif (ichannel == 1) then + isrc = (gitwst_copyBufferR > 0) ? gitwst_copyBufferR : gitwst_copyBufferL + kdone1, gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex], ipastelen chop_pastek isrc, isrc, gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex], istart, inumber, imix + kdone chop_setsilencek istart, ilen, gitwst_bufferL[instanceindex], -1, kdone1 + endif + iresponse = 1 + inewlen = ftlen(gitwst_bufferL[instanceindex]) + +complete: + xout iresponse, kdone, istart, (istart + ipastelen) +endop + +opcode twst_paste, k, ojjp + istart, ichannel, instanceindex, inumber xin + istatus, kdone, istart, iend twst_trypaste istart, ichannel, instanceindex, inumber + xout kdone +endop + + +instr twst_paste + icbid = p4 + istart = p5 + iend = p6 + ichannel = p7 + inocheckpoint = p8 + + if (inocheckpoint == 0) then + twst_checkpoint() + endif + + istatus, kdone, istart, iend twst_trypaste istart, ichannel + if (istatus < 0) then + io_sendstring("callback", twst_failresponse(icbid, istatus)) + turnoff + else + if (kdone == 1) then + schedulek("twst_overviews_response", 0, 1, icbid, istart, iend) + turnoff + endif + endif +endin + + + +instr twst_pastespecial + icbid = p4 + istart = p5 + iend = p6 + ichannel = p7 + inocheckpoint = p8 + + if (inocheckpoint == 0) then + twst_checkpoint() + endif + + inumber = chnget:i(sprintf("%s_repetitions0", nstrstr(p1))) + inumber = (inumber < 1) ? 1 : inumber + imix = chnget:i(sprintf("%s_mixpaste0", nstrstr(p1))) + istatus, kdone, istart, iend twst_trypaste istart, ichannel, -1, inumber, imix + if (istatus < 0) then + io_sendstring("callback", twst_failresponse(icbid, istatus)) + turnoff + else + if (kdone == 1) then + schedulek("twst_overviews_response", 0, 1, icbid, istart, iend) + turnoff + endif + endif +endin + + +instr twst_nexttransientresponse + icbid = p4 + iselstart = p5 + iselend = p6 + if (iselstart == -1 && iselend == -1) then + io_sendstring("callback", sprintf("{\"cbid\":%d}", icbid)) + else + io_sendstring("callback", sprintf("{\"cbid\":%d,\"selstart\":%f,\"selend\":%f}", icbid, iselstart, iselend)) + endif + turnoff +endin + +instr twst_nexttransient + icbid = p4 + istart = p5 + iend = p6 + ichannel = p7 + p3 = 60 + + instanceindex = gitwst_instanceindex + isamps = ftlen(gitwst_bufferL[instanceindex]) + + istartsamp = iend * isamps + idurationsamp = isamps - istartsamp + idurations = idurationsamp / sr + + ileft = 1 + iright = 1 + if (ichannel == 0 || gitwst_channels[gitwst_instanceindex] == 1) then + iright = 0 + elseif (ichannel == 1 && gitwst_channels[gitwst_instanceindex] == 2) then + ileft = 0 + endif + + ktimek timeinstk + ikcycles = idurationsamp / ksmps + if (ktimek == 1) then + kcount init 0 + while (kcount < ikcycles) do + apos linseg istartsamp, idurations, isamps + if (ileft == 1 && iright == 1) then + asig = (table3:a(apos, gitwst_bufferL[instanceindex]) + table3:a(apos, gitwst_bufferR[instanceindex])) * 0.5 + elseif (iright == 1) then + asig = table3:a(apos, gitwst_bufferR[instanceindex]) + else + asig = table3:a(apos, gitwst_bufferL[instanceindex]) + endif + ktrig transientdetect asig + if (ktrig == 1 && kcount != 0) then + kselend = ((kcount * ksmps) + istartsamp) / isamps + kselstart = (istart == iend) ? kselend : istart + schedulek("twst_nexttransientresponse", 0, 1, icbid, kselstart, kselend) + turnoff + endif + kcount += 1 + od + else + schedulek("twst_nexttransientresponse", 0, 1, icbid, -1, -1) + turnoff + endif +endin + + +instr twst_undo + icbid = p4 + istatus twst_undo + if (istatus < 0) then + Sresponse = twst_failresponse(icbid) + else + Sresponse = twst_createoverviews(icbid) + endif + + io_sendstring("callback", Sresponse) + turnoff +endin + + +instr twst_destroytables + ifnL = p4 + ifnR = p5 + twst_clearbuffers(ifnL, ifnR) + turnoff +endin + + +opcode twst_loadfile, ik, Sj + Spath, instanceindex xin + instanceindex = (instanceindex == -1) ? gitwst_instanceindex : instanceindex + 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 + + twst_checkpoint_clear(instanceindex) + + twst_clearbuffers(gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex]) + gitwst_channels[instanceindex] = ifilechannels + + gitwst_bufferL[instanceindex] = ftgen(0, 0, -ilen, 1, Spath, 0, 0, 1) + if (gitwst_channels[instanceindex] == 2) then + gitwst_bufferR[instanceindex] = ftgen(0, 0, -ilen, 1, Spath, 0, 0, 2) + gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex], kdone tab_samplerateconvert gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex] + imono = 0 + else + gitwst_bufferL[instanceindex], kdone tab_samplerateconvert gitwst_bufferL[instanceindex] + imono = 1 + endif + + + iresponse = 1 +complete: + xout iresponse, kdone +endop + + +/* +opcode twst_loadfile, ik, Sj + Spath, instanceindex xin + instanceindex = (instanceindex == -1) ? gitwst_instanceindex : instanceindex + 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 + + twst_checkpoint_clear(instanceindex) + + gitwst_channels[instanceindex] = ifilechannels + twst_clearbuffers(gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex]) + + gitwst_bufferL[instanceindex] = ftgen(0, 0, -ilen, 1, Spath, 0, 0, 1) + if (gitwst_channels[instanceindex] == 2) then + gitwst_bufferR[instanceindex] = 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, gitwst_bufferL[instanceindex] + tablew asig, aposw, ifnnewL + if (imono == 0) then + asig table3 aposr, gitwst_bufferR[instanceindex] + tablew asig, aposw, ifnnewR + endif + kcount += 1 + od + else + kdone = 1 + endif + + ftfree gitwst_bufferL[instanceindex], 1 + gitwst_bufferL[instanceindex] = ifnnewL + if (imono == 0) then + ftfree gitwst_bufferR[instanceindex], 1 + gitwst_bufferR[instanceindex] = ifnnewR + endif + else + kdone = 1 + endif + + iresponse = 1 +complete: + xout iresponse, kdone +endop +*/ + +instr twst_loadclipboard + icbid = p4 + p3 = 60 + + instanceindex = gitwst_instanceindex + twst_clearbuffers(gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex]) + + ilen = ftlen(gitwst_copyBufferL) + ifnL ftgen 0, 0, -ilen, -2, 0 + tableicopy ifnL, gitwst_copyBufferL + gitwst_bufferL[instanceindex] = ifnL + if (gitwst_copyBufferR > 0 && ftexists(gitwst_copyBufferR) == 1) then + ifnR ftgen 0, 0, -ilen, -2, 0 + tableicopy ifnR, gitwst_copyBufferR + gitwst_bufferR[instanceindex] = ifnR + gitwst_channels[instanceindex] = 2 + else + gitwst_channels[instanceindex] = 1 + gitwst_bufferR[instanceindex] = 0 + endif + schedule("twst_overviews_response", 0, 1, icbid, 0, 0) + turnoff +endin + +instr twst_loadftable + icbid = p4 + ifnL = p5 + ifnR = p6 + iclearbuffers = p7 + p3 = 60 + instanceindex = gitwst_instanceindex + + if (ifnL <= 0 || ftexists(ifnL) == 0 || (ifnR > 0 && ftexists(ifnR) == 0)) then + io_sendstring("callback", twst_failresponse(icbid, -1)) + turnoff + endif + + twst_checkpoint_clear(instanceindex) + + if (iclearbuffers == 1) then + twst_clearbuffers(gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex]) + endif + + gitwst_bufferL[instanceindex] = ifnL + if (ifnR > 0) then + gitwst_bufferR[instanceindex] = ifnR + gitwst_channels[instanceindex] = 2 + else + gitwst_channels[instanceindex] = 1 + endif + + schedule("twst_overviews_response", 0, 1, icbid, 0, 0) + turnoff +endin + +instr twst_getbuffers + icbid = p4 + instanceindex = gitwst_instanceindex + if (gitwst_channels[instanceindex] == 2) then + Stables = sprintf("[%d,%d]", gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex]) + else + Stables = sprintf("[%d]", gitwst_bufferL[instanceindex]) + endif + io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":1,\"tables\":%s}", icbid, Stables)) + turnoff +endin + + +instr twst_loadfile + icbid = p4 + p3 = 120 + Spath = strget(p5) + istatus, kdone twst_loadfile Spath, -1, 1 + if (istatus < 0) then + Sresponse = twst_failresponse(icbid, istatus) + io_sendstring("callback", Sresponse) + turnoff + else + if (kdone == 1) then + schedulek("twst_overviews_response", 0, 1, icbid, 0, 0) + turnoff + endif + endif +endin + + + +/* +instr twst_loadfile + icbid = p4 + Spath = strget(p5) + if (filevalid(Spath) != 1) then + Sresponse = twst_failresponse(icbid) + else + twst_clearbuffers() + gitwst_channels[gitwst_instanceindex] = filenchnls(Spath) + gitwst_bufferL[gitwst_instanceindex] = ftgen(0, 0, 0, 1, Spath, 0, 0, 1) + if (gitwst_channels[gitwst_instanceindex] == 2) then + gitwst_bufferR[gitwst_instanceindex] = ftgen(0, 0, 0, 1, Spath, 0, 0, 2) + endif + Sresponse = twst_createoverviews(icbid) + endif + io_sendstring("callback", Sresponse) + turnoff +endin +*/ + + + +opcode twst_createempty, i, ijj + iduration, ichannels, instanceindex xin + ichannels = (ichannels == -1) ? 2 : ichannels + instanceindex = (instanceindex == -1) ? gitwst_instanceindex : instanceindex + twst_clearbuffers(gitwst_bufferL[instanceindex], gitwst_bufferR[instanceindex]) + idurationsamps = iduration * sr + + if (idurationsamps >= gihost_max32bitftlen) then ; limitation with WASM Csound build at the moment + iresponse = -2 + goto complete + endif + + twst_checkpoint_clear(instanceindex) + + gitwst_bufferL[instanceindex] ftgen 0, 0, -idurationsamps, -2, 0 + if (ichannels == 2) then + gitwst_channels[instanceindex] = 2 + gitwst_bufferR[instanceindex] ftgen 0, 0, -idurationsamps, -2, 0 + else + gitwst_channels[instanceindex] = 1 + endif + iresponse = 1 +complete: + xout iresponse +endop + + +instr twst_createempty + icbid = p4 + iduration = p5 + ichannels = p6 + p3 = 60 + istatus twst_createempty iduration, ichannels + if (istatus < 0) then + io_sendstring("callback", twst_failresponse(icbid, istatus)) + else + schedule("twst_overviews_response", 0, 1, icbid, 0, 0) + endif + turnoff +endin + + +instr twst_savefile_response + icbid = p4 + io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":1}", icbid)) + turnoff +endin + + +instr twst_savefile + icbid = p4 + p3 = 60 + Spath = strget(p5) + ktimek timeinstk + idurations = ftlen(gitwst_bufferL[gitwst_instanceindex]) / ftsr(gitwst_bufferL[gitwst_instanceindex]) + ikcycles = idurations * kr + if (ktimek == 1) then + kcount init 0 + while (kcount < ikcycles) do + apos lphasor 1 + aL table apos, gitwst_bufferL[gitwst_instanceindex] + if (gitwst_channels[gitwst_instanceindex] == 1) then + fout Spath, 14, aL + else + aR table3 apos, gitwst_bufferR[gitwst_instanceindex] + fout Spath, 14, aL, aR + endif + kcount += 1 + od + else + schedulek("twst_savefile_response", 0, 1, icbid) + turnoff + endif +endin + + + +instr twst_auditioncomplete_response + icbid = p4 + istatus = 0 + if (gitwst_userstopped == 1) then + istatus = 3 + endif + io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":%d}", icbid, istatus)) + turnoff +endin + +instr twst_stop + gitwst_userstopped = 1 + turnoff2 "twst_audition", 0, 1 + turnoff2 "twst_record", 0, 1 + turnoff +endin + +#ifdef TWST_FAILONLAG +instr twst_auditionlag_response + icbid = p4 + turnoff2 "twst_audition", 0, 0 + io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":-1}", icbid)) + turnoff +endin +#end + +instr twst_play + schedule("twst_audition", 0, p3, p4, p5, p6, p7, "", 0) + turnoff +endin + +instr twst_audition + icbid = p4 + gitwst_userstopped = 0 + io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":1}", icbid)) + istart = p5 + iend = p6 + if (istart == iend) then + iend = 1 + endif + ichannel = p7 + Stransform = strget(p8) + iautomating = p9 + icrossfadein = p10 + icrossfadeout = p11 + iuniqueid = p12 + iapplymode chnget sprintf("applymode%d", iuniqueid) + kapplymodedry chnget sprintf("applymodedry%d", iuniqueid) + kapplymodewet chnget sprintf("applymodewet%d", iuniqueid) + + i_, aL, aR, i_, i_, iextracycles, i_, i_ twst_playback istart, iend, ichannel, Stransform, 0, iautomating, icrossfadein, icrossfadeout, iuniqueid + + gitwst_currentplayduration = p3 + +#ifdef TWST_FAILONLAG + if (strcmp(Stransform, "") != 0) then + klagging lagdetect 0.8 + if (klagging == 1) then + schedulek("twst_auditionlag_response", 0, 1, icbid) + endif + endif +#end + + kreleasing init 0 + ktimek timeinstk + iduration = (p3 * kr) + (iextracycles / sr) + krelease release + if (kreleasing == 0 && (krelease == 1 || ktimek >= iduration)) then + kreleasing = 1 + schedulek("twst_auditioncomplete_response", 0, 1, icbid) + turnoff + endif + + outs aL, aR +endin + + +instr twst_recordcomplete_response + icbid = p4 + iselstart = p5 + iselend = p6 + io_sendstring("callback", twst_createoverviews(icbid, iselstart, iselend, 2)) +endin + +instr twst_record + icbid = p4 + gitwst_userstopped = 0 + io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":1}", icbid)) + istart = p5 + iend = p6 + if (istart == iend) then + iend = 1 + endif + ichannel = p7 + ibuflen = ftlen(gitwst_bufferL[gitwst_instanceindex]) + istartsamp, ilensamp, iendsamp twst_getstartend istart, iend, gitwst_instanceindex + ilens = ilensamp / sr + p3 = ilens + + twst_checkpoint() + + apos linseg istartsamp, ilens, iendsamp + aL init 0 + aR init 0 + + if (gitwst_channels[gitwst_instanceindex] == 1) then + if (ichannel == 1) then + aL inch 2 + else + aL inch 1 + endif + tablew aL, apos, gitwst_bufferL[gitwst_instanceindex] + else + if (ichannel == -1 || ichannel == 0) then + aL inch 1 + tablew aL, apos, gitwst_bufferL[gitwst_instanceindex] + endif + if (ichannel == -1 || ichannel == 1) then + aR inch 2 + tablew aR, apos, gitwst_bufferR[gitwst_instanceindex] + endif + endif + + chnset k(aL), "recordmonitorL" + chnset k(aR), "recordmonitorR" + + ktimeenv linseg istart, p3, iend + chnset ktimeenv, "twst_playposratio" + kreleasing init 0 + ktimek timeinstk + iduration = p3 * kr + if (kreleasing == 0 && (release:k() == 1 || ktimek >= iduration)) then + kreleasing = 1 + klastwritten = k(apos) + schedulek("twst_recordcomplete_response", 0, 1, icbid, istart, klastwritten / ibuflen) + turnoff + endif +endin + + + +instr twst_commit_response + icbid = p4 + ifnL = p5 + ifnR = p6 + iselstart = p7 + iselend = p8 + if (ifnL > 0 && ifnL != gitwst_bufferL[gitwst_instanceindex]) then + if (gitwst_bufferL[gitwst_instanceindex] > 0 && ftexists(gitwst_bufferL[gitwst_instanceindex]) == 1) then + ftfree gitwst_bufferL[gitwst_instanceindex], 0 + endif + gitwst_bufferL[gitwst_instanceindex] = ifnL + endif + if (ifnR > 0 && ifnR != gitwst_bufferR[gitwst_instanceindex]) then + if (gitwst_bufferR[gitwst_instanceindex] > 0 && gitwst_bufferR[gitwst_instanceindex] == 1) then + ftfree gitwst_bufferR[gitwst_instanceindex], 0 + endif + gitwst_bufferR[gitwst_instanceindex] = ifnR + endif + + io_sendstring("callback", twst_createoverviews(icbid, iselstart, iselend)) + turnoff +endin + +instr twst_commit + icbid = p4 + istart = p5 + iend = p6 + if (istart == iend) then + istart = 0 + iend = 1 + endif + ichannel = p7 + Stransform = strget(p8) + iautomating = p9 + icrossfadein = p10 + icrossfadeout = p11 + inoCheckpoint = p12 + iuniqueid = p13 + + ibuflen = ftlen(gitwst_bufferL[gitwst_instanceindex]) + istartsamp = ibuflen * istart + iendsamp = ibuflen * iend + idurations = (iendsamp - istartsamp) / ftsr(gitwst_bufferL[gitwst_instanceindex]) + + if (inoCheckpoint == 0) then + twst_checkpoint() + endif + + iblocks = 100 + ikcycles = round(idurations * kr) + if (ikcycles < iblocks) then + ikcyclesperblock = ikcycles + else + ikcyclesperblock = round(ikcycles / iblocks) + endif + ktotalcount init 0 + klastpercent init 100 + + kreleasing init 0 + ifnL = 0 + ifnR = 0 + + if (ktotalcount < ikcycles) then + kcount = 0 + while (kcount < ikcyclesperblock) do + istatus, a_, a_, ifnL, ifnR, iextracycles, iselstart, iselend twst_playback istart, iend, ichannel, Stransform, 1, iautomating, icrossfadein, icrossfadeout, iuniqueid + if (istatus <= 0) then + io_sendstring("callback", twst_failresponse(icbid, istatus)) + turnoff + endif + ikcycles += iextracycles ; weird in loop but it's a k loop, so i is set here... + + kcount += 1 + ktotalcount += 1 + od + kpercent = round((100 / ikcycles) * ktotalcount) + if (kpercent != klastpercent) then + io_send "percent", kpercent + klastpercent = kpercent + endif + else + schedulek("twst_commit_response", 0, 1, icbid, ifnL, ifnR, iselstart, iselend) + turnoff + endif +endin + + +#include "/twist/automation.udo" +#include "/twist/transforms.udo" + + +#end -- cgit v1.2.3