How to Create a Randomized Melody Generator in SuperCollider?

Hey guys… :wave:

I am trying to build a simple randomized melody generator. My goal is to have a system that randomly selects notes from a given scale and plays them in a sequence with varying durations and dynamics. I’m familiar with some basics like creating synths and playing simple patterns, but I’m not quite sure how to combine these elements to achieve a fully randomized melody.

Here is the points that I faced:

  • How do I set up a pattern that selects random pitches from a specific scale?
  • What’s the best way to introduce randomness in note durations while ensuring that the rhythm stays somewhat coherent?
  • Is there an efficient way to control dynamics so that some notes are louder or softer, without making it sound too chaotic?

I also check this: https://scsynth.org/t/create-a-randomly-generated-melody-based-on-the-chord-progression-playirails But I have not found any solution. Could anyone guide me about this?

Thanks in advance!

Respected community member! :blush:

Hello, and welcome !

I propose you to test this code:

(
SynthDef(\PercSine, {
	|out = 0, amp = 0.1, freq = 440, duration = 1|
	
	var snd = SinOsc.ar(freq, mul: amp);
	snd = snd * EnvGen.kr(Env.perc(0.01, duration));
	Out.ar(0, snd!2);
	
}).add;
)

(
var notes = Scale.at(\minor).ratios * 440;

Pbind(
	\instrument, \PercSine,
	
	// Time between emissions
	\dur, Prand([0.25, 0.5, 1, 2], inf),
	
	// Note duration
	\duration, Prand([0.125, 0.25, 0.5, 1, 2, 4], inf),

	// Volume between 0.025 and 0.2
	\amp, Pwhite(0.025, 0.2, inf),
	
	// Random note from the scale
	\freq, Prand(notes, inf),
).play;
)

First, evaluate the SynthDef, then play the Pbind. It should give you a somewhat simple random melody!

The only thing I didn’t cover is the ‘coherent rythm’, but that’s not too complicated.

I think this is a good way to start. SuperCollider includes a ‘Pattern Interface’ that allows to easily build automatic melodies. Here, I’m using Prand to select random values within a given list every time a note is played, and Pwhite to get a random value within a range. This is purely random, but you have several ways to control or weight the randomness of synths parameters.

In the IDE, you can click on Browse > Tutorials > Streams-Patterns-Events to get a full tutorial about Patterns :slight_smile: . It might be a little confusing at first, but it is very rewarding when you get to see the full picture.

This might lead to other questions, do not hesitate to post them here if needed,

Simon

This here is a bit more complex, but patterns can be concatenated together, or nested, which allows for complex behaviors. This allows to control the effective randomness to get more musical results.

One way to solve the rythm coherence might be this:

(
var notes = Scale.at(\minor).ratios * 440;

var rythms = [
	[1, 1, 1, 1],
	[2, 2],
	[2, 1.5, 0.5],
	[1, 0.5, 0.5, 1, 0.5, 0.5],
] / 4;

Pbind(
	\instrument, \PercSine,
	
	// Select a random rythmic pattern every time
	// the previous one has finished
	\dur, Pn(Plazy({ Pseq(rythms[rythms.size.rand], 1) }, 1), inf),

	\duration, 0.5,
	\amp, Pwhite(0.025, 0.2, inf),
	\freq, Prand(notes, inf),
).play;
)

So you predefine ‘valid’ rythmic patterns first, which are then successively played in a random order. Here, this ensure 4 times bar is preserved. But there are infinite ways to conceptualize, and solve, this problem.

EDIT: Some different syntax might have equivalent results. This is a simpler version of the previous algo:

(
var notes = Scale.at(\minor).ratios * 440;

Pbind(
	\instrument, \PercSine,
	
	// Select a random rythmic pattern every time
	// the previous one has finished
	\dur, Prand(
		[
			Pseq([1, 1, 1, 1] / 4, 1),
			Pseq([2, 2] / 4, 1),
			Pseq([2, 1.5, 0.5] / 4, 1),
			Pseq([1, 0.5, 0.5, 1, 0.5, 0.5] / 4, 1),
		], inf,
	),
	
	\duration, 0.5,
	\amp, Pwhite(0.025, 0.2, inf),
	\freq, Prand(notes, inf),
).play;
)