P5.js en geluid
Je kunt in P5.js naast veel visuele dingen ook met geluid werken, wel zo interessant voor Muziektechnologen. Bij P5.js is een extra bibliotheek met geluidsobjecten toegevoegd. Een aantal daarvan zullen hieronder behandeld worden. Meer informatie hierover is te vinden in de reference van P5.js
makeNote
Om snel gebruik te kunnen maken van geluid hebben we een extra functie toegevoegd aan P5.js
makeNote gebruiken
makeNote is een functie die een noot afspeelt in een gegeven frequentie, amplitude en duur.
je kunt drie argumenten invullen:
- frequentie in midi-noot,
- amplitude tussen de 0. en 1.
- duur in milliseconden
voorbeeld: makeNote(60, 0.5, 100) //een c op half volume met een duur van 100 miliseconden.
let op: omdat browsers ervoor zorgen dat geluiden niet zomaar automatisch afgespeeld kunnen worden zal je eerst in het canvas moeten klikken voordat er geluid afspeelt.
uitgebreider voorbeeld:
function setup () {
createCanvas(800, 600);
background(255);
}
function draw () {
// hier gebeurt in prinicpe niets.
}
function mousePressed () {
makeNote(random(48, 72), random(0.1, 0.6), random(10, 500));
// speelt een willekeurige noot af elke keer als je klikt
// willekeurige toonhoogte tussen midinoot 48 en 72
// willekeurige amplitude tussen 0.1 en 0.6
// willekeurige duur tussen 10 en 500 miliseconden
}
P5.js Sound basics
In de basis werken onderstaande objecten allemaal hetzelfde:
- Je maakt globaal, dus boven de
setup()
- endraw()
-functie een variabele aan om het geluidsobject in op te slaan - In de
setup()
-functie maak je in deze variabele een nieuw object aan. - Vervolgens pas je optioneel al enkele parameters aan met behulp van methods (functies voor een object)
- Het verdere aanpassen of afspelen gebeurt op de plek waar je dat wil; na een druk op een toets, een muisklik of nadat een sequencer een stap heeft gemaakt.
P5.js Sound maakt gebruik van het concept classes en objecten, meer daarover is te vinden in het aparte hoofdstuk in de syllabus
Dit betekent dat je elk p5.Sound-object op dezelfde manier aanmaakt:
let obj;
function setup() {
obj = new p5.Object();
}
dus in het geval van een oscillator:
let osc;
function setup() {
osc = new p5.Oscillator();
}
Let er daarbij op dat p5 met kleine letters is en de eerste letter van het object met een hoofdletter.
Oscillator
De oscillator is een van de belangrijkste bouwblokken van een P5.js synth.
Je kan met de ingebouwde oscillator kiezen uit een aantal golfvormen:
- sinus (sine)
- driehoek (triangle)
- zaagtand (sawtooth)
- blokgolf (square)
Verder kan je de frequentie, amplitude en fase aanpassen.
Hieronder een voorbeeld hoe je een oscillator maakt
let osc;
function setup() {
createCanvas(800,600);
background(255);
//maak een nieuw oscillator-object
osc = new p5.Oscillator();
//pas amplitude, frequentie en type aan
osc.amp(0.5);
osc.freq(220);
osc.setType('sawtooth');
}
function draw() {
}
function mousePressed() {
//start afspelen van de oscillator
osc.start();
}
function mouseReleased() {
//stop afspelen van de oscillator
osc.stop();
}
Envelope
Door een envelope op een oscillator te zetten kan je het verloop van de klank beΓ―nvloeden. Een envelope in P5.js Sound werkt op twee verschillende manieren:
- als ADSR waarbij alleen de hele envelope aangestuurd kan worden (met
play()
) - als ADSR waarbij de attack en de release apart aangestuurd kunnen worden. (met
triggerAttack()
entriggerRelease()
)
In beide gevallen kan je de volgende parameters meegeven:
- attack-tijd (in seconden)
- decay-tijd (in seconden)
- sustain-level (0. - 1.)
- release-tijd (in seconden)
hieronder een voorbeeld om de envelope 1x af te laten spelen bij en muisklik:
let osc;
let env;
function setup() {
createCanvas(800,600);
background(255);
//maak een oscillator en pas parameters aan
osc = new p5.Oscillator();
osc.setType('sawtooth');
osc.freq(220);
//maak een envelope en pas adsr-parameters aan
env = new p5.Envelope();
env.setADSR(1,0.1,0.5,1);
// zorg dat de envelope over het volume van de oscillator gaat
osc.amp(env);
}
function draw() {
}
function mousePressed() {
//speel oscillator en envelope af
osc.start();
env.play();
}
en hieronder een voorbeeld waarbij de envelope sustained zolang je de muis ingedrukt houdt.
let osc;
let env;
function setup() {
createCanvas(800,600);
background(255);
//maak een oscillator en pas parameters aan
osc = new p5.Oscillator();
osc.setType('sawtooth');
osc.freq(220);
//maak een envelope en pas adsr-parameters aan
env = new p5.Envelope();
env.setADSR(1,0.1,0.5,1);
// zorg dat de envelope over het volume van de oscillator gaat
osc.amp(env);
}
function draw() {
}
function mousePressed() {
//start oscillator en attack-deel van de envelope
osc.start();
env.triggerAttack();
}
function mouseReleased() {
//start het release-deel van de envelope
env.triggerRelease()
}
Filter
Een filter toevoegen aan je geluid kan met behulp van drie verschillende objecten:
p5.LowPass
p5.BandPass
p5.HighPass
instelbare parameters zijn:
- cutoff frequentie (
freq()
, 0 - 24000) - resonance (
res()
, 0.001 - 1000) - gain (
gain()
, 0. - 1.)
Met behulp van de functies connect()
en disconnect()
kan je oscillators koppelen aan een filter.
Daarbij is het belangrijk dat je eerst disconnect()
gebruikt om je oscillator los te koppen van de oorspronkelijke output (de speakers) en vervolgens de koppeling te maken met het filter.
Zie hieronder voor een voorbeeld:
let osc;
let env;
let lpf;
function setup() {
createCanvas(800,600);
background(255);
//maak een oscillator en pas parameters aan
osc = new p5.Oscillator();
osc.setType('sawtooth');
osc.freq(220);
//maak een envelope en pas adsr-parameters aan
env = new p5.Envelope();
env.setADSR(1,0.1,0.5,1);
// zorg dat de envelope over het volume van de oscillator gaat
osc.amp(env);
//maak een filter aan
lpf = new p5.LowPass();
lpf.freq(220);
lpf.res(0.5);
//koppel oscillator los van speakers
//en verbind aan het filter
osc.disconnect();
osc.connect(lpf);
}
function draw() {
}
function mousePressed() {
//speel oscillator en envelope af
osc.start();
env.triggerAttack();
}
function mouseReleased() {
env.triggerRelease()
}
Delay
Een delay toevoegen werkt min of meer hetzelfde als het toevoegen van een filter. Je maakt een delay-object en koppelt dit aan het object waar je het aan wil koppelen.
Parameters die te gebruiken zijn met de een delay zijn:
- delaytijd (
delayTime()
, in seconden, max 1.) - feedback (
feedback()
, 0. - 1.) - filter (
filter()
, cutofffrequentie van lpf op de delay)
Een voorbeeld van toegepaste delay staat hieronder:
let osc;
let env;
let lpf;
let delay;
function setup() {
createCanvas(800,600);
background(255);
//maak een oscillator en pas parameters aan
osc = new p5.Oscillator();
osc.setType('sawtooth');
osc.freq(220);
//maak een envelope en pas adsr-parameters aan
env = new p5.Envelope();
env.setADSR(1,0.1,0.5,1);
// zorg dat de envelope over het volume van de oscillator gaat
osc.amp(env);
//maak een filter aan
lpf = new p5.LowPass();
lpf.freq(220);
lpf.res(0.5);
//koppel oscillator los van speakers
//en verbind aan het filter
osc.disconnect();
osc.connect(lpf);
//maak een delay aan en bepaal delaytijd en feedback
delay = new p5.Delay();
delay.delayTime(0.5);
delay.feedback(0.5);
//koppel het filter aan de delay
lpf.disconnect();
lpf.connect(delay);
}
function draw() {
}
function mousePressed() {
//speel oscillator en envelope af
osc.start();
env.triggerAttack();
}
function mouseReleased() {
env.triggerRelease()
}
Reverb
Reverb werkt net anders dan delay en filter. Hierbij connect je niet de reverb aan een ander object, maar gebruik je process()
om de reverb toe te passen