Synth Iteration Help

Hello, I asked for help on the lines forum about iteration and executing events. I received help but have some questions… what I am trying to do is as follows

-a single SinOsc frequency ascending by multiples of a fundamental, i.e- overtones.
-the amplitude envelope of each new overtone decreasing exponentially
over a total, finite duration of time.
-each new enveloped overtone sent to different output within an 8-channel array, linearly distributed and wrapping back to the first channel, i.e 0…7, 0…7, 0…7, etc.

In other words, what I am trying to create is a single tone raising in pitch by sequential order of its harmonics, each new harmonic is exponentially shorter in duration than the previous harmonic, and each new harmonic is sent to a different channel in an 8 channel circular array, over a defined total duration.

the following code was posted…

(
SynthDef (\sine_tone) {
arg freq = 440, amp = 1, len = 1, bus = 0;
var sig, env;
env = Env.step ([ amp ], [ len ]);
env = EnvGen.kr (env, doneAction: 2);
sig = SinOsc.ar (freq, 0, env);
Out.ar (bus, sig);
}.add;
)

(
t = 2; // initial duration
f = 220; // initial frequency
~harmonic_bus_pattern = Pbind (
\instrument, \sine_tone,
\delta, t * (2 ** Pseq ((0…-7), 1)),
\len, Pkey (\delta),
\amp, (2 ** Pseq ((0…-7), 1)),
\freq, f * Pseq ((0…7), 1), // will give you octaves. see edit
\bus, Pseq ((0…7), 1),
);
)

~harmonic_bus_pattern.play

When I execute this I hear one channel of audio, then silence. I suspected it was because I was listening on my computer and not an 8-channel system so I checked on the meter there were events happening on the other channels but it didn’t wrap or continue, it seemed like it stopped/was freed, which was confirmed after inspecting the node tree. I tried to change it to two channel but failed.

Also, I tried to implement a exponential envelope but kept getting errors. I didn’t think of using Env.step but it seems like an effective option.

Finally, there is a wait/delay equal to the “initial duration” variable, I haven’t figured out why this is.

Any and all help is greatly appreciated as I try to figure this out… thank you!!!

Hi,

First you need to set number of output bus channels, even if you don’t have an 8 channel hardware.
In earlier SC versions (before SC 3.7 or so), this was set to 8 by default, then it was changed to stereo (which confused many former multichannel users)

s.options.numOutputBusChannels = 8;

Secondly your frequencies start with zero (delay comes from that), you probably want

\freq, f * Pseq ((1..8), 1),

For the envelope try Env.perc as a simple solution

env = Env.perc(releaseTime: len);

You can shape the release with the curve arg, many other options though. BTW, the miSCellaneous_lib quark contains a tutorial “Event patterns and array args”. It shows some possibilities of array args on the basis of an example with partials. Not exactly the same as your approach, but usage of arrays brings many advantages when organizing overtone stuff.

Daniel

2 Likes

I should add: if Patterns are rather new to you, start with James Harkins’ Pattern Guide in SCDoc first. Patterns are a language in its own.

Thank you for the reply and help.

I set the number of output bus channels and am still having the same issue with hearing only 2 events, one in left channel then one in right channel. However, I notice on the node tree 5 nodes are created before the node is freed and I see these 5 other channels receive a signal on the level meter but I only hear the first 2. Also, it’s still not wrapping back to the first channel and continuing. I tried changing other instances of (0…7) to (1…8) thinking that might be a solution but it is not. Perhaps it’s a doneAction issue?

Changing the \freq argument worked to remove the delay. Also the envelope recommendation is a great fix.

I have read into patterns and it seems like a very good way to achieve what I’m after. I’ll continue looking into it.

Again, thanks!

(
SynthDef (\sine_tone) {
arg freq = 440, amp = 1, len = 1, bus = 0;
var sig, env;
env = Env.step ([ amp ], [ len ]);
env = EnvGen.kr (env, doneAction: 2);
sig = SinOsc.ar (freq, 0, env);
Out.ar (bus % 2, sig); // bus modulo 2 here to wrap to stereo
}.add;
)

maybe try wrapping the bus array to [ 0, 1 ] by using modulo: bus % 2. this should let you hear what is going on using a stereo output

by using a Pbind, each “note” is being instantiated as a separate synth with its own length, amplitude, frequency and bus. the doneAction: 2 argument in the EnvGen.kr ugen just means each synth will free itself once it is done playing the note it has been assigned.

1 Like

As you are defining outs 0 to 7 you cannot expect them to play on 0 an 1 alone (therefore capogreco’s hint to take modulo). As you have no 8 ch hardware connected it simply falls silent. However, as you discovered, you can watch the meter window to see if something’s going on, you can also do s.scope(8)

You defined several Pseq patterns with a repeats arg of 1, one alone would be enough to stop playing after 8 events.

Enjoy!

1 Like

This should work:

(
SynthDef (\sine_tone) {
  arg freq = 440, amp = 1, len = 1, bus = 0;
  var sig, env;
  env = Env.perc(len/2, len/2, amp);
  env = EnvGen.kr (env, doneAction: 2);
  sig = SinOsc.ar (freq, 0, env);
  Out.ar (bus, sig);
}.add;
)


(
var t = 2; // initial duration
var f = 220; // initial frequency
var sust = 0.8; //ratio of event duration that the note should play.

~harmonic_bus_pattern = Pbind (
  \instrument, \sine_tone,
  \dur, t * (2 ** Pseq ((0..-7), inf)),
  \len, Pkey (\dur) * sust,
  \amp, (2 ** Pseq ((0..-7), inf)),
  \freq, f * Pseq ((1..8), inf), // will give you octaves. see edit
  \bus, Pseq ((0..7), inf),
);
)
1 Like

