Dear Csounders!
How to manually resynthesize resulting ATS residuals?
If I store ATS results of c_note.wav into c_note.ats using this command:
ires system_i 1,{{ atsa c_note.wav c_note.ats }}
then I can, using ATSread opcode and recursion, pretty simply manually re-synthesize ATS partials using e.g. RecursivePartialsSynth UDO (see code below).
On the other hand when I do similar thing with residuals and want recursively resynthesize 25 critical bands using ATSreadnz opcode, it doesn’t work. Resulting noise is way too strong. (see RecursiveResidualSynth UDO in the code below)
Values for 25 critical band frequency edges I took from 05K04_atsreadnz.csd example in floss manual.
It seems to me that I’m probably calculating bandwidth wrong or I’m using reson opcode wrong.
Any idea how to fix this?
Here is my code:
<CsoundSynthesizer>
<CsOptions>
-odac
</CsOptions>
<CsInstruments>
sr = 48000
ksmps = 32
nchnls = 2
0dbfs = 1
// relevant examples:
// https://flossmanual.csound.com/sound-modification/ats-resynthesis
// https://github.com/csound/manual/issues/561#issuecomment-879122056
ires system_i 1,{{ atsa c_note.wav c_note.ats }} ; default settings
giAtsNoiseFc ftgen 0, 0, 32, -2, 0, 100, 200, 300, 400, 510, 630, 770, 920, 1080, 1270, 1480, 1720, 2000, 2320, 2700, 3150, 3700, 4400, 5300, 6400, 7700, 9500, 12000, 15500, 20000
// UDO to recursively synthesize and add the partials
opcode RecursivePartialsSynth, a, Skip
Sfile,ktime,inparts,istart xin
if istart < inparts then ;if inparts have not yet reached
acall RecursivePartialsSynth Sfile, ktime, inparts, istart+1 ;call another instance of this UDO
endif
kfreq, kamp ATSread ktime, Sfile, istart ; take the istart-th partial
aout oscili kamp, kfreq
aout = aout + acall ;add the audio signals
xout aout
endop
opcode RecursiveResidualSynth, a, Skip
Sfile,ktime,inparts,istart xin
if istart < inparts then ;if inparts have not yet reached
acall RecursiveResidualSynth Sfile, ktime, inparts, istart+1 ;call another instance of this UDO
endif
iscal = 1 ;reson filter scaling factor
iband = istart ;energy band required
if1 table iband-1, giAtsNoiseFc ;lower edge
if2 table iband, giAtsNoiseFc ;upper edge
idif = if2-if1
icf = if1 + idif*.5 ;center frequency value
ibw = idif*0.7 ; NOTE: this is probably wrong
ken ATSreadnz ktime, Sfile, iband ;energy value for this band
anoise gauss 1
aout reson anoise*sqrt(ken), icf, ibw, iscal ;synthesize with scaling NOTE: or maybe Im using reson wrong
aout = aout + acall ;add the audio signals
xout aout
endop
// Instrument that reads ats file and resynthesie it manualy usinig oscilators and noise generators
instr AtsResynth
Sfile = "c_note.ats"
isr ATSinfo Sfile, 0
ifs ATSinfo Sfile, 1
iws ATSinfo Sfile, 2
inp ATSinfo Sfile, 3
inf ATSinfo Sfile, 4
ima ATSinfo Sfile, 5
imf ATSinfo Sfile, 6
id ATSinfo Sfile, 7
ift ATSinfo Sfile, 8
prints {{
*****c_note.ats*********************
0. Sample rate = %d Hz
1. Frame Size = %d samples
2. Window Size = %d samples
3. contains %d partials
4. contains %d frames
5. Max. Ampl. = %f
6. Max. Freq. = %f Hz
7. Duration = %f seconds
8. File Type = %d
*********************************\\n
}}, isr, ifs, iws, inp, inf, ima, imf, id, ift
p3 = id ;set instrument duration to file duration
ktime timeinsts
aoutPartials RecursivePartialsSynth Sfile, ktime, inp, 1 ;call the UDO
aoutResiduals RecursiveResidualSynth Sfile, ktime, 25, 1 ;call the UDO -> there are always 25 critical bands
if p4 == 0 then
aout = aoutPartials ;use only partials
fout "c_note_partials_only.wav", 18, aout ;write to soundfile
else
aout = aoutPartials + aoutResiduals ;add the partials and residuals
fout "c_note_partials_and_residuals.wav", 18, aout ;write to soundfile
endif
outs aout, aout
endin
</CsInstruments>
<CsScore>
i "AtsResynth" 0 3 0 ; p4=1 -> use resiudals also, p4=0 -> use only partials
</CsScore>
</CsoundSynthesizer>