Chat and questions about the Scala based SuperCollider client. Newbies welcome. @ me if you need fast replies, otherwise I might not see new posts in a few days. Also checkout https://gitter.im/Sciss/Mellite for the computer music environment that embeds ScalaCollider.
var summation: GE = SinOsc.ar(220.0)
(2 to 16 ).zipWithIndex.foreach{
case (ot, idx) => {
summation = summation + (SinOsc.ar(220.0 * ot) * weights(idx))
}
}
@Bmottomus Yes sure; so let's say your complete example is
play {
val f0 = 220.0
var summation: GE = SinOsc.ar(f0)
val weights = Seq.tabulate(15)(i => 1.0 / (i + 1))
(2 to 16 ).zipWithIndex.foreach{
case (ot, idx) => {
summation = summation + (SinOsc.ar(f0 * ot) * weights(idx))
}
}
summation * 0.2
}
That is, weights are 1.0, 0.5, 0.333, .... You could write that more concisely as
play {
val f0 = 220.0 // fudamental
val n = 16 // number of partials
val sum = Mix.tabulate(n) { i =>
val j = i + 1
SinOsc.ar(f0 * j) * 1.0 / j
}
sum * 0.2
}
Or use multi-channel expansion followed by a Mix
:
play {
val f0 = 220.0 // fudamental
val n = 16 // number of partials
val f = (1 to n).map(_ * f0)
val w = (1 to n).map(_.reciprocal)
val sum = Mix(SinOsc.ar(f) * w)
sum * 0.2
}
Mix.tabulate(n)(...)
is kind of the same as Mix(Seq.tabulate(n)(...))
AudioControlProxy
? Something like Env.Step(...)
but instead of a Seq[GE] a Proxy which expands to a Seq[Float] like below? SynthDef.recv("envl") {
Out.ar(0,
PanAz.ar(2,
SinOsc.ar(220) *
EnvGen.ar(Env.step("levels".ar(Seq(1f,0f,2f,0f)), "durs".ar(Seq(1f,1f,1f,1f)))),
orient = 0.5 )
)
}
Synth.play("envl", Seq(
"levels" -> Seq(1f, 0f, 1f, 0f),
"durs" -> Seq(1f, 1f, 1f, 1f),
)
@Bmottomus yes, there is a bit of mismatch between unexpanded multi-channel UGen and explicit requirement for Seq[GE]
, which comes from the fact that the envelope generator must have a static number of elements. This would be the workaround if there wasn't another bug:
SynthDef.recv("envl") {
val lvl = "levels".ar(Seq(1f,0f,2f,0f))
val dur = "durs" .ar(Seq(1f,1f,1f,1f))
val lvlSq = Seq.tabulate(4)(lvl.out)
val durSq = Seq.tabulate(4)(dur.out)
val eg = EnvGen.ar(Env.step(lvlSq, durSq))
Out.ar(0, Pan2.ar(SinOsc.ar(441) * eg))
}
So you still need to statically know that the number of controls is four.
Unfortunately, it seems that Env.step
is buggy, it swaps levels and durations. So you have to create the envelope by hand:
SynthDef.recv("envl") {
val lvl = "levels".ar(Seq(1f,0f,2f,0f))
val dur = "durs" .ar(Seq(1f,1f,1f,1f))
val lvlSq = Seq.tabulate(4)(lvl.out)
val durSq = Seq.tabulate(4)(dur.out)
val env = new Env(lvlSq.head, (durSq zip lvlSq).map { case (d, l) =>
new Env.Segment(d, l, Curve.step)
})
val eg = EnvGen.ar(env)
Out.ar(0, Pan2.ar(SinOsc.ar(441) * eg))
}
Synth.play("envl", Seq(
"levels" -> Seq(1f, 0f, 1f, 0f),
"durs" -> Seq(1f, 1f, 1f, 1f),
))
(The bug is noted)
play {
val h = HenonN.ar(5000,
LFNoise2.kr(1).mulAdd(0.20, 1.20),
LFNoise2.kr(1).mulAdd(0.15, 0.15),
)
val lo = 40
val hi = LFNoise2.kr(0.1).linLin(-1, 1, 1000, 10000)
val f = (h * 0.6).linLin(-1, 1, lo, hi)
val p = (Pulse.ar(f) * 0.2).ring3(0.5).clip2(0.8)
val dry = LeakDC.ar(p)
val vrb = Greyhole.ar(dry, dry, feedback = 0.2, diff = 1, delayTime = 0.6) // needs sc3plugins installed
dry + vrb * 0.7
}
@Bmottomus yes, they are integer multiples, because it's filling a wavetable, so naturally there are only integer overtones.
val b = Buffer.alloc(s, 512, 1)
b.sine1((1 to 4).map(_.reciprocal), normalize = true, wavetable = true, clear = true)
val x = play { Osc.ar(b.id, 200) * 0.2 }
Sadly, we currently don't have freq scope, but you could record and look at a spectrogram.
sine2
you indicate which partials to use; again wavetable, so only integer numbers make sense (indeed I'm not sure why it accepts float at all).b.sine2(Seq((1, 1.0f), (3, 0.5f)), true, true, true) // fundamental at 1.0 amplitude, second overtone (third partial) at 0.5 or -6 dB
sine3
you have triplets with third component being the phase for each given partial.
val bRec = Buffer.alloc(s, 16384, 1)
val b = Buffer.alloc(s, 512, 1)
b.sine1((1 to 4).map(_.reciprocal), normalize = true, wavetable = true, clear = true)
(play {
val sig = Osc.ar(b.id, 200)
RecordBuf.ar(sig, bRec.id, loop = 0, doneAction = freeSelf)
Pan2.ar(sig * 0.2)
}).onEnd {
bRec.getData().foreach { sig =>
val f = de.sciss.dsp.Fourier(bRec.numFrames)
val sigA = (sig :+ 0f :+ 0f).toArray
f.realForward(sigA)
val spect = sigA.iterator.grouped(2).map { case Seq(re, im) => (re.squared + im.squared).sqrt.ampDb } .toVector
scala.swing.Swing.onEDT(spect.take(1024).plot())
}
}
thanks! I forgot to announce it here, so here's the demo link: https://www.sciss.de/temp/scalacollider.js/
Working now on the possibility to export Mellite workspaces so they can be directly read in the browser (this still needs a few things, but I expect that to work in the next few weeks)