aboutsummaryrefslogtreecommitdiff
path: root/site/udo/spectral_transforms.udo
diff options
context:
space:
mode:
authorRichard <q@1bpm.net>2025-04-13 18:48:02 +0100
committerRichard <q@1bpm.net>2025-04-13 18:48:02 +0100
commit9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22 (patch)
tree291bd79ce340e67affa755a8a6b4f6a83cce93ea /site/udo/spectral_transforms.udo
downloadapps.csound.1bpm.net-9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22.tar.gz
apps.csound.1bpm.net-9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22.tar.bz2
apps.csound.1bpm.net-9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22.zip
initial
Diffstat (limited to 'site/udo/spectral_transforms.udo')
-rwxr-xr-xsite/udo/spectral_transforms.udo358
1 files changed, 358 insertions, 0 deletions
diff --git a/site/udo/spectral_transforms.udo b/site/udo/spectral_transforms.udo
new file mode 100755
index 0000000..7e9424f
--- /dev/null
+++ b/site/udo/spectral_transforms.udo
@@ -0,0 +1,358 @@
+#ifndef UDO_SPECTRALTRANSFORMS
+#define UDO_SPECTRALTRANSFORMS ##
+/*
+ Spectral transforms, mostly recursive using pvsbin
+
+ This file is part of the SONICS UDO collection by Richard Knight 2024
+ License: GPL-2.0-or-later
+ http://1bpm.net
+*/
+
+#include "/wavetables.udo"
+
+/*
+ Validate start and end bins against a f-sig, and check/set common variables
+ If start and end are <= 1, treat them as ratios and calculate accordingly
+
+ istartbin, iendbin, ibin, kportamento, ifnwave _spc_validatebins fsig [, istart=0, iend=1, kportamento=-1, ifnwave=-1]
+
+ istartbin resulting bin number
+ iendbin resulting bin number
+ ibin initial bin to use
+ kportamento portamento in/out
+ ifnwave wave f-table in/out
+ fsig f-sig to validate maximum bin number against
+ istart start bin number or ratio
+ iend end bin number or ratio
+*/
+opcode _spc_validatebins, iiiki, fopJj
+ fsig, istart, iend, kportamento, ifnwave xin
+ ioverlap, inumbins, iwinsize, iformat pvsinfo fsig
+
+ if (istart <= 1 && iend <= 1) then ; is ratio
+ istartbin = max(round(inumbins * istart), 1)
+ iendbin = round(inumbins * iend)
+ else ; is absolute bin number
+ istartbin = max(1, istart)
+ iendbin = min(inumbins, iend)
+ endif
+ ibin = istartbin
+ kportamento = (kportamento == -1) ? 0.02 : kportamento
+ ifnwave = (ifnwave == -1) ? gifnSine : ifnwave
+
+ xout istartbin, iendbin, ibin, kportamento, ifnwave
+endop
+
+
+/*
+ Spectral delay
+
+ aout spc_delay fsig, kdeltime, kdeladd [, istart=0, iend=1, kfreqmod=1, kportamento=0.01, ifnwave=-1, ibin=-1]
+
+ aout audio output
+ fsig input signal
+ kdeltime initial delay time in seconds
+ kdeladd increment delay by this with each bin increment or decrement
+ istart absolute bin number or ratio of the start bin, top end bins may be quite low, around a ratio of 0.1
+ iend absolute bin number or ratio of the end bin
+ kfreqmod frequency modulation ratio in resynthesis
+ kportamento portamento time for amp and frequency
+ ifnwave f-table to use for the oscillator, default is sine
+ ibin bin tracking used internally, should not be set
+*/
+opcode spc_delay, a, fkkopPJjj
+ fsig, kdeltime, kdeladd, istart, iend, kfreqmod, kportamento, ifnwave, ibin xin
+ if (ibin == -1) then
+ istart, iend, ibin, kportamento, ifnwave _spc_validatebins fsig, istart, iend, kportamento, ifnwave
+ endif
+
+ idirection = (istart < iend) ? 1 : -1
+ kamp, kfreq pvsbin fsig, ibin
+ imaxdelay = 1000
+ aout oscili portk(kamp, kportamento), portk(kfreq, kportamento) * kfreqmod, ifnwave
+ kdel = min:k(imaxdelay, kdeltime + (kdeladd * (((idirection == 1) ? ibin - istart : istart - ibin) + 1)) * 1000)
+ aout vdelay aout, a(kdel), imaxdelay
+
+ if ((idirection == 1 && ibin + 1 < iend) || (idirection == -1 && ibin - 1 >= iend)) then
+ arecurse spc_delay fsig, kdeltime, kdeladd, istart, iend, kfreqmod, kportamento, ifnwave, ibin + idirection
+ aout += arecurse
+ endif
+
+ xout aout
+endop
+
+
+/*
+ Spectral incremental shift
+
+ aout spc_shift fsig, kfreqincr [, istart=0, iend=1, kfreqmod=1, kportamento=0.01, ifnwave=-1, ibin=-1]
+
+ aout audio output
+ fsig input signal
+ kfreqincr frequency increment for each bin, may be positive or negative
+ istart absolute bin number or ratio of the start bin, top end bins may be quite low, around a ratio of 0.1
+ iend absolute bin number or ratio of the end bin
+ kfreqmod frequency modulation ratio in resynthesis
+ kportamento portamento time for amp and frequency
+ ifnwave f-table to use for the oscillator, default is sine
+ ibin bin tracking used internally, should not be set
+*/
+opcode spc_shift, a, fkopPJjj
+ fsig, kfreqincr, istart, iend, kfreqmod, kportamento, ifnwave, ibin xin
+ if (ibin == -1) then
+ istart, iend, ibin, kportamento, ifnwave _spc_validatebins fsig, istart, iend, kportamento, ifnwave
+ endif
+
+ idirection = (istart < iend) ? 1 : -1
+ kamp, kfreq pvsbin fsig, ibin
+ kfreqadd = (((idirection == 1) ? ibin - istart : istart - ibin) + 1) * kfreqincr
+ aout oscili portk(kamp, kportamento), portk(kfreq + kfreqadd, kportamento) * kfreqmod, ifnwave
+
+ if ((idirection == 1 && ibin + 1 < iend) || (idirection == -1 && ibin - 1 >= iend)) then
+ arecurse spc_shift fsig, kfreqincr, istart, iend, kfreqmod, kportamento, ifnwave, ibin + idirection
+ aout += arecurse
+ endif
+
+ xout aout
+endop
+
+
+/*
+ Spectral gate
+
+ aout spc_gate fsig, kthresh [, khold=0, istart=0, iend=1, kfreqmod=1, kportamento=0.01, ifnwave=-1, ibin=-1]
+
+ aout audio output
+ fsig input signal
+ kthresh threshold amplitude for gating
+ khold hold amplitudes rather than decaying them
+ istart absolute bin number or ratio of the start bin, top end bins may be quite low, around a ratio of 0.1
+ iend absolute bin number or ratio of the end bin
+ kfreqmod frequency modulation ratio in resynthesis
+ kportamento portamento time for amp and frequency
+ ifnwave f-table to use for the oscillator, default is sine
+ ibin bin tracking used internally, should not be set
+*/
+opcode spc_gate, a, fkOopPJjj
+ fsig, kthresh, khold, istart, iend, kfreqmod, kportamento, ifnwave, ibin xin
+ if (ibin == -1) then
+ istart, iend, ibin, kportamento, ifnwave _spc_validatebins fsig, istart, iend, kportamento, ifnwave
+ endif
+
+ idirection = (istart < iend) ? 1 : -1
+ klastamp init 0
+ klastfreq init 0
+ kamp, kfreq pvsbin fsig, ibin
+
+ if (kamp > kthresh) then
+ klastamp = kamp
+ klastfreq = kfreq
+ else
+ kamp = (khold == 1) ? klastamp : 0
+ kfreq = klastfreq
+ endif
+ aout oscili portk(kamp, kportamento), portk(kfreq, kportamento) * kfreqmod, ifnwave
+
+ if ((idirection == 1 && ibin + 1 < iend) || (idirection == -1 && ibin - 1 >= iend)) then
+ arecurse spc_gate fsig, kthresh, khold, istart, iend, kfreqmod, kportamento, ifnwave, ibin + idirection
+ aout += arecurse
+ endif
+
+ xout aout
+endop
+
+
+
+/*
+ Spectral granular resynthesis 1
+ Internal opcode
+*/
+opcode _spc_grain1_inner, a, ikkpopPJJOJjpp
+ ipbuf, ktime, kgraindur, ilayers, istart, iend, kfreqmod, kfreqrand, kdurrand, kpitchrand, kportamento, ifnwave, ibin, ibingrain xin
+ idirection = (istart < iend) ? 1 : -1
+ kchange metro 1 / kgraindur;/ 1
+ if (kchange == 1) then
+ if (kfreqrand > 1) then
+ kfreqrandv random 1 / kfreqrand, kfreqrand
+ elseif (kfreqrand == 1) then
+ kfreqrandv = 1
+ else
+ kfreqrandv random 0.5, 2
+ endif
+
+ if (kdurrand > 1) then
+ kdurrandv random 1 / kdurrand, kdurrand
+ elseif (kdurrand == 1) then
+ kdurrandv = 1
+ else
+ kdurrandv random 0.5, 2
+ endif
+
+ if (kpitchrand > 1) then
+ kpitchrandv random 1 / kpitchrand, kpitchrand
+ else
+ kpitchrandv = 1
+ endif
+ endif
+
+ kreadfreq = (1 / kgraindur) * kfreqrandv ;5 + random:k(1, 5) ;random(10, 20) ;10 + random:k(0, 5)
+ kenv = abs:k(oscili:k(1, kreadfreq, gifnHanning, random(0, 1)))
+ areadpos phasor kreadfreq, random(0, 1)
+
+ kreadtime = ktime + (k(areadpos) * kgraindur * kdurrandv) ;ktime + random(0, 0.6) ;portk(ktime + random:k(0, 0.6), kportamento)
+ fsig pvsbufread kreadtime, ipbuf
+ kamp, kfreq pvsbin fsig, ibin
+ kfreq *= kpitchrandv
+ kamp *= kenv
+
+ aout oscil portk(kamp, kportamento), portk(kfreq, kportamento) * kfreqmod, ifnwave
+ if (ibingrain < ilayers) then
+ arecurse _spc_grain1_inner ipbuf, ktime, kgraindur, ilayers, istart, iend, kfreqmod, kfreqrand, kdurrand, kpitchrand, kportamento, ifnwave, ibin, ibingrain + 1
+ aout += arecurse
+ elseif ((idirection == 1 && ibin + 1 < iend) || (idirection == -1 && ibin - 1 >= iend)) then
+ arecurse _spc_grain1_inner ipbuf, ktime, kgraindur, ilayers, istart, iend, kfreqmod, kfreqrand, kdurrand, kpitchrand, kportamento, ifnwave, ibin + idirection
+ aout += arecurse
+ endif
+ xout aout
+endop
+
+
+/*
+ Spectral granular resynthesis 1
+
+ aout spc_grain1 ifn, ktime, kgraindur [, ifftsize=512, ilayers=1, istart=0, iend=1, kfreqmod=1, kfreqrand=1, kdurrand=1, kpitchrand=0, kportamento=0.01, ifnwave=-1]
+
+ aout audio output
+ ifn f-table containing mono source sound
+ ktime read time in seconds
+ kgraindur grain duration in seconds
+ ifftsize fft size for the input
+ ilayers number of overlapping layers of grains to use
+ istart absolute bin number or ratio of the start bin, top end bins may be quite low, around a ratio of 0.1
+ iend absolute bin number or ratio of the end bin
+ kfreqmod frequency modulation ratio in resynthesis
+ kfreqrand read frequency random variation ratio
+ kdurrand grain duration random variation ratio
+ kpitchrand grain pitch random variation ratio
+ kportamento portamento time for amp and frequency
+ ifnwave f-table to use for the oscillator, default is sine
+*/
+opcode spc_grain1, a, ikkjpopPJJOJj
+ ifn, ktime, kgraindur, ifftsize, ilayers, istart, iend, kfreqmod, kfreqrand, kdurrand, kpitchrand, kportamento, ifnwave xin
+ ifftsize = (ifftsize == -1) ? 512 : ifftsize
+ ktimek timeinstk
+ ilen = ftlen(ifn) / ftsr(ifn)
+ ikcycles = ilen * kr
+ kcount init 0
+ if (ktimek == 1) then
+ while (kcount < ikcycles) do
+ apos linseg 0, ilen, ftlen(ifn)
+ asig table3 apos, ifn
+ fsig pvsanal asig, ifftsize, ifftsize/4, ifftsize, 1
+ ipbuf, k_ pvsbuffer fsig, ilen
+ kcount += 1
+ od
+ else
+ istartbin, iendbin, ibin, kportamento, ifnwave _spc_validatebins fsig, istart, iend, kportamento, ifnwave
+ aout _spc_grain1_inner ipbuf, ktime, kgraindur, ilayers, istartbin, iendbin, kfreqmod, kfreqrand, kdurrand, kpitchrand, kportamento, ifnwave, ibin
+ endif
+ xout aout
+endop
+
+/*
+ Alter the phase of FFT values
+
+ aout spc_phasemash ain, kphasemode, kphasevalue, ifftsize
+
+ aout audio output
+ ain audio input
+ kphasemode phase mode: 0 = multiply phase with kphasevalue; 1 = replace phase with kphasevalue
+ kphasevalue phase value, between -pi and +pi
+ ifftsize fft size
+*/
+opcode spc_phasemash, a, akkj
+ ain1, kphasemode, kphasevalue, ifftsize xin
+ ifftsize = (ifftsize == -1) ? 512 : ifftsize
+ ihopsize = ksmps
+ iolaps = (ifftsize / ihopsize)
+ ibw = (sr / ifftsize)
+ kcnt init 0
+ krow init 0
+ kOla1[] init ifftsize
+ kIn1[] init ifftsize
+ kOut[][] init iolaps, ifftsize
+
+ if (kcnt == ihopsize) then
+ kdx = 0
+ kWin1[] window kIn1, krow * ihopsize
+ kSpec1[] rfft kWin1
+ kmags1[] mags kSpec1
+ kphs1[] phs kSpec1 ;init lenarray(kmags1) ;phs kSpec1
+ kindex = 0
+ while (kindex < lenarray(kphs1)) do
+ if (kindex > 0) then
+ if (kphasemode == 0) then
+ kphs1[kindex] = kphs1[kindex] * kphasevalue
+ else
+ kphs1[kindex] = kphasevalue
+ endif
+ endif
+ kindex += 1
+ od
+
+ kSpec1 pol2rect kmags1, kphs1
+ kRow[] rifft kSpec1
+ kWin1 window kRow, krow * ihopsize
+ kOut setrow kWin1, krow
+
+ kOla1 = 0
+ ki = 0
+ until (ki == iolaps) do
+ kRow getrow kOut, ki
+ kOla1 = kOla1 + kRow
+ ki += 1
+ od
+ krow = (krow + 1) % iolaps
+ kcnt = 0
+ endif
+
+ kIn1 shiftin ain1
+ aout shiftout kOla1
+ aouter = aout / iolaps
+ kcnt += ksmps
+ xout aouter
+endop
+
+
+/*
+opcode spc_attack, a, fkOopPJjj
+ fsig, kthresh, khold, istart, iend, kfreqmod, kportamento, ifnwave, ibin xin
+ if (ibin == -1) then
+ istart, iend, ibin, kportamento, ifnwave _spc_validatebins fsig, istart, iend, kportamento, ifnwave
+ endif
+
+ idirection = (istart < iend) ? 1 : -1
+ klastamp init 0
+ klastfreq init 0
+ kamp, kfreq pvsbin fsig, ibin
+
+ if (kamp > kthresh) then
+ klastamp = kamp
+ klastfreq = kfreq
+ else
+ kamp = (khold == 1) ? klastamp : 0
+ kfreq = klastfreq
+ endif
+ aout oscil portk(kamp, kportamento), portk(kfreq, kportamento) * kfreqmod, ifnwave
+
+ if ((idirection == 1 && ibin + 1 < iend) || (idirection == -1 && ibin - 1 >= iend)) then
+ arecurse spc_gate fsig, kthresh, khold, istart, iend, kfreqmod, kportamento, ifnwave, ibin + idirection
+ aout += arecurse
+ endif
+
+ xout aout
+endop
+*/
+
+
+#end