//A midi controlled triangle synthetisizer
//By: Pyry Pakkanen ( 2007 )
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
Gain output => JCRev reverb => dac; //Use a gain-pipe for the oscillators and add reverb
0.2 => output.gain; //The notes are a bit loud but having a max amplitude of 1.0 comes handy when you want to add individual effects to the oscillators.
0.05 => reverb.mix;
//MIDI related global arrays and variables:
int notes[128]; //The noteon array
0.0 => float pitch_bend;
0.0 => float modulation;
0.5 => float modulation_depth; //The depth of vibrato in semitones.
8.0 => float modulation_freq; 2.0*pi*modulation_freq => float modulation_omega;
spork~midi_input(); //Take control of the synth output and cross adc with it.
me.yield(); //It's good to yield after sporking letting the shreds to initialize. (In this case it wouldn't be really necessary.)
while(true){ //Run forever in the background and let the shreds handle everything
second => now;
}
//This one sporks new oscillators at the pitches indicated by the midi.
fun void midi_input(){
MidiIn min;
//connect to port 0
if( !min.open(0) ) { <<<"No midi","found on port 0">>>; me.exit(); }
// print out device that was opened
<<< "MIDI device:", min.num(), " -> ", min.name() >>>;
MidiMsg msg;
while(true){
// Use the MIDI Event from MidiIn
min => now;
while( min.recv(msg) ){
<<>>; //Print the message
if (msg.data1 == 144){ msg.data2 => int the_pitch;
spork~tri_osc_note( the_pitch,msg.data3/128.0 ); //Send pitch and velocity information
true => notes[the_pitch]; //Set note on
}
if (msg.data1 == 128){ false => notes[msg.data2]; /*Set note off, notes[] is a global array that controls all the playing oscillators*/}
//Pitch bend and modulation:
if (msg.data1 == 224){ (msg.data3/32.0 - 2.0) => pitch_bend; }
if (msg.data1 == 176){ modulation_depth * (msg.data3/128.0) => modulation; }
}
}
}
//Simple triangle wave
fun void tri_osc_note(int pitch, float velocity)
{
10::ms => dur update_time; //ChucK doesn't have a global control rate. We can define any control rate we want. :) Smaller value here => nicer for the ears.
0.2::second => dur falloff_time; //How long of a release do we want to do
Math.pow(0.01,update_time/falloff_time) => float k; //The exponential falloff coefficient
TriOsc tri => Gain g => output; //The oscillator
velocity => g.gain;
while (notes[pitch]){ //While the note is on.
Std.mtof(pitch + pitch_bend + modulation*Math.sin(now/second*modulation_omega) ) => tri.freq; //Apply pitch_bend and modulation
update_time => now;
}
now + falloff_time => time later;
while (now < later){ //Note off, time to release
Std.mtof(pitch + pitch_bend + modulation*Math.sin(now/second*modulation_omega) ) => tri.freq; //Apply pitch_bend and modulation
//Decrease volume exponentially
g.gain()*k => g.gain; //After all the multiplications g.gain() will be down to 0.01
update_time => now;
}
}