moved files. added requires support. added Panner

This commit is contained in:
Yotam Mann 2014-04-05 18:05:42 -04:00
parent 0055cc683f
commit a9a84fc07c
30 changed files with 740 additions and 1020 deletions

View file

@ -6,14 +6,20 @@
<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
<!--
<script type="text/javascript" src="../deps/require.js"></script>
-->
<script type="text/javascript" src='../Tone.js'></script>
-->
<script type="text/javascript" src="../deps/require.js"></script>
</head>
<body>
<script type="text/javascript">
require.config({
baseUrl : "../src"
});
require(["core/Tone"], function(Tone){
console.log(Tone);
});
</script>
</body>

60
examples/mergeSplit.html Normal file
View file

@ -0,0 +1,60 @@
<html>
<head>
<title>MERGE/SPLIT</title>
<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
<script type="text/javascript" src="../deps/require.js"></script>
</head>
<body>
<style type="text/css">
</style>
<div id='mono'>0</div>
<div id='left'>0</div>
<div id='right'>0</div>
<script type="text/javascript">
require.config({
baseUrl : "../src"
});
require(["core/Tone", "signal/Signal", 'signal/Merge', "signal/Split", "component/Meter"],
function(Tone){
//two signals into one (stereo) channel
var left = new Tone.Signal(-100);
var right = new Tone.Signal(75);
var mergeMeter = new Tone.Meter();
var merge = new Tone.Merge();
//connect it up
left.connect(merge.left);
right.connect(merge.right);
merge.connect(mergeMeter);
//one (stereo) signal split into two channels
var split = new Tone.Split();
merge.connect(split);
var rightMeter = new Tone.Meter();
var leftmeter = new Tone.Meter();
split.right.connect(rightMeter);
split.left.connect(leftmeter);
var $mono = $("#mono");
var $left = $("#left");
var $right = $("#right");
setInterval(function(){
$mono.html("merged: " + mergeMeter.getValue(0).toFixed(3));
$left.html("left: " + rightMeter.getValue(0).toFixed(3));
$right.html("right: " + leftmeter.getValue(0).toFixed(3));
}, 100);
});
</script>
</body>
</html>

View file

@ -1,21 +1,9 @@
<html>
<head>
<title>SIGNAL PROCESSING</title>
<link rel="stylesheet" type="text/css" href="../style/GUI.css">
<title>PANNER</title>
<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
<script type="text/javascript" src="../src/core/Tone.js"></script>
<script type="text/javascript" src="../src/signal/Signal.js"></script>
<script type="text/javascript" src="../src/signal/Scale.js"></script>
<script type="text/javascript" src="../src/signal/Invert.js"></script>
<script type="text/javascript" src="../src/signal/Mono.js"></script>
<script type="text/javascript" src="../src/signal/Stereo.js"></script>
<script type="text/javascript" src="../src/component/DryWet.js"></script>
<script type="text/javascript" src="../src/component/Panner.js"></script>
<script type="text/javascript" src="../src/component/Meter.js"></script>
<script type="text/javascript" src="../src/component/LFO.js"></script>
<script type="text/javascript" src="../deps/require.js"></script>
</head>
<body>
<style type="text/css">
@ -25,40 +13,47 @@
<div id='left'>0</div>
<div id='right'>0</div>
<script type="text/javascript">
require.config({
baseUrl : "../src"
});
require(["core/Tone", "core/Master", "component/Panner", "component/Meter"],
function(Tone){
//panner
var pan = new Tone.Panner();
//panner
var pan = new Tone.Panner();
//input signals
var sine = Tone.context.createOscillator();
sine.start(0);
//input signals
var sine = Tone.context.createOscillator();
sine.start(0);
// var sine = new Tone.Signal(100);
//connect it up
sine.connect(pan);
//connect it up
sine.connect(pan);
pan.toMaster();
pan.toMaster();
//meters
var output = new Tone.Meter(2);
//meters
var output = new Tone.Meter(2);
//meter the outputs
pan.connect(output);
//meter the outputs
pan.connect(output);
var $left = $("#left");
var $right = $("#right");
var $left = $("#left");
var $right = $("#right");
setInterval(function(){
$left.html("left: " + output.getDb(0).toFixed(2) + " db");
$right.html("right: " + output.getDb(1).toFixed(2) + " db");
}, 100);
setInterval(function(){
$left.html("left: " + output.getDb(0).toFixed(2) + " db");
$right.html("right: " + output.getDb(1).toFixed(2) + " db");
}, 100);
var range = $("input")[0];
range.onchange = function(){
var val = range.value;
var now = pan.now();
pan.setPan(val/50 - 1);
}
var range = $("input")[0];
range.onchange = function(){
var val = range.value;
var now = pan.now();
pan.setPan(val/50 - 1, now+.1);
}
});
</script>
</body>

View file

