//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; } }