From 9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22 Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 13 Apr 2025 18:48:02 +0100 Subject: initial --- site/udo/pvs_tabproc.udo | 640 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 640 insertions(+) create mode 100755 site/udo/pvs_tabproc.udo (limited to 'site/udo/pvs_tabproc.udo') diff --git a/site/udo/pvs_tabproc.udo b/site/udo/pvs_tabproc.udo new file mode 100755 index 0000000..dc2dc04 --- /dev/null +++ b/site/udo/pvs_tabproc.udo @@ -0,0 +1,640 @@ +#ifndef UDO_PVSTABPROC +#define UDO_PVSTABPROC ## +/* + Frame based PVS processing + + ksmps must be 64 or lower: setksmps(64) can be set in the calling instrument if required + + tpv data tables have the following indexes: + 0: number of channels + 1: amp left + 2: amp right + 3: frequency left + 4: frequency right + + This file is part of the SONICS UDO collection by Richard Knight 2021, 2022, 2024, 2025 + License: GPL-2.0-or-later + http://1bpm.net +*/ + +/* + Make container for processing tables and information + itpvdata tpv_makecontainer ichannels, inumbins + + itpvdata tpv information for subsequent opcodes + ichannels number of channels to account for + inumbins number of frequency bins +*/ +opcode tpv_makecontainer, i, ii + ichannels, inumbins xin + itpv ftgentmp 0, 0, -5, -2, ichannels + index = 1 + while (index < 5) do + if (ichannels == 1 && (index == 2 || index == 4)) then + ival = 0 + else + ival ftgentmp 0, 0, -inumbins, -2, 0 + endif + tabw_i ival, index, itpv + index += 1 + od + xout itpv +endop + +/* + Shorthand to get tpv data items + ichannels, isize, ifnampL, ifnampR, ifnfreqL, ifnfreqR tpv_get itpvdata + + ichannels number of channels + isize bin size + ifnampL left amp table + ifnampR right amp table + ifnfreqL left freq table + ifnfreqR right freq table + iptvdata tpv data table +*/ +opcode tpv_get, iiiiii, i + itpvdata xin + ifnAmpL = tab_i(1, itpvdata) + xout tab_i(0, itpvdata), ftlen(ifnAmpL), ifnAmpL, tab_i(2, itpvdata), tab_i(3, itpvdata), tab_i(4, itpvdata) +endop + +/* + Analyse f-signal to table (mono) + kready, itpvdata tpv_anal fsrc + + fsrc source f-signal + kready done trigger + iptvdata tpv analysis data +*/ +opcode tpv_anal, ki, f + fsrc xin + ioverlap, inumbins, iwinsize, iformat pvsinfo fsrc + itpvdata tpv_makecontainer 1, inumbins + kready pvsftw fsrc, tab_i(1, itpvdata), tab_i(3, itpvdata) + xout kready, itpvdata +endop + +/* + Analyse f-signal to table (stereo) + kready, itpvdata tpv_anal fsrcL, fsrcR + + fsrcL source f-signal left + fsrcR source f-signal right + kready done trigger + iptvdata tpv analysis stream handles for use in other opcodes +*/ +opcode tpv_anal, ki, ff + fsrcL, fsrcR xin + ioverlap, inumbins, iwinsize, iformat pvsinfo fsrcL + itpvdata tpv_makecontainer 2, inumbins + kreadyL pvsftw fsrcL, tab_i(1, itpvdata), tab_i(3, itpvdata) + kreadyR pvsftw fsrcR, tab_i(2, itpvdata), tab_i(4, itpvdata) + xout (kreadyL & kreadyR), itpvdata +endop + +/* + Reform tpv data (mono). Input and output f-signals must be the same. + + foutM tpv_resynth itpvdata, foutM + + itpvdata tpv analysis stream handles + foutM f-signal to write to +*/ +opcode tpv_resynth, f, if + itpvdata, foutM xin + pvsftr foutM, tab_i(1, itpvdata), tab_i(3, itpvdata) + xout foutM +endop + +/* + Reform tpv data (stereo). Input and output f-signals must be the same. + foutL, foutR tpv_resynth itpvdata, foutL, foutR + + itpvdata tpv analysis stream handles + foutL f-signal to write to left + foutR f-signal to write to right +*/ +opcode tpv_resynth, ff, iff + itpvdata, foutL, foutR xin + pvsftr foutL, tab_i(1, itpvdata), tab_i(3, itpvdata) + pvsftr foutR, tab_i(2, itpvdata), tab_i(4, itpvdata) + xout foutL, foutR +endop + +/* + Smear frames + tpv_smear kready, itpvdata, imaxframes, kframes, kavgfreqs, kincludeoriginal + + kready done trigger from tpv_anal + itpvdata tpv analysis stream handles + imaxframes maximum frames for smearage + kframes frames of smearage to apply + kavgfreqs average frequencies as well as smearing amplitudes (bool) + kincludeoriginal include the original frame in output +*/ +opcode tpv_smear, 0, kijJOP + kready, itpvdata, imaxframes, kframes, kavgfreqs, kincludeoriginal xin + imaxframes = (imaxframes == -1) ? 8 : imaxframes + kframes = (kframes < 1 || kframes > imaxframes) ? imaxframes: kframes + ichans, isize, ifnampL, ifnampR, ifnfreqL, ifnfreqR tpv_get itpvdata + itpvtemps ftgentmp 0, 0, -imaxframes, -2, 0 + index = 0 + while (index < imaxframes) do + tabw_i(tpv_makecontainer(ichans, isize), index, itpvtemps) + index += 1 + od + kindexframew init 0 + + if (kready == 1) then + ktpvfnw = tab:k(kindexframew, itpvtemps) + tablecopy tablekt:k(1, ktpvfnw), ifnampL + tablecopy tablekt:k(3, ktpvfnw), ifnfreqL + if (ichans == 2) then + tablecopy tablekt:k(2, ktpvfnw), ifnampR + tablecopy tablekt:k(4, ktpvfnw), ifnfreqR + endif + + kindexframer = (kindexframew - 1 < 0) ? imaxframes - 1 : kindexframew - 1 + kframescale = 1 / kframes + kindex = 0 + while (kindex < isize) do + kampL = (kincludeoriginal == 1) ? tab:k(kindex, ifnampL) : 0 + kfreqL = (kincludeoriginal == 1) ? tab:k(kindex, ifnfreqL) : 0 + if (ichans == 2) then + kampR = (kincludeoriginal == 1) ? tab:k(kindex, ifnampR) : 0 + kfreqR = (kincludeoriginal == 1) ? tab:k(kindex, ifnfreqR) : 0 + endif + kindexframeabs = 0 + while (kindexframeabs < kframes) do + kcurscale = (kframescale * (kframes - kindexframeabs)) + ktpvframe tab kindexframer, itpvtemps + ;kampL = (kampL + tablekt:k(kindex, ktpvframe)) * 0.5 + kampL += tablekt:k(kindex, tablekt:k(1, ktpvframe)) * kcurscale + if (kavgfreqs == 1) then + kfreqL = (kfreqL + tablekt:k(kindex, tablekt:k(3, ktpvframe))) * 0.5 + + endif + if (ichans == 2) then + kampR += tablekt:k(kindex, tablekt:k(2, ktpvframe)) * kcurscale + if (kavgfreqs == 1) then + kfreqR = (kfreqR + tablekt:k(kindex, tablekt:k(4, ktpvframe))) * 0.5 + endif + endif + kindexframer = (kindexframer - 1 < 0) ? imaxframes - 1 : kindexframer - 1 + kindexframeabs += 1 + od + + tabw kampL, kindex, ifnampL + if (kavgfreqs == 1) then + tabw kfreqL, kindex, ifnfreqL + endif + if (ichans == 2) then + tabw kampR, kindex, ifnampR + if (kavgfreqs == 1) then + tabw kfreqR, kindex, ifnfreqR + endif + endif + kindex += 1 + od + if (kindexframew + 1 < imaxframes) then + kindexframew += 1 + else + kindexframew = 0 + endif + endif +endop + +/* + Wrap spectrum + tpv_wrap kready, itpvdata, kwrapstart + + kready done trigger from tpv_anal + itpvdata tpv analysis stream handles + kwrapAmpBin start bin for amplitude wrapping + kwrapFreqBin start bin for frequency wrapping +*/ +opcode tpv_wrap, 0, kikk + kready, itpvdata, kwrapAmpBin, kwrapFreqBin xin + ichans, isize, ifnampL, ifnampR, ifnfreqL, ifnfreqR tpv_get itpvdata + itpvdatatemp tpv_makecontainer ichans, isize + i_, i_, ifnampLtemp, ifnampRtemp, ifnfreqLtemp, ifnfreqRtemp tpv_get itpvdatatemp + + if (kready == 1) then + tablecopy ifnampLtemp, ifnampL + tablecopy ifnfreqLtemp, ifnfreqL + if (ichans == 2) then + tablecopy ifnampRtemp, ifnampR + tablecopy ifnfreqRtemp, ifnfreqR + endif + + kindex = 0 + while (kindex < isize) do + kwrapAmpIndexW = (kwrapAmpBin + kindex) % isize + kwrapFreqIndexW = (kwrapFreqBin + kindex) % isize + + tabw tab:k(kindex, ifnampLtemp), kwrapAmpIndexW, ifnampL + tabw tab:k(kindex, ifnfreqLtemp), kwrapFreqIndexW, ifnfreqL + + if (ichans == 2) then + tabw tab:k(kindex, ifnampRtemp), kwrapAmpIndexW, ifnampR + tabw tab:k(kindex, ifnfreqRtemp), kwrapFreqIndexW, ifnfreqR + endif + kindex += 1 + od + endif +endop + +/* + Set random bin amplitudes to 0. Ported from pvtool + tpv_bubble kready, itpvdata, kchance, kstereounique + + kready done trigger from tpv_anal + itpvdata tpv analysis stream handles + kchance chance of applying bin amplitude, between 0 and 1 + kstereounique whether to apply the effect channel independently +*/ +opcode tpv_bubble, 0, kikP + kready, itpvdata, kchance, kstereounique xin + ichans, isize, ifnampL, ifnampR, ifnfreqL, ifnfreqR tpv_get itpvdata + kreplacement init 0 + if (kready == 1) then + kindex = 0 + while (kindex < isize) do + kapplyL = (random:k(0, 1) <= kchance) ? 1 : 0 + if (ichans == 1) then + if (kapplyL == 1) then + tabw 0, kindex, ifnampL + endif + else + if (kstereounique == 0) then + if (kapplyL == 1) then + tabw kreplacement, kindex, ifnampL + tabw kreplacement, kindex, ifnampR + endif + else + if (kapplyL == 1) then + tabw kreplacement, kindex, ifnampL + endif + if (random:k(0, 1) <= kchance) then + tabw kreplacement, kindex, ifnampR + endif + endif + endif + kindex += 1 + od + endif + +endop + +/* + Swap spectrum areas + tpv_swap kready, itpvdata, kampStart, kampLength, kampTarget, kfreqStart, kfreqLength, kfreqTarget [, kwrapmode = 1] + + kready done trigger from tpv_anal + itpvdata tpv analysis stream handles + kampStart bin start for amplitude + kampLength bins length for amplitude + kampTarget bin target start for amplitude + kfreqStart bin start for frequency + kfreqLength bins length for frequency + kfreqTarget bin target start for frequency + kwrapmode wrap mode: 0 = limit; 1 = wrap +*/ +opcode tpv_swap, 0, kikOkkOkP + kready, itpvdata, kampStart, kampLength, kampTarget, kfreqStart, kfreqLength, kfreqTarget, kwrapmode xin + ichans, isize, ifnampL, ifnampR, ifnfreqL, ifnfreqR tpv_get itpvdata + itpvdatatemp tpv_makecontainer ichans, isize + i_, i_, ifnampLtemp, ifnampRtemp, ifnfreqLtemp, ifnfreqRtemp tpv_get itpvdatatemp + + kampLength = (kampLength == 0) ? isize : kampLength + kfreqLength = (kfreqLength == 0) ? isize : kfreqLength + + if (kready == 1) then + tablecopy ifnampLtemp, ifnampL + tablecopy ifnfreqLtemp, ifnfreqL + if (ichans == 2) then + tablecopy ifnampRtemp, ifnampR + tablecopy ifnfreqRtemp, ifnfreqR + endif + + kampStartW = min:k(kampStart, kampTarget) + kampTargetW = max:k(kampStart, kampTarget) + kfreqStartW = min:k(kfreqStart, kfreqTarget) + kfreqTargetW = max:k(kfreqStart, kfreqTarget) + + kindex = 0 + while (kindex < isize) do + if (kwrapmode == 1) then + kampStartW = kampStartW % isize + kampEndW = (kampStartW + kampLength) % isize + kampTargetW = (kampTargetW + kindex) % isize + + kfreqStartW = kfreqStartW % isize + kfreqEndW = (kfreqStartW + kfreqLength) % isize + kfreqTargetW = (kfreqTargetW + kindex) % isize + else + kampStartW = (kampStartW >= isize) ? isize - 1 : kampStart + kampEnd = kampStartW + kampLength + kampEndW = (kampEnd >= isize) ? isize - 1 : kampEnd + kampTargetW = (kampTargetW + kindex >= isize) ? isize - 1 : kampTargetW + kindex + + kfreqStartW = (kfreqStartW >= isize) ? isize - 1 : kfreqStart + kfreqEnd = kfreqStartW + kfreqLength + kfreqEndW = (kfreqEnd >= isize) ? isize - 1 : kfreqEnd + kfreqTargetW = (kfreqTargetW + kindex >= isize) ? isize - 1 : kfreqTargetW + kindex + endif + + if (kindex >= kampStartW && kindex < kampEndW) then + tabw tab:k(kindex, ifnampLtemp), kampTargetW, ifnampL + tabw tab:k(kampTargetW, ifnampLtemp), kindex, ifnampL + if (ichans == 2) then + tabw tab:k(kindex, ifnampRtemp), kampTargetW, ifnampR + tabw tab:k(kampTargetW, ifnampRtemp), kindex, ifnampR + endif + endif + + if (kindex >= kfreqStartW && kindex < kfreqEndW) then + tabw tab:k(kindex, ifnfreqLtemp), kfreqTargetW, ifnfreqL + tabw tab:k(kfreqTargetW, ifnfreqLtemp), kindex, ifnfreqL + if (ichans == 2) then + tabw tab:k(kindex, ifnfreqRtemp), kfreqTargetW, ifnfreqR + tabw tab:k(kfreqTargetW, ifnfreqRtemp), kindex, ifnfreqR + endif + endif + kindex += 1 + od + endif +endop + +/* + Invert spectrum + tpv_invert kready, itpvdata, [kinvertamp, kinvertfreq] + + kready done trigger from tpv_anal + itpvdata tpv analysis stream handles + kinvertamp whether to invert amp or not (1 or 0) + kinvertfreq whether to invert frequency or not (1 or 0) +*/ +opcode tpv_invert, 0, kiPP + kready, itpvdata, kinvertamp, kinvertfreq xin + ichans, isize, ifnampL, ifnampR, ifnfreqL, ifnfreqR tpv_get itpvdata + if (kready == 1) then + kindex = 0 + while (kindex < isize) do + if (kinvertamp == 1) then + tabw tab:k(isize-kindex, ifnampL), kindex, ifnampL + endif + + if (kinvertfreq == 1) then + tabw tab:k(isize-kindex, ifnfreqL), kindex, ifnfreqL + endif + + if (ichans == 2) then + if (kinvertamp == 1) then + tabw tab:k(isize-kindex, ifnampR), kindex, ifnampR + endif + + if (kinvertfreq == 1) then + tabw tab:k(isize-kindex, ifnfreqR), kindex, ifnfreqR + endif + endif + + kindex += 1 + od + endif +endop + +/* + Filter bins with a ftable mask + tpv_binfilter kready, itpvdata, ifnamps + + kready done trigger from tpv_anal + itpvdata tpv analysis stream handles + ifnamps ftable containing amplitude values per bin +*/ +opcode tpv_binfilter, 0, kii + kready, itpvdata, ifnamps xin + ichans, isize, ifnampL, ifnampR, ifnfreqL, ifnfreqR tpv_get itpvdata + if (kready == 1) then + kindex = 0 + while (kindex < isize) do + tabw tab:k(kindex, ifnampL) * tab:k(kindex, ifnamps), kindex, ifnampL + + if (ichans == 2) then + tabw tab:k(kindex, ifnampR) * tab:k(kindex, ifnamps), kindex, ifnampR + endif + kindex += 1 + od + endif +endop + +/* + Allow bins over or below a certain threshold; a spectral gate + tpv_threshold kready, itpvdata, kthreshold, kabove + + kready done trigger from tpv_anal + itpvdata tpv analysis stream handles + kthreshold amplitude threshold to apply + kabove above or below threshold will be let through the gate (1 = above, 0 = below) +*/ +opcode tpv_threshold, 0, kikO + kready, itpvdata, kthresh, kabove xin + ichans, isize, ifnampL, ifnampR, ifnfreqL, ifnfreqR tpv_get itpvdata + if (kready == 1) then + kindex = 0 + while (kindex < isize) do + + kvalL tab kindex, ifnampL + if ((kabove == 0 && kvalL < kthresh) || (kabove == 1 && kvalL > kthresh)) then + tabw 0, kindex, ifnampL + tabw 0, kindex, ifnfreqL + endif + + if (ichans == 2) then + kvalR tab kindex, ifnampR + if ((kabove == 0 && kvalR < kthresh) || (kabove == 1 && kvalR > kthresh)) then + tabw 0, kindex, ifnampR + tabw 0, kindex, ifnfreqR + endif + endif + + kindex += 1 + od + endif +endop + +/* + Scramble amplitude and/or frequency + tpv_scramble kready, itpvdata, kstepratio, kdoamp, kdofreq + + kready done trigger from tpv_anal + itpvdata tpv analysis stream handles + kstepratio partitioning ratio + kdoamp scramble amplitudes (bool) + kdofreq scramble frequencies (bool) +*/ +opcode tpv_scramble, 0, kiJPP + kready, itpvdata, kstepratio, kdoamp, kdofreq xin + ichans, isize, ifnampL, ifnampR, ifnfreqL, ifnfreqR tpv_get itpvdata + kstep = (kstepratio == -1) ? 1 : max:k(round:k(kstepratio * isize), 1) + if (kready == 1) then + kindex = 0 + while (kindex < isize) do + kdest = int:k(random:k(kstep, isize)) - kstep + kindex2 = 0 + while (kindex2 < kstep) do + + if (kdoamp == 1) then + kval table kindex+kindex2, ifnampL, 0, 0, 1 + kcurrentval table kdest+kindex2, ifnampL, 0, 0, 1 + tablew (kval+kcurrentval)/2, kdest+kindex2, ifnampL, 0, 0, 1 + if (ichans == 2) then + kval table kindex+kindex2, ifnampR, 0, 0, 1 + kcurrentval table kdest+kindex2, ifnampR, 0, 0, 1 + tablew (kval+kcurrentval)/2, kdest+kindex2, ifnampR, 0, 0, 1 + endif + endif + + if (kdofreq == 1) then + kval table kindex+kindex2, ifnfreqL, 0, 0, 1 + kcurrentval table kdest+kindex2, ifnfreqL, 0, 0, 1 + tablew (kval+kcurrentval)/2, kdest+kindex2, ifnfreqL, 0, 0, 1 + if (ichans == 2) then + kval table kindex+kindex2, ifnfreqR, 0, 0, 1 + kcurrentval table kdest+kindex2, ifnfreqR, 0, 0, 1 + tablew (kval+kcurrentval)/2, kdest+kindex2, ifnfreqR, 0, 0, 1 + endif + endif + kindex2 += 1 + od + kindex += kstep + od + endif +endop + + + + +opcode tpv_freeze1, 0, kikPPP + kready, itpvdata, kfreeze, kfreezeamp, kfreezefreq, kcrossfade xin + ichans, isize, ifnampL, ifnampR, ifnfreqL, ifnfreqR tpv_get itpvdata + itpvtemp tpv_makecontainer ichans, isize + i_, i_, ifnampLtemp, ifnampRtemp, ifnfreqLtemp, ifnfreqRtemp tpv_get itpvtemp + + if (kready == 1) then + kindex = 0 + while (kindex < isize) do + if (kfreeze >= 0) then + kamount min kfreeze-1, 1 + + if (kfreezeamp == 1) then + if (kcrossfade == 1) then + tabw ((1-kamount)*tab:k(kindex, ifnampL) + (kamount * tab:k(kindex, ifnampLtemp))), kindex, ifnampL + if (ichans == 2) then + tabw ((1-kamount)*tab:k(kindex, ifnampR) + (kamount * tab:k(kindex, ifnampRtemp))), kindex, ifnampR + endif + else + tabw tab:k(kindex, ifnampLtemp), kindex, ifnampL + if (ichans == 2) then + tabw tab:k(kindex, ifnampRtemp), kindex, ifnampR + endif + endif + endif + + if (kfreezefreq == 1) then + if (kcrossfade == 1) then + tabw ((1-kamount)*tab:k(kindex, ifnfreqL) + (kamount * tab:k(kindex, ifnfreqLtemp))), kindex, ifnfreqL + if (ichans == 2) then + tabw ((1-kamount)*tab:k(kindex, ifnfreqR) + (kamount * tab:k(kindex, ifnfreqRtemp))), kindex, ifnfreqR + endif + else + tabw tab:k(kindex, ifnfreqLtemp), kindex, ifnfreqL + if (ichans == 2) then + tabw tab:k(kindex, ifnfreqRtemp), kindex, ifnfreqR + endif + endif + endif + + else + tabw tab:k(kindex, ifnampL), kindex, ifnampLtemp + tabw tab:k(kindex, ifnfreqL), kindex, ifnfreqLtemp + + if (ichans == 2) then + tabw tab:k(kindex, ifnampR), kindex, ifnampRtemp + tabw tab:k(kindex, ifnfreqR), kindex, ifnfreqRtemp + endif + endif + kindex += 1 + od + endif +endop + + + +opcode tpv_average, 0, kikPPO + kready, itpvdata, kmax, kavgamp, kavgfreq, ktrig xin + ichans, isize, ifnampL, ifnampR, ifnfreqL, ifnfreqR tpv_get itpvdata + itpvtemp tpv_makecontainer ichans, isize + i_, i_, ifnampLtemp, ifnampRtemp, ifnfreqLtemp, ifnfreqRtemp tpv_get itpvtemp + + kcount init 1 + if (kready == 1) then + kindex = 0 + while (kindex < isize) do + + ; store to average + tabw tab:k(kindex, ifnampL), kindex, ifnampLtemp + tabw tab:k(kindex, ifnfreqL), kindex, ifnfreqLtemp + + ; read average + if (kavgamp == 1) then + tabw tab:k(kindex, ifnampLtemp) / kcount, kindex, ifnampL + endif + + if (kavgfreq == 1) then + tabw tab:k(kindex, ifnfreqLtemp) / kcount, kindex, ifnfreqL + endif + + if (ichans == 2) then + + ; store to average + tabw tab:k(kindex, ifnampR), kindex, ifnampRtemp + tabw tab:k(kindex, ifnfreqR), kindex, ifnfreqRtemp + + ; read average + if (kavgamp == 1) then + tabw tab:k(kindex, ifnampRtemp) / kcount, kindex, ifnampR + endif + + if (kavgfreq == 1) then + tabw tab:k(kindex, ifnfreqRtemp) / kcount, kindex, ifnfreqR + endif + endif + + kindex += 1 + od + + if (kcount >= kmax || ktrig == 1) then + kindex = 0 + while (kindex < isize) do + + ; empty + tabw 0, kindex, ifnampLtemp + tabw 0, kindex, ifnfreqLtemp + + if (ichans == 2) then + tabw 0, kindex, ifnampRtemp + tabw 0, kindex, ifnfreqRtemp + endif + + kindex += 1 + od + kcount = 1 + else + kcount += 1 + endif + endif +endop + +#end -- cgit v1.2.3