@ -2,17 +2,8 @@
<head>
<title>SIGNAL PROCESSING</title>
<link rel="stylesheet" type="text/css" href="../style/GUI.css">
<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
<script type="text/javascript" src="../src/core/Tone.js"></script>
<script type="text/javascript" src="../src/signal/Signal.js"></script>
<script type="text/javascript" src="../src/signal/Add.js"></script>
<script type="text/javascript" src="../src/signal/Invert.js"></script>
<script type="text/javascript" src="../src/signal/Normalize.js"></script>
<script type="text/javascript" src="../src/signal/Scale.js"></script>
<script type="text/javascript" src="../src/component/Meter.js"></script>
<script type="text/javascript" src="../deps/require.js"></script>
</head>
<body>
<style type="text/css">
@ -20,66 +11,66 @@
</style>
<input type='range' value='50'>
<div id='signal'>0</div>
<div id='invert'>0</div>
<div id='add'>0</div>
<div id='normalize'>0</div>
<div id='sub'>0</div>
<div id='scale'>0</div>
<script type="text/javascript">
var signal = new Tone.Signal();
var dryMeter = new Tone.Meter();
signal.connect(dryMeter);
//the inverter
var inverter = new Tone.Invert();
var invertMeter = new Tone.Meter();
inverter.connect(invertMeter);
signal.connect(inverter);
//the adder
var adder = new Tone.Add(100);
var addMeter = new Tone.Meter();
adder.connect(addMeter);
inverter.connect(adder);
//normalize back to -1 to 1
var norm = new Tone.Normalize(99, 101);
var normMeter = new Tone.Meter();
norm.connect(normMeter);
adder.connect(norm);
//the scaler
var scaler = new Tone.Scale(5, 10);
var scaleMeter = new Tone.Meter();
scaler.connect(scaleMeter);
norm.connect(scaler);
require.config({
baseUrl : "../src"
});
var $signal = $("#signal");
var $invert = $("#invert");
var $add = $("#add");
var $norm = $("#normalize");
var $scale = $("#scale");
setInterval(function(){
$signal.html("signal: " + dryMeter.getValue().toFixed(3));
$invert.html("inverted: " + invertMeter.getValue().toFixed(3));
$add.html("add 100: " + addMeter.getValue().toFixed(3));
$norm.html("normalized : "+normMeter.getValue().toFixed(3));
$scale.html("scaled 5 to 10: " + scaleMeter.getValue().toFixed(3));
/*$signal.html("signal: " + dryMeter.getValue());
$invert.html("incoming: " + );
$add.html("add 10: " + addMeter.getValue());*/
}, 100);
var range = $("input")[0];
range.onchange = function(){
var val = range.value;
var now = signal.now();
signal.linearRampToValueAtTime(val / 50 - 1, now + .1);
}
require(["core/Tone", "core/Master", "signal/Signal", "signal/Add", "signal/Scale", "component/Meter",
"signal/Subtract"],
function(Tone){
var signal = new Tone.Signal();
var dryMeter = new Tone.Meter();
signal.connect(dryMeter);
// signal.toMaster();
//the adder
var adder = new Tone.Add(100);
var addMeter = new Tone.Meter();
adder.connect(addMeter);
signal.connect(adder);
//the adder
var subtract = new Tone.Subtract(100);
var subMeter = new Tone.Meter();
subtract.connect(subMeter);
signal.connect(subtract);
//the scaler
var scaler = new Tone.Scale(5, 10);
var scaleMeter = new Tone.Meter();
scaler.connect(scaleMeter);
signal.connect(scaler);
var $signal = $("#signal");
var $add = $("#add");
var $scale = $("#scale");
var $sub = $("#sub");
setInterval(function(){
$signal.html("signal: " + dryMeter.getValue().toFixed(3));
$add.html("signal + 100: " + addMeter.getValue().toFixed(3));
$scale.html("scaled 5 to 10: " + scaleMeter.getValue().toFixed(3));
$sub.html("100 - signal: " + subMeter.getValue().toFixed(3));
}, 100);
var range = $("input")[0];
range.onchange = function(){
var val = range.value;
var now = signal.now();
signal.linearRampToValueAtTime(val / 50 - 1, now + .1);
}
window.Tone = Tone;
});
</script>
</body>

View file

