JSMixer class to make life easier

Hello all, i created a mixer class that is easy to use so you can concentrate on music and sound instead of on the plumming.

->--mono--<strip>--------->-----------------o
            |  |                            |
->--stereo--o  o--stereo--<send>--fx--<fx>--o--master--<master>-->-

Above, you see buses like -mono- and synths like -<strip>-.
Each “strip” has mono/stereo inputs, pan/volume control and optional sends to any “effects” that you add to the mixer. The “master strip” has volume control only. This is all easily extended in the class code.

Below is an example of how you can use it, including “automation”.

  • add() adds one or more strips, each having its own name.
  • addFx() creates and adds a named effect synth (the name must equal the name of the Synthdef for the effect).
  • vol() changes volume, pan() changes panning for a strip.
  • send() creates or alters a synth that sends stereo sound from strip to fx input bus.
  • no limits on the amount of strips or effects!
(
Synthdef(\reverb, {
 . . .
}).add;

s.waitForBoot({
	s.freeAll();
	s.sync;

	m = JSMixer();
	s.sync;
	m.add(\drum, \bass);
	~reverb = m.addFx(\reverb);
	m.vol(\bass, 0.2);
	m.pan(\bass, -0.5);

	Ppar([
		Pseq([
			Pbind(
				\midinote, Pseq([
					40,  \,  \, 43, 45,  \,  \,  \,
					40, 43, 47,  \, 45,  \, 43,  \,
				]+12, 4),
				\dur, 1/4,
				\out, m.mono(\bass)
			),
			Pbind(
				\midinote, Pseq([40]+12, 1),
				\dur, 1/4,
				\out, m.mono(\bass)
			)
		]),
		Pbind(
			\play, { m.vol(\bass, ~vol); },
			\vol, Pseries(0.1, 0.1, 8),
		),
		Pbind(
			\play, { m.send(\bass, \reverb, ~level); },
			\level, Pseries(0, 0.1, 8),
		)
	]).play;
});
)

The code for the class is below (116 lines).
You can save this in a .sc file and place that in the SuperCollider Extensions directory of your home directory. The language interpreter will find it, compile it, and hopefully like it.

// JSMixer, 2020-12-08
//
JSMixer {
	var master, masterIn, masterGroup,
	mixerGroup, stripGroup, sendGroup, fxGroup,
	strips, effects;

	*new { | out=0 | ^super.new.init(out);	}

	init { | out=0 |
		strips = ();
		effects = ();

		// create groups
		mixerGroup = Group.new();
		masterGroup = Group.new(mixerGroup);
		fxGroup = Group.new(mixerGroup);
		sendGroup = Group.new(mixerGroup);
		stripGroup = Group.new(mixerGroup);

		// create master channel
		masterIn = Bus.audio(numChannels: 2);
		master = {
			var sig;

			sig = In.ar(masterIn, 2);
			sig = sig * \amp.kr(1).varlag(\lag.kr(0.1));
			sig = LeakDC.ar(sig);
			sig = Limiter.ar(sig);
		}.play(masterGroup, out);

		SynthDef(\jsvol, {
			var sig;

			sig = In.ar(\in.kr(0), 2);
			sig = Limiter.ar(sig);
			// mute / eq goes here
			Out.ar(\out.kr(0), sig * \amp.kr(0));
		}).add;

		SynthDef(\jspan, {
			var sig;

			sig = In.ar(\in.kr(0), 1);
			sig = Pan2.ar(sig, \pan.kr(0));
			Out.ar(\out.kr(0), sig);
		}).add;

		SynthDef(\jssend, {
			var sig;

			sig = In.ar(\in.kr(0), 2);
			sig = Limiter.ar(sig);
			Out.ar(\out.kr(0), sig * \amp.kr(0));
		}).add;

		^this;
	}

	add { | ... stripNames |
		stripNames.do({ | name |
			strips.put(name, JSStrip.new(stripGroup, masterIn));
		});
	}

	addFx { | defname |
		var bus = Bus.audio(numChannels:2);
		effects.put(defname, bus);
		^Synth.new(defname, [\in, bus,\out, masterIn], fxGroup);
	}

	mono { | name | ^strips.at(name).mono; }
	stereo { | name | ^strips.at(name).stereo; }

	vol { | name, level=0 | strips.at(name).vol(level); }
	pan { | name, pan=0 | strips.at(name).pan(pan); }
	out { | level=0 | master.set(\amp, level); }
	send { | name, fxdef, level=0 |
		var bus = effects.at(fxdef);
		strips.at(name).send(bus, level, sendGroup);
	}
}

JSStrip {
	var <mono, <stereo, panner, fader, sends;

	*new { | group, out | ^super.new.init(group, out); }

	init { | group, out |
		sends = ();
		mono = Bus.audio(numChannels: 1);
		stereo = Bus.audio(numChannels: 2);
		fader = Synth(\jsvol, [\in, stereo, \out, out], group);
		panner = Synth(\jspan, [\in, mono, \out, stereo], group);
		^this;
	}

	vol { | level=0 | fader.set(\amp, level); }
	pan { | pan=0 | panner.set(\pan, pan); }
	// mute / solo / eq / ..

	send { | bus, level=0, group |
		sends.atFail(bus.index, {
			sends.put(bus.index,
				Synth(\jssend, [\in, stereo, \out, bus], group);
			);
		});
		sends.at(bus.index).set(\amp, level);
	}
}

Note: i prepended every class or synthdef name with my initials “js” so there will be no clashes with existing class- or synthdef names.

Explore and/or modify the class to what you need, be inspired.

Some plans i have with it before it is time to make some music:

  • mute and solo
  • fadein / fadeout (use lag i suppose)
  • eq (also on master channel)

Enjoy!
JS

4 Likes