mirror of
https://github.com/Tonejs/Tone.js
synced 2024-11-10 05:54:20 +00:00
updated examples
This commit is contained in:
parent
3d8fe205f7
commit
f1e1a6b13f
16 changed files with 8079 additions and 647 deletions
|
@ -45,7 +45,8 @@
|
|||
<div id="Content">
|
||||
<div id="Title">Envelope</div>
|
||||
<div id="Explanation">
|
||||
Envelopes ramp amplitude, frequency or any other parameter over time. Tone.Envelope and the classes that extend it
|
||||
Envelopes ramp amplitude, frequency or any other parameter over time.
|
||||
Tone.Envelope and the classes that extend it
|
||||
implement an <a href="https://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope" target="_blank">ADSR</a> envelope type
|
||||
which splits its ramp into four distinct phases: Attack, Decay, Sustain, Release.
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/e/ea/ADSR_parameter.svg">
|
||||
|
@ -84,8 +85,6 @@
|
|||
|
||||
var envGUI = Notone.add(env, "Envelope");
|
||||
|
||||
console.log($("#Sliders").get(0));
|
||||
|
||||
new Interface.Slider({
|
||||
param : "attack",
|
||||
name : "attack",
|
||||
|
|
|
@ -2,20 +2,17 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>MONOSYNTH</title>
|
||||
<title>SimpleFM</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
|
||||
<script type="text/javascript" src="./scripts/jquery.min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../build/Tone.js"></script>
|
||||
<script type="text/javascript" src="../build/Tone.Preset.js"></script>
|
||||
<script type="text/javascript" src="./deps/nexusUI.js"></script>
|
||||
<script type="text/javascript" src="./deps/prism.js"></script>
|
||||
<script type="text/javascript" src="./scripts/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../../Notone.js/build/Notone.GUI.js"></script>
|
||||
<script type="text/javascript" src="./scripts/Interface.js"></script>
|
||||
<script type="text/javascript" src="./deps/qwerty-hancock.js"></script>
|
||||
<script type="text/javascript" src="./scripts/qwerty-hancock.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./style/examples.css">
|
||||
<link rel="stylesheet" type="text/css" href="./style/prism.css">
|
||||
|
||||
<script type="text/javascript">
|
||||
// jshint ignore: start
|
||||
|
@ -23,107 +20,63 @@
|
|||
|
||||
</head>
|
||||
<body>
|
||||
<style type="text/css">
|
||||
#Amplitude0, #Amplitude1 {
|
||||
/*position: relative;*/
|
||||
width: calc(40% - 10px)!important;
|
||||
}
|
||||
#FilterEnvelope0, #FilterEnvelope1 {
|
||||
/*position: relative;*/
|
||||
width: calc(60% - 10px)!important;
|
||||
}
|
||||
.FilterEnvelope.Envelope {
|
||||
width: 100%!important;
|
||||
}
|
||||
|
||||
.Envelope {
|
||||
width: 100%!important;
|
||||
}
|
||||
.Label {
|
||||
width: 100%;
|
||||
font-size : 10px;
|
||||
line-height: 7px;
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 5px;
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
<div id="Explanation">
|
||||
FMSynth
|
||||
<br>
|
||||
<br>
|
||||
FMSynth is a monophonic Frequency Modulation Synthesizer composed of two MonoSyths: one as the carrier and one as the frequency modulator.
|
||||
</div>
|
||||
<div id="Content">
|
||||
<div id="KeyRack">
|
||||
<div id="Keyboard"></div>
|
||||
<div id="Title">FMSynth</div>
|
||||
<div id="Explanation">
|
||||
SimpleFM is composed of two Tone.SimpleSynths where one Tone.SimpleSynth modulates
|
||||
the frequency of a second Tone.SimpleSynth.
|
||||
</div>
|
||||
<div id="Oscillator">
|
||||
</div>
|
||||
<div id="Envelope">
|
||||
<div id="Amplitude0"></div>
|
||||
<div id="FilterEnvelope0"></div>
|
||||
<div id="Amplitude1"></div>
|
||||
<div id="FilterEnvelope1"></div>
|
||||
</div>
|
||||
<div id="Filter"></div>
|
||||
<div id="Voices"></div>
|
||||
<div id="Presets"></div>
|
||||
</div>
|
||||
|
||||
<script id="ToneCode" type="text/javascript">
|
||||
var synth = new Tone.FMSynth().toMaster();
|
||||
<script type="text/javascript">
|
||||
var synth = new Tone.SimpleFM({
|
||||
"modulationIndex" : 12.22
|
||||
}).toMaster();
|
||||
</script>
|
||||
<script id="GUI" type="text/javascript">
|
||||
|
||||
Interface.Rack("KeyRack", "Keyboard", true).open();
|
||||
//the keyboard
|
||||
var keyboard = new QwertyHancock({
|
||||
id: "Keyboard",
|
||||
width: $("#KeyRack").width(),
|
||||
height: 75,
|
||||
octaves : 3,
|
||||
startNote: "A2",
|
||||
<script type="text/javascript">
|
||||
|
||||
$(function(){
|
||||
Notone.config({
|
||||
"search" : false,
|
||||
"expandInDrawer" : true,
|
||||
"hideDrawer" : Interface.isMobile,
|
||||
"drawer" : true,
|
||||
"container" : "body"
|
||||
});
|
||||
|
||||
var fmGUI = Notone.add(synth, "SimpleFM");
|
||||
|
||||
new Interface.Slider({
|
||||
gui : fmGUI,
|
||||
param : "modulationIndex",
|
||||
name : "mod index",
|
||||
max : 100
|
||||
});
|
||||
|
||||
$("<div>", {
|
||||
"id" : "Keyboard"
|
||||
}).appendTo("#Content");
|
||||
|
||||
var keyboard = new QwertyHancock({
|
||||
id: "Keyboard",
|
||||
width: $("#Content").width(),
|
||||
height: 150,
|
||||
octaves: Interface.isMobile ? 1.26 : 3,
|
||||
startNote: "C3",
|
||||
whiteKeyColour: "white",
|
||||
blackKeyColour: "#ECECEC",
|
||||
activeColour : "#FFFC0C"
|
||||
});
|
||||
|
||||
keyboard.keyDown = function (note) {
|
||||
synth.triggerAttack(note);
|
||||
};
|
||||
|
||||
keyboard.keyUp = function (note) {
|
||||
synth.triggerRelease();
|
||||
};
|
||||
});
|
||||
keyboard.keyDown = function(note, freq){
|
||||
synth.triggerAttack(freq);
|
||||
};
|
||||
keyboard.keyUp = function(){
|
||||
synth.triggerRelease();
|
||||
};
|
||||
|
||||
//the oscillator
|
||||
Interface.Rack("Oscillator", "Oscillators", true);
|
||||
$("<div>").addClass("Label").appendTo("#Oscillator").text("carrier");
|
||||
Interface.DropDown("Oscillator", synth.carrier.oscillator, "type", ["sine", "square", "triangle", "sawtooth", "pwm", "pulse"]).listen();
|
||||
$("<div>").addClass("Label").appendTo("#Oscillator").text("modulator");
|
||||
Interface.DropDown("Oscillator", synth.modulator.oscillator, "type", ["sine", "square", "triangle", "sawtooth", "pwm", "pulse"]).listen();
|
||||
//the envelopes
|
||||
Interface.Rack("Envelope", "Envelopes", true);
|
||||
var ampGroup0 = Interface.Group("Amplitude0", "Carrier Amplitude");
|
||||
Interface.AmplitudeEnvelope(ampGroup0, synth.carrier.envelope).listen();
|
||||
var filtGroup0 = Interface.Group("FilterEnvelope0", "Carrier Filter");
|
||||
Interface.FilterEnvelope(filtGroup0, synth.carrier.filterEnvelope).listen();
|
||||
var ampGroup1 = Interface.Group("Amplitude1", "Modulator Amplitude");
|
||||
Interface.AmplitudeEnvelope(ampGroup1, synth.modulator.envelope).listen();
|
||||
var filtGroup1 = Interface.Group("FilterEnvelope1", "Modulator Filter");
|
||||
Interface.FilterEnvelope(filtGroup1, synth.modulator.filterEnvelope).listen();
|
||||
//the filters
|
||||
Interface.Rack("Filter", "Filter", true);
|
||||
$("<div>").addClass("Label").appendTo("#Filter").text("Carrier");
|
||||
var type = Interface.DropDown("Filter", synth.carrier.filter, "type", ["lowpass", "highpass", "bandpass"]).listen();
|
||||
var Q = Interface.Slider("Filter", synth.carrier.filter, "Q", 0.1, 20).listen();
|
||||
$("<div>").addClass("Label").appendTo("#Filter").text("Modulator");
|
||||
var type = Interface.DropDown("Filter", synth.modulator.filter, "type", ["lowpass", "highpass", "bandpass"]).listen();
|
||||
var Q = Interface.Slider("Filter", synth.modulator.filter, "Q", 0.1, 20).listen();
|
||||
//other settings
|
||||
Interface.Rack("Voices", "Voices", true);
|
||||
Interface.Slider("Voices", synth, "harmonicity", 0.25, 5).listen();
|
||||
Interface.Slider("Voices", synth, "modulationIndex", 1, 20).listen();
|
||||
//presets
|
||||
Interface.Rack("Presets", "Presets", true);
|
||||
Interface.Presets("Presets", synth);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -6,57 +6,51 @@
|
|||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
|
||||
<script type="text/javascript" src="../build/Tone.min.js"></script>
|
||||
<script type="text/javascript" src="./scripts/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="./scripts/ExampleList.js"></script>
|
||||
<script type="text/javascript" src="./scripts/Interface.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./style/examples.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<style type="text/css">
|
||||
#Content {
|
||||
width: 300px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
#Content div{
|
||||
font-size: 16px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
#Content a {
|
||||
margin-left: 10px;
|
||||
font-weight: normal!important;
|
||||
}
|
||||
.Category {
|
||||
font-weight: 900;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
#ExampleList {
|
||||
width: 200px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
</style>
|
||||
<div id="TopBar">
|
||||
<div id="Homepage" title="github">
|
||||
<a href="http://github.com/TONEnoTONE/Tone.js">Tone.js</a>
|
||||
</div>
|
||||
<div id="Examples" title="examples">
|
||||
<a href="./index.html">examples</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="Content"></div>
|
||||
<div id="Content" class="FullScreen"></div>
|
||||
<script type="text/javascript">
|
||||
|
||||
var content = $("#Content");
|
||||
var container = $("<div>", {
|
||||
"id" : "ExampleList",
|
||||
}).appendTo("#Content");
|
||||
|
||||
for (var catName in ExampleList){
|
||||
$("<div>").addClass("Category").text(catName)
|
||||
.appendTo(content);
|
||||
var category = ExampleList[catName];
|
||||
for (var example in category){
|
||||
$("<div>").addClass("Item")
|
||||
.appendTo(content)
|
||||
.html($("<a>").attr("href", category[example]+".html").text(example));
|
||||
$("<div>").addClass("Category").text(catName).appendTo(container);
|
||||
var category = ExampleList[catName];
|
||||
for (var example in category){
|
||||
$("<div>").addClass("Item")
|
||||
.appendTo(container)
|
||||
.html($("<a>").attr("href", category[example]+".html").text(example));
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style type="text/css">
|
||||
#Content div{
|
||||
font-size: 14px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
a:visited {
|
||||
color: black;
|
||||
}
|
||||
a {
|
||||
margin-left: 10px;
|
||||
color: black;
|
||||
}
|
||||
.Category {
|
||||
font-weight: 900;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
|
@ -22,17 +22,6 @@
|
|||
<body>
|
||||
<style type="text/css">
|
||||
|
||||
img {
|
||||
width: 80%;
|
||||
max-width: 700px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#Keyboard {
|
||||
margin: 3px!important;
|
||||
}
|
||||
</style>
|
||||
<div id="Content">
|
||||
<div id="Title">MonoSynth</div>
|
||||
|
|
|
@ -6,14 +6,12 @@
|
|||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
|
||||
<script type="text/javascript" src="./scripts/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../build/Tone.js"></script>
|
||||
<script type="text/javascript" src="./deps/nexusUI.js"></script>
|
||||
<script type="text/javascript" src="./deps/prism.js"></script>
|
||||
<script type="text/javascript" src="./scripts/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../../Notone.js/build/Notone.GUI.js"></script>
|
||||
<script type="text/javascript" src="./scripts/Interface.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./style/examples.css">
|
||||
<link rel="stylesheet" type="text/css" href="./style/prism.css">
|
||||
|
||||
<script type="text/javascript">
|
||||
// jshint ignore: start
|
||||
|
@ -27,18 +25,13 @@
|
|||
display: block;
|
||||
}
|
||||
</style>
|
||||
<div id="Explanation">
|
||||
Ping Pong Delay
|
||||
<br>
|
||||
<br>
|
||||
A Ping Pong Delay is a stereo feedback delay where the delay bounces back and forth between the left and right channels. Hit the button to trigger a snare sample into the effect.
|
||||
</div>
|
||||
<div id="Content">
|
||||
<div id="LoadingBar"></div>
|
||||
<div id="Rack"></div>
|
||||
<div id="Code"></div>
|
||||
<div id="Title">Ping Pong Delay</div>
|
||||
<div id="Explanation">
|
||||
A Ping Pong Delay is a stereo feedback delay where the delay bounces back and forth between the left and right channels. Hit the button to trigger a snare sample into the effect.
|
||||
</div>
|
||||
</div>
|
||||
<script id="ToneCode" type="text/javascript">
|
||||
<script type="text/javascript">
|
||||
//the feedback delay
|
||||
var feedbackDelay = new Tone.PingPongDelay({
|
||||
"delayTime" : "8n",
|
||||
|
@ -47,20 +40,29 @@
|
|||
}).toMaster();
|
||||
|
||||
//play a snare sound through it
|
||||
var player = new Tone.Player("./audio/505/snare.mp3")
|
||||
.connect(feedbackDelay);
|
||||
var player = new Tone.Player("./audio/505/snare.mp3").connect(feedbackDelay);
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
Interface.Loading("LoadingBar");
|
||||
Interface.Rack("Rack", "PingPongDelay");
|
||||
Interface.Momentary("Rack", function(on){
|
||||
if (on){
|
||||
player.start();
|
||||
}
|
||||
$(function(){
|
||||
Notone.config({
|
||||
"search" : false,
|
||||
"expandInDrawer" : true,
|
||||
"hideDrawer" : Interface.isMobile,
|
||||
"drawer" : true,
|
||||
"container" : "body"
|
||||
});
|
||||
|
||||
Notone.add(feedbackDelay);
|
||||
|
||||
new Interface.Loader();
|
||||
|
||||
new Interface.Button({
|
||||
text : "trigger",
|
||||
start : function(){
|
||||
player.start();
|
||||
},
|
||||
});
|
||||
});
|
||||
Interface.Slider("Rack", feedbackDelay, "feedback", 0, 0.95);
|
||||
Interface.Slider("Rack", feedbackDelay, "delayTime", 0.1, 0.5);
|
||||
Interface.Code("Code", "ToneCode");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -22,20 +22,12 @@
|
|||
<body>
|
||||
<style type="text/css">
|
||||
|
||||
#Content {
|
||||
width: calc(100% - 6px)!important;
|
||||
max-width: calc(100% - 6px)!important;
|
||||
}
|
||||
|
||||
#Keyboard {
|
||||
margin: 3px!important;
|
||||
}
|
||||
</style>
|
||||
<div id="Content">
|
||||
<div id="Content" class="FullScreen">
|
||||
<div id="Title">PolySynth</div>
|
||||
<div id="Explanation">
|
||||
Tone.PolySynth handles voice creation and allocation for any
|
||||
instruments passed in as the second paramter. PolySynth is
|
||||
instruments passed in as the second parameter. PolySynth is
|
||||
not a synthesizer by itself, it merely manages voices of
|
||||
one of the other types of synths, allowing any of the
|
||||
monophonic synthesizers to be polyphonic.
|
||||
|
|
145
examples/rampTo.html
Normal file
145
examples/rampTo.html
Normal file
|
@ -0,0 +1,145 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>SIGNAL RAMP</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
|
||||
<script type="text/javascript" src="../build/Tone.js"></script>
|
||||
<script type="text/javascript" src="./scripts/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../../Notone.js/build/Notone.GUI.js"></script>
|
||||
<script type="text/javascript" src="./scripts/Interface.js"></script>
|
||||
<script type="text/javascript" src="./scripts/nexusUI.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./style/examples.css">
|
||||
|
||||
<script type="text/javascript">
|
||||
// jshint ignore: start
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<style type="text/css">
|
||||
canvas {
|
||||
margin-top: 3px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="Content" class="FullScreen">
|
||||
<div id="Title">rampTo</div>
|
||||
<div id="Explanation">
|
||||
In Tone.js, many of a class' members are Tone.Signals. Working with signals is different
|
||||
than working with numbers or strings: Signals are values which are updated at audio rate,
|
||||
which allows for sample-accurate scheduling and ramping. <code>.rampTo(value, rampTime)</code>
|
||||
smoothly changes the signal from the current value to the target value over the duration of the rampTime.
|
||||
This example uses <code>.rampTo</code> in to smooth out changes in volume and frequency.
|
||||
<br><br>
|
||||
As the large dot gets closer to each of the smaller dots, a different harmonic is heard depending
|
||||
on the distance to that smaller dot. The "harmony" slider adjusts each of the oscillators frequencies'
|
||||
distance from the fundamental frequency.
|
||||
</div>
|
||||
<canvas nx="joints"></canvas>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
Tone.Master.volume.value = -Infinity;
|
||||
|
||||
var oscillators = {};
|
||||
|
||||
var bassFreq = 32;
|
||||
|
||||
var reverb = new Tone.JCReverb().toMaster();
|
||||
|
||||
for (var i = 0; i < 7; i++){
|
||||
oscillators["node" + i] = new Tone.Oscillator({
|
||||
"frequency" : bassFreq * i,
|
||||
"type" : "sawtooth10",
|
||||
"detune" : Math.random() * 30 - 15,
|
||||
}).connect(reverb).start();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
nx.onload = function(){
|
||||
nx.colorize("#7F33ED");
|
||||
|
||||
joints1.nodeSize = 45;
|
||||
joints1.val.x = Math.random();
|
||||
joints1.val.y = Math.random();
|
||||
joints1.resize($("#Content").width(), 250);
|
||||
joints1.animate("bounce");
|
||||
var width = joints1.width;
|
||||
var height = joints1.height;
|
||||
joints1.threshold = Math.max($("#Content").width() / 1.5, 60);
|
||||
randomPlacement();
|
||||
joints1.init();
|
||||
joints1.draw();
|
||||
|
||||
$(window).on("resize", function(){
|
||||
joints1.resize($("#Content").width(), 250);
|
||||
joints1.threshold = Math.max($("#Content").width() / 1.5, 60);
|
||||
joints1.draw();
|
||||
});
|
||||
|
||||
function randomPlacement(){
|
||||
var width = $("#Content").width();
|
||||
var height = joints1.height;
|
||||
var len = Object.keys(oscillators).length;
|
||||
for (var i = 0; i < len; i++){
|
||||
joints1.joints[i] = {
|
||||
x : Math.random() * width,
|
||||
y : Math.random() * height
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setValues(data){
|
||||
for (var n in oscillators){
|
||||
if (data.hasOwnProperty(n)){
|
||||
oscillators[n].volume.rampTo((1 - Math.pow(data[n], 0.5)) * -60, 0.3);
|
||||
} else {
|
||||
oscillators[n].volume.rampTo(-Infinity, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
joints1.on("*", setValues);
|
||||
|
||||
new Interface.Slider({
|
||||
name : "harmony",
|
||||
min : 0.5,
|
||||
max : 2,
|
||||
value : 1,
|
||||
drag : function(value){
|
||||
var i = 0;
|
||||
for (var n in oscillators){
|
||||
var osc = oscillators[n];
|
||||
osc.frequency.rampTo(bassFreq * i * value, 0.4);
|
||||
i++;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
new Interface.Button({
|
||||
text : "Unmute",
|
||||
activeText : "Mute",
|
||||
type : "toggle",
|
||||
key : 32, //spacebar
|
||||
start : function(){
|
||||
Tone.Master.volume.rampTo(-20, 0.5);
|
||||
},
|
||||
end : function(){
|
||||
Tone.Master.volume.rampTo(-Infinity, 0.5);
|
||||
},
|
||||
});
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -2,38 +2,46 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>USING TONE WITH REQUIRE</title>
|
||||
<title>MODULE LOADERS</title>
|
||||
|
||||
<script type="text/javascript" src="./deps/require.js"></script>
|
||||
<script type="text/javascript" src="./scripts/require.js"></script>
|
||||
|
||||
<script type="text/javascript" src="./scripts/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="./scripts/Interface.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./style/examples.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id='meter'></div>
|
||||
<div id="Content" class="FullScreen">
|
||||
<div id="Title">Module Loaders</div>
|
||||
<div id="Explanation">
|
||||
<a href="http://requirejs.org/" target="_blank">RequireJS</a>
|
||||
is a powerful module and build system which Tone.js uses internally.
|
||||
By only including the modules that your application needs, your build can be
|
||||
much smaller and your code much more modular.
|
||||
<br><br>
|
||||
If you use RequireJS (or any other UMD module loader), but build-size is less of a concern,
|
||||
you can simply include the entire Tone.js build.
|
||||
<br><br>
|
||||
Take a look at the source to see how.
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
//minimal example using requirejs
|
||||
|
||||
require.config({
|
||||
baseUrl : "./",
|
||||
//make sure there is a path which points to
|
||||
//make a path to the Tone.js/Tone directory
|
||||
//then include the sources as they are below
|
||||
paths : {
|
||||
"Tone" : "../Tone"
|
||||
"Tone" : "../Tone",
|
||||
}
|
||||
});
|
||||
require(["Tone/core/Tone", "Tone/component/LFO", "Tone/signal/Scale", "Tone/component/Meter"],
|
||||
function(Tone, LFO, Scale, Meter){
|
||||
|
||||
var osc = new LFO(0.5, 0, 1);
|
||||
var scale = new Scale(10, 100);
|
||||
var meter = new Meter();
|
||||
|
||||
osc.chain(scale, meter);
|
||||
|
||||
osc.start();
|
||||
|
||||
var meterEl = document.querySelector("#meter");
|
||||
|
||||
setInterval(function(){
|
||||
meterEl.textContent = meter.getValue().toFixed(2);
|
||||
}, 100);
|
||||
require(["Tone/core/Master", "Tone/instrument/SimpleSynth"],
|
||||
function(Master, SimpleSynth){
|
||||
var synth = new SimpleSynth().toMaster();
|
||||
synth.triggerAttackRelease("C4", "8n");
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -7,15 +7,11 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
|
||||
<script type="text/javascript" src="../build/Tone.js"></script>
|
||||
<script type="text/javascript" src="../build/Tone.Preset.js"></script>
|
||||
<script type="text/javascript" src="./scripts/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="./deps/qwerty-hancock.js"></script>
|
||||
<script type="text/javascript" src="./deps/nexusUI.js"></script>
|
||||
<script type="text/javascript" src="./deps/prism.js"></script>
|
||||
<script type="text/javascript" src="../../Notone.js/build/Notone.GUI.js"></script>
|
||||
<script type="text/javascript" src="./scripts/Interface.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./style/examples.css">
|
||||
<link rel="stylesheet" type="text/css" href="./style/prism.css">
|
||||
|
||||
<script type="text/javascript">
|
||||
// jshint ignore: start
|
||||
|
@ -23,93 +19,142 @@
|
|||
|
||||
</head>
|
||||
<body>
|
||||
<div id="Explanation">
|
||||
Tone.Note
|
||||
<br>
|
||||
<br>
|
||||
Tone.Note lets you to schedule a note on a particular "channel". Then use Tone.Note.route
|
||||
to listen for events on that channel. Multiple notes can be put into a JSON-friendly score
|
||||
which can be parsed using Tone.Note.parseScore(). Take a look at source to see the
|
||||
score format. MIDI files can also be converted to JSON score format using utils/MidiToScore.js.
|
||||
</div>
|
||||
<div id="Content">
|
||||
<div id="LoadingBar"></div>
|
||||
<div id="Rack"></div>
|
||||
<div id="Code"></div>
|
||||
<div id="Title">Scores</div>
|
||||
<div id="Explanation">
|
||||
Scores lets you to schedule a note on a particular "channel". Then use <code>Tone.Note.route</code>
|
||||
to listen for events on that channel. Multiple notes can be put into a JSON-friendly score
|
||||
which can be parsed using <code>Tone.Note.parseScore</code>.
|
||||
<br><br>
|
||||
Take a look at source to see the score format.
|
||||
MIDI files can also be converted to JSON score format using utils/MidiToScore.js.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script id="ToneCode" type="text/javascript">
|
||||
var bass = new Tone.MonoSynth()
|
||||
.toMaster()
|
||||
.setPreset("Bassy");
|
||||
bass.volume.value = -10;
|
||||
/*
|
||||
KICK
|
||||
*/
|
||||
var kick = new Tone.DrumSynth({
|
||||
"envelope" : {
|
||||
"sustain" : 0,
|
||||
"attack" : 0.02,
|
||||
"decay" : 0.8
|
||||
},
|
||||
"octaves" : 10
|
||||
}).toMaster();
|
||||
|
||||
var keys = new Tone.PolySynth(3, Tone.MonoSynth)
|
||||
.toMaster()
|
||||
.setPreset("Pianoetta");
|
||||
keys.volume.value = -30;
|
||||
Tone.Note.route("Kick", function(time){
|
||||
kick.triggerAttackRelease("C2", "8n", time);
|
||||
});
|
||||
|
||||
var kick = new Tone.Player("./audio/505/kick.mp3")
|
||||
.toMaster();
|
||||
/*
|
||||
SNARE
|
||||
*/
|
||||
var snare = new Tone.NoiseSynth().toMaster();
|
||||
|
||||
var snare = new Tone.Player("./audio/505/snare.mp3")
|
||||
.toMaster();
|
||||
Tone.Note.route("Snare", function(time){
|
||||
snare.triggerAttackRelease("8n", time);
|
||||
});
|
||||
|
||||
var hh = new Tone.Player("./audio/505/hh.mp3")
|
||||
.toMaster();
|
||||
|
||||
var Score = {
|
||||
"kick" : ["0", "0:2:2", "0:3:1"],
|
||||
//use any Tone.Time representation or expression
|
||||
"snare" : ["4n*1", "4n*3"],
|
||||
"hh" : ["0*8n", "1*8n", "2*8n", "3*8n", "4*8n", "5*8n", "6*8n", "7*8n"],
|
||||
//if the array is composed of other arrays time is the first value
|
||||
//the rest of the values are given to the callback in order
|
||||
"bass" : [["0:0", "C2", "2n"], ["0:3:2", "C3", "8n"]],
|
||||
"keys" : [["0:0:2", ["E4", "G4", "A4"]], ["0:0:3", ["E4", "G4", "A4"]], ["0:1:3", ["E4", "G4", "A4"]]],
|
||||
};
|
||||
/**
|
||||
* PIANO
|
||||
*/
|
||||
var piano = new Tone.PolySynth(4, Tone.SimpleSynth).toMaster();
|
||||
|
||||
//create events for all of the notes
|
||||
Tone.Note.parseScore(Score);
|
||||
Tone.Note.route("Piano", function(time){
|
||||
piano.triggerAttackRelease(["c4", "e4", "a4"], "8n", time);
|
||||
});
|
||||
|
||||
//route the note channels
|
||||
Tone.Note.route("bass", function(time, note, duration){
|
||||
/*
|
||||
BASS
|
||||
*/
|
||||
var bass = new Tone.MonoSynth({
|
||||
"volume" : -10,
|
||||
"envelope" : {
|
||||
"attack" : 0.1,
|
||||
"decay" : 0.3,
|
||||
"release" : 2,
|
||||
},
|
||||
"filterEnvelope" : {
|
||||
"attack" : 0.01,
|
||||
"decay" : 0.1,
|
||||
"sustain" : 0.5,
|
||||
"min" : 200,
|
||||
"max" : 1200
|
||||
}
|
||||
}).toMaster();
|
||||
|
||||
Tone.Note.route("Bass", function(time, note, duration){
|
||||
bass.triggerAttackRelease(note, duration, time);
|
||||
});
|
||||
Tone.Note.route("keys", function(time, value){
|
||||
var velocity = Math.random() * 0.5 + 0.4;
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
keys.triggerAttackRelease(value[i], "16n", time, velocity);
|
||||
}
|
||||
});
|
||||
Tone.Note.route("kick", function(time){
|
||||
kick.start(time);
|
||||
});
|
||||
Tone.Note.route("snare", function(time){
|
||||
snare.start(time);
|
||||
});
|
||||
Tone.Note.route("hh", function(time){
|
||||
hh.start(time);
|
||||
});
|
||||
|
||||
//setup the transport values
|
||||
Tone.Transport.loopStart = 0;
|
||||
Tone.Transport.loopEnd = "1:0";
|
||||
/**
|
||||
* SCORE
|
||||
*/
|
||||
var Score = {
|
||||
"Kick" : [
|
||||
"0:0", "0:2" ,
|
||||
"1:0", "1:2" ,
|
||||
"2:0", "2:2" ,
|
||||
"3:0", "3:2" ,
|
||||
],
|
||||
"Snare" : [
|
||||
"0:1", "0:3",
|
||||
"1:1", "1:3",
|
||||
"2:1", "2:3",
|
||||
"3:1", "3:3"
|
||||
],
|
||||
"Piano" : [
|
||||
"0:0", "0:0:3",
|
||||
"1:0", "1:0:3",
|
||||
"2:0", "2:0:3",
|
||||
"3:0", "3:0:3"
|
||||
],
|
||||
//additional arguments to the array format are
|
||||
//passed back to the route's callback function
|
||||
"Bass" : [
|
||||
["0:0", "C2", "4n"],
|
||||
["1:0", "F2", "2n"],
|
||||
["2:0", "C2", "4n"],
|
||||
["3:0", "F2", "2n"],
|
||||
]
|
||||
};
|
||||
|
||||
Tone.Note.parseScore(Score);
|
||||
|
||||
Tone.Transport.loop = true;
|
||||
Tone.Transport.bpm.value = 100;
|
||||
Tone.Transport.swing = 0.2;
|
||||
Tone.Transport.bpm.value = 90;
|
||||
Tone.Transport.setLoopPoints(0, "4m");
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
Interface.Loading("LoadingBar");
|
||||
Interface.Rack("Rack", "Transport");
|
||||
Interface.Toggle("Rack", function(on){
|
||||
if (on){
|
||||
Tone.Transport.start();
|
||||
} else {
|
||||
Tone.Transport.stop();
|
||||
}
|
||||
|
||||
$(function(){
|
||||
Notone.config({
|
||||
"search" : false,
|
||||
"expandInDrawer" : true,
|
||||
"hideDrawer" : Interface.isMobile,
|
||||
"drawer" : true,
|
||||
"container" : "body"
|
||||
});
|
||||
|
||||
Notone.add(kick, "Kick");
|
||||
Notone.add(snare, "Snare");
|
||||
Notone.add(bass, "Bass");
|
||||
|
||||
new Interface.Button({
|
||||
key : 32,
|
||||
type : "toggle",
|
||||
text : "Start",
|
||||
activeText : "Stop",
|
||||
start : function(){
|
||||
Tone.Transport.start();
|
||||
},
|
||||
end : function(){
|
||||
Tone.Transport.stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
Interface.Code("Code", "ToneCode");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,33 +1,31 @@
|
|||
var ExampleList = {
|
||||
"Sources" : {
|
||||
"Basic" : {
|
||||
"Oscillators" : "oscillator",
|
||||
"Envelope" : "envelope",
|
||||
"Noise" : "noises",
|
||||
"Player" : "player"
|
||||
},
|
||||
"Components" : {
|
||||
"Envelope" : "envelope",
|
||||
"LFO" : "lfo"
|
||||
},
|
||||
"Signal" : {
|
||||
"Signal Math" : "signalMath",
|
||||
"Instruments" : {
|
||||
"SimpleSynth" : "simpleSynth",
|
||||
"MonoSynth" : "monoSynth",
|
||||
"FMSynth" : "fmSynth",
|
||||
"PolySynth" : "polySynth",
|
||||
},
|
||||
"Effects" : {
|
||||
"AutoPanner" : "autoPanner",
|
||||
"LFO Effects" : "lfoEffects",
|
||||
"PingPongDelay" : "pingPongDelay",
|
||||
"Buses" : "buses",
|
||||
},
|
||||
"Instruments" : {
|
||||
"MonoSynth" : "monoSynth",
|
||||
"DuoSynth" : "duoSynth",
|
||||
"FMSynth" : "fmSynth",
|
||||
},
|
||||
"Timing" : {
|
||||
"Notes / Scores" : "score",
|
||||
"Transport" : "stepSequencer"
|
||||
},
|
||||
"Apps" : {
|
||||
"JSON Sandbox" : "json",
|
||||
"Dots" : "interaction",
|
||||
"Sequencing / Timing" : {
|
||||
"Scores" : "score",
|
||||
"Step Sequencer" : "stepSequencer",
|
||||
"Play Along" : "shiny"
|
||||
},
|
||||
"Signals" : {
|
||||
"Control Voltage" : "signal",
|
||||
"Ramping Values" : "rampTo",
|
||||
},
|
||||
"Advanced" : {
|
||||
"Module Loaders" : "require",
|
||||
},
|
||||
};
|
|
@ -39,7 +39,7 @@ $(function(){
|
|||
.appendTo(element);
|
||||
}
|
||||
//get the master output
|
||||
if (Tone && Tone.Master){
|
||||
if (typeof Tone !== "undefined"){
|
||||
var meter = new Tone.Meter(2);
|
||||
Tone.Master.connect(meter);
|
||||
var meterElement = $("<div>").attr("id", "Meter").appendTo(topbar);
|
||||
|
@ -60,29 +60,26 @@ $(function(){
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
* LOADING INDICATOR
|
||||
*
|
||||
*/
|
||||
Interface.Loader = function(){
|
||||
this.element = $("<div>", {
|
||||
"id" : "Loading",
|
||||
}).appendTo("body");
|
||||
|
||||
Interface.Code = function(container, codeID){
|
||||
Interface.Rack(container, "Code", true);
|
||||
var element = Interface.getElement(container);
|
||||
var codeContainer = $("<code>").addClass("language-javascript Code");
|
||||
element.append(codeContainer);
|
||||
var code = Interface.getElement(codeID);
|
||||
var codeText = code.text();
|
||||
var lines = codeText.split("\n");
|
||||
//remove the same level of indentation for everyone
|
||||
while(lines[1].charAt(0)==="\t"){
|
||||
for (var i = 0; i < lines.length; i++){
|
||||
var line = lines[i];
|
||||
lines[i] = line.substr(1);
|
||||
}
|
||||
}
|
||||
codeText = lines.join("\n");
|
||||
codeContainer.text(codeText);
|
||||
codeContainer.addClass("Code");
|
||||
this.text = $("<div>", {
|
||||
"id" : "Text",
|
||||
"text" : "Loading"
|
||||
}).appendTo(this.element);
|
||||
|
||||
Tone.Buffer.onload = function(){
|
||||
this.element.addClass("Loaded");
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
|
@ -93,7 +90,7 @@ Interface.Dragger = function(params){
|
|||
|
||||
if ($("#DragContainer").length === 0){
|
||||
$("<div>", {
|
||||
"class" : "DragContainer"
|
||||
"id" : "DragContainer"
|
||||
}).appendTo(params.parent || "#Content");
|
||||
}
|
||||
|
||||
|
@ -116,7 +113,7 @@ Interface.Dragger = function(params){
|
|||
/**
|
||||
* the name
|
||||
*/
|
||||
var name = params.name || this.gui ? this.gui.name : "";
|
||||
var name = params.name ? params.name : this.gui.name ? this.gui.name : "";
|
||||
|
||||
/**
|
||||
* elements
|
||||
|
@ -371,12 +368,19 @@ Interface.Button = function(params){
|
|||
|
||||
this.text = params.text || "Button";
|
||||
|
||||
this.type = params.type || "moment";
|
||||
|
||||
this.element = $("<div>", {
|
||||
"class" : "Button",
|
||||
"text" : this.text
|
||||
}).appendTo(params.parent || "#Content")
|
||||
.on("mousedown touchstart", this._start.bind(this))
|
||||
.on("mouseup touchend", this._end.bind(this));
|
||||
.on("mousedown touchstart", this._start.bind(this));
|
||||
|
||||
if (this.type === "moment"){
|
||||
this.element.on("mouseup touchend", this._end.bind(this));
|
||||
} else {
|
||||
this.element.addClass("Toggle");
|
||||
}
|
||||
|
||||
/**
|
||||
* the button state
|
||||
|
@ -395,7 +399,9 @@ Interface.Button = function(params){
|
|||
if (params.key){
|
||||
this.key = params.key;
|
||||
$(window).on("keydown", this._keydown.bind(this));
|
||||
$(window).on("keyup", this._keyup.bind(this));
|
||||
if (this.type === "moment"){
|
||||
$(window).on("keyup", this._keyup.bind(this));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -409,6 +415,8 @@ Interface.Button.prototype._start = function(){
|
|||
if (this.start){
|
||||
this.start();
|
||||
}
|
||||
} else if (this.type === "toggle" && this.active){
|
||||
this._end();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -435,7 +443,4 @@ Interface.Button.prototype._keyup = function(e){
|
|||
e.preventDefault();
|
||||
this._end();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
};
|
7227
examples/scripts/nexusUI.js
Normal file
7227
examples/scripts/nexusUI.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -7,15 +7,11 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
|
||||
<script type="text/javascript" src="../build/Tone.js"></script>
|
||||
<script type="text/javascript" src="../build/Tone.Preset.js"></script>
|
||||
<script type="text/javascript" src="./scripts/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="./deps/qwerty-hancock.js"></script>
|
||||
<script type="text/javascript" src="./deps/nexusUI.js"></script>
|
||||
<script type="text/javascript" src="./deps/prism.js"></script>
|
||||
<script type="text/javascript" src="../../Notone.js/build/Notone.GUI.js"></script>
|
||||
<script type="text/javascript" src="./scripts/Interface.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./style/examples.css">
|
||||
<link rel="stylesheet" type="text/css" href="./style/prism.css">
|
||||
|
||||
<script type="text/javascript">
|
||||
// jshint ignore: start
|
||||
|
@ -23,298 +19,307 @@
|
|||
|
||||
</head>
|
||||
<body>
|
||||
<div id="Explanation">
|
||||
Play Along
|
||||
<br>
|
||||
<br>
|
||||
Touch/Mouse and drag to play along with the probabilistic backtrack. X = pitch, Y = modulation.
|
||||
</div>
|
||||
<div id="Content">
|
||||
<div id="LoadingBar"></div>
|
||||
<div id="Rack"></div>
|
||||
<div id="Title">Play Along</div>
|
||||
<div id="Explanation">
|
||||
Touch/Mouse and drag to play along with the probabilistic backtrack. X = pitch, Y = modulation.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style type="text/css">
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
border: 1px solid black;
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
<script type="text/javascript">
|
||||
|
||||
//DRUMS//
|
||||
|
||||
//and a compressor
|
||||
var drumCompress = new Tone.Compressor({
|
||||
"threshold" : -30,
|
||||
"ratio" : 6,
|
||||
"attack" : 0.3,
|
||||
"release" : 0.1
|
||||
}).toMaster();
|
||||
|
||||
var distortion = new Tone.Distortion({
|
||||
"distortion" : 0.4,
|
||||
"wet" : 0.4
|
||||
});
|
||||
|
||||
//hats
|
||||
var hats = new Tone.Sampler("./audio/505/hh.mp3", {
|
||||
"volume" : -10,
|
||||
"envelope" : {
|
||||
"attack" : 0.001,
|
||||
"decay" : 0.02,
|
||||
"sustain" : 0.01,
|
||||
"release" : 0.01
|
||||
},
|
||||
"filterEnvelope" : {
|
||||
"attack" : 0.001,
|
||||
"decay" : 0.02,
|
||||
"sustain" : 1,
|
||||
"min" : 6000,
|
||||
"max" : 600
|
||||
},
|
||||
"filter" : {
|
||||
"type" : "highpass"
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
}).chain(distortion, drumCompress);
|
||||
|
||||
var loadedCount = 0;
|
||||
function sampleLoaded(){
|
||||
loadedCount++;
|
||||
if (loadedCount == 2){
|
||||
$("#Loading").remove();
|
||||
startButton.enable();
|
||||
}
|
||||
var snare = new Tone.Sampler("./audio/505/snare.mp3", {
|
||||
"envelope" : {
|
||||
"attack" : 0.01,
|
||||
"decay" : 0.05,
|
||||
"sustain" : 0
|
||||
},
|
||||
"filterEnvelope" : {
|
||||
"attack" : 0.001,
|
||||
"decay" : 0.01,
|
||||
"sustain" : 0,
|
||||
"min" : 3000,
|
||||
"max" : 10000
|
||||
},
|
||||
|
||||
}).chain(distortion, drumCompress);
|
||||
|
||||
var kick = new Tone.MonoSynth({
|
||||
"portamento" : 0.00,
|
||||
"oscillator" : {
|
||||
"type" : "square"
|
||||
},
|
||||
"filter" : {
|
||||
"Q" : 2,
|
||||
"type" : "bandpass",
|
||||
"rolloff" : -12
|
||||
},
|
||||
"envelope" : {
|
||||
"attack" : 0.01,
|
||||
"decay" : 0.2,
|
||||
"sustain" : 0.0,
|
||||
"release" : 0.2
|
||||
},
|
||||
"filterEnvelope" : {
|
||||
"attack" : 0.01,
|
||||
"decay" : 0.2,
|
||||
"sustain" : 1,
|
||||
"release" : 0.4,
|
||||
"min" : 3000,
|
||||
"max" : 30
|
||||
}
|
||||
|
||||
//DRUMS//
|
||||
|
||||
//hats
|
||||
var crusher = new Tone.Distortion({
|
||||
"distortion" : 0.4,
|
||||
"wet" : 0.4
|
||||
});
|
||||
var hats = new Tone.Sampler("./audio/505/hh.mp3", {
|
||||
"volume" : -10,
|
||||
"envelope" : {
|
||||
"attack" : 0.001,
|
||||
"decay" : 0.02,
|
||||
"sustain" : 0.01,
|
||||
"release" : 0.01
|
||||
},
|
||||
"filterEnvelope" : {
|
||||
"attack" : 0.001,
|
||||
"decay" : 0.02,
|
||||
"sustain" : 1,
|
||||
"min" : 6000,
|
||||
"max" : 600
|
||||
},
|
||||
"filter" : {
|
||||
"type" : "highpass"
|
||||
}
|
||||
}).connect(crusher);
|
||||
|
||||
var snare = new Tone.Sampler("./audio/505/snare.mp3", {
|
||||
"envelope" : {
|
||||
"attack" : 0.01,
|
||||
"decay" : 0.05,
|
||||
"sustain" : 0
|
||||
},
|
||||
"filterEnvelope" : {
|
||||
"attack" : 0.001,
|
||||
"decay" : 0.01,
|
||||
"sustain" : 0,
|
||||
"min" : 3000,
|
||||
"max" : 10000
|
||||
},
|
||||
|
||||
}).connect(crusher);
|
||||
|
||||
var kick = new Tone.MonoSynth({
|
||||
"portamento" : 0.00,
|
||||
}).connect(drumCompress);
|
||||
|
||||
// BASS
|
||||
var bass = new Tone.SimpleFM({
|
||||
"harmonicity" : 2,
|
||||
"modulationIndex" : 3,
|
||||
"carrier" : {
|
||||
"oscillator" : {
|
||||
"type" : "square"
|
||||
},
|
||||
"envelope" : {
|
||||
"attack" : 0.08,
|
||||
"decay" : 0.3,
|
||||
"sustain" : 0,
|
||||
},
|
||||
},
|
||||
"modulator" : {
|
||||
"oscillator" : {
|
||||
"type" : "sine"
|
||||
},
|
||||
"envelope" : {
|
||||
"attack" : 0.1,
|
||||
"decay" : 0.2,
|
||||
"sustain" : 0.3,
|
||||
"release" : 0.01
|
||||
},
|
||||
}
|
||||
}).toMaster();
|
||||
|
||||
//SYNTH
|
||||
var synth = new Tone.DuoSynth({
|
||||
"vibratoAmount" : 0.5,
|
||||
"vibratoRate" : 5,
|
||||
"portamento" : 0.1,
|
||||
"harmonicity" : 1.005,
|
||||
"volume" : 5,
|
||||
"voice0" : {
|
||||
"volume" : -2,
|
||||
"oscillator" : {
|
||||
"type" : "sawtooth"
|
||||
},
|
||||
"filter" : {
|
||||
"Q" : 1,
|
||||
"type" : "lowpass",
|
||||
"rolloff" : -24
|
||||
},
|
||||
"envelope" : {
|
||||
"attack" : 0.01,
|
||||
"decay" : 0.25,
|
||||
"sustain" : 0.4,
|
||||
"release" : 1.2
|
||||
},
|
||||
"filterEnvelope" : {
|
||||
"attack" : 0.001,
|
||||
"decay" : 0.05,
|
||||
"sustain" : 0.3,
|
||||
"release" : 2,
|
||||
"min" : 100,
|
||||
"max" : 10000
|
||||
}
|
||||
},
|
||||
"voice1" : {
|
||||
"volume" : -10,
|
||||
"oscillator" : {
|
||||
"type" : "sawtooth"
|
||||
},
|
||||
"filter" : {
|
||||
"Q" : 2,
|
||||
"type" : "bandpass",
|
||||
"rolloff" : -12
|
||||
},
|
||||
"envelope" : {
|
||||
"attack" : 0.01,
|
||||
"decay" : 0.2,
|
||||
"sustain" : 0.0,
|
||||
"release" : 0.2
|
||||
"attack" : 0.25,
|
||||
"decay" : 4,
|
||||
"sustain" : 0.1,
|
||||
"release" : 0.8
|
||||
},
|
||||
"filterEnvelope" : {
|
||||
"attack" : 0.01,
|
||||
"decay" : 0.2,
|
||||
"sustain" : 1,
|
||||
"release" : 0.4,
|
||||
"min" : 3000,
|
||||
"max" : 30
|
||||
"attack" : 0.05,
|
||||
"decay" : 0.05,
|
||||
"sustain" : 0.7,
|
||||
"release" : 2,
|
||||
"min" : 5000,
|
||||
"max" : 2000
|
||||
}
|
||||
});
|
||||
|
||||
//an EQ for the kick
|
||||
var eq = new Tone.EQ3(4, -20, 0);
|
||||
kick.connect(eq);
|
||||
|
||||
//and a compressor
|
||||
var drumCompress = new Tone.Compressor({
|
||||
"threshold" : -30,
|
||||
"ratio" : 6,
|
||||
"attack" : 0.01,
|
||||
"release" : 0.01
|
||||
}).toMaster();
|
||||
|
||||
//connections
|
||||
eq.connect(drumCompress);
|
||||
crusher.connect(drumCompress);
|
||||
|
||||
var bass = new Tone.FMSynth({
|
||||
"volume" : -10,
|
||||
"harmonicity" : 1,
|
||||
"modulationIndex" : 0.5,
|
||||
"modulator" : {
|
||||
"filter" : {
|
||||
"type" : "lowpass"
|
||||
}
|
||||
},
|
||||
"carrier" : {
|
||||
"envelope" : {
|
||||
"decay" : 1
|
||||
}
|
||||
}
|
||||
}).toMaster().setPreset("ScratchAttack");
|
||||
|
||||
var synth = new Tone.DuoSynth({
|
||||
"volume" : -10
|
||||
}).toMaster().setPreset("Unicorn");
|
||||
|
||||
// SCORE //
|
||||
|
||||
var synthNotes = ["C2", "E2", "G2", "A2", "C3", "D3", "E3", "G3", "A3", "B3", "C4", "D4", "E4", "G4", "A4", "B4", "C5"];
|
||||
|
||||
//randomly generate a highhat score on each refresh
|
||||
var highHatNotes = [];
|
||||
for (var i = 0; i < 16*4; i++){
|
||||
var probability = (i % 2) === 0 ? 1 : 0.2;
|
||||
highHatNotes.push([i+"*16n", probability]);
|
||||
}
|
||||
|
||||
var Score = {
|
||||
"hats" : highHatNotes,
|
||||
"kick" : [["0", 1],["0:2", 1], ["1:0", 1],["1:2", 1], ["1:3:2", 0.3], ["2:0", 1],["2:2", 1], ["3:0", 1],["3:2", 1], ["3:3:2", 0.5]],
|
||||
"snare" : ["0:1", "0:3", "1:1", "1:3", "2:1", "2:3", "3:1", "3:3"],
|
||||
"bass" : [["0:0", "C2", "4n + 8n", 1], ["0:2", "C2", "8n", 0.5], ["0:2 + 4t", "C2", "8n", 0.2], ["0:2 + 4t*2", "C2", "8n", 0.7],
|
||||
["1:0", "C2", "4n + 8n", 1], ["1:2", "C2", "8n", 0.5], ["1:2 + 4t", "C2", "8n", 0.2], ["1:2 + 4t*2", "E2", "8n", 0.7],
|
||||
["2:0", "F2", "4n + 8n", 1], ["2:2", "F2", "8n", 0.5], ["2:2 + 4t", "F2", "8n", 0.2], ["2:2 + 4t*2", "F2", "8n", 0.7],
|
||||
["3:0", "F2", "4n + 8n", 1], ["3:2", "F2", "8n", 0.5], ["3:2 + 4t", "F2", "8n", 0.2], ["3:2 + 4t*2", "B1", "8n", 0.7]]
|
||||
};
|
||||
//parse the score
|
||||
Tone.Note.parseScore(Score);
|
||||
}).toMaster();
|
||||
|
||||
var globalProbability = 0;
|
||||
var probabilityLFO = 0;
|
||||
// SCORE //
|
||||
|
||||
//modulate the globalProbability with an LFO
|
||||
setInterval(function(){
|
||||
globalProbability = (Math.cos(probabilityLFO + Math.PI) + 1)/2;
|
||||
probabilityLFO += 0.1;
|
||||
}, 1000);
|
||||
var synthNotes = ["C2", "E2", "G2", "A2",
|
||||
"C3", "D3", "E3", "G3", "A3", "B3",
|
||||
"C4", "D4", "E4", "G4", "A4", "B4", "C5"];
|
||||
|
||||
//route note events
|
||||
Tone.Note.route("hats", function(time, probability){
|
||||
if (Math.random() < probability + globalProbability / 2){
|
||||
hats.triggerAttackRelease(0,"8n", time);
|
||||
}
|
||||
});
|
||||
Tone.Note.route("kick", function(time, probability){
|
||||
if (Math.random() < probability + globalProbability){
|
||||
kick.triggerAttack("C2", time);
|
||||
}
|
||||
});
|
||||
Tone.Note.route("snare", function(time){
|
||||
snare.triggerAttack(0, time);
|
||||
});
|
||||
Tone.Note.route("bass", function(time, note, duration, probability){
|
||||
if (Math.random() < probability + globalProbability){
|
||||
bass.triggerAttack(note, time);
|
||||
}
|
||||
});
|
||||
//randomly generate a highhat score on each refresh
|
||||
var highHatNotes = [];
|
||||
for (var i = 0; i < 16*4; i++){
|
||||
var probability = (i % 2) === 0 ? 1 : 0.2;
|
||||
highHatNotes.push([i+"*16n", probability]);
|
||||
}
|
||||
|
||||
//setup the transport looping
|
||||
Tone.Transport.loopStart = 0;
|
||||
Tone.Transport.loopEnd = "4:0";
|
||||
Tone.Transport.loop = true;
|
||||
Tone.Transport.bpm.value = 125;
|
||||
Tone.Transport.swing = 0.2;
|
||||
var Score = {
|
||||
"hats" : highHatNotes,
|
||||
"kick" : [["0", 1],["0:2", 1],
|
||||
["1:0", 1],["1:2", 1], ["1:3:2", 0.3],
|
||||
["2:0", 1],["2:2", 1],
|
||||
["3:0", 1],["3:2", 1], ["3:3:2", 0.5]],
|
||||
"snare" : ["0:1", "0:3",
|
||||
"1:1", "1:3",
|
||||
"2:1", "2:3",
|
||||
"3:1", "3:3"],
|
||||
"bass" : [["0:0", "C2", "4n + 8n", 1], ["0:2", "C2", "8n", 0.5],
|
||||
["0:2 + 4t", "C2", "8n", 0.2], ["0:2 + 4t*2", "C2", "8n", 0.7],
|
||||
["1:0", "C2", "4n + 8n", 1], ["1:2", "C2", "8n", 0.5],
|
||||
["1:2 + 4t", "C2", "8n", 0.2], ["1:2 + 4t*2", "E2", "8n", 0.7],
|
||||
["2:0", "F2", "4n + 8n", 1], ["2:2", "F2", "8n", 0.5],
|
||||
["2:2 + 4t", "F2", "8n", 0.2], ["2:2 + 4t*2", "F2", "8n", 0.7],
|
||||
["3:0", "F2", "4n + 8n", 1], ["3:2", "F2", "8n", 0.5],
|
||||
["3:2 + 4t", "F2", "8n", 0.2], ["3:2 + 4t*2", "B1", "8n", 0.7]]
|
||||
};
|
||||
//parse the score
|
||||
Tone.Note.parseScore(Score);
|
||||
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
|
||||
Interface.Loading("LoadingBar");
|
||||
Interface.Rack("Rack", "Shiny");
|
||||
Interface.Toggle("Rack", function(down){
|
||||
if (down){
|
||||
Tone.Transport.start();
|
||||
} else {
|
||||
Tone.Transport.stop();
|
||||
}
|
||||
});
|
||||
//modulate the globalProbability with an LFO so the probability of all the parts changes over time
|
||||
var globalProbability = 0;
|
||||
var probabilityLFO = 0;
|
||||
setInterval(function(){
|
||||
globalProbability = (Math.cos(probabilityLFO + Math.PI) + 1)/2;
|
||||
probabilityLFO += 0.1;
|
||||
}, 1000);
|
||||
|
||||
//setup the touch interface
|
||||
var content = $("#Rack");
|
||||
var canvas = $("<canvas>").appendTo(content);
|
||||
var context = canvas[0].getContext("2d");
|
||||
var width = canvas.width();
|
||||
var height = canvas.height();
|
||||
context.canvas.width = width;
|
||||
context.canvas.height = height;
|
||||
//route note events
|
||||
Tone.Note.route("hats", function(time, probability){
|
||||
if (Math.random() < probability + globalProbability / 2){
|
||||
hats.triggerAttackRelease(0,"8n", time);
|
||||
}
|
||||
});
|
||||
Tone.Note.route("kick", function(time, probability){
|
||||
if (Math.random() < probability + globalProbability){
|
||||
kick.triggerAttack("C2", time);
|
||||
}
|
||||
});
|
||||
Tone.Note.route("snare", function(time){
|
||||
snare.triggerAttack(0, time);
|
||||
});
|
||||
Tone.Note.route("bass", function(time, note, duration, probability){
|
||||
if (Math.random() < probability + globalProbability){
|
||||
bass.triggerAttack(note, time);
|
||||
}
|
||||
});
|
||||
|
||||
//setup the events
|
||||
var mouseIsDown = false;
|
||||
var circles = [];
|
||||
canvas.on("mousemove touchmove", function(e){
|
||||
if (mouseIsDown){
|
||||
e.preventDefault();
|
||||
getTouchXY(e);
|
||||
//choose the note
|
||||
var normalizedX = Math.min(e.offsetX / width, 0.999);
|
||||
var normalizedY = Math.min(e.offsetY / height, 0.999);
|
||||
var note = synthNotes[Math.floor(normalizedX * synthNotes.length)];
|
||||
synth.setNote(note);
|
||||
//set the vibrato amount
|
||||
synth.vibratoAmount.value = normalizedY * 2;
|
||||
circles.push({
|
||||
x : e.offsetX,
|
||||
y : e.offsetY
|
||||
});
|
||||
}
|
||||
})
|
||||
.on("mousedown touchstart", function(e){
|
||||
mouseIsDown = true;
|
||||
getTouchXY(e);
|
||||
e.preventDefault();
|
||||
var normalizedX = Math.min(e.offsetX / width, 0.999);
|
||||
var note = synthNotes[Math.floor(normalizedX * synthNotes.length)];
|
||||
synth.triggerAttack(note);
|
||||
circles = [];
|
||||
circles.push({
|
||||
x : e.offsetX,
|
||||
y : e.offsetY
|
||||
//setup the transport looping
|
||||
Tone.Transport.setLoopPoints(0, "4m");
|
||||
Tone.Transport.loop = true;
|
||||
Tone.Transport.bpm.value = 125;
|
||||
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
|
||||
$(function(){
|
||||
Notone.config({
|
||||
"search" : false,
|
||||
"expandInDrawer" : true,
|
||||
"hideDrawer" : Interface.isMobile,
|
||||
"drawer" : true,
|
||||
"container" : "body"
|
||||
});
|
||||
})
|
||||
.on("mouseup touchend mouseout", function(){
|
||||
mouseIsDown = false;
|
||||
synth.triggerRelease();
|
||||
context.clearRect(0, 0, width, height);
|
||||
circles = [];
|
||||
});
|
||||
|
||||
function getTouchXY(e){
|
||||
var offset = canvas.offset();
|
||||
if (e.originalEvent.touches){
|
||||
e.offsetX = e.originalEvent.touches[0].pageX - offset.left;
|
||||
e.offsetY = e.originalEvent.touches[0].pageY - offset.top;
|
||||
}
|
||||
}
|
||||
Notone.add(synth, "Synth Lead");
|
||||
Notone.add(bass, "Bass");
|
||||
Notone.add(distortion, "Distortion");
|
||||
Notone.add(drumCompress, "Drum Compressor");
|
||||
|
||||
setInterval(function(){
|
||||
if (circles.length === 0){
|
||||
return;
|
||||
}
|
||||
//draw the points
|
||||
context.clearRect(0, 0, width, height);
|
||||
context.strokeStyle = "#D76767";
|
||||
context.lineWidth = 2;
|
||||
var twoPi = Math.PI * 2;
|
||||
if (circles.length > 1){
|
||||
circles.shift();
|
||||
for (var i = 0, len = circles.length; i < len; i++){
|
||||
var circle = circles[i];
|
||||
context.beginPath();
|
||||
var radius = (i / (len - 1)) * 30 + 1;
|
||||
context.arc(circle.x, circle.y, radius, 0, twoPi, false);
|
||||
context.stroke();
|
||||
new Interface.Button({
|
||||
key : 32,
|
||||
type : "toggle",
|
||||
text : "Start",
|
||||
activeText : "Stop",
|
||||
start : function(){
|
||||
Tone.Transport.start();
|
||||
},
|
||||
end : function(){
|
||||
Tone.Transport.stop();
|
||||
}
|
||||
} else if (circles.length === 1){
|
||||
var circle = circles[0];
|
||||
context.beginPath();
|
||||
var radius = 30;
|
||||
context.arc(circle.x, circle.y, radius, 0, twoPi, false);
|
||||
context.stroke();
|
||||
}
|
||||
}, 20);
|
||||
});
|
||||
|
||||
var lastSynthNote = synthNotes[0];
|
||||
new Interface.Dragger({
|
||||
// container : "#Content",
|
||||
x : {
|
||||
options : synthNotes,
|
||||
drag : function(note){
|
||||
synth.setNote(note);
|
||||
lastSynthNote = note;
|
||||
}
|
||||
},
|
||||
y : {
|
||||
min : 0,
|
||||
max : 2,
|
||||
drag : function(val){
|
||||
synth.vibratoAmount.value = val;
|
||||
}
|
||||
},
|
||||
start : function(){
|
||||
synth.triggerAttack(lastSynthNote);
|
||||
},
|
||||
end : function(){
|
||||
synth.triggerRelease();
|
||||
},
|
||||
name : "Synth"
|
||||
});
|
||||
|
||||
new Interface.Loader();
|
||||
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -32,7 +32,6 @@
|
|||
signal value and applies the results of those mappings
|
||||
to the frequency attribute of 3 sawtooth oscillators.
|
||||
</div>
|
||||
<div id="DragContainer"></div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
//initially muted
|
||||
|
|
|
@ -7,15 +7,12 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
|
||||
<script type="text/javascript" src="../build/Tone.js"></script>
|
||||
<script type="text/javascript" src="../build/Tone.Preset.js"></script>
|
||||
<script type="text/javascript" src="./scripts/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="./deps/qwerty-hancock.js"></script>
|
||||
<script type="text/javascript" src="./deps/nexusUI.js"></script>
|
||||
<script type="text/javascript" src="./deps/prism.js"></script>
|
||||
<script type="text/javascript" src="../../Notone.js/build/Notone.GUI.js"></script>
|
||||
<script type="text/javascript" src="./scripts/Interface.js"></script>
|
||||
<script type="text/javascript" src="./scripts/nexusUI.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./style/examples.css">
|
||||
<link rel="stylesheet" type="text/css" href="./style/prism.css">
|
||||
|
||||
<script type="text/javascript">
|
||||
// jshint ignore: start
|
||||
|
@ -24,26 +21,21 @@
|
|||
</head>
|
||||
<body>
|
||||
<style type="text/css">
|
||||
|
||||
canvas {
|
||||
margin-top: 3px;
|
||||
}
|
||||
</style>
|
||||
<div id="Explanation">
|
||||
Tone.Transport
|
||||
<br>
|
||||
<br>
|
||||
Tone.Transport is the application-wide timekeeper. It uses an OscillatorNode
|
||||
as it's clock source which enables sample-accurate scheduling as well as
|
||||
tempo-curves and automation. This example uses Tone.Transport.setInterval
|
||||
to invoke a callback every 16th note.
|
||||
</div>
|
||||
<div id="Content">
|
||||
<div id="LoadingBar"></div>
|
||||
<div id="Controls"></div>
|
||||
<div id="Rack">
|
||||
|
||||
<div id="Content" class="FullScreen">
|
||||
<div id="Title">Tone.Transport</div>
|
||||
<div id="Explanation">
|
||||
Tone.Transport is the application-wide timekeeper. It uses an OscillatorNode
|
||||
as it's clock source which enables sample-accurate scheduling as well as
|
||||
tempo-curves and automation. This example uses Tone.Transport.setInterval
|
||||
to invoke a callback every 16th note.
|
||||
</div>
|
||||
<div id="Code"></div>
|
||||
</div>
|
||||
<script id="ToneCode" type="text/javascript">
|
||||
<canvas nx="matrix"></canvas>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
//setup a polyphonic sampler
|
||||
var keys = new Tone.PolySynth(4, Tone.Sampler, {
|
||||
"A" : "./audio/casio/A1.mp3",
|
||||
|
@ -79,19 +71,45 @@
|
|||
Tone.Transport.loop = true;
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
Interface.Loading("LoadingBar");
|
||||
Interface.Rack("Rack", "Step Sequencer");
|
||||
Interface.StepSequencer("Rack", 32, 8).randomize();
|
||||
Interface.Slider("Rack", Tone.Transport, "bpm", 100, 150);
|
||||
Interface.Toggle("Rack", function(on){
|
||||
if (on){
|
||||
Tone.Transport.start();
|
||||
} else {
|
||||
Tone.Transport.stop();
|
||||
}
|
||||
});
|
||||
Interface.Code("Code", "ToneCode");
|
||||
nx.onload = function(){
|
||||
nx.colorize("#f5871f");
|
||||
|
||||
matrix1.col = 16;
|
||||
matrix1.init();
|
||||
matrix1.resize($("#Content").width(), 250);
|
||||
matrix1.draw();
|
||||
}
|
||||
|
||||
$(function(){
|
||||
|
||||
new Interface.Slider({
|
||||
name : "BPM",
|
||||
min : 80,
|
||||
max : 200,
|
||||
value : Tone.Transport.bpm.value,
|
||||
drag : function(val){
|
||||
Tone.Transport.bpm.value = val;
|
||||
}
|
||||
});
|
||||
|
||||
new Interface.Button({
|
||||
text : "Start",
|
||||
activeText : "Stop",
|
||||
type : "toggle",
|
||||
key : 32, //spacebar
|
||||
start : function(){
|
||||
Tone.Transport.start();
|
||||
},
|
||||
end : function(){
|
||||
Tone.Transport.stop();
|
||||
},
|
||||
});
|
||||
|
||||
$(window).on("resize", function(){
|
||||
matrix1.resize($("#Content").width(), 250);
|
||||
matrix1.draw();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -145,16 +145,22 @@ html, body {
|
|||
border: 3px solid black;
|
||||
border-top-width: 0px;
|
||||
width: 100%; }
|
||||
#Content #Explanation a {
|
||||
color: black;
|
||||
font-family: monospace;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-decoration: none; }
|
||||
#Content #Explanation a:hover {
|
||||
color: #1EDF3E; }
|
||||
#Content #Explanation a:hover:active {
|
||||
color: #ED33CF; }
|
||||
#Content #Explanation img {
|
||||
width: 80%;
|
||||
max-width: 700px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block; }
|
||||
#Content a {
|
||||
color: black;
|
||||
font-family: monospace;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-decoration: none; }
|
||||
#Content a:hover {
|
||||
color: #1EDF3E; }
|
||||
#Content a:hover:active {
|
||||
color: #ED33CF; }
|
||||
#Content #DragContainer {
|
||||
margin-left: 3px;
|
||||
margin-top: 3px;
|
||||
|
@ -231,6 +237,53 @@ html, body {
|
|||
#Content .Button:hover {
|
||||
color: white;
|
||||
background-color: #3833ED; }
|
||||
#Content .Button.Active {
|
||||
#Content .Button:hover:active, #Content .Button:hover:active.Active {
|
||||
color: #22DBC0;
|
||||
background-color: #ED33CF; }
|
||||
#Content .Button.Toggle.Active {
|
||||
box-sizing: border-box;
|
||||
border: 3px solid black;
|
||||
line-height: 84px;
|
||||
color: black;
|
||||
background-color: white; }
|
||||
|
||||
#Content.FullScreen {
|
||||
width: calc(100% - 6px) !important;
|
||||
max-width: calc(100% - 6px) !important; }
|
||||
|
||||
#Keyboard {
|
||||
margin: 3px !important; }
|
||||
|
||||
code {
|
||||
background-color: #ECECEC;
|
||||
color: #8C8C8C;
|
||||
padding: 1px; }
|
||||
|
||||
#Loading {
|
||||
font-family: monospace;
|
||||
z-index: 100000;
|
||||
position: absolute;
|
||||
background-color: rgba(140, 140, 140, 0.5);
|
||||
width: 100%;
|
||||
height: calc(100% - 37.5px);
|
||||
top: 37.5px;
|
||||
left: 0px;
|
||||
opacity: 1;
|
||||
-webkit-transition: opacity 0.4s;
|
||||
transition: opacity 0.4s; }
|
||||
#Loading #Text {
|
||||
color: white;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 300px;
|
||||
margin-left: -150px;
|
||||
height: 60px;
|
||||
margin-top: -30px;
|
||||
line-height: 60px;
|
||||
font-size: 42px; }
|
||||
|
||||
#Loading.Loaded {
|
||||
pointer-events: none;
|
||||
opacity: 0; }
|
||||
|
|
Loading…
Reference in a new issue