MM – Wavetable synth

This one uses several waveform samples and crossfades between them. Sort of what a vector synth does.

It also contains reverb and full MIDI implementation. CC1 controls vibrato rate.

Here are the samples I used.

AKWF FREE (waveform samples)

You can use your own samples.

Have fun!

//Wavetable vector style synth. 2020 Matias Monteagudo.

//My interface options. Change at will.

(
Server.local.options.device = "ASIO : ASIO PreSonus FireStudio";
Server.local.options.sampleRate=48000;
Server.local.options.hardwareBufferSize=128;
)

//Reverb.
((
	SynthDef(\verb, {
		|in, predelay=1, revtime=2, lpf=4500,mix=0.5,amp=1,out=0|
		var dry,wet,temp,sig;
		dry = In.ar(in, 2);
		temp = In.ar(in, 2);
		wet=0;
		temp=DelayN.ar(temp, 0.2, predelay);
		32.do {temp=AllpassN.ar(temp, 0.05, {Rand(0.001,0.05)}!2,revtime);
			temp=LPF.ar(temp,lpf);
			wet=wet+temp;
		};
		sig=XFade2.ar(dry,wet,mix*2-1,amp);
		Out.ar(out,sig);
	}).add;
);
)

//After evaluating this. You can hit "CMD+." or even restart the server and the verb will be there. (You'll need to re evaluate only if you restart SC)
(
~revBus = Bus.audio(s,2);
~createReverb={~reverbSynth=Synth(\verb, [\mix,0.23, \in, ~revBus])};
ServerTree.add(~createReverb);
)

ServerTree.removeAll;//If you wanna empty the Tree.

//The buffers. You can use any waveform you want. Or bigger samples if you wanna experiment. it will probably work fine with loops too.
(
b=Buffer.readChannel(s,"G:/SAMPLES/Waveforms/AKWF_violin/AKWF_violin_0001.wav");
c=Buffer.readChannel(s,"G:/SAMPLES/Waveforms/AKWF_violin/AKWF_violin_0002.wav");
d=Buffer.readChannel(s,"G:/SAMPLES/Waveforms/AKWF_violin/AKWF_violin_0003.wav");
e=Buffer.readChannel(s,"G:/SAMPLES/Waveforms/AKWF_violin/AKWF_violin_0005.wav");
f=Buffer.readChannel(s,"G:/SAMPLES/Waveforms/AKWF_violin/AKWF_violin_0006.wav");
g=Buffer.readChannel(s,"G:/SAMPLES/Waveforms/AKWF_violin/AKWF_violin_0007.wav");
h=Buffer.readChannel(s,"G:/SAMPLES/Waveforms/AKWF_violin/AKWF_violin_0008.wav");
i=Buffer.readChannel(s,"G:/SAMPLES/Waveforms/AKWF_violin/AKWF_violin_0009.wav");
)

//You can test your buffers here.
{Out.ar(0,[PlayBuf.ar(1,b)]!2)}.play;
{Out.ar(0,[PlayBuf.ar(1,c)]!2)}.play;
{Out.ar(0,[PlayBuf.ar(1,d)]!2)}.play;
{Out.ar(0,[PlayBuf.ar(1,e)]!2)}.play;
{Out.ar(0,[PlayBuf.ar(1,f)]!2)}.play;
{Out.ar(0,[PlayBuf.ar(1,g)]!2)}.play;
{Out.ar(0,[PlayBuf.ar(1,h)]!2)}.play;
{Out.ar(0,[PlayBuf.ar(1,i)]!2)}.play;

//Connect MIDI devices. (0,6) is my keyboard under a virtual MIDI cable. You probably need to evaluate only "MIDIIn.connectAll"
MIDIClient.init;
MIDIIn.connect(0,6);
MIDIIn.disconnect(0,6);
MIDIIn.connectAll

