diff --git a/Gruntfile.js b/Gruntfile.js index 92911303..6a4d63d8 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -125,7 +125,9 @@ module.exports = function(grunt) { 'signal': 'src/signal', 'metro': 'src/metro', 'peakdetect': 'src/peakDetect', - 'gain': 'src/gain' + 'gain': 'src/gain', + 'audiovoice': 'src/audiovoice', + 'polysynth': 'src/polysynth' }, useStrict: true, wrap: { diff --git a/src/app.js b/src/app.js index 06a7da03..8171020a 100644 --- a/src/app.js +++ b/src/app.js @@ -24,6 +24,8 @@ define(function (require) { require('soundRecorder'); require('peakdetect'); require('gain'); + require('audiovoice'); + require('polysynth'); return p5SOUND; diff --git a/src/audiovoice.js b/src/audiovoice.js new file mode 100644 index 00000000..f2e68bf1 --- /dev/null +++ b/src/audiovoice.js @@ -0,0 +1,128 @@ +define(function (require) { + 'use strict'; + + var p5sound = require('master'); + require('sndcore'); + + /** + * An AudioVoice is used as a single voice for sound synthesis. + * + * @class p5.AudioVoice + * @constructor + * + * This is a class to be used in conjonction with the PolySynth + * class. Custom synthetisers should be built inheriting from + * this class. + **/ + +p5.AudioVoice = function (){ + + this.osctype = 'sine'; + this.volume= 0.33; + this.note = 60; + + this.attack = 0.25; + this.decay=0.25; + this.sustain=0.95; + this.release=0.25; + this.env = new p5.Env(this.attack,this.volume, this.decay,this.volume, this.sustain, this.volume,this.release); + + this.filter = new p5.LowPass(); + this.filter.set(22050, 5); + + this.env.connect(this.filter); + +} + + +/** + * Play the envelopp + * + * @method voicePlay + */ + +p5.AudioVoice.prototype.voicePlay = function (){ + this.env.play(this.filter); +} + +/** + * Trigger the attack + * + * @method attackPlay + */ +p5.AudioVoice.prototype.attackPlay = function (){ + this.env.triggerAttack(this.oscillator); +} + +/** + * Trigger the release + * + * @method releasePlay + */ + +p5.AudioVoice.prototype.releasePlay = function (){ + this.env.triggerRelease(this.oscillator); +} + +/** + * Set the note to be played. + * This method can be overriden when creating custom synth + * + * @method setNote + * @param {Number} Midi note to be played (from 0 to 127). + * + */ + +p5.AudioVoice.prototype.setNote = function(note){ + this.oscillator.freq(midiToFreq(note)); +} + +/** + * Set cutoms parameters to a specific synth implementation. + * This method does nothing by default unless you implement + * something for it. + * For instance if you want to build a complex synthetiser + * with one or more filters, effects etc. this is where you + * will want to set them. + * + * @method setParams + * @param + * + */ + +p5.AudioVoice.prototype.setParams = function(params){ + +} + +/** + * Set values like a traditional + * + * ADSR envelope + * . + * + * @method setADSR + * @param {Number} attackTime Time (in seconds before envelope + * reaches Attack Level + * @param {Number} [decayTime] Time (in seconds) before envelope + * reaches Decay/Sustain Level + * @param {Number} [susRatio] Ratio between attackLevel and releaseLevel, on a scale from 0 to 1, + * where 1.0 = attackLevel, 0.0 = releaseLevel. + * The susRatio determines the decayLevel and the level at which the + * sustain portion of the envelope will sustain. + * For example, if attackLevel is 0.4, releaseLevel is 0, + * and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is + * increased to 1.0 (using setRange), + * then decayLevel would increase proportionally, to become 0.5. + * @param {Number} [releaseTime] Time in seconds from now (defaults to 0) + **/ + +p5.AudioVoice.prototype.setADSR = function (a,d,s,r){ + this.attack = a; + this.decay=d; + this.sustain=s; + this.release=r; + this.env = new p5.Env(this.attack, this.decay, this.sustain, this.release); + this.env.play(this.filter); +} + +}); diff --git a/src/polysynth.js b/src/polysynth.js new file mode 100644 index 00000000..87f9acf6 --- /dev/null +++ b/src/polysynth.js @@ -0,0 +1,101 @@ +define(function (require) { + 'use strict'; + + var p5sound = require('master'); + require('sndcore'); + require('audiovoice'); + + /** + * An AudioVoice is used as a single voice for sound synthesis. + * The PolySynth class holds an array of AudioVoice, and deals + * with voices allocations, with setting notes to be played, and + * parameters to be set. + * + * @class p5.PolySynth + * @constructor + * @param {Number} [num] Number of voices used by the polyphonic + * synthetiser. + * + * @param {Number} [synthVoice] A monophonic synth voice inheriting + * the AudioVoice class. + **/ + +p5.PolySynth = function(num,synthVoice){ + this.voices = []; + this.num_voices = num; + this.poly_counter=0; + + for (var i = 0 ; i < this.num_voices ; i++){ + this.voices.push(new synthVoice()); + } +} + +/** + * Play a note. + * + * @method play + */ + +p5.PolySynth.prototype.play = function (){ + this.voices[this.poly_counter].voicePlay(); + this.poly_counter += 1; + this.poly_counter = this.poly_counter % this.num_voices; +} + + +/** + * Set values like a traditional + * + * ADSR envelope + * . + * + * @method setADSR + * @param {Number} attackTime Time (in seconds before envelope + * reaches Attack Level + * @param {Number} [decayTime] Time (in seconds) before envelope + * reaches Decay/Sustain Level + * @param {Number} [susRatio] Ratio between attackLevel and releaseLevel, on a scale from 0 to 1, + * where 1.0 = attackLevel, 0.0 = releaseLevel. + * The susRatio determines the decayLevel and the level at which the + * sustain portion of the envelope will sustain. + * For example, if attackLevel is 0.4, releaseLevel is 0, + * and susAmt is 0.5, the decayLevel would be 0.2. If attackLevel is + * increased to 1.0 (using setRange), + * then decayLevel would increase proportionally, to become 0.5. + * @param {Number} [releaseTime] Time in seconds from now (defaults to 0) + **/ + +p5.PolySynth.prototype.setADSR = function (a,d,s,r){ + this.voices[this.poly_counter].setADSR(a,d,s,r); +} + +/** + * Set the note to be played. + * This method can be overriden when creating custom synth + * + * @method setNote + * @param {Number} Midi note to be played (from 0 to 127). + * + */ + +p5.PolySynth.prototype.setNote = function (note){ + this.voices[this.poly_counter].setNote(note); +} + + +/** + * Set cutoms parameters to a specific synth implementation + * with the help of JavaScript Object Notation (JSON). + * + * @method setParams + * @param JSON object + * + * For instance to set the detune parameter of a synth, call : + * setParams({detune: 15 }); + * + */ +p5.PolySynth.prototype.setParams = function (params){ + this.voices[this.poly_counter].setParams(params); +} + +});