Merge pull request #3898 from DaveDubUK/walk-JS-1.12

Version 1.12 of the walk.js script
This commit is contained in:
Philip Rosedale 2014-12-04 16:29:19 -08:00
commit dbf64b2de7
4 changed files with 2072 additions and 5937 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,225 +1,277 @@
// //
// walkFilters.js // walkFilters.js
// //
// version 1.001 // version 1.002
// //
// Created by David Wooldridge, Autumn 2014 // Created by David Wooldridge, Autumn 2014
// //
// Provides a variety of filters for use by the walk.js script v1.1 // Provides a variety of filters for use by the walk.js script v1.12
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
AveragingFilter = function(length) { AveragingFilter = function(length) {
//this.name = name; //this.name = name;
this.pastValues = []; this.pastValues = [];
for(var i = 0; i < length; i++) { for(var i = 0; i < length; i++) {
this.pastValues.push(0); this.pastValues.push(0);
} }
// single arg is the nextInputValue // single arg is the nextInputValue
this.process = function() { this.process = function() {
if (this.pastValues.length === 0 && arguments[0]) { if (this.pastValues.length === 0 && arguments[0]) {
return arguments[0];
} else if (arguments[0]) { return arguments[0];
// apply quick and simple LP filtering
this.pastValues.push(arguments[0]); } else if (arguments[0] !== null) {
this.pastValues.shift();
var nextOutputValue = 0; // apply quick and simple LP filtering
for (var ea in this.pastValues) nextOutputValue += this.pastValues[ea]; this.pastValues.push(arguments[0]);
return nextOutputValue / this.pastValues.length; this.pastValues.shift();
} else { var nextOutputValue = 0;
return 0; for (var ea in this.pastValues) nextOutputValue += this.pastValues[ea];
} return nextOutputValue / this.pastValues.length;
};
}; } else {
// 2nd order Butterworth LP filter - calculate coeffs here: http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html return 0;
// provides LP filtering with a more stable frequency / phase response }
ButterworthFilter = function(cutOff) { };
};
// cut off frequency = 5Hz
this.gain = 20.20612010;
this.coeffOne = -0.4775922501; // 1st order Butterworth filter - calculate coeffs here: http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
this.coeffTwo = 1.2796324250; // provides LP filtering with a more stable frequency / phase response (-3 dB @ 3 Hz)
ButterworthFilter1 = function() {
// initialise the arrays
this.xv = []; this.gain = 7.313751515;
this.yv = []; this.coeff = 0.7265425280;
for(var i = 0; i < 3; i++) {
this.xv.push(0); // initialise the arrays
this.yv.push(0); this.xv = [];
} this.yv = [];
// process values for(var i = 0; i < 2; i++) {
this.process = function(nextInputValue) {
this.xv.push(0);
this.xv[0] = this.xv[1]; this.yv.push(0);
this.xv[1] = this.xv[2]; }
this.xv[2] = nextInputValue / this.gain;
// process values
this.yv[0] = this.yv[1]; this.process = function(nextInputValue) {
this.yv[1] = this.yv[2];
this.yv[2] = (this.xv[0] + this.xv[2]) + this.xv[0] = this.xv[1];
2 * this.xv[1] + this.xv[1] = nextInputValue / this.gain;
(this.coeffOne * this.yv[0]) +
(this.coeffTwo * this.yv[1]); this.yv[0] = this.yv[1];
this.yv[1] = this.xv[0] + this.xv[1] + this.coeff * this.yv[0];
return this.yv[2];
}; return this.yv[1];
}; // end Butterworth filter contructor };
// Add harmonics to a given sine wave to form square, sawtooth or triangle waves }; // end Butterworth filter constructor
// Geometric wave synthesis fundamentals taken from: http://hyperphysics.phy-astr.gsu.edu/hbase/audio/geowv.html
WaveSynth = function(waveShape, numHarmonics, smoothing) { // 2nd order Butterworth LP filter - calculate coeffs here: http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
// provides LP filtering with a more stable frequency / phase response
this.numHarmonics = numHarmonics; ButterworthFilter2 = function(cutOff) {
this.waveShape = waveShape;
this.averagingFilter = new AveragingFilter(smoothing); switch(cutOff) {
// NB: frequency in radians case 5:
this.shapeWave = function(frequency) { default:
// make some shapes this.gain = 20.20612010;
var harmonics = 0; this.coeffOne = -0.4775922501;
var multiplier = 0; this.coeffTwo = 1.2796324250;
var iterations = this.numHarmonics * 2 + 2; break;
if (this.waveShape === TRIANGLE) { }
iterations++;
} // initialise the arrays
this.xv = [];
for(var n = 2; n < iterations; n++) { this.yv = [];
for(var i = 0; i < 3; i++) {
switch(this.waveShape) {
this.xv.push(0);
case SAWTOOTH: { this.yv.push(0);
}
multiplier = 1 / n;
harmonics += multiplier * Math.sin(n * frequency); // process values
break; this.process = function(nextInputValue) {
}
this.xv[0] = this.xv[1];
case TRIANGLE: { this.xv[1] = this.xv[2];
this.xv[2] = nextInputValue / this.gain;
if (n % 2 === 1) {
var mulitplier = 1 / (n * n); this.yv[0] = this.yv[1];
// multiply (4n-1)th harmonics by -1 this.yv[1] = this.yv[2];
if (n === 3 || n === 7 || n === 11 || n === 15) { this.yv[2] = (this.xv[0] + this.xv[2]) +
mulitplier *= -1; 2 * this.xv[1] +
} (this.coeffOne * this.yv[0]) +
harmonics += mulitplier * Math.sin(n * frequency); (this.coeffTwo * this.yv[1]);
}
break; return this.yv[2];
} };
}; // end Butterworth filter constructor
case SQUARE: {
if (n % 2 === 1) { // Add harmonics to a given sine wave to form square, sawtooth or triangle waves
multiplier = 1 / n; // Geometric wave synthesis fundamentals taken from: http://hyperphysics.phy-astr.gsu.edu/hbase/audio/geowv.html
harmonics += multiplier * Math.sin(n * frequency); WaveSynth = function(waveShape, numHarmonics, smoothing) {
}
break; this.numHarmonics = numHarmonics;
} this.waveShape = waveShape;
} this.smoothingFilter = new AveragingFilter(smoothing);
}
// NB: frequency in radians
// smooth the result and return this.calculate = function(frequency) {
return this.averagingFilter.process(harmonics);
}; // make some shapes
}; var harmonics = 0;
var multiplier = 0;
// Create a wave shape by summing pre-calcualted sinusoidal harmonics var iterations = this.numHarmonics * 2 + 2;
HarmonicsFilter = function(magnitudes, phaseAngles) { if (this.waveShape === TRIANGLE) {
iterations++;
this.magnitudes = magnitudes; }
this.phaseAngles = phaseAngles;
for(var n = 1; n < iterations; n++) {
this.calculate = function(twoPiFT) {
switch(this.waveShape) {
var harmonics = 0;
var numHarmonics = magnitudes.length; case SAWTOOTH: {
for(var n = 0; n < numHarmonics; n++) { multiplier = 1 / n;
harmonics += this.magnitudes[n] * Math.cos(n * twoPiFT - this.phaseAngles[n]); harmonics += multiplier * Math.sin(n * frequency);
} break;
return harmonics; }
};
}; case TRIANGLE: {
// the main filter object literal if (n % 2 === 1) {
filter = (function() { var mulitplier = 1 / (n * n);
// multiply (4n-1)th harmonics by -1
// Bezier private functions if (n === 3 || n === 7 || n === 11 || n === 15) {
function _B1(t) { return t * t * t }; mulitplier *= -1;
function _B2(t) { return 3 * t * t * (1 - t) }; }
function _B3(t) { return 3 * t * (1 - t) * (1 - t) }; harmonics += mulitplier * Math.sin(n * frequency);
function _B4(t) { return (1 - t) * (1 - t) * (1 - t) }; }
break;
return { }
// helper methods case SQUARE: {
degToRad: function(degrees) {
if (n % 2 === 1) {
var convertedValue = degrees * Math.PI / 180; multiplier = 1 / n;
return convertedValue; harmonics += multiplier * Math.sin(n * frequency);
}, }
break;
radToDeg: function(radians) { }
}
var convertedValue = radians * 180 / Math.PI; }
return convertedValue;
}, // smooth the result and return
return this.smoothingFilter.process(harmonics);
// these filters need instantiating, as they hold arrays of previous values };
createAveragingFilter: function(length) { };
var newAveragingFilter = new AveragingFilter(length); // Create a motion wave by summing pre-calcualted sinusoidal harmonics
return newAveragingFilter; HarmonicsFilter = function(magnitudes, phaseAngles) {
},
this.magnitudes = magnitudes;
createButterworthFilter: function(cutoff) { this.phaseAngles = phaseAngles;
var newButterworthFilter = new ButterworthFilter(cutoff); this.calculate = function(twoPiFT) {
return newButterworthFilter;
}, var harmonics = 0;
var numHarmonics = magnitudes.length;
createWaveSynth: function(waveShape, numHarmonics, smoothing) {
for(var n = 0; n < numHarmonics; n++) {
var newWaveSynth = new WaveSynth(waveShape, numHarmonics, smoothing); harmonics += this.magnitudes[n] * Math.cos(n * twoPiFT - this.phaseAngles[n]);
return newWaveSynth; }
}, return harmonics;
};
createHarmonicsFilter: function(magnitudes, phaseAngles) { };
var newHarmonicsFilter = new HarmonicsFilter(magnitudes, phaseAngles);
return newHarmonicsFilter; // the main filter object
}, filter = (function() {
// Bezier private functions
// the following filters do not need separate instances, as they hold no previous values function _B1(t) { return t * t * t };
bezier: function(percent, C1, C2, C3, C4) { function _B2(t) { return 3 * t * t * (1 - t) };
function _B3(t) { return 3 * t * (1 - t) * (1 - t) };
// Bezier functions for more natural transitions function _B4(t) { return (1 - t) * (1 - t) * (1 - t) };
// based on script by Dan Pupius (www.pupius.net) http://13thparallel.com/archive/bezier-curves/
var pos = {x: 0, y: 0}; return {
pos.x = C1.x * _B1(percent) + C2.x * _B2(percent) + C3.x * _B3(percent) + C4.x * _B4(percent);
pos.y = C1.y * _B1(percent) + C2.y * _B2(percent) + C3.y * _B3(percent) + C4.y * _B4(percent); // helper methods
return pos; degToRad: function(degrees) {
},
var convertedValue = degrees * Math.PI / 180;
// simple clipping filter (clips bottom of wave only, special case for hips y-axis skeleton offset) return convertedValue;
clipTrough: function(inputValue, peak, strength) { },
var outputValue = inputValue * strength; radToDeg: function(radians) {
if (outputValue < -peak) {
outputValue = -peak; var convertedValue = radians * 180 / Math.PI;
} return convertedValue;
return outputValue; },
}
} // these filters need instantiating, as they hold arrays of previous values
createAveragingFilter: function(length) {
var newAveragingFilter = new AveragingFilter(length);
return newAveragingFilter;
},
createButterworthFilter1: function() {
var newButterworthFilter = new ButterworthFilter1();
return newButterworthFilter;
},
createButterworthFilter2: function(cutoff) {
var newButterworthFilter = new ButterworthFilter2(cutoff);
return newButterworthFilter;
},
createWaveSynth: function(waveShape, numHarmonics, smoothing) {
var newWaveSynth = new WaveSynth(waveShape, numHarmonics, smoothing);
return newWaveSynth;
},
createHarmonicsFilter: function(magnitudes, phaseAngles) {
var newHarmonicsFilter = new HarmonicsFilter(magnitudes, phaseAngles);
return newHarmonicsFilter;
},
// the following filters do not need separate instances, as they hold no previous values
bezier: function(percent, C1, C2, C3, C4) {
// Bezier functions for more natural transitions
// based on script by Dan Pupius (www.pupius.net) http://13thparallel.com/archive/bezier-curves/
var pos = {x: 0, y: 0};
pos.x = C1.x * _B1(percent) + C2.x * _B2(percent) + C3.x * _B3(percent) + C4.x * _B4(percent);
pos.y = C1.y * _B1(percent) + C2.y * _B2(percent) + C3.y * _B3(percent) + C4.y * _B4(percent);
return pos;
},
// simple clipping filter (clips bottom of wave only)
clipTrough: function(inputValue, peak, strength) {
var outputValue = inputValue * strength;
if (outputValue < -peak) {
outputValue = -peak;
}
return outputValue;
}
}
})(); })();

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff