; Original research and code by Jon Downing as in paper
; Real-time digital modeling of the Roland Space Echo by Jon Downing, Christian Terjesen (ECE 472 - Audio Signal Processing, May 2016)
;
; Reimplemented in Csound by Anton Kholomiov
; Error function approximation ~ 2% accuracy
opcode ErrorFunApprox, a, a
aIn xin
kCoeff init ( (3.1415926535 ^ 0.5) * log(2) )
xout tanh(kCoeff * aIn)
endop
; Bandpass Chebyshev Type I filter
opcode bandpassCheby1, a, akkii
aIn, kLowFreq, kHighFreq, iOrder, iRipple xin
aHigh clfilt aIn, kLowFreq, 1, iOrder, 1, iRipple
aLow clfilt aHigh, kHighFreq, 0, iOrder, 1, iRipple
xout aLow
endop
; Function to read from tape.
;
; tapeRead aIn, kDelay, kRandomSpread
;
; The function is used in the same manner as deltapi
; first init the delay buffer and the use tapeRead.
;
; aIn - input signal
; kDelay - delay time
; kRandomSpread - [0, Inf] - the random spread of reading from the tape
; the higher the worser the quality of the tape.
opcode tapeRead, a, akk
aIn, kDelay, kRandomSpread xin
iTauUp = 1.07
iTauDown = 1.89
aPrevDelay init 0.06
kOldDelay init 0.06
kLambda init 0.5
kDelChange changed kDelay
if (kDelChange == 1) then
if (kOldDelay < kDelay) then
kLambda = exp(-1/(iTauUp*sr))
else
kLambda = exp(-1/(iTauDown*sr))
endif
endif
anoise noise kRandomSpread, 0
anoise = 3*(7.5 - aPrevDelay*(10^-3))*(10^-7)*anoise
anoiseMod butterlp anoise, 0.25 ; (0.5 / sr) * giNyquistFreq
aActualDelay = (1 - kLambda) * kDelay + kLambda * aPrevDelay + anoiseMod
aPrevDelay = aActualDelay
; measured
aDelaySamps = aActualDelay * sr
aReadSr = floor(aDelaySamps) ; in samples
aLastSr = aReadSr + 1 ; in samples
aReadIndex = aReadSr / sr ; in seconds
aLastIndex = aLastSr / sr ; in seconds
aFrac = aDelaySamps - aReadSr
aFracScale = (1 - aFrac) * (1 + aFrac)
aReadSample deltapi aReadIndex
aLastSample deltapi aLastIndex
aEcho ErrorFunApprox (aLastSample + aFracScale * (aReadSample - aLastSample))
kOldDelay = kDelay
xout aEcho
endop
; function to write to tape
;
; tapeWrite aIn, aOut, kFbGain
;
; It should be though of as delayw for magnetic tape.
;
; aIn - input signal
; aOut - output signal
; kFbGain - gain of feedback [0, 2]
opcode tapeWrite, 0, aak
aIn, aOut, kFbGain xin
iOrder = 2
iRippleDb = 6
aProc bandpassCheby1 aOut * kFbGain, 95, 3000, iOrder, iRippleDb
delayw aIn + aProc * kFbGain
endop
opcode tapeReadBatch, a, akkii
aIn, kDelay, kRandomSpread, iSize, iStart xin
if iStart <= iSize then
acall tapeReadBatch aIn, kDelay, kRandomSpread, iSize, iStart + 1
else
acall = 0
endif
iScale = iStart
aEcho tapeRead aIn, kDelay * iScale, kRandomSpread
xout acall + aEcho / iScale
endop
opcode TapeEchoN, a, akkkkki
aIn, kDelay, kEchoGain, kFbGain, kTone, kRandomSpread, iSize xin
aDummy delayr (16 * iSize)
aEcho tapeReadBatch aIn, kDelay, kRandomSpread, iSize, 1
aOut = aIn + kEchoGain * aEcho
tapeWrite aIn, aOut, kFbGain
xout aOut
endop