#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