#ifndef UDO_TRANSIENTDETECT #define UDO_TRANSIENTDETECT ## /* Transient detection This file is part of the SONICS UDO collection by Richard Knight 2021 License: GPL-2.0-or-later http://1bpm.net */ /* Internal transient detection base */ opcode _transientdetect, kk,kikkki kin, iresponse, ktthresh, klowThresh, kdecThresh, idoubleLimit xin kinDel delayk kin, iresponse / 1000 ktrig = ((kin > kinDel + ktthresh) ? 1 : 0) klowGate = (kin < klowThresh ? 0 : 1) ktrig = ktrig * klowGate ktransLev init 0 ktransLev samphold kin, 1-ktrig kreGate init 1 ktrig = ktrig * kreGate kmaxAmp init -99999 kmaxAmp max kmaxAmp, kin kdiff = kmaxAmp-kin kreGate limit kreGate-ktrig, 0, 1 kreGate = (kdiff > kdecThresh ? 1 : kreGate) kmaxAmp = (kreGate == 1 ? -99999 : kmaxAmp) xout ktrig, kdiff endop opcode transientdetect, k, akkiikkk ain, kattack, krelease, iresponse, idoublelimit, ktthresh, klowthresh, kdecthresh xin afollow follow2 ain, kattack, krelease kfollow downsamp afollow kfollowdb = dbfsamp(kfollow) ktrig, kdiff _transientdetect kfollowdb, iresponse, ktthresh, klowthresh, kdecthresh, idoublelimit xout ktrig endop /* Default transient detection ktrigger transientdetect ainput ktrigger fires when a transient has been detected ainput the audio signal to track */ opcode transientdetect, k, a ain xin kattack init 0.05 krelease init 0.06 iresponse = 10 ktthresh = 9 klowthresh = -50 idoublelimit = 0.1 kdecthresh = 6 ktrig transientdetect ain, kattack, krelease, iresponse, idoublelimit, ktthresh, klowthresh, kdecthresh xout ktrig endop /* opcode transientdetect, k, a ain xin kattack init 0.05 krelease init 0.06 afollow follow2 ain, kattack, krelease kfollow downsamp afollow kfollowdb = dbfsamp(kfollow) iresponse = 10 ktthresh = 9 klowthresh = -50 idoublelimit = 0.1 kdecthresh = 6 ktrig, kdiff _transientdetect kfollowdb, iresponse, ktthresh, klowthresh, kdecthresh, idoublelimit xout ktrig endop */ /* Detect transients in audio ftable; count or output to ftable p4 ftable to read sound from p5 instrument name to invoke when complete, ftable contaqining transients is passed as p4 p6 0 = stage 1, count and recall; 1 = stage 2, write to ftable p7 number of transients for ftable initialisation as used with stage 2 */ instr _transientdetect_tofn_inner ifnsound = p4 SonComplete = p5 istate = p6 itransientnum = p7 if (istate == 0) then ifntransients = -1 else ifntransients ftgen 0, 0, itransientnum, 7, 0 endif kdone init 0 ktransientnum init 0 ktimek timeinstk if (ktimek == 1) then inputduration = ftlen(ifnsound) / ftsr(ifnsound) kcycles = inputduration * kr kcount init 0 while (kcount < kcycles) do if (ftchnls(ifnsound) == 1) then asound loscil 1, 1, ifnsound, 1 else aL, aR loscil 1, 1, ifnsound, 1 asound = (aL + aR) / 2 endif ;ktransient, kdiff _transientdetectinner asound ktransient transientdetect asound if (ktransient == 1) then if (ifntransients != -1) then tablew (inputduration / kcycles) * kcount, ktransientnum, ifntransients endif ktransientnum += 1 endif kcount += 1 od else if (istate == 0) then if (ktransientnum == 0) then schedulek(SonComplete, 0, 3600, -1) else schedulek(p1, 0, 1, ifnsound, SonComplete, 1, ktransientnum) endif else schedulek(SonComplete, 0, 3600, ifntransients) endif turnoff endif endin opcode transientdetect_tofn, 0, iS ifn, SonComplete xin schedule("_transientdetect_tofn_inner", 0, 600, ifn, SonComplete, 0, 0) endop opcode randomtransient, ii, i ifntransients xin iftlen = ftlen(ifntransients) if (iftlen < 2) then istart = tab_i(0, ifntransients) ilen = 0.1 else istartindex = round(random(0, iftlen - 2)) istart = tab_i(istartindex, ifntransients) iend = tab_i(istartindex + 1, ifntransients) ilen = iend - istart endif if (ilen > 1) then ilen = 1 endif xout istart, ilen endop /* By Brandtsegg, I think; tweaked by RK */ opcode onsetdetect, k, aiiiiii ain, iMinFreq, iMaxFreq, iAboveMed, iOffset, iMinSec, iMedLen xin ifftsize = 1024 iIndexStart limit int(iMinFreq*(ifftsize/sr))*2,0,sr/2 iIndexEnd limit int(iMaxFreq*(ifftsize/sr))*2,0,sr/2 fsrc pvsanal ain,ifftsize,ifftsize/4,ifftsize,1 kArr[] init ifftsize+2 kflag pvs2array kArr, fsrc ksumold init 0 kMedIndex init 0 kMedSum init 0 kMedian[] init iMedLen kMinDist init 0 iMinDist = iMinSec*(sr/ksmps) kMinDist limit kMinDist-1,0,100000 if changed(kflag) == 1 && kMinDist == 0 then ksum = 0 kIndex = iIndexStart until kIndex = iIndexEnd do ksum = ksum+kArr[kIndex] kIndex += 2 od kFLUX = ksum-ksumold ksumold = ksum kOnset = 0 if kFLUX > (kMedSum*iAboveMed)+iOffset then kOnset = 1 kMinDist = iMinDist endif kMedian[kMedIndex] = (kFLUX>=0?kFLUX:0) kMedSum = sumarray(kMedian)/iMedLen kMedIndex = (kMedIndex+1)%iMedLen endif xout changed(kOnset)==1 && kOnset==1 ? 1 : 0 endop #end