diff --git a/.DS_Store b/.DS_Store index d3eb8d9..0e9fb13 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..3345269 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Chris Wilson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/index.html b/index.html index 315837f..e3ae86c 100644 --- a/index.html +++ b/index.html @@ -59,7 +59,7 @@ - + @@ -127,8 +127,8 @@ Flanger depth:
Flanger feedback: -
An octave-doubling effect, using sample-accurate delay ramping.
- +
A pitch-shifting effect, using sample-accurate delay ramping. Defaults to one octave down.
+ Pitch-shift:
A delay with a basic chorus effect.
Delay time:
diff --git a/js/effects.js b/js/effects.js index 2fdf785..3328bd7 100644 --- a/js/effects.js +++ b/js/effects.js @@ -265,8 +265,8 @@ function changeEffect(effect) { case 9: // Stereo Flange currentEffectNode = createStereoFlange(); break; - case 10: // Octave doubling - currentEffectNode = createDoubler(); + case 10: // Pitch shifting + currentEffectNode = createPitchShifter(); break; case 11: // Mod Delay currentEffectNode = createModDelay(); @@ -295,7 +295,7 @@ function changeEffect(effect) { var tempWetGain = wetGain; wetGain = pingPong.input; wetGain = createAutowah(); - currentEffectNode = createDoubler(); + currentEffectNode = createPitchShifter(); wetGain = tempWetGain; break; case 18: // Distorted Wah Chorus @@ -341,7 +341,11 @@ function createTelephonizer() { } function createDelay() { - var delayNode = audioContext.createDelay(); + var delayNode = null; + if (window.location.search.substring(1) == "webkit") + delayNode = audioContext.createDelayNode(); + else + delayNode = audioContext.createDelay(); delayNode.delayTime.value = parseFloat( document.getElementById("dtime").value ); dtime = delayNode; @@ -680,7 +684,7 @@ function createStereoFlange() { return inputNode; } -function createDoubler() { +function createPitchShifter() { effect = new Jungle( audioContext ); effect.output.connect( wetGain ); return effect.input; diff --git a/js/jungle.js b/js/jungle.js index 9daee4a..4119442 100644 --- a/js/jungle.js +++ b/js/jungle.js @@ -65,7 +65,7 @@ function createFadeBuffer(context, activeTime, fadeTime) { return buffer; } -function createDelayTimeBuffer(context, activeTime, fadeTime) { +function createDelayTimeBuffer(context, activeTime, fadeTime, shiftUp) { var length1 = activeTime * context.sampleRate; var length2 = (activeTime - 2*fadeTime) * context.sampleRate; var length = length1 + length2; @@ -76,10 +76,12 @@ function createDelayTimeBuffer(context, activeTime, fadeTime) { // 1st part of cycle for (var i = 0; i < length1; ++i) { - // This line does octave-down transpose - p[i] = i / length1; - // This line does octave-up transpose -// p[i] = (length1-i)/length; + if (shiftUp) + // This line does shift-up transpose + p[i] = (length1-i)/length; + else + // This line does shift-down transpose + p[i] = i / length1; } // 2nd part @@ -105,20 +107,42 @@ function Jungle(context) { // Delay modulation. var mod1 = context.createBufferSource(); var mod2 = context.createBufferSource(); - var delayTimeBuffer = createDelayTimeBuffer(context, bufferTime, fadeTime); - mod1.buffer = delayTimeBuffer; - mod2.buffer = delayTimeBuffer; + var mod3 = context.createBufferSource(); + var mod4 = context.createBufferSource(); + this.shiftDownBuffer = createDelayTimeBuffer(context, bufferTime, fadeTime, false); + this.shiftUpBuffer = createDelayTimeBuffer(context, bufferTime, fadeTime, true); + mod1.buffer = this.shiftDownBuffer; + mod2.buffer = this.shiftDownBuffer; + mod3.buffer = this.shiftUpBuffer; + mod4.buffer = this.shiftUpBuffer; mod1.loop = true; mod2.loop = true; - + mod3.loop = true; + mod4.loop = true; + + // for switching between oct-up and oct-down + var mod1Gain = context.createGainNode(); + var mod2Gain = context.createGainNode(); + var mod3Gain = context.createGainNode(); + mod3Gain.gain.value = 0; + var mod4Gain = context.createGainNode(); + mod4Gain.gain.value = 0; + + mod1.connect(mod1Gain); + mod2.connect(mod2Gain); + mod3.connect(mod3Gain); + mod4.connect(mod4Gain); + // Delay amount for changing pitch. var modGain1 = context.createGainNode(); var modGain2 = context.createGainNode(); var delay1 = context.createDelayNode(); var delay2 = context.createDelayNode(); - mod1.connect(modGain1); - mod2.connect(modGain2); + mod1Gain.connect(modGain1); + mod2Gain.connect(modGain2); + mod3Gain.connect(modGain1); + mod4Gain.connect(modGain2); modGain1.connect(delay1.delayTime); modGain2.connect(delay2.delayTime); @@ -152,11 +176,17 @@ function Jungle(context) { var t2 = t + bufferTime - fadeTime; mod1.start(t); mod2.start(t2); + mod3.start(t); + mod4.start(t2); fade1.start(t); fade2.start(t2); this.mod1 = mod1; this.mod2 = mod2; + this.mod1Gain = mod1Gain; + this.mod2Gain = mod2Gain; + this.mod3Gain = mod3Gain; + this.mod4Gain = mod4Gain; this.modGain1 = modGain1; this.modGain2 = modGain2; this.fade1 = fade1; @@ -173,3 +203,21 @@ Jungle.prototype.setDelay = function(delayTime) { this.modGain1.gain.setTargetValueAtTime(0.5*delayTime, 0, 0.010); this.modGain2.gain.setTargetValueAtTime(0.5*delayTime, 0, 0.010); } + +var previousPitch = -1; + +Jungle.prototype.setPitchOffset = function(mult) { + if (mult>0) { // pitch up + this.mod1Gain.gain.value = 0; + this.mod2Gain.gain.value = 0; + this.mod3Gain.gain.value = 1; + this.mod4Gain.gain.value = 1; + } else { // pitch down + this.mod1Gain.gain.value = 1; + this.mod2Gain.gain.value = 1; + this.mod3Gain.gain.value = 0; + this.mod4Gain.gain.value = 0; + } + this.setDelay(delayTime*Math.abs(mult)); + previousPitch = mult; +}