#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