Nice! You’re totally right!
So here is one for two tables then, first writing to two tables, then crossfading with eachother. If you use the delay method you’re just postponing the same table content right? While if you do something like this, you should be able to write two independent buffers of audio at different times and overlap those two tables. Should be a better solution or?
There is still a slight clicking in this one though. One thing I noticed is that I can’t initialize with a k-rate like this: kWritePointer2 init kTableLength/2
, so I put it in the changed if-statement, which I’m thinking could be the culprit.
Also, does setksmps
need to be changed?
<Cabbage>
form caption("Reverse") size(400, 300), guiMode("queue"), colour(58, 110, 182), pluginId("def1")
rslider bounds(26, 28, 60, 60) channel("length") range(0, 1, 1, 1, 0.1), text("Length")
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d --midi-key=4 --midi-velocity-amp=5
</CsOptions>
<CsInstruments>
ksmps = 32
nchnls = 2
0dbfs = 1
giTableLen = 2^16
giTableL1 ftgen 0, 0, giTableLen, 7, 0, giTableLen, 0
giTableL2 ftgen 0, 0, giTableLen, 7, 0, giTableLen, 0
giTableR1 ftgen 0, 0, giTableLen, 7, 0, giTableLen, 0
giTableR2 ftgen 0, 0, giTableLen, 7, 0, giTableLen, 0
giEnvTable ftgen 0, 0, giTableLen, 9, 0.5, 1, 0
opcode Reverse, a, aiiik
setksmps 2
aIn, iFn1, iFn2, iEnvTable, kLength xin
kWritePointer1 init 0
kReadPointer1 init 0
kWritePointer2 init ftlen(iFn2)/2
kReadPointer2 init ftlen(iFn2)/2
kTableLength = int(ftlen(iFn1)*kLength)
if changed(kTableLength) == 1 then
reinit resetPhase
kWritePointer2 = kTableLength/2
kReadPointer2 = kTableLength/2
endif
resetPhase:
kWritePointer1 init 0
kReadPointer1 init 0
tablew aIn, a(kReadPointer1), iFn1
aSignal1 table kTableLength-a(kReadPointer1), iFn1
tablew aIn, a(kReadPointer2), iFn2
aSignal2 table kTableLength-a(kReadPointer2), iFn2
kWritePointer1 = kWritePointer1 < kTableLength ? kWritePointer1 + 1 : 0
kReadPointer1 = kReadPointer1 < kTableLength ? kReadPointer1 + 1 : 0
kWritePointer2 = kWritePointer2 < kTableLength ? kWritePointer2 + 1 : 0
kReadPointer2 = kReadPointer2 < kTableLength ? kReadPointer2 + 1 : 0
aEnvPhs1 phasor (sr/(kTableLength))
aEnvPhs2 phasor (sr/(kTableLength)), 0.5
aEnv1 table aEnvPhs1, iEnvTable, 1
aEnv2 table aEnvPhs2, iEnvTable, 1
xout (aSignal1*aEnv1) + (aSignal2*aEnv2)
endop
instr 1
kLength cabbageGetValue "length"
a1 inch 1
a2 inch 2
aRevL Reverse a1, giTableL1, giTableL2, giEnvTable, kLength
aRevR Reverse a2, giTableR1, giTableR2, giEnvTable, kLength
outs aRevL, aRevR
endin
</CsInstruments>
<CsScore>
i1 0 z
</CsScore>
</CsoundSynthesizer>
Or maybe a better solution than doing the crossfading inside the opcode, would be to add a normalized offset parameter? Something like this?
aRevL1 Reverse a1, giTableL1, giEnvTable, kLength, 0 ;Offset = 0
aRevL2 Reverse a1, giTableL2, giEnvTable, kLength, 0.5 ;Offset = 0.5
aRevL1 + aRevL2