Skip to content

Instantly share code, notes, and snippets.

@Sciss
Created April 13, 2020 20:51
Show Gist options
  • Save Sciss/4f9b6c885df90e7e4ec94950cc6893ac to your computer and use it in GitHub Desktop.
Save Sciss/4f9b6c885df90e7e4ec94950cc6893ac to your computer and use it in GitHub Desktop.
def snd = AudioFileIn("in")
val dur = 60.0
//val pch = Seq(0.5, 1, 1.5, 2, 4)
val pch = Seq(0.8, 1.0, 1.2, 1.4, 1.6)
val freq0 = 200.0 // 100
val freq1 = 5000.0
val gain0 = 128.0
val gain1 = 1.0
val frag0 = 0.2 // 1.0
val frag1 = 4.0
val ovrlp = 4.0
val sr = snd.sampleRate
val framesIn = snd.numFrames
val framesOut = (dur * sr).toInt
def mkPosBs(phase: Double,
el: Double = 0.0, posSq: Seq[Double] = Nil, bsSq: Seq[Double] = Nil): (GE, GE) =
if (el >= dur) {
// println(s"# segments: ${posSq.size}")
(ValueDoubleSeq(posSq: _*), ValueDoubleSeq(bsSq: _*))
} else {
val pos = el / dur
val bs = ((pos + phase) * 2 * math.Pi).sin.linLin(-1, 1, frag0, frag1)
mkPosBs(phase, el + bs/ovrlp, posSq :+ pos, bsSq :+ bs)
}
val mix = pch.zipWithIndex.foldLeft(0.0: GE) { case (in, (speed, si)) =>
val (pos, bs) = mkPosBs(phase = si.linLin(0, pch.size, 0.0, 1.0))
val f = speed.reciprocal
val r = Resample(snd, f)
val frInR = framesIn * f
val posInFr = (pos * frInR).toInt
val posOutFr= (pos * framesOut).toInt
val winSz = (bs * sr).toInt
val fftSz = (winSz * 2).nextPowerOfTwo // toInt
val step = posOutFr.differentiate
val spans = posInFr zip (posInFr + winSz)
val slic = Slices(r, spans)
// winSz.poll(1, "winSz")
// posInFr.poll(1, s"posInFr ($speed)")
val fft = Real1FFT(slic, winSz, padding = fftSz - winSz, mode = 1)
val magSz = fftSz/2 + 1
val mag = fft.complex.mag
val phase = fft.complex.phase
val freq = pos.linLin(0, 1, freq0, freq1)
val gain = pos.linExp(0, 1, gain0, gain1)
val gainH = RepeatWindow(gain, 1, magSz)
val freqN = RepeatWindow(freq / sr, 1, magSz)
val lpf = LPF(mag, freqN) * gainH
val rec = (lpf zip phase).complex.polToCar
val ifft = Real1IFFT(rec, fftSz, mode = 1)
val ifftR = ResizeWindow(ifft, fftSz, stop = winSz - fftSz)
// val layer = ifftR * GenWindow.Hann(winSz)
val layer = ifftR
val lap = OverlapAdd(layer, winSz, step).take(framesOut)
in + LeakDC(lap)
}
val amp = mix.abs.maximum
val norm = BufferDisk(mix) / amp
AudioFileOut("out", norm, sampleRate = sr)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment