p5.jsでシンセサイザーを作る 第16話 p5.sound 発音のバグを探す!なおす!
Javascriptとp5.jsを使って、オリジナルなシンセサイザーを作るプログラミングの記事です。とりあえず何を作るのかを手っ取り早くお伝えしたいので、第0話で公開している完成品もチェックしてみてください。
前回、やっと音が出ました。が。。
ようやく音を出すことに成功しました。こちらがそのコードになります。
let keySize = 50
let keyTop = keySize / 1.4;
let topSize = 7;
let keyX = 50;
let keyY = 50;
let keyInterval = 50;
let keyStat = false;
let strokeValue = 2;
let osc; // オシレーターを入れるハコです。
function setup() {
createCanvas(500, 400);
osc = new p5.Oscillator('sin'); // ハコの中にサイン波を入れる
}
function draw() {
background(250); //背景の色
drawHousing();
drawInterface();
noteOn(); //ここでオシレーターの音を鳴らします!!
}
function drawHousing(){
stroke(150, 100, 100);
strokeWeight(strokeValue);
fill(230, 230, 230); // キーのベース
rect(keyX, keyY, keySize, keySize);
fill(100, 100, 100); // キーの影部分の色
triangle(
keyX, keyY, //左上
keyX, keyY + keySize, //左下
keyX+ keySize, keyY + keySize //右下
);
fill(250, 250, 250) // キーのトップ部分
rect(keyX+ topSize, keyY + topSize, keyTop, keyTop);
}
function drawInterface(){
if (keyStat == true){ // オレンジ色で白鍵のキートップを塗り替える
fill(255, 125, 0);
rect(keyX+ topSize, keyY + topSize, keyTop, keyTop);
}
}
function noteOn(){
if (keyStat == true){
osc.start(); //キーが押されたらオシレーターを発音する
}
if (keyStat == false){
osc.stop(); //キーが離れたら発音を停止する
}
}
function touchStarted() {
if (
mouseX > keyX &&
mouseX < keyX + keySize &&
mouseY > keyY &&
mouseY < keyY + keySize
)
{
keyStat = true;
}
}
function touchEnded() {
keyStat = false;
}
前回のコードを実行した時の挙動
確かに音は出るのですが、どうしてもサイン波のポーーーーーっという綺麗な音が出ません。
ボボボボボボーーー
といった感じで、雑音?のような音が混ざっています。今回はこのような不具合の原因を探って、解決するまでのお話をします。
挙動を観察しましょう
上にあげた動画をよく観察するか、実際にコードをp5.jsのエディターで実行してみます。
発音している音を聞くと、、
よーく音を聞いてみると、雑音が入っていると言うよりか、どうやら、小刻みにサイン波が発音し直されているようです。
draw()の中身で毎回毎回、noteOn()が呼び出されているのが原因のようです。
draw()は1秒間に60回繰り返し自動的に実行される関数なので、この中にあるnoteOn()も同じく1秒間に60回発音を繰り返していることになります。
function draw() {
background(250); //背景の色
drawHousing();
drawInterface();
noteOn(); //ここでオシレーターの音を鳴らします!!
}
ここでオシレータの音を鳴らします!!と威勢よく発言していますが、これがそもそもの元凶だったのですか。。。
バグを修正します。
draw()の中でnoteOn()を呼び出してはいけないと言うことで、以下のアプローチでバグを修正します。
draw()ではnoteOn()を呼び出さないようにする
ボタンが押された時にtouchStarted()からnoteOn()を呼び出す
ボタンが離された時にtouchEnded()からnoteOn()を呼び出す
noteOn()の中でボタンが押されたか離されたかによって音を出したり止めたりする
まずdraw()の中からnoteOn()を削除
function draw() {
background(250); //背景の色
drawHousing();
drawInterface();
}
次にtouchStarted()とtouchEnded()からnoteOn()を呼び出す
function touchStarted() {
if (
mouseX > keyX &&
mouseX < keyX + keySize &&
mouseY > keyY &&
mouseY < keyY + keySize
)
{
keyStat = true;
noteOn();
}
}
function touchEnded() {
keyStat = false;
noteOn();
}
ここで大事なのは、keyStatをtrueにしたり、falseにしてから、noteOn()を呼び出しているところです。
こうすることで、次にnoteOn()が呼び出された時に音を出すのか、止めるのかを判別できるようになります。
最後にnoteOn()で発音の開始と終了を判定します。
ここは前回と変更はありませんが、前段階のボタン判定でkeyStatのtrue,falseが設定されているため、この関数に処理が入ってきた時、if文がうまく機能してくれるはずです。
function noteOn(){
if (keyStat == true){
osc.start(); //キーが押されたらオシレーターを発音する
}S
if (keyStat == false){
osc.stop(); //キーが離れたら発音を停止する
}
}
それでは実行してみます。
綺麗に音が出ました!うまくいっています。
これでバグが無事解決できました。
この記事のコード全文
let keySize = 50
let keyTop = keySize / 1.4;
let topSize = 7;
let keyX = 50;
let keyY = 50;
let keyInterval = 50;
let keyStat = false;
let strokeValue = 2;
let osc; // オシレーターを入れるハコです。
function setup() {
createCanvas(500, 400);
osc = new p5.Oscillator('sin'); // ハコの中にサイン波を入れる
}
function draw() {
background(250); //背景の色
drawHousing();
drawInterface();
}
function drawHousing(){
stroke(150, 100, 100);
strokeWeight(strokeValue);
fill(230, 230, 230); // キーのベース
rect(keyX, keyY, keySize, keySize);
fill(100, 100, 100); // キーの影部分の色
triangle(
keyX, keyY, //左上
keyX, keyY + keySize, //左下
keyX+ keySize, keyY + keySize //右下
);
fill(250, 250, 250) // キーのトップ部分
rect(keyX+ topSize, keyY + topSize, keyTop, keyTop);
}
function drawInterface(){
if (keyStat == true){ // オレンジ色で白鍵のキートップを塗り替える
fill(255, 125, 0);
rect(keyX+ topSize, keyY + topSize, keyTop, keyTop);
}
}
function noteOn(){
if (keyStat == true){
osc.start(); //キーが押されたらオシレーターを発音する
}
if (keyStat == false){
osc.stop(); //キーが離れたら発音を停止する
}
}
function touchStarted() {
if (
mouseX > keyX &&
mouseX < keyX + keySize &&
mouseY > keyY &&
mouseY < keyY + keySize
)
{
keyStat = true;
noteOn();
}
}
function touchEnded() {
keyStat = false;
noteOn();
}
全文をコピペして試してみてください。
これで、ようやくまともな発音ができるようになりました。
p5.soundは豊富な機能がラインアップされているのですが、上手にスクリプトを呼び出していかないと思わぬバグが起きることも教訓になります。
また、このような不具合が起こった時、プログラムの挙動について、視覚的にも聴覚的にも注意深く観察することで、原因を特定する糸口が見えてくることもとても勉強になりました。
もう少しで楽器らしいプログラムに発展していきそうです!
引き続きよろしくお願いします!