//The Synth. It will crossfade across all buffers (like a Vector synth)
(
SynthDef(\wts,{
    | gate=1,vel=1,fq=5,out,bend=0,vr=6,va=0.1|
    var sig1,sig2,sig3,sig4,sig5,sig6,sig7,sig8,mix,vib,env, signal;
	vib=SinOsc.ar(vr,0,EnvGen.kr(Env([0,0.1],[1],4),1)*va);
	sig1=PlayBuf.ar(1,b,fq+vib* bend.midiratio,gate,0,1);
	sig2=PlayBuf.ar(1,c,fq+vib* bend.midiratio,gate,0,1);
	sig3=PlayBuf.ar(1,d,fq+vib* bend.midiratio,gate,0,1);
	sig4=PlayBuf.ar(1,e,fq+vib* bend.midiratio,gate,0,1);
	sig5=PlayBuf.ar(1,f,fq+vib* bend.midiratio,gate,0,1);
	sig6=PlayBuf.ar(1,g,fq+vib* bend.midiratio,gate,0,1);
	sig7=PlayBuf.ar(1,h,fq+vib* bend.midiratio,gate,0,1);
	sig8=PlayBuf.ar(1,i,fq+vib* bend.midiratio,gate,0,1);
	mix=DXMix.ar(Dseq([0,1,2,3,4,5,6,7],inf),`[sig1,sig2,sig3,sig4,sig5,sig6,sig7,sig8],SinOsc.ar(Rand(0.01,1),mul:Rand(0.003, 0.01),add:Rand(0.7,0.9))); //Each note modulates in Xfade speed.
    env = EnvGen.ar(Env.asr(0.2, vel, 0.005),gate, doneAction: 2);
	Out.ar(~revBus, mix*env!2)
}).add;
)

~notes

//MIDI functions. Play the synth with a keyboard. (Or equivalent MIDI controller)

(
~notes = Array.newClear(128);
~liftednotes = Array.newClear(128);
~pedaldown = 0;
~cc1= 0;
~bend = 8192;

MIDIdef.noteOn(\noteOn, {
	arg vel, nn, chan, src;
	if(~notes[nn] != nil){ //release notes if you're trying to repeat them
		~notes[nn].set(\gate, 0); ~notes[nn] = nil
	};

	~notes[nn] = Synth.new(\wts,
		[
			\fq, nn.midicps/40,
			\gate, 1,
			\vel, vel/1000,
			\vr, ~cc1.linlin(0, 127, 0, 8),
			\va, ~cc1.lincurve(0, 127, 0, 1,-100),//This uses the last used value from cc1
			\bend, ~bend.linlin(0, 16383, -2, 2),//This uses the last used value from your pitch bend wheel.
		]
	);
});

MIDIdef.noteOff(\noteOff, {
	arg vel, nn;
	if(~pedaldown == 127) {//if pedal is down:
		~liftednotes[nn] = ~notes[nn];
	}
	{//else if pedal is up:
		~notes[nn].set(\gate,0);
		~notes[nn] = nil;
	}
} );

MIDIdef.cc(\cc1, {
	arg val, chan, src;
	['ModWheel', val].postln;
	~cc1 = val; //This will store the last used cc1 value.
	~notes.do{arg synth; synth.set(\vr, val.linlin(0, 127, 0, 8), \va, val.lincurve(0,127,0,1,-100))};
},ccNum:1, chan: 0);

MIDIdef.bend(\bend, {
	arg val, chan, src;
	['bend', val, chan, src].postln;  // [ bend, 11888, 0, 1 ]
	~bend = val;//This will store the last used bend value.
	// also update any notes currently in ~notes
	~notes.do{arg synth; synth.set(\bend, val.linlin(0, 16383, -2, 2))};
}, chan: 0);

MIDIdef.cc(\pedal,{
	arg val, key;
	['pedal',val].postln;
	if(key == 64) { //only worry about pedal control messages
	~pedaldown = val;
	if(val == 0) {
			~liftednotes.do{arg synth; synth.set(\gate, 0);
			}
	};
	};
},ccNum:64);
)
Author
554 PM
  • Platform:
  • Category: Synthesizer
  • Revision: 1.2 Tweaks and fix for out of tune min vibrato.
  • License: GNU General Public License family
  • Views: 1354
  • Modified: 2 years ago
Chat about this patch on Discord!
Appreciate 1

Leave a Reply