There were a couple of issues with the code. I also replaced the envelope with a percussion envelope.

Firstly as Daniel stated all your patterns need to repeat infinitely. Secondly your frequency sequence started on 0, not 1 which meant that the first note was 0 hz (hence the delay you were experiencing).

\dur here defines the length of the event which uses your exponential thing. And I set sustain so the envelop is open for 80% of the envelope (it starts at the beginning of the event - the last 20% is silent). Obviously that can be changed fairly easily - just didn’t quite understand what you expected there.

You could also use other envelopes. Some kind of bell envelope might interesting for example. And maybe increasing sust to 1.

James Harkins tutorial is a must. Read it. Reread it. And feel free to ask questions here. Probably a better place to get SuperCollider info (and feel free to point other liines people here).

1 Like

yeah I made a bunch of mistakes with my initial answer.

the corrected code works as described however.

1 Like

I don’t think you posted a correction to the pattern did you? Apologies if I missed it.

Generally Env.step isn’t something you really want to use for audio signals. I’d probably use an ASR envelope with a fast attack and release. Can be great if you need to generate control signals though.

1 Like

I corrected it on the lines thread.

depends on what you want to do. using a step envelope can be a terser way to write out an amplitude envelope like this:

[ 0, amp, amp, 0], [ 0, dur, 0 ]

for use in glitchy minimal music like Ryoji Ikeda or Alva Noto.

1 Like

gives you harmonics. see the corrected code here

1 Like

Yes but step envelopes join the points with straight lines, whereas when you’re dealing with frequencies, or amplitudes, you want to use logarithmic/exponential curves typically. That’s all I was getting at.

Obviously the situation where you want a synth to amplitude at the max for it’s duration is a special case, and that’s certainly one way of handling cleanup. But for your general purpose musical use case I would default to envelopes with log/exp curves. Which doesn’t have to be ADSRs, or percussive ones. I’ve had good experiences with gaussian curves for certain applications. You can have a lot of fun with the envelopes in SuperCollider.

1 Like

sure. but when the segments take 0 seconds to move from value to value, as is the case with Env.step, there is no difference between logarithmic, exponential, and linear curves.

You can have a lot of fun with the envelopes in SuperCollider.

I love experimenting with envelopes. and yes, they are a very important factor in imparting a particular quality to a sound. but in this case I used a plain old Env.step because that’s what I thought the initial description called for:

In other words, what I am trying to create is a single tone raising in pitch by sequential order of its harmonics, each new harmonic is exponentially shorter in duration than the previous harmonic, and each new harmonic is sent to a different channel in an 8 channel circular array, over a defined total duration.

to me sounds more like an experimental installation similar to Ryoji Ikeda’s test pattern, which, to my ears, calls for rudimentary rectangular envelopes; rather than a general purpose musical use case, which would call for exponential decay envelopes.

1 Like

¡Thank you @cian, @dkmayer, @capogreco!

This code sounds amazing and I’ve been experimenting with variables and hearing profound things.

With the current code, the envelope durations of overtones wraps back to the initial value after a finite number of overtones and duration, then raises one overtone and repeats the envelope durations.
I am trying to figure out a function whose where the envelope continuously gets faster as the frequency raises, and only the output bus wraps to create the effect of rotation within the circularly positioned speaker array.
Ideally to the point of not perceiving it as separate events, aka event fusion (32-128 events per second)

I don’t know know if this is possible, or what it will actually sound like, but I’m very excited about the possibilities.

My initial thought was to change the variables in the Pbind from 1…7, to something like 1…1000. But the durations still wrap back to the initial value.
Then I thought, maybe the the frequency is rising to ultrasound, but then it returns to audibility at equal periodic intervals.
I can’t find the cause of this, though I still don’t know much about Patterns and Supercollider in general so perhaps there’s a process occurring that I’m not aware of that is also not explicitly defined?

Again, thank you all for the enormous help.

Maybe post the code here again so we know exactly which version of the code you are referring to.

Do you mean so the frequency keeps going up, and doesn’t come back down?

Each parameter (frequency, duration, output channel, etc.) is set individually by an argument in the Pbind. If you want to change the sequence of arguments that are being fed to that parameter, you will need to adjust the corresponding Pseq.

I highly recommend you watch this, and read this.

Yes, this is what I mean

The following code is what I’ve been working with

(
SynthDef (\sine_tone) {
arg freq = 440, amp = 1, len = 1, bus = 0;
var sig, env;
env = Env.perc(len/2, len/2, amp);
env = EnvGen.kr (env, doneAction: 2);
sig = SinOsc.ar (freq, 0, env);
Out.ar (bus % 2, sig);
}.add;
)

(
var t = 10; // initial duration
var f = 40; // initial frequency
var sust = 1; //ratio of event duration that the note should play.

~harmonic_bus_pattern = Pbind (
\instrument, \sine_tone,
\dur, t * (2 ** Pseq ((0…-1000), inf)),
\len, Pkey (\dur) * sust,
\amp, (2 ** Pseq ((0…-1000), inf)),
\freq, f * Pseq ((1…1000), inf),
\bus, Pseq ((0…1000), inf),
);
)

~harmonic_bus_pattern.play

I’ve been reading through the Harkins’ tutorials… They are invaluable.