MM – FM DX7 Style synth.

4 operators in series over a Sine.

Not meant to be an emulation, instead is something you can have fun with and obtain quick results.

Based on Linear Phase modulation. So whatever you do will sound harmonic.

You can use cc 12,13,14,15 to play with the operator ratios.

cc1 on the keyboard adjusts the overall modulation amount.

You can achieve bell like sounds as well as more gritty things.

Have fun!

//Phase modulation (DX7) 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;
)


//Add reverb to start with. Makes everything more pleasant ;-)
((
SynthDef(\FreeVerb2x2, { |out, mix = 0.25, room = 0.15, damp = 0.5, amp = 1.0|
    var signal;

    signal = In.ar(out, 2);

    ReplaceOut.ar(out,
        FreeVerb2.ar( // FreeVerb2 - true stereo UGen
            signal[0], // Left channel
            signal[1], // Right Channel
            mix, room, damp, amp
        )
    ); // same params as FreeVerb 1 chn version

}).add;
);

z = Synth(\FreeVerb2x2, [\outbus, 0,\room,1], addAction:\addToTail);
)

//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); //My Keyboard
MIDIIn.connect(0,3); //My NanoKontrol, using cc 12,13,14,15 later on.
MIDIIn.connectAll

//Phase modulation Synth with 4 operators modulating a Sine.
(
SynthDef(\fms,{
    |gate=1, fq=440, vel=1, fm=1,bend,r1,r2,r3,r4|
	var sig, env, pm1,pm2,pm3,pm4;
	pm1=SinOsc.ar(fq*bend.midiratio*r1,0,fm);
	pm2=SinOsc.ar(fq*bend.midiratio*r2,0,fm);
	pm3=SinOsc.ar(fq*bend.midiratio*r3,0,fm);
	pm4=SinOsc.ar(fq*bend.midiratio*r4,0,fm);
	sig=SinOsc.ar(fq*bend.midiratio, pm1+pm2+pm3+pm4,0.5);
	env=EnvGen.ar(Env([0, vel, 0],[0.01,4],-4), gate, doneAction: 2);
	Out.ar(0, sig*env!2)
}).add;
)

//MIDI functions. Play the synth with a keyboard. cc1 sets the overal level of modulation. Four extra cc's (12,13,14,15) control ratios for the operators. Play with them to obtain different colors.

(
~notes = Array.newClear(128);
~liftednotes = Array.newClear(128);
~pedaldown = 0;
~cc1= 127;
~r1= 0;
~r2= 0;
~r3= 0;
~r4= 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(\fms,
		[
			\fq, nn.midicps*4,
			\gate, 1,
			\vel, vel/100,
			\fm, ~cc1.linlin(0, 127, 0, 1), //This uses the last used value from cc1
			\r1, ~r1.linlin(0, 127, 0, 32), //This uses the last used value from cc12
			\r2, ~r2.linlin(0, 127, 0, 32), //This uses the last used value from cc13
			\r3, ~r3.linlin(0, 127, 0, 32), //This uses the last used value from cc14
			\r4, ~r4.linlin(0, 127, 0, 32), //This uses the last used value from cc15
			\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(\fm, val.linlin(0, 127, 0, 1))}; //send value to all active nodes, also rescale 0,127(values) to 0,8(Hz)
},ccNum:1, chan: 0);

MIDIdef.cc(\r1, {
	arg val, chan, src;
	['Ratio 1', val].postln;
	~r1 = val; //This will store the last used cc1 value.
	~notes.do{arg synth; synth.set(\r1, val.linlin(0, 127, 0, 32))}; //send value to all active nodes, also rescale 0,127(values) to 0,8(Hz)
},ccNum:12, chan: 0);

MIDIdef.cc(\r2, {
	arg val, chan, src;
	['Ratio 2', val].postln;
	~r2 = val; //This will store the last used cc1 value.
	~notes.do{arg synth; synth.set(\r2, val.linlin(0, 127, 0, 32))}; //send value to all active nodes, also rescale 0,127(values) to 0,8(Hz)
},ccNum:13, chan: 0);

MIDIdef.cc(\r3, {
	arg val, chan, src;
	['ModWheel', val].postln;
	~r3 = val; //This will store the last used cc1 value.
	~notes.do{arg synth; synth.set(\r3, val.linlin(0, 127, 0, 32))}; //send value to all active nodes, also rescale 0,127(values) to 0,8(Hz)
},ccNum:14, chan: 0);

MIDIdef.cc(\r4, {
	arg val, chan, src;
	['ModWheel', val].postln;
	~r4 = val; //This will store the last used cc1 value.
	~notes.do{arg synth; synth.set(\r4, val.linlin(0, 127, 0, 32))}; //send value to all active nodes, also rescale 0,127(values) to 0,8(Hz)
},ccNum:15, chan: 0);

MIDIdef.bend(\bend, {
	arg val, chan, src;
	['bend', val].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); synth = nil;
			}
	};
	}
},ccNum:64);
)
Author
554 PM
  • Platform:
  • Category: Synthesizer
  • Revision: 1.0
  • License: GNU General Public License family
  • Views: 553
  • Modified: 2 years ago
Chat about this patch on Discord!
Appreciate 1

Leave a Reply