Skip to content

Commit 0222a92

Browse files
committed
added this fun bell example to show the use of the rampAD function
1 parent 9fcb678 commit 0222a92

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed
Binary file not shown.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>bells_envelope_test</title>
6+
<script src="libraries/p5.js" type="text/javascript"></script>
7+
8+
<script src="libraries/p5.dom.js" type="text/javascript"></script>
9+
<script src="libraries/p5.sound.js" type="text/javascript"></script>
10+
11+
<script src="sketch.js" type="text/javascript"></script>
12+
13+
<style> body {padding: 0; margin: 0;} canvas {vertical-align: top;} </style>
14+
</head>
15+
<body>
16+
</body>
17+
</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 .rampAD 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+
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].setRampAD(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].rampAD(osc[whichNote][i], time, (oscVols[whichNote][i] * random(.8, 1.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+
}

0 commit comments

Comments
 (0)