@ -8,61 +8,64 @@
// 1 = 100% wet
///////////////////////////////////////////////////////////////////////////////
Tone.DryWet = function(initialDry){
Tone.call(this);
define(["core/Tone", "signal/Signal", "signal/Invert", "signal/Scale"], function(Tone){
//components
this.dry = this.context.createGain();
this.wet = this.context.createGain();
this.output = this.context.createGain();
this.equalGain = this.context.createWaveShaper();
//control signal
this.control = new Tone.Signal();
this.invert = new Tone.Invert();
this.dryScale = new Tone.Scale(0, 1);
this.wetScale = new Tone.Scale(0, 1);
Tone.DryWet = function(initialDry){
Tone.call(this);
//alias
this.input = this.dry;
//components
this.dry = this.context.createGain();
this.wet = this.context.createGain();
this.output = this.context.createGain();
this.equalGain = this.context.createWaveShaper();
//control signal
this.control = new Tone.Signal();
this.invert = new Tone.Invert();
this.dryScale = new Tone.Scale(0, 1);
this.wetScale = new Tone.Scale(0, 1);
//connections
this.dry.connect(this.output);
this.wet.connect(this.output);
//control signal connections
this.control.connect(this.equalGain);
//wet chain
this.chain(this.equalGain, this.wetScale, this.wet.gain);
//dry chain
this.chain(this.equalGain, this.invert, this.dryScale, this.dry.gain);
//setup
this._equalPowerGainCurve();
this.dry.gain.value = 0;
this.wet.gain.value = 0;
this.setDry(0);
}
//connections
this.dry.connect(this.output);
this.wet.connect(this.output);
//control signal connections
this.control.connect(this.equalGain);
//wet chain
this.chain(this.equalGain, this.wetScale, this.wet.gain);
//dry chain
this.chain(this.equalGain, this.invert, this.dryScale, this.dry.gain);
Tone.extend(Tone.DryWet);
Tone.DryWet.prototype.setDry = function(val, rampTime){
rampTime = this.defaultArg(rampTime, 0);
this.control.linearRampToValueAtTime(val, rampTime);
}
Tone.DryWet.prototype.setWet = function(val, rampTime){
this.setDry(-val, rampTime);
}
//generates the values for the waveshaper
Tone.DryWet.prototype._equalPowerGainCurve = function(){
var len = this.bufferSize;
var curve = new Float32Array(len);
for (var i = 0; i < len; i++){
//values between -1 to 1
var baseline = (i / (len - 1)) * 2 - 1;
// scale it by amount
curve[i] = this.equalPowerGain(baseline);
// curve[i] = baseline;
//setup
this._equalPowerGainCurve();
this.dry.gain.value = 0;
this.wet.gain.value = 0;
this.setDry(0);
}
this.equalGain.curve = curve;
}
Tone.extend(Tone.DryWet);
Tone.DryWet.prototype.setDry = function(val, rampTime){
rampTime = this.defaultArg(rampTime, 0);
this.control.linearRampToValueAtTime(val, rampTime);
}
Tone.DryWet.prototype.setWet = function(val, rampTime){
this.setDry(-val, rampTime);
}
//generates the values for the waveshaper
Tone.DryWet.prototype._equalPowerGainCurve = function(){
var len = this.bufferSize;
var curve = new Float32Array(len);
for (var i = 0; i < len; i++){
//values between -1 to 1
var baseline = (i / (len - 1)) * 2 - 1;
// scale it by amount
curve[i] = this.equalPowerGain(baseline);
// curve[i] = baseline;
}
this.equalGain.curve = curve;
}
return Tone.DryWet;
});

View file

@ -8,85 +8,91 @@
// The MIT License (MIT) Copyright (c) 2014 Chris Wilson
///////////////////////////////////////////////////////////////////////////////
//@param {number=} channels
Tone.Meter = function(channels){
//extends Unit
Tone.call(this);
define(["core/Tone", "core/Master"], function(Tone){
this.channels = this.defaultArg(channels, 1);
this.volume = new Array(this.channels);
this.values = new Array(this.channels);
//zero out the volume array
for (var i = 0; i < this.channels; i++){
this.volume[i] = 0;
this.values[i] = 0;
}
this.clipTime = 0;
//@param {number=} channels
Tone.Meter = function(channels){
//extends Unit
Tone.call(this);
//components
this.jsNode = this.context.createScriptProcessor(this.bufferSize, this.channels, this.channels);
this.jsNode.onaudioprocess = this.onprocess.bind(this);
//signal just passes
this.input.connect(this.output);
this.input.connect(this.jsNode);
this.toMaster(this.jsNode);
}
Tone.extend(Tone.Meter, Tone);
//@param {number=} channel
//@returns {number}
Tone.Meter.prototype.getLevel = function(channel){
channel = this.defaultArg(channel, 0);
var vol = this.volume[channel];
if (vol < .00001){
return 0;
} else {
return vol;
}
}
//@param {number=} channel
//@returns {number}
Tone.Meter.prototype.getValue = function(channel){
channel = this.defaultArg(channel, 0);
return this.values[channel];
}
//@param {number=} channel
//@returns {number} the channel volume in decibels
Tone.Meter.prototype.getDb = function(channel){
return this.gainToDb(this.getLevel(channel));
}
// @returns {boolean} if the audio has clipped in the last 500ms
Tone.Meter.prototype.isClipped = function(){
return Date.now() - this.clipTime < 500;
}
//get the max value
Tone.Meter.prototype.onprocess = function(event){
var bufferSize = this.jsNode.bufferSize;
for (var channel = 0; channel < this.channels; channel++){
var input = event.inputBuffer.getChannelData(channel);
var sum = 0;
var total = 0;
var x;
var clipped = false;
for (var i = 0; i < bufferSize; i++){
x = input[i];
if (!clipped && x > .95){
clipped = true;
this.clipTime = Date.now();
}
total += x;
sum += x * x;
this.channels = this.defaultArg(channels, 1);
this.volume = new Array(this.channels);
this.values = new Array(this.channels);
//zero out the volume array
for (var i = 0; i < this.channels; i++){
this.volume[i] = 0;
this.values[i] = 0;
}
var average = total / bufferSize;
var rms = Math.sqrt(sum / bufferSize);
this.volume[channel] = Math.max(rms, this.volume[channel] * .8);
this.values[channel] = average;
this.clipTime = 0;
//components
this.jsNode = this.context.createScriptProcessor(this.bufferSize, this.channels, this.channels);
this.jsNode.onaudioprocess = this.onprocess.bind(this);
//signal just passes
this.input.connect(this.output);
this.input.connect(this.jsNode);
//so it doesn't get garbage collected
this.jsNode.toMaster();
}
}
Tone.extend(Tone.Meter, Tone);
//@param {number=} channel
//@returns {number}
Tone.Meter.prototype.getLevel = function(channel){
channel = this.defaultArg(channel, 0);
var vol = this.volume[channel];
if (vol < .00001){
return 0;
} else {
return vol;
}
}
//@param {number=} channel
//@returns {number}
Tone.Meter.prototype.getValue = function(channel){
channel = this.defaultArg(channel, 0);
return this.values[channel];
}
//@param {number=} channel
//@returns {number} the channel volume in decibels
Tone.Meter.prototype.getDb = function(channel){
return this.gainToDb(this.getLevel(channel));
}
// @returns {boolean} if the audio has clipped in the last 500ms
Tone.Meter.prototype.isClipped = function(){
return Date.now() - this.clipTime < 500;
}
//get the max value
Tone.Meter.prototype.onprocess = function(event){
var bufferSize = this.jsNode.bufferSize;
for (var channel = 0; channel < this.channels; channel++){
var input = event.inputBuffer.getChannelData(channel);
var sum = 0;
var total = 0;
var x;
var clipped = false;
for (var i = 0; i < bufferSize; i++){
x = input[i];
if (!clipped && x > .95){
clipped = true;
this.clipTime = Date.now();
}
total += x;
sum += x * x;
}
var average = total / bufferSize;
var rms = Math.sqrt(sum / bufferSize);
this.volume[channel] = Math.max(rms, this.volume[channel] * .8);
this.values[channel] = average;
}
}
return Tone.Meter;
});

View file

@ -7,53 +7,44 @@
// 1 = 100% Right
///////////////////////////////////////////////////////////////////////////////
Tone.Panner = function(){
Tone.call(this);
define(["core/Tone", "signal/Merge", "signal/Signal", "signal/Scale", "signal/Subtract"],
function(Tone){
//components
this.mono = new Tone.Mono();
this.split = new Tone.Stereo();
this.control = new Tone.Signal();
this.invert = new Tone.Invert();
this.leftScale = new Tone.Scale(0, 1);
this.rightScale = new Tone.Scale(0, 1);
this.equalGain = this.context.createWaveShaper();
this.merger = this.context.createChannelMerger(2);
Tone.Panner = function(){
Tone.call(this);
//connections
this.chain(this.input, this.mono, this.split);
this.split.right.connect(this.merger, 0, 0);
this.split.left.connect(this.merger, 0, 1);
this.merger.connect(this.output);
//control connections
this.control.connect(this.equalGain);
this.chain(this.equalGain, this.leftScale, this.split.left.gain);
this.chain(this.equalGain, this.invert, this.rightScale, this.split.right.gain);
//components
//incoming signal is sent to left and right
this.left = this.context.createGain();
this.right = this.context.createGain();
this.control = new Tone.Signal();
this.merge = new Tone.Merge();
this.invert = new Tone.Scale(1, -1);
this.equalPowerL = new Tone.Scale(0, 1, "equalPower");
this.equalPowerR = new Tone.Scale(0, 1, "equalPower");
//setup
this.split.left.gain.value = 0;
this.split.right.gain.value = 0;
this.setPan(0);
this._equalPowerGainCurve();
}
//connections
this.chain(this.input, this.left, this.merge.left);
this.chain(this.input, this.right, this.merge.right);
this.merge.connect(this.output);
//left channel control
this.chain(this.control, this.invert, this.equalPowerL, this.left.gain);
//right channel control
this.chain(this.control, this.equalPowerR, this.right.gain);
Tone.extend(Tone.Panner);
Tone.Panner.prototype.setPan = function(val, rampTime){
rampTime = this.defaultArg(rampTime, 0);
this.control.linearRampToValueAtTime(val, rampTime);
}
//generates the values for the waveshaper
Tone.Panner.prototype._equalPowerGainCurve = function(){
var len = this.bufferSize;
var curve = new Float32Array(len);
for (var i = 0; i < len; i++){
//values between -1 to 1
var baseline = (i / (len - 1)) * 2 - 1;
// scale it by amount
curve[i] = this.equalPowerGain(baseline);
// curve[i] = baseline;
//setup
this.left.gain.value = 0;
this.right.gain.value = 0;
this.setPan(0);
}
this.equalGain.curve = curve;
}
Tone.extend(Tone.Panner);
Tone.Panner.prototype.setPan = function(val, rampTime){
rampTime = this.defaultArg(rampTime, 0);
this.control.linearRampToValueAtTime(val, rampTime);
}
return Tone.Panner;
});;

View file

@ -1,43 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// STEREO Split
//
// splits left/right, gives leftSend/Return and rightSend/Return
///////////////////////////////////////////////////////////////////////////////
Tone.StereoSplit = function(){
//extends Unit
Tone.call(this);
//components
this.splitter = Tone.context.createChannelSplitter();
this.mono = this.context.createGain();
this.merger = this.context.createChannelMerger(2);
this.leftSend = this.context.createGain();
this.leftReturn = this.context.createGain();
this.rightSend = this.context.createGain();
this.rightReturn = this.context.createGain();
//connections
//mono input
this.input.connect(this.splitter);
this.splitter.connect(this.mono, 0, 0);
this.splitter.connect(this.mono, 1, 0);
this.mono.connect(this.leftSend);
this.mono.connect(this.rightSend);
this.leftReturn.connect(this.merger, 0, 0);
this.rightReturn.connect(this.merger, 0, 1);
this.merger.connect(this.output);
}
Tone.extend(Tone.StereoSplit, Tone);
Tone.StereoSplit.prototype.connectLeft = function(unit){
this.chain(this.leftSend, unit, this.leftReturn);
}
Tone.StereoSplit.prototype.connectRight = function(unit){
this.chain(this.rightSend, unit, this.rightReturn);
}

42
src/core/Master.js Normal file
View file

@ -0,0 +1,42 @@
///////////////////////////////////////////////////////////////////////////////
//
// MASTER OUTPUT
//
// a single master output
// adds a toMaster method on AudioNodes and components
///////////////////////////////////////////////////////////////////////////////
define(["core/Tone"], function(Tone){
var Master = function(){
//extend audio unit
Tone.call(this);
//put a hard limiter on the output so we don't blow any eardrums
this.limiter = this.context.createDynamicsCompressor();
this.limiter.threshold.value = 0;
this.limiter.ratio.value = 20;
this.chain(this.input, this.limiter, this.output, this.context.destination);
}
Tone.extend(Master);
//a single master output
Tone.Master = new Master();
///////////////////////////////////////////////////////////////////////////
// Add toMaster methods
///////////////////////////////////////////////////////////////////////////
//@param {AudioNode|Tone=} unit
Tone.prototype.toMaster = function(){
this.connect(Tone.Master);
}
AudioNode.prototype.toMaster = function(){
this.connect(Tone.Master);
}
return Tone.Master;
})

View file

@ -6,20 +6,28 @@
// MIT License (MIT)
///////////////////////////////////////////////////////////////////////////////
(function (global, undefined) {
define(function () {
//////////////////////////////////////////////////////////////////////////
// HELPERS
///////////////////////////////////////////////////////////////////////////
function isUndef(val){
return typeof val === "undefined";
}
//////////////////////////////////////////////////////////////////////////
// WEB AUDIO CONTEXT
///////////////////////////////////////////////////////////////////////////
//ALIAS
if (!global.AudioContext){
global.AudioContext = global.webkitAudioContext;
if (!window.AudioContext){
window.AudioContext = window.webkitAudioContext;
}
var audioContext;
if (global.AudioContext){
audioContext = new global.AudioContext();
if (window.AudioContext){
audioContext = new window.AudioContext();
}
//SHIMS////////////////////////////////////////////////////////////////////
@ -69,6 +77,7 @@
Tone.prototype.context = audioContext;
Tone.prototype.fadeTime = .005; //5ms
Tone.prototype.bufferSize = 2048; //default buffer size
Tone.prototype.waveShaperResolution = 1024; //default buffer size
///////////////////////////////////////////////////////////////////////////
// CLASS METHODS
@ -149,16 +158,28 @@
//@param {*} fallback
//@returns {*}
Tone.prototype.defaultArg = function(given, fallback){
return typeof(given) !== 'undefined' ? given : fallback;
return isUndef(given) ? fallback : given;
}
//@param {number} percent (0-1)
//@returns {number} the equal power gain
//@returns {number} the equal power gain (0-1)
//good for cross fades
Tone.prototype.equalPowerGain = function(percent){
Tone.prototype.equalPowerScale = function(percent){
return Math.sin((percent) * 0.5*Math.PI);
}
//@param {number} gain
//@returns {number} gain (decibel scale but betwee 0-1)
Tone.prototype.logScale = function(gain) {
return Math.max(this.normalize(this.gainToDb(gain), -100, 0), 0);
}
//@param {number} gain
//@returns {number} gain (decibel scale but betwee 0-1)
Tone.prototype.expScale = function(gain) {
return this.dbToGain(this.interpolate(gain, -100, 0));
}
//@param {number} db
//@returns {number} gain
Tone.prototype.dbToGain = function(db) {
@ -171,18 +192,6 @@
return 20 * (Math.log(gain) / Math.LN10);
}
//@param {number} gain
//@returns {number} gain (decibel scale but betwee 0-1)
Tone.prototype.gainToLogScale = function(gain) {
return Math.max(this.normalize(this.gainToDb(gain), -100, 0), 0);
}
//@param {number} gain
//@returns {number} gain (decibel scale but betwee 0-1)
Tone.prototype.gainToPowScale = function(gain) {
return this.dbToGain(this.interpolate(gain, -100, 0));
}
//@param {number} input 0-1
Tone.prototype.interpolate = function(input, outputMin, outputMax){
return input*(outputMax - outputMin) + outputMin;
@ -208,16 +217,6 @@
return samples / audioContext.sampleRate;
}
///////////////////////////////////////////////////////////////////////////
// CHANNEL ROUTING
///////////////////////////////////////////////////////////////////////////
//@param {AudioNode|Tone=} unit
Tone.prototype.toMaster = function(node){
node = this.defaultArg(node, this.output);
node.connect(Tone.Master);
}
///////////////////////////////////////////////////////////////////////////
// MUSICAL TIMING
//
@ -294,7 +293,7 @@
//based on closure library 'inherit' function
Tone.extend = function(child, parent){
if (parent === undefined){
if (isUndef(parent)){
parent = Tone;
}
/** @constructor */
@ -307,24 +306,5 @@
Tone.context = audioContext;
///////////////////////////////////////////////////////////////////////////
// MASTER OUTPUT
///////////////////////////////////////////////////////////////////////////
var Master = function(){
//extend audio unit
Tone.call(this);
//put a hard limiter on the output so we don't blow any eardrums
this.limiter = this.context.createDynamicsCompressor();
this.limiter.threshold.value = 0;
this.limiter.ratio.value = 20;
this.chain(this.input, this.limiter, this.output, this.context.destination);
}
Tone.extend(Master, Tone);
Tone.Master = new Master();
//make it global
global.Tone = Tone;
})(this);
return Tone;
});

View file

@ -22,7 +22,7 @@ Tone.AutoPanner = function(rate, amount){
this.osc.connect(this.panner.control);
}
//extend StereoSplit
//extend Effect
Tone.extend(Tone.AutoPanner, Tone.Effect);
Tone.AutoPanner.prototype.start = function(time){

View file

@ -5,33 +5,38 @@
// adds a constant value to the incoming signal in normal range (-1 to 1)
///////////////////////////////////////////////////////////////////////////////
Tone.Add = function(constant){
Tone.call(this);
define(["core/Tone"], function(Tone){
this.constant = constant;
Tone.Add = function(constant){
Tone.call(this);
//component
this.adder = this.context.createWaveShaper();
this.constant = constant;
//connections
this.chain(this.input, this.adder, this.output);
//component
this.adder = this.context.createWaveShaper();
//setup
this._adderCurve();
}
//connections
this.chain(this.input, this.adder, this.output);
Tone.extend(Tone.Add);
//adds a constant value to the incoming signal
Tone.Add.prototype._adderCurve = function(){
var len = this.bufferSize;
var curve = new Float32Array(len);
for (var i = 0; i < len; i++){
///scale the values between -1 to 1
var baseline = (i / (len - 1)) * 2 - 1;
//all inputs produce the output value
curve[i] = baseline + this.constant;
//setup
this._adderCurve();
}
//console.log(curve);
this.adder.curve = curve;
}
Tone.extend(Tone.Add);
//adds a constant value to the incoming signal
Tone.Add.prototype._adderCurve = function(){
var len = this.waveShaperResolution;
var curve = new Float32Array(len);
for (var i = 0; i < len; i++){
///scale the values between -1 to 1
var baseline = (i / (len - 1)) * 2 - 1;
//all inputs produce the output value
curve[i] = baseline + this.constant;
}
//console.log(curve);
this.adder.curve = curve;
}
return Tone.Add;
});

View file

@ -1,27 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// EQUAL POWER GAIN
//
// takes an input and between -1 and 1
// outputs values between -1 and 1 equal power gain
///////////////////////////////////////////////////////////////////////////////
Tone.EqualPowerGain = function(){
Tone.call(this);
}
Tone.extend(Tone.EqualPowerGain);
//generates the values for the waveshaper
Tone.EqualPowerGain.prototype._equalPowerGainCurve = function(){
var len = this.bufferSize;
var curve = new Float32Array(len);
for (var i = 0; i < len; i++){
//values between -1 to 1
var baseline = (i / (len - 1)) * 2 - 1;
// scale it by amount
curve[i] = this.equalPowerGain(baseline);
// curve[i] = baseline;
}
this.equalGain.curve = curve;
}

View file

@ -1,37 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// INVERT
//
// accepts normal range signal (-1 to 1) and inverts the output
//
///////////////////////////////////////////////////////////////////////////////
Tone.Invert = function(){
Tone.call(this);
//components
this.inverter = Tone.context.createWaveShaper();
//connections
this.chain(this.input, this.inverter, this.output);
//setup
this._inverterCurve();
}
//extend StereoSplit
Tone.extend(Tone.Invert);
//generates the values for the waveshaper
Tone.Invert.prototype._inverterCurve = function(){
var len = this.bufferSize;
var curve = new Float32Array(len);
for (var i = 0; i < len; i++){
//values between -1 to 1
var baseline = (i / (len - 1)) * 2 - 1;
//scale it by amount
curve[i] = -baseline;
}
this.inverter.curve = curve;
}

27
src/signal/Merge.js Normal file
View file

@ -0,0 +1,27 @@
///////////////////////////////////////////////////////////////////////////////
//
// MONO
//
// Merge a left and a right into a single left/right channel
///////////////////////////////////////////////////////////////////////////////
define(["core/Tone"], function(Tone){
Tone.Merge = function(){
Tone.call(this);
//components
this.left = this.context.createGain();
this.right = this.context.createGain();
this.merger = this.context.createChannelMerger(2);
//connections
this.left.connect(this.merger, 0, 0);
this.right.connect(this.merger, 0, 1);
this.merger.connect(this.output);
}
Tone.extend(Tone.Merge);
return Tone.Merge;
})

View file

@ -1,20 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// MONO
//
// Sum a stereo channel into a mono channel
///////////////////////////////////////////////////////////////////////////////
Tone.Mono = function(){
Tone.call(this);
//components
this.merger = this.context.createChannelMerger(2);
//connections
this.input.connect(this.merger, 0, 0);
this.input.connect(this.merger, 0, 1);
this.merger.connect(this.output);
}
Tone.extend(Tone.Mono, Tone);

View file

@ -4,35 +4,41 @@
//
// normalizes the incoming signal (between inputMin and inputMax)
// to normal range (-1 to 1)
// should deprecate!
///////////////////////////////////////////////////////////////////////////////
Tone.Normalize = function(inputMin, inputMax){
Tone.call(this);
define(["core/Tone"], function(Tone){
//vars
this.inputMin = this.defaultArg(inputMin, -1);
this.inputMax = this.defaultArg(inputMax, 1);
Tone.Normalize = function(inputMin, inputMax){
Tone.call(this);
//components
this.normalize = this.context.createScriptProcessor(this.bufferSize, 1, 1);
//vars
this.inputMin = this.defaultArg(inputMin, -1);
this.inputMax = this.defaultArg(inputMax, 1);
//connections
this.chain(this.input, this.normalize, this.output);
//components
this.normalize = this.context.createScriptProcessor(this.bufferSize, 1, 1);
//setup
this.normalize.onaudioprocess = this._process.bind(this);
}
//connections
this.chain(this.input, this.normalize, this.output);
Tone.extend(Tone.Normalize);
Tone.Normalize.prototype._process = function(e) {
var bufferSize = this.normalize.bufferSize;
var input = e.inputBuffer.getChannelData(0);
var output = e.outputBuffer.getChannelData(0);
var min = this.inputMin;
var max = this.inputMax;
var divisor = (max - min) / 2;
for (var i = 0; i < bufferSize; i++) {
output[i] = (input[i] - min) / divisor - 1;
//setup
this.normalize.onaudioprocess = this._process.bind(this);
}
}
Tone.extend(Tone.Normalize);
Tone.Normalize.prototype._process = function(e) {
var bufferSize = this.normalize.bufferSize;
var input = e.inputBuffer.getChannelData(0);
var output = e.outputBuffer.getChannelData(0);
var min = this.inputMin;
var max = this.inputMax;
var divisor = (max - min) / 2;
for (var i = 0; i < bufferSize; i++) {
output[i] = (input[i] - min) / divisor - 1;
}
}
return Tone.Normalize;
})

View file

@ -1,61 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// OSCILLATOR
//
// just an oscillator,
// but starting and stopping is easier than the native version
///////////////////////////////////////////////////////////////////////////////
Tone.Oscillator = function(freq, type){
Tone.call(this);
this.playing = false;
//components
this.oscillator = this.context.createOscillator();
this.oscillator.frequency.value = this.defaultArg(freq, 440);
this.oscillator.type = this.defaultArg(type, "sine");
console.log(freq);
//connections
this.chain(this.oscillator, this.output);
}
Tone.extend(Tone.Oscillator);
//@param {number=} time
Tone.Oscillator.prototype.start = function(time){
if (!this.playing){
var freq = this.oscillator.frequency.value;
var type = this.oscillator.type;
var detune = this.oscillator.frequency.value;
this.oscillator = this.context.createOscillator();
this.oscillator.frequency.value = freq;
this.oscillator.type = type;
this.oscillator.detune.value = detune;
this.oscillator.connect(this.output);
this.playing = true;
time = this.defaultArg(time, this.now());
this.oscillator.start(time);
}
}
//@param {number=} time
Tone.Oscillator.prototype.stop = function(time){
if (this.playing){
time = this.defaultArg(time, this.now());
this.oscillator.stop(time);
this.playing = false;
}
}
//@param {number} val
//@param {number=} rampTime
Tone.Oscillator.prototype.setFrequency = function(val, rampTime){
rampTime = this.defaultArg(rampTime, 0);
this.oscillator.linearRampToValueAtTime(val, rampTime);
}
//@param {string} type
Tone.Oscillator.prototype.setType = function(type){
this.oscillator.type = type;
}

View file

@ -5,47 +5,66 @@
// scales the input in normal range (-1 to 1) to the output between min and max
///////////////////////////////////////////////////////////////////////////////
Tone.Scale = function(min, max){
Tone.call(this);
define(["core/Tone"], function(Tone){
//vals
this.min = min;
this.max = max;
//@param {number} min
//@param {number} max
//@param {string} scaling (lin|exp|log|equalPower)
Tone.Scale = function(min, max, scaling){
Tone.call(this);
//components
this.scaler = Tone.context.createWaveShaper();
//vals
this.min = min;
this.max = max;
this.scaling = this.defaultArg(scaling, "lin");
this.scalingFunction = this._selectScalingFunction(this.scaling);
//connections
this.chain(this.input, this.scaler, this.output);
//components
this.scaler = this.context.createWaveShaper();
//setup
this._scaleCurve();
}
//connections
this.chain(this.input, this.scaler, this.output);
//extend StereoSplit
Tone.extend(Tone.Scale);
//generates the values for the waveshaper
Tone.Scale.prototype._scaleCurve = function(){
var len = 512;
var curve = new Float32Array(len);
var min = this.min;
var max = this.max;
for (var i = 0; i < len; i++){
//values between 0 and 1
var terp = (i / (len - 1));
curve[i] = terp * (max - min) + min;
//setup
this._scaleCurve();
}
//console.log(curve);
this.scaler.curve = curve;
}
Tone.Scale.prototype.setMax = function(max){
this.max = max;
this._scaleCurve();
}
//extend StereoSplit
Tone.extend(Tone.Scale);
Tone.Scale.prototype.setMin = function(min){
this.min = min;
this._scaleCurve();
}
//generates the values for the waveshaper
Tone.Scale.prototype._scaleCurve = function(){
var len = this.waveShaperResolution;
var curve = new Float32Array(len);
var min = this.min;
var max = this.max;
for (var i = 0; i < len; i++){
//values between 0 and 1
var terp = this.scalingFunction(i / (len - 1));
curve[i] = terp * (max - min) + min;
}
this.scaler.curve = curve;
}
//
Tone.Scale.prototype._selectScalingFunction = function(scaling){
switch(scaling){
case "lin" : return function(x) {return x};
case "exp" : return this.expScale;
case "log" : return this.logScale;
case "equalPower" : return this.equalPowerScale;
}
}
Tone.Scale.prototype.setMax = function(max){
this.max = max;
this._scaleCurve();
}
Tone.Scale.prototype.setMin = function(min){
this.min = min;
this._scaleCurve();
}
return Tone.Scale;
});

View file

@ -6,69 +6,73 @@
// useful for controlling AudioParams
///////////////////////////////////////////////////////////////////////////////
Tone.Signal = function(){
Tone.call(this);
define(["core/Tone"], function(Tone){
//components
this.signal = this.context.createWaveShaper();
this.scalar = this.context.createGain();
//generator to drive values
this.generator = this.context.createOscillator();
//@param {number=} value
Tone.Signal = function(value){
Tone.call(this);
//connections
this.chain(this.generator, this.signal, this.scalar, this.output);
//connect the input to the scalar's gain so that can be controlled with the incoming signal
this.input.connect(this.scalar.gain);
//components
this.signal = this.context.createWaveShaper();
this.scalar = this.context.createGain();
//generator to drive values
this.generator = this.context.createOscillator();
//setup
this.generator.start(0);
this.scalar.gain.value = 0;
this._signalCurve();
}
//connections
this.chain(this.generator, this.signal, this.scalar, this.output);
Tone.extend(Tone.Signal);
//generates a constant output of 1
Tone.Signal.prototype._signalCurve = function(){
var len = 8;
var curve = new Float32Array(len);
for (var i = 0; i < len; i++){
//all inputs produce the output value
curve[i] = 1;
//setup
this.generator.start(0);
this._signalCurve();
this.setValue(this.defaultArg(value, 0));
}
//console.log(curve);
this.signal.curve = curve;
}
Tone.Signal.prototype.getValue = function(val){
return this.scalar.gain.value;
}
Tone.extend(Tone.Signal);
Tone.Signal.prototype.setValue = function(val){
this.scalar.gain.value = val;
}
//generates a constant output of 1
Tone.Signal.prototype._signalCurve = function(){
var len = 8;
var curve = new Float32Array(len);
for (var i = 0; i < len; i++){
//all inputs produce the output value
curve[i] = 1;
}
//console.log(curve);
this.signal.curve = curve;
}
//all of the automation curves are available
Tone.Signal.prototype.setValueAtTime = function(value, time){
this.scalar.gain.setValueAtTime(value, time);
}
Tone.Signal.prototype.getValue = function(val){
return this.scalar.gain.value;
}
Tone.Signal.prototype.linearRampToValueAtTime = function(value, endTime){
this.scalar.gain.linearRampToValueAtTime(value, endTime);
}
Tone.Signal.prototype.setValue = function(val){
this.scalar.gain.value = val;
}
Tone.Signal.prototype.exponentialRampToValueAtTime = function(value, endTime){
this.scalar.gain.exponentialRampToValueAtTime(value, endTime);
}
//all of the automation curves are available
Tone.Signal.prototype.setValueAtTime = function(value, time){
this.scalar.gain.setValueAtTime(value, time);
}
Tone.Signal.prototype.setTargetAtTime = function(target, startTime, timeConstant){
this.scalar.gain.setTargetAtTime(target, startTime, timeConstant);
}
Tone.Signal.prototype.linearRampToValueAtTime = function(value, endTime){
this.scalar.gain.linearRampToValueAtTime(value, endTime);
}
Tone.Signal.prototype.setValueCurveAtTime = function(values, startTime, duration){
this.scalar.gain.setValueCurveAtTime(values, startTime, duration);
}
Tone.Signal.prototype.exponentialRampToValueAtTime = function(value, endTime){
this.scalar.gain.exponentialRampToValueAtTime(value, endTime);
}
Tone.Signal.prototype.cancelScheduledValues = function(startTime){
this.scalar.gain.cancelScheduledValues(startTime);
}
Tone.Signal.prototype.setTargetAtTime = function(target, startTime, timeConstant){
this.scalar.gain.setTargetAtTime(target, startTime, timeConstant);
}
Tone.Signal.prototype.setValueCurveAtTime = function(values, startTime, duration){
this.scalar.gain.setValueCurveAtTime(values, startTime, duration);
}
Tone.Signal.prototype.cancelScheduledValues = function(startTime){
this.scalar.gain.cancelScheduledValues(startTime);
}
return Tone.Signal;
})

28
src/signal/Split.js Normal file
View file

@ -0,0 +1,28 @@
///////////////////////////////////////////////////////////////////////////////
//
// STEREO
//
// splits the incoming signal into left and right outputs
// one input two outputs
///////////////////////////////////////////////////////////////////////////////
define(["core/Tone"], function(Tone){
Tone.Split = function(){
Tone.call(this);
//components
this.splitter = this.context.createChannelSplitter(2);
this.left = this.context.createGain();
this.right = this.context.createGain();
//connections
this.input.connect(this.splitter);
this.splitter.connect(this.left, 1, 0);
this.splitter.connect(this.right, 0, 0);
}
Tone.extend(Tone.Split);
return Tone.Split;
});

View file

@ -1,22 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// STEREO
//
// splits the incoming signal into left and right outputs
///////////////////////////////////////////////////////////////////////////////
Tone.Stereo = function(){
Tone.call(this);
//components
this.splitter = this.context.createChannelSplitter();
this.left = this.context.createGain();
this.right = this.context.createGain();
//connections
this.input.connect(this.splitter);
this.splitter.connect(this.left, 0, 0);
this.splitter.connect(this.right, 1, 0);
}
Tone.extend(Tone.Stereo);

43
src/signal/Subtract.js Normal file
View file

@ -0,0 +1,43 @@
///////////////////////////////////////////////////////////////////////////////
//
// SUBTRACT FROM
//
// subtract the signal from the constant
// for subtracting from the signal, use Tone.Add with a negative number
///////////////////////////////////////////////////////////////////////////////
define(["core/Tone"], function(Tone){
Tone.Subtract = function(constant){
Tone.call(this);
this.constant = constant;
//component
this.subber = this.context.createWaveShaper();
//connections
this.chain(this.input, this.subber, this.output);
//setup
this._subCurve();
}
Tone.extend(Tone.Subtract);
//subtracts the signal from the value
Tone.Subtract.prototype._subCurve = function(){
var len = this.waveShaperResolution;
var curve = new Float32Array(len);
for (var i = 0; i < len; i++){
///scale the values between -1 to 1
var baseline = (i / (len - 1)) * 2 - 1;
//all inputs produce the output value
curve[i] = this.constant - baseline;
}
//console.log(curve);
this.subber.curve = curve;
}
return Tone.Subtract;
});

66
src/source/Oscillator.js Normal file
View file

@ -0,0 +1,66 @@
///////////////////////////////////////////////////////////////////////////////
//
// OSCILLATOR
//
// just an oscillator,
// but starting and stopping is easier than the native version
///////////////////////////////////////////////////////////////////////////////
define(["core/Tone"], function(Tone){
Tone.Oscillator = function(freq, type){
Tone.call(this);
this.playing = false;
//components
this.oscillator = this.context.createOscillator();
this.oscillator.frequency.value = this.defaultArg(freq, 440);
this.oscillator.type = this.defaultArg(type, "sine");
console.log(freq);
//connections
this.chain(this.oscillator, this.output);
}
Tone.extend(Tone.Oscillator);
//@param {number=} time
Tone.Oscillator.prototype.start = function(time){
if (!this.playing){
var freq = this.oscillator.frequency.value;
var type = this.oscillator.type;
var detune = this.oscillator.frequency.value;
this.oscillator = this.context.createOscillator();
this.oscillator.frequency.value = freq;
this.oscillator.type = type;
this.oscillator.detune.value = detune;
this.oscillator.connect(this.output);
this.playing = true;
time = this.defaultArg(time, this.now());
this.oscillator.start(time);
}
}
//@param {number=} time
Tone.Oscillator.prototype.stop = function(time){
if (this.playing){
time = this.defaultArg(time, this.now());
this.oscillator.stop(time);
this.playing = false;
}
}
//@param {number} val
//@param {number=} rampTime
Tone.Oscillator.prototype.setFrequency = function(val, rampTime){
rampTime = this.defaultArg(rampTime, 0);
this.oscillator.linearRampToValueAtTime(val, rampTime);
}
//@param {string} type
Tone.Oscillator.prototype.setType = function(type){
this.oscillator.type = type;
}
return Tone.Oscillator;
});

View file

@ -1,146 +0,0 @@
.label {
font-family: monospace;
text-align: center;
width: 100%; }
/*=============================================================================
BAR
=============================================================================*/
.bar {
padding: 0px 2px 0px 2px; }
.bar .segment {
width: 30px;
height: 6px;
margin: 2px auto 2px auto;
opacity: 1;
/*@include transitionAndTime(opacity, .016s);*/ }
.bar .segment.peak {
background-color: red; }
.bar .segment.high {
background-color: orange; }
.bar .segment.normal {
background-color: green; }
.meter .bar .label {
font-size: 10px; }
/*=============================================================================
METER
=============================================================================*/
.meter {
position: relative;
float: left;
margin: 5px;
display: table;
border: 1px solid black;
border-radius: 3px; }
.meter .label {
clear: both;
font-size: 15px; }
.meter .bar {
position: relative;
float: left; }
/*=============================================================================
FADER
=============================================================================*/
.fader {
width: 40px;
display: table;
border: 1px solid black;
border-radius: 3px;
position: relative;
float: left;
margin: 5px; }
.fader .track {
position: relative;
width: auto;
height: auto;
margin: 0px; }
.fader .slider {
position: absolute;
width: 100%;
height: 100%;
margin: 0px;
top: 0px;
left: 0px;
-webkit-appearance: slider-vertical;
-moz-appearance: slider-vertical;
appearance: slider-vertical; }
.fader input.label {
padding: 0px;
border: 0px;
font-size: 10px;
height: 15px; }
.fader .bar .segment {
width: 40px;
background-color: black; }
/*=============================================================================
BUTTONS
=============================================================================*/
.button {
margin: 5px;
width: 40px;
height: 20px;
position: relative;
left: 0px;
border: none;
display: inline-block; }
.button input {
width: 100%;
height: 100%;
position: absolute;
left: 0px;
top: 0px;
border: none;
cursor: pointer; }
.button .label {
position: absolute;
top: 0px;
left: 0px;
height: 100%;
line-height: 20px;
color: white;
pointer-events: none; }
.button:active input {
background-color: white; }
.button:active .label {
color: black; }
/*=============================================================================
TRANSPORT
=============================================================================*/
.transport {
border: 1px solid black;
border-radius: 3px;
position: absolute;
width: auto;
height: auto; }
.transport .button {
float: left; }
.transport .progress {
margin: 5px;
float: left;
display: inline-block;
width: 60px;
text-align: center;
border: none;
font-size: 14px;
font-family: monospace; }

View file

@ -1,196 +0,0 @@
$fastUpdateTime : .1s;
@mixin transitionAndTime($property, $time){
-webkit-transition: $property $time linear;
-moz-transition: $property $time linear;
-o-transition: $property $time linear;
transition: $property $time linear;
}
$unitWidth : 30px;
@mixin borderStyle{
border: 1px solid black;
border-radius: 3px;
}
.label {
font-family: monospace;
text-align: center;
width: 100%;
}
/*=============================================================================
BAR
=============================================================================*/
.bar {
padding: 0px 2px 0px 2px;
}
.bar .segment {
width: $unitWidth;
height: 6px;
margin: 2px auto 2px auto;
opacity: 1;
/*@include transitionAndTime(opacity, .016s);*/
}
.bar .segment.peak {
background-color: red;
}
.bar .segment.high {
background-color: orange;
}
.bar .segment.normal {
background-color: green;
}
.meter .bar .label {
font-size: 10px;
}
/*=============================================================================
METER
=============================================================================*/
.meter {
position: relative;
float: left;
margin: 5px;
display: table;
@include borderStyle;
}
.meter .label {
clear: both;
font-size: 15px;
}
.meter .bar {
position: relative;
float: left;
}
/*=============================================================================
FADER
=============================================================================*/
$faderWidth: 40px;
.fader {
width: $faderWidth;
display: table;
@include borderStyle;
position: relative;
float: left;
margin: 5px;
}
.fader .track {
position: relative;
width: auto;
height: auto;
margin: 0px;
}
.fader .slider {
position: absolute;
width: 100%;
height: 100%;
margin: 0px;
top: 0px;
left: 0px;
-webkit-appearance: slider-vertical;
-moz-appearance: slider-vertical;
appearance: slider-vertical;
}
.fader input.label {
padding: 0px;
border: 0px;
font-size: 10px;
height: 15px;
}
.fader .bar .segment {
width: $faderWidth;
background-color: black;
}
/*=============================================================================
BUTTONS
=============================================================================*/
$buttonWidth: 40px;
$buttonHeight: 20px;
.button {
margin: 5px;
width: $buttonWidth;
height: $buttonHeight;
position: relative;
left: 0px;
border: none;
display: inline-block;
}
.button input{
width: 100%;
height: 100%;
position: absolute;
left: 0px;
top:0px;
border: none;
cursor: pointer;
}
.button .label {
position: absolute;
top: 0px;
left: 0px;
height: 100%;
line-height: $buttonHeight;
color: white;
pointer-events: none;
}
.button:active input{
background-color: white;
}
.button:active .label{
color: black;
}
/*=============================================================================
TRANSPORT
=============================================================================*/
.transport {
@include borderStyle;
position: absolute;
width: auto;
height: auto;
}
.transport .button{
float: left;
}
.transport .progress{
margin: 5px;
float: left;
display: inline-block;
width: 60px;
text-align: center;
border: none;
font-size: 14px;
font-family: monospace;
}