Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Hanns Holger Rutz
    @Sciss
    ScalaCollider v1.20.0 is a major version bump because we deactivate some extension methods (.reciprocal) that are now provided by the Numbers library, and the conversion from String to ControlProxyFactory moved into the Ops object, meaning that you may have to add import Ops._ if you hadn't done already and are using the "control".kr syntax. The reason for this change is that I need to get hold of this syntax in SoundProcesses where controls are created differently.
    Hanns Holger Rutz
    @Sciss

    ScalaCollider v1.21.0 includes the fix for LocalIn; this is a breaking change from LocalIn.ar(numChannels: Int) to LocalIn.ar(init: GE). Unfortunately, this may appear source compatible if your code was previously LocalIn.ar(4) for example. So be sure to scan through your sources if you used LocalIn. LocalIn.ar without argument will work as before, and this also shows why using named arguments LocalIn.ar(numChannels = 4) can be very useful.

    A number of other issues on the -UGens and the main project have been closed, too.

    The UGenSource API has been changed to move out the unwrap and rewrap methods in the hope that the class files become significantly smaller (they do, but the gain is not very high). If you have written custom graph elements, you may need to import UGenSource._ which now contains these utility methods.

    ScalaColliderSwing v1.31.0 corresponds with this release. It includes the -DOT library now, and the syntax for getting GUI methods on a graph function. Before gui { ... } .waveform() which was odd because you needed to replace play by gui. Now: play { ... } and graph { ... } play() are equivalent. The gui is now graph { ... } .gui.waveform(), and the DOT is hidden behind graph { ... } .gui.diagram(). The latter is a bit hackish as it only works if the dot Unix command is found. Also the rendering on Swing using Apache Batik is quite horrible, so this will hopefully improve in the next versions. But for now, it's useful enough to get a visual overview of an expanded SynthGraph (the old viewDef based on Prefuse is not imported automatically any longer, as it was never really fully worked out and not very useful, although pretty).

    Hanns Holger Rutz
    @Sciss
    There is a new tiny library out that can help debugging intricate UGen graph structures and precise timings: https://github.com/iem-projects/ScalaCollider-Trace - README shows a couple of examples.
    Hanns Holger Rutz
    @Sciss
    Getting my genetic programming back to work. Soon more…
    play {
      val standardN = StandardN.ar(freq = Nyquist(), k = 0.37251696, xi = 0.0028863533, yi = 0.0028863533)
      val difsqr    = 0.37251696 difsqr standardN
      Pan2.ar(LeakDC.ar(difsqr))
    Hanns Holger Rutz
    @Sciss
    There will be soon a proper announcement with more details; so this is
    just a heads-up in advance -- I will be organising a workshop on
    ScalaCollider & Co
    at the Institute of Electronic Music and Acoustics
    (IEM) in Graz, on Saturday, 10 December. So if you are interested, mark
    the date, and watch this space!
    Hanns Holger Rutz
    @Sciss

    The call for the workshop on ScalaCollider & Co on 10 December is out. Details in German: http://iem.kug.ac.at/institut-aktuell/details/article/sc-meeting-iem-graz-10-dezember-2016.html :

    SC meeting @ IEM Graz, December 10th, 2016

    For the second time a SC meeting is scheduled at the Institute of Electronic Music and
    Acoustics at University of Music and Performing Arts Graz, Austria. Idea of the format: a
    thematic focus should be set by a lecturer with subsequent resp. included opportunity of
    practical programming, testing of examples and discussions with the participants. The
    event is open to all interested people, students and colleagues as well as the SC
    community in Austria and abroad. In this edition Hanns Holger Rutz will present his
    software developments.

    ScalaCollider is a dialect of SuperCollider based on Scala, a statically typed, object-
    functional language that principally targets the Java Virtual Machine (JVM). ScalaCollider
    comes with a mini-IDE and various extensions, and it forms the basis for the computer
    music platform SoundProcesses and its graphical environment Mellite, all of which are
    cross-platform and open source software. SoundProcesses/Mellite in turn contain further
    components, such as an interface for live improvisation, a timeline editor or multi-tracker,
    and furthermore the SysSon sonification platform is designed as an extension of Mellite.
    The workshop begins with an introduction to ScalaCollider and focuses on the specific
    architectural strengths and weaknesses that differentiate it from SuperCollider, making it
    an interesting alternative. In the further course of the workshop, we look at the Mellite
    application and some typical scenarios.

    Schedule:
    Saturday, December 10th, 2016, 10:00 h - ca. 14:45 h

    • 10:00 h until 11:30 h -- first block -- ScalaCollider
    • 11:45 h until 12:45 h -- second block -- SoundProcesses / Mellite
    • 12:45 h until 13:45 h -- lunch break
    • 13:45 h until 14:45 h -- third Block -- Specialisation: FScape-next (UGen based offline rendering)

    Requirements:
    Basic knowledge of SuperCollider: SynthDefs
    The participants are kindly asked to bring their own laptops and headphones and to
    register via e-mail, so they will receive on time information about software installation links
    (Linux, Mac, Windows).

    Fee: none

    Location:
    Institute of Electronic Music and Acoustics – CUBE
    Inffeldgasse 10 / 3, 8010 Graz, Austria
    http://iem.at

    Hanns Holger Rutz
    @Sciss
    ScalaCollider v1.22.0 is out. It adds improved support for buffer-generation commands (sine1, cheby etc.). Other changes include new channel range proxy element, e.g. ugen \ (0 until 4) (first four channels).
    Hanns Holger Rutz
    @Sciss
    ScalaCollider v1.22.2 mainly improves on UGen documentation. There's also a new website, although still pretty much empty: https://sciss.github.io/ScalaCollider/
    Hanns Holger Rutz
    @Sciss

    There are new updates to ScalaCollider (v1.22.3) and ScalaCollider-Swing (v1.32.2). As the versions indicate, these are binary compatible to the previous versions, but now are also published against Scala 2.12.

    I have also uploaded a new binary build for ScalaCollider-Swing; this is relevant to users, as this build is using Scala 2.12, having two implications:

    • code completion has been greatly improved, and now also extends to implicit conversions, e.g. with val x = Line.kr(0, 6, 10) typing x.db<tab> finds .dbamp. It is still limited when trying to chain calls, though.
    • you need Java 8 now to run it! If this is a problem (Java 6 seems still default on many OS X installations), you can stick to v1.32.1 or build v1.32.2 yourself using sbt ++2.11.8 clean assembly.
    Hanns Holger Rutz
    @Sciss
    Since I was asked if there is not a way to define synths with controls that don't require strings – x.set("key" -> value) – here is a quick hack:
    object Control {
      implicit def toGE(c: Control): GE = c.name.kr(c())
    }
    class Control(p: Player, val name: String, private var value: Double) {
      def apply(): Double = value
      def update(x: Double): Unit = {
        value = x
        p.synth.set(name -> x)
      }
    
      override def toString = s"$name = $value"
    }
    
    trait Player {
      private var _synth: Synth = _
    
      def synth: Synth = {
        require(_synth != null, "Forgot to call play")
        _synth
      }
    
      def stop(): Unit = synth.free()
    
      protected def control(name: String, init: Double = 0.0) = 
        new Control(this, name, init)
    
      protected def play[A](body: => A)
                           (implicit r: GraphFunction.Result[A]): Unit = {
        require(_synth == null, "Called play twice")
    
        val gf = new GraphFunction[A](() => body)
        _synth = gf.play()
      }
    }
    Example:
    class SineSynth extends Player {
      val freq = control("freq", 100)
    
      play {
        val sin = SinOsc.ar(freq)
        sin * 0.25
      }
    }
    
    val sin  = new SineSynth
    sin.freq() = 441
    sin.freq() = 666
    sin.stop()
    Of course, this is not thread safe or anything, it's just a PoC; for more complex systems, I would still recommend to have a look at SoundProcesses
    Hanns Holger Rutz
    @Sciss

    New versions are out for ScalaCollider (1.23.0) and ScalaCollider-Swing (1.35.0). not much to say about them, they mainly clean up a couple of issues; i added the 3rd party DEIND plugins (e.g. JPverb) -- if you are interested in more 3rd party plugins, please let me know or even better, contribute some XML files to the -UGens project.

    another construction site is the patterns project -- https://github.com/Sciss/Patterns -- which came out of my conversation with Ron Kuivila about his use of the SuperCollider patterns library; i'm looking here at possibilities to implement some of them for Scala, eventually ScalaCollider and SoundProcesses.

    Hanns Holger Rutz
    @Sciss

    there are new versions of ScalaCollider (v1.27.0) and -Swing (v1.39.0).
    The most apparent (and breaking) change is that I adopted camel-case
    style for the GE operators; I'm still looking at the result and
    wondering if this is good or not; I do think it's more consistent with
    idiomatic Scala, but the eye has to get used to it. So if you look at
    the examples
    (https://raw.githubusercontent.com/Sciss/ScalaCollider/master/ExampleCmd.sc),
    you'll mostly notice these changes:

    • madd --> mulAdd
    • midicps --> midiCps
    • \ --> out

    this goes for all similar things (e.g. linLin now instead of
    linlin). You may prefer the old style because it requires less typing,
    but the new style makes everything more regular (and UGen arguments have
    always used camel-case).

    Missing random unary and binary ops have been added now, such as coin
    or rand, or rangeRand:

    graph {
      SinOsc.ar.mulAdd(0.5, 0.5).coin
    } .gui.waveform(duration = 0.02)
    
    graph {
      SinOsc.ar.rand
    } .gui.waveform(duration = 0.02)
    
    graph {
      SinOsc.ar.rand
    } .gui.waveform(duration = 0.02)
    
    graph {
      SinOsc.ar.rangeRand(1.0)
    } .gui.waveform(duration = 0.02)

    (These don't work yet on numbers, e.g. 0.5.coin doesn't exist. I will
    add that feature in a future version, the reason being that we need to
    assume a mutable random number generator on the client side.)

    Shubham Kamthania
    @ikamthania

    Hi, I was trying out scala collider. I installed the scala collider swing booted the server and tried out the example.sc . However I am getting few errors. Here is the log

    JACK server starting in realtime mode with priority 10
    self-connect-mode is "Don't restrict self connect requests"
    Cannot lock down 82280346 byte memory area (Cannot allocate memory)
    audio_reservation_init
    Acquire audio card Audio0
    creating alsa driver ... hw:0|hw:0|1024|2|48000|0|0|nomon|swmeter|-|32bit
    configuring for 48000Hz, period = 1024 frames (21.3 ms), buffer = 2 periods
    ALSA: final selected sample format for capture: 32bit integer little-endian
    ALSA: use 2 periods for capture
    ALSA: final selected sample format for playback: 32bit integer little-endian
    ALSA: use 2 periods for playback
    Cannot use real-time scheduling (RR/10)(1: Operation not permitted)
    AcquireSelfRealTime error
    Cannot lock down 82280346 byte memory area (Cannot allocate memory)
    JackDriver: client name is 'SuperCollider'
    SC_AudioDriver: sample rate = 48000.000000, driver's block size = 1024
    Cannot use real-time scheduling (RR/5)(1: Operation not permitted)
    JackClient::AcquireSelfRealTime error
    SuperCollider 3 server ready.
    <console>:580: error: not found: value viewDef
           val f25 = viewDef(df25)
                     ^
    <console>:649: error: scrutinee is incompatible with pattern type;
     found   : Seq[A]
     required: de.sciss.synth.ugen.Pitch
           val Seq(freq0, hasFreq0) = Pitch.kr(???)

    Any pointers ?

    Hanns Holger Rutz
    @Sciss
    Oh, the example might be outdated. Let me check that.
    df25.gui.diagram() should work if you have graphviz installed (dot must be on the PATH).
    Hanns Holger Rutz
    @Sciss

    Yes, I removed the import for that function, because it's not too useful, given the more cleaned up look of gui.diagram. But it's still here:

    de.sciss.synth.swing.SynthGraphPanel.viewDef(df25)

    I added an issue to fix that in the next version.

    The second error is "intentional"; you do not get a Seq[GE] from Pitch; instead you need to use out, or hasFreq and freq (see following section "you can do")
    Hanns Holger Rutz
    @Sciss
    Also if you're on linux - booting Jack is always easier using the dedicated QJackCtl application (usually sudo apt install qjackctl), although Jack probably does work in your case despite the RT errors. If you start Jack audio server from QJackCtl, SuperCollider will just use that instead of launching one itself.
    Shubham Kamthania
    @ikamthania
    Thanks. I will try that.
    Shubham Kamthania
    @ikamthania
    Thanks @Sciss I started the jack audio driver from qjackctl. For time being I commented out the line which were giving errors. I tried it again and this time console was filled with lot more errors. Here is the log
    FAILURE IN SERVER /n_set Node 1001 not found
    FAILURE IN SERVER /n_set Node 1001 not found
    FAILURE IN SERVER /n_set Node 1001 not found
    FAILURE IN SERVER /n_free Node 1002 not found
    FAILURE IN SERVER /n_free Node 1003 not found
    FAILURE IN SERVER /n_free Node 1004 not found
    FAILURE IN SERVER /n_free Node 1005 not found
    FAILURE IN SERVER /n_free Node 1006 not found
    FAILURE IN SERVER /n_free Node 1007 not found
    FAILURE IN SERVER /n_free Node 1008 not found
    FAILURE IN SERVER /n_free Node 1010 not found
    FAILURE IN SERVER /n_free Node 1011 not found
    FAILURE IN SERVER /n_free Node 1012 not found
    FAILURE IN SERVER /n_free Node 1013 not found
    FAILURE IN SERVER /n_free Node 1015 not found
    FAILURE IN SERVER /n_free Node 1016 not found
    FAILURE IN SERVER /n_free Node 1017 not found
    FAILURE IN SERVER /n_free Node 1018 not found
    FAILURE IN SERVER /n_free Node 1019 not found
    FAILURE IN SERVER /n_free Node 1020 not found
    File 'sounds/a11wlk01.wav' could not be opened: System error : No such file or directory.
    FAILURE IN SERVER /n_set Node 1021 not found
    FAILURE IN SERVER /n_set Node 1022 not found
    FAILURE IN SERVER /n_free Node 1023 not found
    Buffer UGen: no buffer data
    FAILURE IN SERVER /n_free Node 1024 not found
    java.lang.NoClassDefFoundError: Could not initialize class $line10.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$
        at $line10.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2.isDefinedAt(<console>:559)
        at $line10.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anonfun$2.isDefinedAt(<console>:558)
        at de.sciss.synth.message.Responder$Impl.handle(Responder.scala:49)
        at de.sciss.synth.impl.OnlineServerImpl$OSCReceiverActor$.$anonfun$$bang$4(ServerImpl.scala:253)
        at de.sciss.synth.impl.OnlineServerImpl$OSCReceiverActor$.$anonfun$$bang$4$adapted(ServerImpl.scala:252)
        at scala.collection.immutable.Set$Set1.foreach(Set.scala:95)
        at de.sciss.synth.impl.OnlineServerImpl$OSCReceiverActor$.$anonfun$$bang$2(ServerImpl.scala:252)
        at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
        at scala.concurrent.impl.ExecutionContextImpl$DefaultThreadFactory$$anon$2$$anon$3.block(ExecutionContextImpl.scala:71)
        at java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3313)
        at scala.concurrent.impl.ExecutionContextImpl$DefaultThreadFactory$$anon$2.blockOn(ExecutionContextImpl.scala:83)
        at scala.concurrent.package$.blocking(package.scala:142)
        at de.sciss.synth.impl.OnlineServerImpl$OSCReceiverActor$.$anonfun$$bang$1(ServerImpl.scala:241)
        at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
        at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:654)
        at scala.util.Success.$anonfun$map$1(Try.scala:251)
        at scala.util.Success.map(Try.scala:209)
        at scala.concurrent.Future.$anonfun$map$1(Future.scala:288)
        at scala.concurrent.impl.Promise.liftedTree1$1(Promise.scala:29)
        at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:29)
        at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
        at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
        at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
        at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
        at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
    *** ERROR: SynthDef mag-above not found
    FAILURE IN SERVER /s_new SynthDef not found
    FAILURE IN SERVER /n_free Node 1025 not found
    FAILURE IN SERVER /n_free Node 1026 not found
        at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
    FAILURE IN SERVER /n_free Node 1027 not found
    It's just a small part of it
    Shubham Kamthania
    @ikamthania
    Here is the complete log if you like https://pastebin.com/csUFwBXu
    Sorry I am new to super/scalacollider
    Hanns Holger Rutz
    @Sciss
    So the examples are meant to be executed one by one; are you running step by step or trying to evaluate the entire document at once (the latter will fail)? If you are running step by step, could you please post the lines that you are executing , along with the output.
    Normally Node x not found means you are trying to use x.set or x.free but the synth corresponding with x has not been created or already freed.
    Shubham Kamthania
    @ikamthania
    Ok I was trying all in one go. So I suppose selecting one example and shift + enter should execute individual example
    Let me try that
    Hanns Holger Rutz
    @Sciss
    The 'sounds/a11wlk01.wav' bit is simply that I couldn't hard code the file path into the examples file. Normally, when you install SuperCollider, this is one of the example files installed. For example, on Linux the absolute path would probably be /usr/local/share/SuperCollider/sounds/a11wlk01.wav
    @ikamthania exactly; I'm still trying to figure out how to "encode" that step by step behaviour visually in the document. Perhaps we have code cells like in Jupyter in a future version.
    Unfortunately, ScalaCollider still makes the assumption that you know a little bit of how SuperCollider works. This should be alleviated by a beginner tutorial (TBA)
    So the idea is you use ScalaCollider-Swing like a REPL, but you have the entire contents of the REPL in one text document.
    If you lose the variable holding a synth, you can stop the sound with ctrl-. (period) or in the menu Actions > Stop Synths
    Hanns Holger Rutz
    @Sciss
    If you run into any other tacit assumptions that are unclear, I shall try to collect them, and make an update to the intro video (there is one, but it's seven years old ... https://vimeo.com/26572695 ; aptly called 'demo' and not 'tutorial' anyways)
    Shubham Kamthania
    @ikamthania
    I started server again. Tried very first example. Here is the error log
    Cannot lock down 82280346 byte memory area (Cannot allocate memory)
    JackDriver: client name is 'SuperCollider'
    SC_AudioDriver: sample rate = 44100.000000, driver's block size = 1024
    Cannot use real-time scheduling (RR/5)(1: Operation not permitted)
    JackClient::AcquireSelfRealTime error
    SuperCollider 3 server ready.
    x0: de.sciss.synth.Synth = Synth(<localhost>,1000) : <temp_55>
    df1: de.sciss.synth.SynthDef = SynthDef(AnalogBubbles)
    x1: de.sciss.synth.Synth = Synth(<localhost>,1001) : <AnalogBubbles>
    FAILURE IN SERVER /n_set Node 1001 not found
    FAILURE IN SERVER /n_set Node 1001 not found
    FAILURE IN SERVER /n_set Node 1001 not found
    Hanns Holger Rutz
    @Sciss

    So the nodes on the sound server have ids, the count beginning at 1000. The first synth x0 you created, is 1000; the second is x1 with 1001; the error log shows that "n_set" does not find node x1 or 1001. This has again todo with the execution order; I assume you executed this en-bloc:

    val df1 = SynthDef("AnalogBubbles") {
      val f1 = "freq1".kr(0.4)
      val f2 = "freq2".kr(8.0)
      val d  = "detune".kr(0.90375)
      val f  = LFSaw.ar(f1).mulAdd(24, LFSaw.ar(Seq(f2, f2 * d)).mulAdd(3, 80)).midiCps // glissando function
      val x  = CombN.ar(SinOsc.ar(f) * 0.04, 0.2, 0.2, 4) // echoing sine wave
      Out.ar(0, x)
    }
    val x1 = df1.play()
    x1.set("freq1" -> 0.1)
    x1.set("freq2" -> 222.2)
    x1.set("detune" -> 0.44)

    However, there are some procedures in SuperCollider which are asynchronous, so they do not complete instantaneously. One of them is SynthDef#play. The server tries to run x1.set before the synth x1 is actually initalised. Sorry, this is not obvious from the document, only if you were familiar with SuperCollider. So you need to execute that in two steps:

    val df1 = SynthDef("AnalogBubbles") {
      val f1 = "freq1".kr(0.4)
      val f2 = "freq2".kr(8.0)
      val d  = "detune".kr(0.90375)
      val f  = LFSaw.ar(f1).mulAdd(24, LFSaw.ar(Seq(f2, f2 * d)).mulAdd(3, 80)).midiCps // glissando function
      val x  = CombN.ar(SinOsc.ar(f) * 0.04, 0.2, 0.2, 4) // echoing sine wave
      Out.ar(0, x)
    }
    val x1 = df1.play()

    And then, separately:

    x1.set("freq1" -> 0.1)
    x1.set("freq2" -> 222.2)
    x1.set("detune" -> 0.44)

    Are you hearing the sounds?

    Shubham Kamthania
    @ikamthania

    Tried that. Not hearing anything. Also tried

    val x0 = play {
      val f = LFSaw.kr(0.4).mulAdd(24, LFSaw.kr(Seq(8, 7.23)).mulAdd(3, 80)).midiCps // glissando function
      CombN.ar(SinOsc.ar(f)*0.04, 0.2, 0.2, 4) // echoing sine wave
    }

    Not working. However super collider client works like a charm without QJackCtl.

    Hanns Holger Rutz
    @Sciss
    Try the menu Actions > Show Server Meter. If you see the level meters moving, the sound is rendered by SuperCollider. If you do not hear it, then its outputs are not routed in Jack. I think that if you run Jack directly from SuperCollider (I know, I have advised against it, but...), then it automatically connects its output. If you launch Jack via QJackCtl, then SuperCollider will not route its outputs automatically to the system output. You have to do that manually in 'Connect' in QJackCtl, or better, create a default setting in 'Patchbay' (make sure you "activate" it after editing).
    (In other words, Jack acts as a patchbay for audio signals, you need to tell it how you want the output of SuperCollider to go onto your sound card, for example.)
    Here is my routing for two channels output only (you can change the number of channels in the preferences):
    Screenshot from 2019-03-04 17-06-28.png
    Shubham Kamthania
    @ikamthania
    Awesome. Now I can hear it. Thanks @Sciss I will try other examples.
    Hanns Holger Rutz
    @Sciss
    Ok cool, I'm glad it's working now. Sorry about the bumpy road, it really needs an intro for people who haven't worked with SuperCollider before.
    Shubham Kamthania
    @ikamthania
    :thumbsup:
    bmott
    @Bmottomus
    Hey - is there a 'correct' way to set overtones and their respective weights with ScalaCollider? I've done it in the below way, but it feels like a hacky way to achieve my goal
      var summation: GE = SinOsc.ar(220.0)
      (2 to 16 ).zipWithIndex.foreach{
        case (ot, idx) => {
          summation = summation + (SinOsc.ar(220.0 * ot) * weights(idx))
        }
      }
    Hanns Holger Rutz
    @Sciss

    @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
    }
    Are you familiar with multi-channel-expansion? (where you pass a sequence of values into a paramter, and that then creates a sequence of UGens)
    Mix.tabulate(n)(...) is kind of the same as Mix(Seq.tabulate(n)(...))
    bmott
    @Bmottomus
    No, wasn't aware I could do that - this is awesome / exactly what I was looking for!! Appreciate the detailed examples - this makes sense, thanks!
    Hanns Holger Rutz
    @Sciss
    :thumbsup: