#ifndef UDO_TABPROC #define UDO_TABPROC ## /* JIT style table processor This file is part of the SONICS UDO collection by Richard Knight 2022 License: GPL-2.0-or-later http://1bpm.net */ #include "lagdetect.udo" #define TP_DFLT_RATE #10# gitabproc_instancetrack = 0 ; internal instance tracking for channel names opcode tabproc_profiler, kkk, ij instrnum, istabletime xin istabletime = (istabletime == -1) ? 5 : istabletime ichannelbase = gitabproc_instancetrack gitabproc_instancetrack += 1 kblocksize init 16384 kprocrate init $TP_DFLT_RATE kdone init 0 ; actual processing at iprocrate if (kdone == 0) then klagging, ktimesincelag lagdetect if (klagging == 1) then ; reduce block size first, then reduce processing rate if (kblocksize > 128) then kblocksize -= 128 elseif (kprocrate > 1) then kprocrate -= 1 endif endif if (ktimesincelag >= istabletime) then kdone = 1 kgoto complete endif ktrig metro kprocrate if (ktrig == 1) then kcount = 0 while (kcount < kblocksize) do atest oscil 1, 1000 ; set channels and call subinstrument for processing SchannelL = sprintf("tabproc%dL", ichannelbase) SchannelR = sprintf("tabproc%dR", ichannelbase) chnset atest, SchannelL chnset atest, SchannelR aL, aR subinstr instrnum, SchannelL, SchannelR kcount += 1 od endif endif complete: xout kdone, kblocksize, kprocrate endop opcode tabproc_profiler, kkk, S Sinstrname xin kdone, kblocksize, kprocrate tabproc_profiler nstrnum(Sinstrname) xout kdone, kblocksize, kprocrate endop /* Process a table with a subinstrument at deferred k-rate. The table ifn is read and passed to the instrument Sinstrname/instrnum which should perform processing and use the outs() or out() opcode to return audio to be written to ifn. Sinstrument is passed the input audio on channels with the names passed as p4 (left) and p5 (right, if the sound is stereo). Hence the instrument should implement something such as aL = chnget:a(strget(p4)) aR = chnget:a(strget(p5)) in order to deal with the incoming audio. The table can be read in reverse by specifying ireverseread=1. Similarly it can be written back to in reverse with ireversewrite=1. tabproc performs processing in chunks at a given rate in order to minimise CPU usage and allow other instruments to continue uninterrupted (without this, it would consume all available CPU and block the performance until complete). The blocksize iblocksize is how many k-cycles are processed in each chunk, and iprocrate determines the frequency at which chunks are processed. Defaults are provided but these will be best altered depending on the load of Sinstrument and the available CPU. iautoadjust can be set to 1 to attempt to automatically reduce iblocksize and iprocrate if it is detected that the CPU cannot keep up. This is done by comparing the realtime clock against Csound's instrument time. If the difference is over iautotimethreshold, then a reduction of block size/frequency is made. kdone, kpercent tabproc ifn, instrnum [, ireverseread=0, ireversewrite=0, iautoadjust=0, iblocksize=2048, iprocrate=TP_DFLT_RATE, iautotimethreshold=TP_DFLT_TTHRESH] kdone, kpercent tabproc ifn, Sinstrname [, ireverseread=0, ireversewrite=0, iautoadjust=0, iblocksize=2048, iprocrate=TP_DFLT_RATE, iautotimethreshold=TP_DFLT_TTHRESH] kdone output trigger when the processing has completed kpercent percent of the table that has been processed ifn table containing audio (typically GEN1 but could be any). Mono and stereo are supported instrnum the instrument number to be invoked to process the table Sinstrname the instrument name to be invoked to process the table ireverseread set to 1 in order to read the table in reverse ireversewrite set to 1 in order to write back to the table in reverse iautoadjust set to 1 to enable automatic reduction of iblocksize and iprocrate if processing lag is detected iblocksize number of k-cycles of audio to be processed in each run iprocrate frequency at which to perform block processing iautotimethreshold time lag at which to automatically adjust, if iautoadjust is specified */ opcode tabproc, kk, iiooojjj ifn, instrnum, ireverseread, ireversewrite, iautoadjust, iblocksize, iprocrate, iautotimethreshold xin kblocksize init (iblocksize == -1) ? 2048 : iblocksize kprocrate init ((iprocrate == -1) ? $TP_DFLT_RATE : iprocrate) iautotimethreshold = (iautotimethreshold == -1) ? $LAG_DFLT_TTHRESH : iautotimethreshold ichannelbase = gitabproc_instancetrack gitabproc_instancetrack += 1 ichannels = ftchnls(ifn) isr = ftsr(ifn) ilenraw = ftlen(ifn) ilen = ilenraw / ichannels kpos init 0 kpercent = 0 kdone init 0 if (kdone == 0) then ; auto adjust block size to account when cpu can't keep up if (iautoadjust == 1 && lagdetect:k(iautotimethreshold) == 1) then if (kblocksize > 128) then kblocksize -= 128 elseif (kprocrate > 1) then kprocrate -= 1 endif endif ; each block processing at iprocrate ktrig metro kprocrate if (ktrig == 1) then kcount = 0 while (kcount < kblocksize) do apos = round:a(lphasor(isr / sr)) ; rounded to deal with stereo offset if required ; if complete, set kdone if (downsamp(apos) >= ilen) then ;? >= ilenraw) then kpercent = 100 kdone = 1 kgoto complete endif ; read and write position calcs for stereo / reverse aposbase = apos * ichannels if (ireverseread == 1) then aposrR = ilen - aposbase aposrL = (ichannels == 2) ? aposrR + 1 : aposrR else aposrL = aposbase aposrR = aposbase + 1 endif if (ireversewrite == 1) then aposwR = ilen - aposbase aposwL = (ichannels == 2) ? aposwR + 1 : aposwR else aposwL = aposbase aposwR = aposbase + 1 endif ; read source table aL table aposrL, ifn if (ichannels == 2) then aR table aposrR, ifn else aR = aL endif ; set channels and call subinstrument for processing SchannelL = sprintf("tabproc%dL", ichannelbase) SchannelR = sprintf("tabproc%dR", ichannelbase) chnset aL, SchannelL chnset aR, SchannelR aL, aR subinstr instrnum, SchannelL, SchannelR ; write back to table tablew aL, aposwL, ifn if (ichannels == 2) then tablew aR, aposwR, ifn endif kcount += 1 od endif ; calculate percent complete kpercent = (100 / ilenraw) * downsamp(apos) endif complete: xout kdone, kpercent endop ; derived opcode for named instruments opcode tabproc, kk, iSooojjj ifn, Sinstrname, ireverseread, ireversewrite, iautoadjust, iblocksize, iprocrate, iautotimethreshold xin kdone, kpercent tabproc ifn, nstrnum(Sinstrname), ireverseread, ireversewrite, iautoadjust, iblocksize, iprocrate, iautotimethreshold xout kdone, kpercent endop #end