Skip to content

Commit 0f8d36f

Browse files
committed
Merge pull request #96 from processing/newTone
envelope improvements
2 parents fbe35c5 + 5a6b23e commit 0f8d36f

File tree

27 files changed

+3364
-757
lines changed

27 files changed

+3364
-757
lines changed

Gruntfile.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ module.exports = function(grunt) {
7070
include: ['src/app'],
7171
onBuildWrite: function( name, path, contents ) {
7272
if (path.indexOf('node_modules/tone/') > -1) {
73-
return '/** Tone.js module by Yotam Mann, MIT License 2014 http://opensource.org/licenses/MIT **/\n' +
73+
return '/** Tone.js module by Yotam Mann, MIT License 2016 http://opensource.org/licenses/MIT **/\n' +
7474
require('amdclean').clean({
7575
'code': contents.replace(/console.log(.*);/g, ''),
7676
'escodegen': {
@@ -103,6 +103,7 @@ module.exports = function(grunt) {
103103
out: 'lib/p5.sound.js',
104104
paths: {
105105
'Tone' : 'node_modules/tone/Tone',
106+
'automation-timeline': 'node_modules/web-audio-automation-timeline/build/automation-timeline-amd',
106107
'panner' : 'src/panner',
107108
'sndcore': 'src/sndcore',
108109
'master': 'src/master',

examples/DelayNoiseEnvelope/sketch.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ function setup() {
2222
delay = new p5.Delay();
2323
delay.process(noise, .12, .7, 2300); // tell delay to process noise
2424

25-
// the Env accepts time / value pairs to
26-
// create a series of timed fades
27-
env = new p5.Env(.01, 1, .2, .1);
25+
// the Env ADSR: attackTime, decayTime, sustainLevel, releaseTime
26+
env = new p5.Env();
27+
env.setADSR(0.01, 0.2, 0.2, 0.1)
28+
env.setRange(1, 0);
2829

2930
// p5.Amplitude will analyze all sound in the sketch
3031
analyzer = new p5.Amplitude();
@@ -52,5 +53,5 @@ function draw() {
5253
}
5354

5455
function mousePressed() {
55-
env.play(noise);
56+
env.play(noise, 0, 0.1, 0);
5657
}
Binary file not shown.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>bells_envelope_test</title>
6+
<script language="javascript" type="text/javascript" src="../../lib/p5.js"></script>
7+
<script language="javascript" type="text/javascript" src="../../lib/addons/p5.dom.js"></script>
8+
<script language="javascript" type="text/javascript" src="../../lib/p5.sound.js"></script>
9+
10+
<script src="sketch.js" type="text/javascript"></script>
11+
12+
<style> body {padding: 0; margin: 0;} canvas {vertical-align: top;} </style>
13+
</head>
14+
<body>
15+
</body>
16+
</html>
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
2+
// This example shows a more complex use of the .ramp function for the envelope.
3+
// You can use it to make a simple attack/decay envelope for struck or plucked style notes.
4+
// Here, we're creating synthetic bells using additive synthesis, and triggering each of their attacks and decays differently to make different harmonics last for different times.
5+
// Have fun! - Jeff Snyder
6+
var osc = [];
7+
var envelope = [];
8+
var fft;
9+
var myPhraseAttack, myPhraseRelease, myPart;
10+
var atPattern = [1, 1,1,1,0,1,1,1,1,0,0,0,0]; // this rhythmic pattern puts some rests in there
11+
var patternArray = [0,1,2,3,3,2,0,1]; // pattern of the notes (in terms of array indices from scaleArray)
12+
var scaleArray = [64, 60, 62, 55]; // classic bell tune
13+
var harmonicsArray = [.5, 1., 1.183, 1.506, 2., 2.514, 2.662, 3.011, 4.166, 5.433, 6.796, 8.215]; // bell partials taken from https://en.wikipedia.org/wiki/Strike_tone
14+
var idealArray = [.5, 1., 1.2, 1.5, 2, 2.5, 2.6667, 3.0, 4.0, 5.3333, 6.6667, 8.0]; // ideal bell partials
15+
var note = 0;
16+
var startPoint = 0;
17+
var endPoint = 0;
18+
var numWaveforms = 100;
19+
var numOsc = 12; // reduce this to reduce the number of overtones, 4 makes a nice, dark gamelan sound
20+
var numNotes = 4;
21+
var rawImpulse;
22+
var cVerb;
23+
var oscVols = [];
24+
var firstNote = 1;
25+
var pitchRatio = .8; //change this to transpose things around
26+
var pitchDeviation = .001;
27+
var idealOrReal = 0; // change this to 1 to change to an ideal bell instead of a measured bell
28+
var maxAttack = .001; // in seconds ... setting to .001 makes things very percussive, setting to > 1 makes them sound far away
29+
var maxDecay = 9.0; // in seconds ... short times make for deader bells
30+
var percentWashed = 0.0;
31+
var washedMax = 4;
32+
33+
34+
function preload()
35+
{
36+
// create a p5.Convolver
37+
cVerb = createConvolver('assets/LadyChapelStAlbansCathedral.wav');
38+
39+
}
40+
41+
function setup()
42+
{
43+
createCanvas(1000, 400);
44+
rawImpulse = loadSound('assets/' + cVerb.impulses[0].name);
45+
46+
for (var i = 0; i < numNotes; i++)
47+
{
48+
// make the arrays into 2D arrays
49+
osc[i] = [];
50+
envelope[i] = [];
51+
oscVols[i] = [];
52+
var midiValue = scaleArray[i];
53+
var freqValue = midiToFreq(midiValue);
54+
55+
for(var j = 0; j < numOsc; j++)
56+
{
57+
// make arrays of sine waves for each note, additive synthesis, and assign independent envelopes, amplitudes, and slight detunings for each harmonic
58+
osc[i][j] = new p5.SinOsc();
59+
envelope[i][j] = new p5.Env();
60+
if (random(0, 1) > percentWashed)
61+
{
62+
myMaxAttack = maxAttack;
63+
print("normal");
64+
}
65+
else
66+
{
67+
myMaxAttack = washedMax;
68+
print("washed");
69+
}
70+
envelope[i][j].setADSR(random(.001, myMaxAttack), random(.01, maxDecay)); // turning sustain level to 0. makes an AD envelope
71+
osc[i][j].amp(0.);
72+
oscVols[i][j] = random(.01, .3);
73+
if (idealOrReal == 0)
74+
{
75+
var myOvertone = harmonicsArray[j];
76+
}
77+
else
78+
{
79+
var myOvertone = idealArray[j];
80+
}
81+
osc[i][j].freq(freqValue * harmonicsArray[j] * random(1.0 - pitchDeviation, 1 + pitchDeviation) * pitchRatio);
82+
osc[i][j].start();
83+
osc[i][j].disconnect();
84+
//put 'em through that reverb, ahhhhhh yeah it's like a New Age in here
85+
cVerb.process(osc[i][j]);
86+
}
87+
}
88+
myPhraseAttack = new p5.Phrase('testerAttack', makeSoundAttack, atPattern);
89+
myPart = new p5.Part();
90+
myPart.addPhrase(myPhraseAttack);
91+
myPart.setBPM(15); // super slow because it's in 16th notes
92+
myPart.loop();
93+
myPart.start();
94+
fft = new p5.FFT(); // for the drawing of the waveform (just using the buffer part)
95+
endPoint = width / numWaveforms; // for the drawing
96+
background(20);
97+
}
98+
99+
function draw()
100+
{
101+
background(0, 0, 0, 9); //to make the trails fade like on a scope :)
102+
var waveform = fft.waveform(); // analyze the waveform
103+
fft.analyze();
104+
beginShape();
105+
noFill();
106+
stroke(fft.getEnergy("bass") * 2.0, fft.getEnergy("mid")* 2.0, fft.getEnergy("treble") * 2.0); // the (* 2.0) is just to make the colors a little brighter
107+
for (var i = 0; i < waveform.length; i++)
108+
{
109+
var x = map(i, 0, waveform.length, startPoint, endPoint);
110+
var y = map(waveform[i], -.9, .9, height, 0);
111+
vertex(x, y);
112+
}
113+
endShape();
114+
startPoint = endPoint + 1;
115+
endPoint += (width / numWaveforms);
116+
if (endPoint > width)
117+
{
118+
redrawWaveform();
119+
}
120+
}
121+
122+
function makeSoundAttack(time, playbackRate)
123+
{
124+
var whichNote = patternArray[note];
125+
for (var i = 0; i < numOsc; i++)
126+
{
127+
envelope[whichNote][i].ramp(osc[whichNote][i], time, (oscVols[whichNote][i] * random(.8, 1.0)), 0); // the added randomness just makes each strike a little different.
128+
}
129+
note = (note + 1) % patternArray.length;
130+
if (firstNote == 1)
131+
{
132+
setTimeout(redrawWaveform, time * 1000.0); // just so the drawing display starts at the left on the first note
133+
}
134+
firstNote = 0;
135+
}
136+
137+
138+
function redrawWaveform()
139+
{
140+
startPoint = 0;
141+
endPoint = (width / numWaveforms);
142+
}

examples/envAmpFreq/index.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!doctype html>
2+
<head>
3+
<script language="javascript" type="text/javascript" src="../../lib/p5.js"></script>
4+
5+
<script language="javascript" type="text/javascript" src="../../lib/addons/p5.dom.js"></script>
6+
7+
<script language="javascript" type="text/javascript" src="../../lib/p5.sound.js"></script>
8+
9+
<script language="javascript" type="text/javascript" src="sketch.js"></script>
10+
11+
</head>
12+
13+
<body>
14+
click to trigger amplitude and frequency envelopes
15+
16+
</body>

examples/envAmpFreq/sketch.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Control the level of an envelope
3+
*/
4+
5+
var env; // this is the env
6+
var osc; // this oscillator will modulate the amplitude of the carrier
7+
var freqEnv; // env for frequency
8+
9+
function setup() {
10+
env = new p5.Env();
11+
env.setADSR(0.01, 0.2, 0.2, 0.3);
12+
env.setRange(0, 1);
13+
14+
freqEnv = new p5.Env();
15+
freqEnv.setADSR(0.01, 0.2, 0.2, 0.3);
16+
freqEnv.setRange(300, 5000);
17+
18+
19+
osc = new p5.Oscillator(); // connects to master output by default
20+
osc.start(0);
21+
osc.freq(220);
22+
// osc.freq(env.scale(0,1,800,300));
23+
osc.freq(freqEnv);
24+
osc.amp(env);
25+
}
26+
27+
function mousePressed() {
28+
env.triggerAttack();
29+
freqEnv.triggerAttack();
30+
}
31+
32+
function mouseReleased() {
33+
env.triggerRelease();
34+
freqEnv.triggerRelease();
35+
}
File renamed without changes.

examples/envExp/sketch.js

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/**
2+
* @name Note Envelope
3+
* @description <p>An Envelope is a series of fades, defined
4+
* as time / value pairs. In this example, the envelope
5+
* will be used to "play" a note by controlling the output
6+
* amplitude of an oscillator.<br/><br/>
7+
* The p5.Oscillator sends its output through
8+
* an internal Web Audio GainNode (p5.Oscillator.output).
9+
* By default, that node has a constant value of 0.5. It can
10+
* be reset with the osc.amp() method. Or, in this example, an
11+
* Envelope takes control of that node, turning the amplitude
12+
* up and down like a volume knob.</p>
13+
* <p><em><span class="small"> To run this example locally, you will need the
14+
* <a href="http://p5js.org/reference/#/libraries/p5.sound">p5.sound library</a> and a
15+
* sound file.</span></em></p>
16+
*/
17+
var osc, envelope, fft;
18+
var myPhraseAttack, myPhraseRelease, myPart;
19+
var atPattern = [1, 0];
20+
var relPattern = [0, 1];
21+
var scaleArray = [60, 62, 64, 65, 67, 69, 71, 72];
22+
var note = 0;
23+
var expOrNot = 1;
24+
var startPoint = 0;
25+
var endPoint = 0;
26+
var numWaveforms = 50;
27+
28+
var audioContext;
29+
30+
function setup() {
31+
createCanvas(710, 200);
32+
osc = new p5.SinOsc();
33+
34+
audioContext = getAudioContext();
35+
36+
// Instantiate the envelope with time / value pairs
37+
envelope = new p5.Env(0.1, 0.5, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0);
38+
osc.amp(0.);
39+
osc.start();
40+
myPhraseAttack = new p5.Phrase('testerAttack', makeSoundAttack, atPattern);
41+
myPhraseRelease = new p5.Phrase('testerRelease', makeSoundRelease, relPattern);
42+
myPart = new p5.Part();
43+
myPart.addPhrase(myPhraseAttack);
44+
//myPart.addPhrase(myPhraseRelease);
45+
myPart.setBPM(120);
46+
myPart.loop();
47+
myPart.start();
48+
fft = new p5.FFT();
49+
fft.setInput(osc);
50+
masterVolume(0);
51+
endPoint = width / numWaveforms;
52+
noStroke();
53+
background(20);
54+
}
55+
56+
function draw() {
57+
58+
var waveform = fft.waveform(); // analyze the waveform
59+
beginShape();
60+
strokeWeight(5);
61+
for (var i = 0; i < waveform.length; i++){
62+
var x = map(i, 0, waveform.length, startPoint, endPoint);
63+
var y = map(waveform[i], -1, 1, height, 0);
64+
vertex(x, y);
65+
}
66+
endShape();
67+
startPoint = endPoint + 1;
68+
endPoint += (width / numWaveforms);
69+
if (endPoint > width)
70+
{
71+
background(20);
72+
startPoint = 0;
73+
endPoint = (width / numWaveforms);
74+
}
75+
76+
77+
}
78+
79+
80+
function makeSoundAttack(time, playbackRate)
81+
{
82+
var midiValue = scaleArray[note];
83+
var freqValue = midiToFreq(midiValue);
84+
85+
if (note == 0)
86+
{
87+
// if (expOrNot == 0)
88+
// {
89+
// envelope.setExp(true);
90+
// expOrNot = 1;
91+
// }
92+
// else
93+
// {
94+
// envelope.setExp(false);
95+
// expOrNot = 0;
96+
// }
97+
}
98+
99+
osc.freq(freqValue * 2, 0, time);
100+
// envelope.play(osc, time);
101+
envelope.triggerAttack(osc, time);
102+
//envelope.triggerRelease(osc);
103+
note = (note + 1) % scaleArray.length;
104+
setTimeout(redrawWaveform, time * 1000.0);
105+
106+
}
107+
108+
function makeSoundRelease(time, playbackRate)
109+
{
110+
envelope.triggerRelease(osc, time);
111+
}
112+
113+
function redrawWaveform()
114+
{
115+
background(20);
116+
startPoint = 0;
117+
endPoint = (width / numWaveforms);
118+
}

examples/envSignalMath/sketch.js

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)