Published Date : 2019年9月1日23:28

p5.jsでギタータブ譜作ろうぜ
Let's make a guitar tab sheet with p5.js


This blog has an English translation






久々のp5.js
I started working on p5.js after a long time.

2年前に色々とP5jsで遊んでおりました。 当時ギターを始めた知り合いに 「ギタータブ譜が見難い、分かりやすいギタータブ譜無いかな?」 と言われたのがきっかけで遊びで作ったものが 結局使われずに過去のバックアップフォルダに眠っておりましたので、 ネタの一つとして引っ張り出してきました。

There was a time when I played with P5 in various ways 2 years ago. I had an acquaintance who started playing guitar 「It is hard to see the guitar tab score, and I wonder if there is a guitar tab score that is easy to understand.」 And so they said, 「Well, you know what?」 After all, it was not used and it was in the past my backup folder. It's a waste, so I think I'll write an blog.

P5.jsとはアーティストの為に作られたProcessingというJAVAベースの言語のJS版です。

P5.js is the Javascript version of Processing, a JAVA-based language created for artists.

今回はWEB上で簡単に試せる環境 https://editor.p5js.org/ で全て書いてしまい、 それをIframeとしてブログ記事に貼り付けるところまでを書いていきます。

This time, I wrote everything in an environment that is easy to try on the website https://editor.p5js.org/. I'm going to take it as Iframe and paste it into a blog post.

おまけとして、FlaskとFlask-bootstrapとPyDroido3を使ってAndroid環境から使えるようにする、 そしてHerokuにアップしてWEBアプリとして使えるようにする方法を簡単に書いていきます。

As a bonus, Flask, Flask-bootstrap, and PyDroido 3 can be used in an Android environment. Then I will write a simple way to upload it to Heroku and use it as a web application.


Lets get started

まずhttps://editor.p5js.org/P5.jsのWEBエディターを開きます。 先にログインしておきましょう。 グーグルアカウントかGITHUBのアカウントがあれば即入れます。

First, open the P5.js WEB editorhttps://editor.p5js.org/. Log in first. If you have a google account or a github account, you can enter right away.

最初に仕様を簡単に説明すると、ギターの形と弦をベクトルと比率で作り、 弦とフレット位置をクリックすると、音の記号が出てくる。 Saveボタンを押すとpngファイルとして保存できるというものです。

First of all, let's briefly describe the specifications. Click on the strings and fret positions and you'll get a sound symbol. If you click the Save button, you can save it as a png file.

Windowsなら保存したpngファイルを WindowsPhotoビューワーでスライドショー、 Macなら「写真.app」で細かいスライドショーの作成ができます。

On Windows, save the png file Slide Show in Windows Photo Viewer. On a Mac, you can create detailed slideshows in "Photos app".

本来なら、もう一つボタンを用意して、保存したタブ譜を リズムごと、テンポごとに自動再生、簡単な音も出るようにする(p5.sound libraryを使う) などの機能を実装する予定でしたが、それは各自で実装してみてください。(すんまそん。面倒くさかった。)

You should have another button and save the tab sheet. Play automatically every rhythm and tempo, and make simple sounds (Use p5.sound library) , but you should implement it yourself. (It was so complicated that the code could be long.)

まあ、上の機能がついたギタータブ譜のデスクトップアプリやスマホアプリは大量にあるので、 探してみてください。

Well, there are a lot of guitar tabulator desktop and smartphone apps with the above features. Please look for it.

あくまでP5.jsでサクッとウェブブラウザ上で試せることに意義があるので、悪しからず。

It makes sense that P5.js allows you to quickly try it in a web browser.

ワーワー言うとりますが、一気にコードを貼って説明していきます。

I've written a lot of things, but I'd like to put a code all at once and explain.


こんな感じの仕上がりになります。

It will look like this.



画面幅は1080px固定にしているので、スクロールするか、 画面を水平に切り替える、もしくはソースコードを編集してください。

The screen width is fixed at 1080 px, so you can scroll or Switch the screen horizontally or edit the source code.

ストロークの記号や、休止なども表現できればいいですよね〜。 各自実装してください。

It would be nice if I could express stroke symbols and pauses. Please implement it yourself.


操作方法は Strings Editボタンを押し、 各フレット(開放弦は0フレット) クリックすることによって音記号が出ます。

Usage: Press the Strings Edit button. Each fret (The open string is 0 fret.) The sound symbol appears when you click it.


Responsive image


Responsive image

Strings Clearを押して、音記号をクリックすると 音記号が消えます。

Press Strings Clear and click the sound symbol. The sound symbol disappears.


Responsive image


Responsive image

All Clearは全てリセットされます。

All Clear is reset.


Responsive image


Responsive image

Save PNGをクリックすると、P5の画面だけがPNGとして保存されます。

If you click Save PNG, only the P5 screen is saved as PNG.


Responsive image


Responsive image

作り方は簡単。 p5.js Webエディターにログインして、 ソースコードを赤枠部分にコピペする。

It's easy to make. Log in to the p5.js Web editor and click Copy and paste the source code into the red box.



Responsive image

FileメニューからSave。またはCTRL+S。

Save from the File menu. or CTRL + S.



Responsive image

Saveしたら、またFileメニューからShareをクリック。

After saving, click Share again from the File menu.



Responsive image

一番上のiframeタグをブログなり、HPなりに貼り付ける。 ソースコードを一緒に貼り付けたいならEDITを選択する。 以上。

Paste the top iframe tag as a blog and as HP. Select Edit if you want to paste the source code together. That's it.



Responsive image


Source code

まず、必要な変数を定義して、用意していきます。

First, define and prepare the required variables.

var threadRatio = 45.5/100;
var wid = 1080;
var hei = 400;
var widthSpacing = 80;
var heightSpacing = 20;
var topRatio = 4.3/100;
var bottomRatio = 5.1/100;

var otoBuffer = [["F3","F#3","G3","G#3","A3","A#3","B3","C4","C#4","D4","D#4","E4","F4","F#4","G4","G#4","A4","A#4","B4","C5","C#5","D5"],
                ["C3","C#3","D3","D#3","E3","F3","F#3","G3","G#3","A3","A#3","B3","C4","C#4","D4","D#4","E4","F4","F#4","G4","G#4","A4"],
                ["G#2","A2","A#2","B2","C3","C#3","D3","D#3","E3","F3","F#3","G3","G#3","A3","A#3","B3","C4","C#4","D4","D#4","E4","F4"],
                ["D#2","E2","F2","F#2","G2","G#2","A2","A#2","B2","C3","C#3","D3","D#3","E3","F3","F#3","G3","G#3","A3","A#3","B3","C4"],
                ["A#1","B1","C2","C#2","D2","D#2","E2","F2","F#2","G2","G#2","A2","A#2","B2","C3","C#3","D3","D#3","E3","F3","F#3","G3"],
                ["F1","F#1","G1","G#1","A1","A#1","B1","C2","C#2","D2","D#2","E2","F2","F#2","G2","G#2","A2","A#2","B2","C3","C#3","D3"]];

var threadLength = ((wid-widthSpacing)*threadRatio)*2;
var topLength = ((hei-heightSpacing)*topRatio)*12;
var bottomLength = ((hei-heightSpacing)*bottomRatio)*12;

var otoIndex;
var stringsIndex;
var stringsChara;
var otoChara;
var saveOto;
var saveStrings;
var otoEnable = false;

var g1=g2=g3=g3=g4=g5=g6= 127;

var r1=r2=r3=r4=r5=r6= 0;

var s1 = 1.2;
var s2 = 1.4;
var s3 = 1.6;
var s4 = 1.8;
var s5 = 2;
var s6 = 2.2;

var testE;
var testb;
var testg;
var testd;
var testa;
var teste;

var checke = false;
var checkB = false;
var checkG = false;
var checkD = false;
var checkA = false;
var checkE = false;

var stringOffsetXLeft = [[],[],[],[],[],[]];
var stringOffsetXRight = [[],[],[],[],[],[]];;
var stringOffsetYUp = [[],[],[],[],[],[]];;
var stringOffsetYDown = [[],[],[],[],[],[]];;

var kc;

var editEnable = true;
var editClear = false;
var editAlpha = 150;
var clearAlpha = 150;
var enableAlpha = 240;
var disableAlpha = 100;
var allClearAlpha = 150;
var randomAllClearAlpha = 200;
var allClearEnableAlpha = 240;
var allClearDisableAlpha = 100;
var allClearCheck = false;
var savePngCheck = false;
var savePngEnableAlpha = 240;
var savePngDisableAlpha = 100;
var savePngAlpha = 150;
var randomSavePngAlpha = 200;

思いつきで、テストも込みのコードなので、無駄に長く、同じことを繰り返すアホなコードです。 各自、クラスファイルを統一するなり、重複を無くすなりしてください。

It's a dumb piece of code that does the same thing over and over for an unnecessarily long time, because it's a whimsical piece of code with tests. Be sure to unify your class files or eliminate duplicates.

続いて、フレッド毎の座標を計算するクラスファイルを作成する。

Next, a class file for calculating the coordinates of each Fred is created.

var keyCalculator = function(){
  this.fredRatioBuffer = [0, 3.4, 3.4, 3.4, 3.1, 2.8, 2.6, 2.6, 2.2, 2.2, 2.1, 2.0, 1.8, 1.8, 1.6, 1.6, 1.5, 1.4, 1.3, 1.3, 1.3, 1.1, 1];
  this.v1 = [];
  this.v2 = [];
  this.v3 = [];
  this.r = [];
  this.cosTheta = [];
  this.sinTheta = [];
  this.sum = 0;
  this.fredR = [];
  this.fredX = [];
  this.fredY = [];
  this.offsetR = [];

  this.keyCalculate = function(){
    for(var i = 0; i < 6; i++){
      this.v1[i] = createVector(widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*(i+1)));
      this.v2[i] = createVector(widthSpacing,(hei/2)-(topLength/2)+((topLength/7)*(i+1)));
      this.v3[i] = this.v1[i].sub(this.v2[i]);
      this.r[i] = this.v3[i].mag();
      this.v3[i].mult(-1);
      this.cosTheta[i] = this.v3[i].x/this.r[i];
      this.sinTheta[i] = this.v3[i].y/this.r[i];
      for(var j = 0; j < this.fredRatioBuffer.length; j++ ){
        this.sum += this.fredRatioBuffer[j];
        this.fredR[j] = this.r[i] * ((45.5-this.sum)/45.5);
        this.fredX[j] = this.fredR[j] * this.cosTheta[i];
        this.fredY[j] = this.fredR[j] * this.sinTheta[i];
        if(j==0){
          this.offsetR[j] = 20.00;
        }else if(j>=1&&j < 4){
          this.offsetR[j] = 21.00;
        }else if(j==4){
          this.offsetR[j] = 20.55;
        }else if(j==5){
          this.offsetR[j] = 20.10;
        }else if(j==6||j==7){
          this.offsetR[j] = 19.80;
        }else if(j==8||j==9){
          this.offsetR[j] = 19.20;
        }else if(j==10){
          this.offsetR[j] = 19.05;
        }else if(j==11){
          this.offsetR[j] = 18.90;
        }else if(j==12||j==13){
          this.offsetR[j] = 18.60;
        }else if(j==14||j==15){
          this.offsetR[j] = 18.30;
        }else if(j==16){
          this.offsetR[j] = 18.15;
        }else if(j==17){
          this.offsetR[j] = 18.00;
        }else if(j==18||j==19||j==20){
          this.offsetR[j] = 17.85;
        }else if(j==21){
          this.offsetR[j] = 17.55;
        }else if(j==22){
          this.offsetR[j] = 17.40;
        }
        stringOffsetXLeft[i][j] = ((this.fredX[j]+(widthSpacing+threadLength))-7.5)-(this.offsetR[j]/2);
        stringOffsetXRight[i][j] = ((this.fredX[j]+(widthSpacing+threadLength))-7.5)+(this.offsetR[j]/2);
        stringOffsetYUp[i][j] = (this.fredY[j]+((hei/2)-(bottomLength/2)+((bottomLength/7)*(i+1))))-this.offsetR[j]/2;
        stringOffsetYDown[i][j] = (this.fredY[j]+((hei/2)-(bottomLength/2)+((bottomLength/7)*(i+1))))+this.offsetR[j]/2;
      }
      this.sum = 0;
    }
  };
};

ベクトルと三角関数が出てきますので、さらっと簡単に説明します。

The vectors and trigonometric functions are shown, so let's briefly explain them.


Responsive image

コンピューター画面では、左上が原点(0、0)になります。

On the computer screen, the origin (0, 0) is at the upper left.

ベクトルをP5で作ると画像のように、原点から指定した座標(200,200)にベクトルができます。

Creating a vector in P5 creates a vector from the origin to the specified coordinates (200,200) as shown in the image.

さらに座標(300、180)に同じようにベクトルを用意します。

It also provides a vector in the same way at the coordinates (300, 180).

(300、180)への矢印がないですが、見えない矢印があるもんだと思ってください。

There is no arrow to (300, 180), but think of it as an invisible arrow.

最初のベクトル(0,0)->(200,200)をベクトルAだとすると、ベクトル(0,0)->(300,180)をベクトルBだとする。

Let the first vector (0, 0) - > (200,200) be vector A, and let the vector (0, 0) - > (300,180) be vector B.

求めるベクトルC(200,200)->(300,180)を導くためには、ベクトル計算をします。

To determine the vector C (200,200) - > (300,180), perform a vector calculation.

細かい事は調べればすぐ分かると思いますが、簡単に説明すると、ベクトルCが既にあると仮定し、ベクトルBを求めたいとすると、 ベクトルB(0,0)->(300,180)を求めるのは簡単です。

The details will be clear as soon as you examine it, but to explain briefly, suppose that the vector C already exists, and you want to obtain the vector B. It is easy to find the vector B (0, 0) - > (300,180).

このサイトがわかりやすいです。

This site is easy to understand.

ベクトルA + ベクトルC = ベクトルBになります。 つまり、ベクトルC = ベクトルB ー ベクトルAです。

Vector A + Vector C = Vector B. That is, vector C = vector B - vector A.

P5には簡単にベクトルを求める関数があるので、上の計算をするだけですが、問題は ベクトルCが(0,0)->(100,−20)になってしまい、画面からはみだして見えなくなります。 こういう仕様なので仕方が無いですが、これを解決するために、translate(移動したいX座標、移動したいY座標) という関数がP5にあります。

P5 has a simple vector function, so all you have to do is compute the above, but the problem is The vector C becomes (0, 0) - > (100, − 20) and is no longer visible on the screen. It can't be helped because of this specification, but in order to solve this, translate (X coordinate to move, Y coordinate to move) function in P5.

translate(移動したいX座標、移動したいY座標)、そして、P5のline(線の始めの座標、線の終わりの座標)関数、 これで図のような線が引けます。

translate (X coordinate to move, Y coordinate to move) and the line (coordinates of the start and end of the line) function of P5. Now you can draw a line as shown in the figure.

fredRatioBufferにはフレッドの間隔が格納されています。 フレッド間隔が徐々に狭くなっていますが、ギターはこのようにして弦の張りの強さを微妙に変えて、音の調整を行っています。 ただコンピューター上ではここまでする必要は無いのですが、見た目をリアルにするために敢えて実物のギターを元に比率を与えています。

The fredRatioBuffer stores the Fred interval. Fred interval is gradually getting narrower, but the guitar adjusts the sound by subtly changing the tension of the strings like this. We don't need to do this on the computer, but I intentionally give the ratio based on the real guitar to make it look real.


Responsive image

お次は簡単な三角関数の例です。

Here is a simple trigonometric example.

要するにsinθはY座標を表し、cosθはX座標を表して、ピタゴラスの定理を元にベクトルの長さが分かり(これはP5のmag()関数で求められます。)、 ベクトルの長さととXかYが分かれば角度が判明し、角度が分かれば、座標が分かります。

In short, sin θ represents the Y coordinate, and cos θ represents the X coordinate, and the length of the vector is known based on the Pythagorean theorem (This is done with the P5 mag () function.). If you know the length of the vector and X or Y, you know the angle; if you know the length and angle, you know the coordinates.

なんでこんなことをしているかというと、真っ直ぐに引いた線に対しては異なる比率に対して座標はすぐ計算できますが、 ギターのような弦がネックの先端と後端とで鋭角になっている場合、各地点(この場合フレッドに対して指を押える場所の座標) がどこになるかが分からないからです。

The reason I do this is because I can quickly calculate the coordinates for different ratios for straight lines. If the string, like a guitar, is sharply angled at the tip and back of the neck, each point (In this case, the coordinates of the place where the finger can be pressed) because I don't know where.

正しく音の記号をフレッドの位置毎に表現させるために、三角関数を使用します。 でも考え方は単純で、ピタゴラスの定理の「斜辺=平方根(底辺の二乗+高さの二乗)だけ覚えていれば導けます。

Trigonometry is used to correctly represent the sound symbols at each Fred position. But the idea is simple: you only need to remember the Pythagorean theorem, the hypotenuse = square root (Square of X + Square of Y).

var fredNumberPotisionCalculator = function(){
  var fredRatioArray = [0, 3.4, 3.4, 3.4, 3.1, 2.8, 2.6, 2.6, 2.2, 2.2, 2.1, 2.0, 1.8, 1.8, 1.6, 1.6, 1.5, 1.4, 1.3, 1.3, 1.3, 1.1, 1];
  var vn1 = createVector(widthSpacing-3,(hei/2)-(topLength/2)-8);
  var vn2 = createVector(widthSpacing+threadLength-6,((hei/2)-(topLength/2))-30);
  vn2.sub(vn1);
  var m = vn2.mag();
  vn2.mult(-1);
  var ct = vn2.x / m;
  var st = vn2.y / m;
  var vn3 = createVector(widthSpacing-3,(hei/2)+(topLength/2)+2);
  var vn4 = createVector(widthSpacing+threadLength-6,(((hei/2)+(bottomLength/2)))+4);
  vn4.sub(vn3);
  var mb = vn4.mag();
  vn4.mult(-1);
  var bct = vn4.x / mb;
  var bst = vn4.y / mb;
  var sumNum = 0;
  fredRatioArray.forEach(function(n,i){
    sumNum += n;
    var tempR = m * ((45.5-sumNum)/45.5);
    var tempX = tempR * ct;
    var tempY = tempR * st;
    var tempRb = mb * ((45.5-sumNum)/45.5);
    var tempXb = tempRb * bct;
    var tempYb = tempRb * bst;
    if(i==0||i==3||i==5||i==7||i==9||i==12||i==15||i==17||i==19){
      fill(250,120,0);
      // fill(255*0.8,255*0.125,0);
    }else{
      fill(0,240,180);
    }
    text(i,tempX+(widthSpacing+threadLength-6),tempY+(((hei/2)-(topLength/2))-30));
    text(i,tempXb+(widthSpacing+threadLength-6),tempYb+(((hei/2)+(bottomLength/2))+20));
  });
}

fredNumberPotisionCalculator関数は上で説明した簡単な三角関数を使用して、フレッドの番号を見やすく表示するために使用します。

The FedNumberPotisionCalculator function uses the simple trigonometric functions described above to make the Fred numbers easier to read.

var guiterOutFrame = function(){
  strokeWeight(3);
  //hieght
  stroke(200,80,0);
  line(widthSpacing,(hei/2)-(topLength/2),widthSpacing,((hei/2)-(topLength/2))+topLength);
  stroke(70*1.5,24*1.5,0);
  line(widthSpacing+threadLength,(hei/2)-(bottomLength/2),widthSpacing+threadLength,((hei/2)-(bottomLength/2))+bottomLength);
  //width
  line(widthSpacing,(hei/2)-(topLength/2),widthSpacing+threadLength,(hei/2)-(bottomLength/2));
  line(widthSpacing,((hei/2)-(topLength/2))+topLength,widthSpacing+threadLength,((hei/2)-(bottomLength/2))+bottomLength);

  //Fred1~3
  for(var i = 1;i < 4;i++){
    if(i==3){
      stroke(180,60,20);
    }else{
      stroke(70*1.5,24*1.5,0);
    }
    strokeWeight(3);
    line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(i*3.4 / 45.5)),(hei / 2)-(topLength / 2)-i,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(i*3.4/45.5)),((hei/2)-(topLength/2))+topLength+(i*1.45));
  }
  //Fred4
  stroke(70*1.5,24*1.5,0);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)),(hei/2)-(topLength/2)-4,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)),((hei/2)-(topLength/2))+topLength+(4*1.48));
  //Fred5
  stroke(180,60,20);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)),(hei/2)-(topLength/2)-5,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)),((hei/2)-(topLength/2))+topLength+(5*1.38));

  //Fred6
  stroke(70*1.5,24*1.5,0);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)),(hei/2)-(topLength/2)-6,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)),((hei/2)-(topLength/2))+topLength+(6*1.30));

  //Fred7
  stroke(180,60,20);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)),(hei/2)-(topLength/2)-7,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)),((hei/2)-(topLength/2))+topLength+(7*1.28));

  //Fred8
  stroke(70*1.5,24*1.5,0);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)),(hei/2)-(topLength/2)-8,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)),((hei/2)-(topLength/2))+topLength+(8*1.26));

  //Fred9
  stroke(180,60,20);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)),(hei/2)-(topLength/2)-9,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)),((hei/2)-(topLength/2))+topLength+(9*1.22));

  //Fred10
  stroke(70*1.5,24*1.5,0);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)),(hei/2)-(topLength/2)-10,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)),((hei/2)-(topLength/2))+topLength+(10*1.16));

  //Fred11
  stroke(70*1.5,24*1.5,0);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)),(hei/2)-(topLength/2)-11,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)),((hei/2)-(topLength/2))+topLength+(11*1.12));

  //Fred12
  stroke(180,60,20);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)),(hei/2)-(topLength/2)-12,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)),((hei/2)-(topLength/2))+topLength+(12*1.08));

  //Fred13
  stroke(70*1.5,24*1.5,0);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)+(threadLength*1.8/45.5)),(hei/2)-(topLength/2)-13,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)+(threadLength*1.8/45.5)),((hei/2)-(topLength/2))+topLength+(13*1.04));

  //Fred14
  stroke(70*1.5,24*1.5,0);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)+(threadLength*1.8/45.5)+(threadLength*1.6/45.5)),(hei/2)-(topLength/2)-14,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)+(threadLength*1.8/45.5)+(threadLength*1.6/45.5)),((hei/2)-(topLength/2))+topLength+(14*1.00));

  //Fred15
  stroke(180,60,20);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)+(threadLength*1.8/45.5)+(threadLength*1.6/45.5)+(threadLength*1.6/45.5)),(hei/2)-(topLength/2)-15,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)+(threadLength*1.8/45.5)+(threadLength*1.6/45.5)+(threadLength*1.6/45.5)),((hei/2)-(topLength/2))+topLength+(15*0.96));

  //Fred16
  stroke(70*1.5,24*1.5,0);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)+(threadLength*1.8/45.5)+(threadLength*1.6/45.5)+(threadLength*1.6/45.5)+(threadLength*1.5/45.5)),(hei/2)-(topLength/2)-16,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)+(threadLength*1.8/45.5)+(threadLength*1.6/45.5)+(threadLength*1.6/45.5)+(threadLength*1.5/45.5)),((hei/2)-(topLength/2))+topLength+(16*0.92));

  //Fred17
  stroke(180,60,20);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)+(threadLength*1.8/45.5)+(threadLength*1.6/45.5)+(threadLength*1.6/45.5)+(threadLength*1.5/45.5)+(threadLength*1.4/45.5)),(hei/2)-(topLength/2)-17+0.9,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)+(threadLength*1.8/45.5)+(threadLength*1.6/45.5)+(threadLength*1.6/45.5)+(threadLength*1.5/45.5)+(threadLength*1.4/45.5)),((hei/2)-(topLength/2))+topLength+(17*0.88));

  //Fred18~20
  for(var i = 18; i < 21; i++){
    if(i==19){
      stroke(180,60,20);
    }else{
      stroke(70*1.5,24*1.5,0);
    }
    strokeWeight(3);
    line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)+(threadLength*1.8/45.5)+(threadLength*1.6/45.5)+(threadLength*1.6/45.5)+(threadLength*1.5/45.5)+(threadLength*1.4/45.5)+((i-17)*(threadLength*1.3/45.5))),(hei/2)-(topLength/2)-i+1.9,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)+(threadLength*1.8/45.5)+(threadLength*1.6/45.5)+(threadLength*1.6/45.5)+(threadLength*1.5/45.5)+(threadLength*1.4/45.5)+((i-17)*(threadLength*1.3/45.5))),((hei/2)-(topLength/2))+topLength+((i*0.82)-((i-17)*0.02)));

  }
  //Fred21
  stroke(70*1.5,24*1.5,0);
  strokeWeight(3);
  line(widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)+(threadLength*1.8/45.5)+(threadLength*1.6/45.5)+(threadLength*1.6/45.5)+(threadLength*1.5/45.5)+(threadLength*1.4/45.5)+(3*(threadLength*1.3/45.5))+(threadLength*1.1/45.5)),(hei/2)-(topLength/2)-18,widthSpacing+(((wid-widthSpacing)*threadRatio)*2*(3*3.4/45.5)+(threadLength*3.1/45.5)+(threadLength*2.8/45.5)+(threadLength*2.6/45.5)+(threadLength*2.6/45.5)+(threadLength*2.2/45.5)+(threadLength*2.2/45.5)+(threadLength*2.1/45.5)+(threadLength*2/45.5)+(threadLength*1.8/45.5)+(threadLength*1.8/45.5)+(threadLength*1.6/45.5)+(threadLength*1.6/45.5)+(threadLength*1.5/45.5)+(threadLength*1.4/45.5)+(3*(threadLength*1.3/45.5))+(threadLength*1.1/45.5)),((hei/2)-(topLength/2))+topLength+(21*0.72));

  //Fred22
  stroke(70*1.5,24*1.5,0);
  strokeWeight(3);

}

続いてギターの外枠を作る関数です。

Next, it is a function to make the outer frame of the guitar.

var guiterStringHiE = function(){
  stroke(r1,0,0);
  strokeWeight(s1);
  line(widthSpacing,(hei/2)-(topLength/2)+((topLength/7)*1),widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*1));

}

var guiterStringB = function(){
  stroke(r2,0,0);
  strokeWeight(s2);
  line(widthSpacing,(hei/2)-(topLength/2)+((topLength/7)*2),widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*2));

}

var guiterStringG = function(){
  stroke(r3,0,0);
  strokeWeight(s3);
  line(widthSpacing,(hei/2)-(topLength/2)+((topLength/7)*3),widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*3));

}

var guiterStringD = function(){
  stroke(r4,0,0);
  strokeWeight(s4);
  line(widthSpacing,(hei/2)-(topLength/2)+((topLength/7)*4),widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*4));

}

var guiterStringA = function(){
  stroke(r5,0,0);
  strokeWeight(s5);
  line(widthSpacing,(hei/2)-(topLength/2)+((topLength/7)*5),widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*5));
;
}

var guiterStringLowE = function(){
  stroke(r6,0,0);
  strokeWeight(s6);
  line(widthSpacing,(hei/2)-(topLength/2)+((topLength/7)*6),widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*6));

}

上の小さな関数群は各ストリングを実際に描画するために使います。ここらへんも1つのクラスファイルにまとめたほうがコードが長くならずに済むと思います。

The small functions above are used to actually render each string. I think it's better to combine all these into one class file so that the code doesn't get long.

function setup(){
  createCanvas(wid,hei);
  frameRate(24);
  console.log("threadLength : " + threadLength);
  console.log("topLength : " + topLength);
  console.log("bottomLength : " + bottomLength);

  teste = new TestHiE();
  testb = new TestB();
  testg = new TestG();
  testd = new TestD();
  testa = new TestA();
  testE = new TestLowE();
  kc = new keyCalculator();
  kc.keyCalculate();
}

setup()はP5に予め用意されている、関数で、ここで行う処理は最初に一回だけ行われるだけです。

setup () is a pre-built function in P5 that does only one thing first.

function draw(){
  // background(15,15,20);  //PC.
  background(90,90,111); //tablet.
  // background(127); //tablet another.
  guiterOuterFrame();
  guiterStringHiE();
  guiterStringB();
  guiterStringG();
  guiterStringD();
  guiterStringA();
  guiterStringLowE();

  teste.testHiEUpdate();
  teste.testHiEShow();
  testb.testBUpdate();
  testb.testBShow();
  testg.testGUpdate();
  testg.testGShow();
  testd.testDUpdate();
  testd.testDShow();
  testa.testAUpdate();
  testa.testAShow();
  testE.testLowEUpdate();
  testE.testLowEShow();

  editButton();
  if(allClearCheck){
    allClearAlpha = random(200,255);
  }
  if(savePngCheck){
    savePngAlpha = random(200,255);
  }
  fredNumberPotisionCalculator();
}

draw()もP5で用意してある関数で、Mainとなる関数で、ここの関数の処理がずっとループし続けます。他の言語のWhile関数だと思えばいいです。

draw () is another P5 function, Main, which keeps looping. Think of it as a While function in another language.

testといった名前のクラスがあったり、ところどころ英語の意味が変なのは気にしないでください。ご愛嬌です。どんどん修正して使ってください。

Don't worry about classes with names like test or the odd meaning of English here and there. Please correct it and use it.

function editButton(){

  fill(240,40,0,editAlpha);
  noStroke();
  ellipse(widthSpacing/4+20,heightSpacing+10,30,30);
  text("Strings Edit.",(widthSpacing/4)-10,heightSpacing*3);

  fill(0,175,240,clearAlpha);
  noStroke();
  ellipse(widthSpacing*2-10,heightSpacing+10,30,30);
  text("Strings Clear.",(widthSpacing*2-40),heightSpacing*3);

  fill(40,240,60,allClearAlpha);
  noStroke();
  ellipse(widthSpacing/4+20,hei-40,30,30);
  text("All Clear.",(widthSpacing/4)-5,hei-10);
  fill(255,255,255,allClearDisableAlpha);

  fill(255,0,255,savePngAlpha);
  noStroke();
  ellipse(widthSpacing*2-10,hei-40,30,30);
  text("Save PNG.",(widthSpacing*2-40),hei-10);
  fill(255,255,255,savePngDisableAlpha);
}

音の記号を編集するための関数です。

Functions for editing sound symbols.

var TestHiE = function(){
  this.fredRatioBuffer = [3.4, 3.4, 3.4, 3.1, 2.8, 2.6, 2.6, 2.2, 2.2, 2.1, 2.0, 1.8, 1.8, 1.6, 1.6, 1.5, 1.4, 1.3, 1.3, 1.3, 1.1, 1];
  this.fredNumburB = 0;

  this.testHiEUpdate = function(){
    if(stringsIndex==1||keyCode==DELETE){
      this.fredNumburB = otoIndex;
    }
    push();
    this.vb1 = createVector(widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*1));
    this.vb2 = createVector(widthSpacing,(hei/2)-(topLength/2)+((topLength/7)*1));
    this.vb3 = this.vb1.sub(this.vb2);
    this.Br = this.vb3.mag();

    this.vb3.mult(-1);

    this.BcosTheta = this.vb3.x/this.Br;

    this.BsinTheta = this.vb3.y/this.Br;

    this.findSumNumberB = 22-this.fredNumburB;
    this.sum = 0;
    for(var i = 0; i < this.fredRatioBuffer.length-this.findSumNumberB; i++ ){
      this.sum += this.fredRatioBuffer[i];
    }
    this.Bfred1R = this.Br * ((45.5-this.sum)/45.5);

    this.Bfred1X = this.Bfred1R * this.BcosTheta;

    this.Bfred1Y = this.Bfred1R * this.BsinTheta;

    if(this.fredNumburB==0){
      this.r = 20.00;
    }else if(this.fredNumburB>=1&&this.fredNumburB < 4){
      this.r = 21.00;
    }else if(this.fredNumburB==4){
      this.r = 20.55;
    }else if(this.fredNumburB==5){
      this.r = 20.10;
    }else if(this.fredNumburB==6||this.fredNumburB==7){
      this.r = 19.80;
    }else if(this.fredNumburB==8||this.fredNumburB==9){
      this.r = 19.20;
    }else if(this.fredNumburB==10){
      this.r = 19.05;
    }else if(this.fredNumburB==11){
      this.r = 18.90;
    }else if(this.fredNumburB==12||this.fredNumburB==13){
      this.r = 18.60;
    }else if(this.fredNumburB==14||this.fredNumburB==15){
      this.r = 18.30;
    }else if(this.fredNumburB==16){
      this.r = 18.15;
    }else if(this.fredNumburB==17){
      this.r = 18.00;
    }else if(this.fredNumburB==18||this.fredNumburB==19||this.fredNumburB==20){
      this.r = 17.85;
    }else if(this.fredNumburB==21){
      this.r = 17.55;
    }else if(this.fredNumburB==22){
      this.r = 17.40;
    }
    pop();
  };

  this.testHiEShow = function(){
    push();

    if(stringsIndex==1||keyCode==DELETE){
      this.fredNumburB = otoIndex;
    }

    translate(widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*1));

    if(this.fredNumburB == 0&&checke==true){
      stroke(255,0,0);
    }else{
      noStroke();
    }
    if(this.fredNumburB>0&&this.fredNumburB < 23){
      stroke(255,50,25);
    }

    line(0,0,this.Bfred1X,this.Bfred1Y);

    if(this.sum==0&&checke==true){
      noFill();
    }else if(this.fredNumburB==0&&checke==false){
      noFill();
    }else{
      fill(25,50,255);
    }
    noStroke();
    ellipse(this.Bfred1X-7.5,this.Bfred1Y,this.r,this.r);

    this.BstringKeyBuffer = ["E3","F3","F#3","G3","G#3","A3","A#3","B3","C4","C#4","D4","D#4","E4","F4","F#4","G4","G#4","A4","A#4","B4","C5","C#5","D5"];
    if(this.fredNumburB==0){
      fill(0,240,180);
    }else{
      fill(255);
    }
    text(this.BstringKeyBuffer[this.fredNumburB],this.Bfred1X-15, this.Bfred1Y+3.75);
    pop();
  };
};

var TestB = function(){
  this.fredRatioBuffer = [3.4, 3.4, 3.4, 3.1, 2.8, 2.6, 2.6, 2.2, 2.2, 2.1, 2.0, 1.8, 1.8, 1.6, 1.6, 1.5, 1.4, 1.3, 1.3, 1.3, 1.1, 1];
  this.fredNumburB = 0;

  this.testBUpdate = function(){
    push();
    if(stringsIndex==2||keyCode==DELETE){
      this.fredNumburB = otoIndex;
    }
    this.vb1 = createVector(widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*2));
    this.vb2 = createVector(widthSpacing,(hei/2)-(topLength/2)+((topLength/7)*2));
    this.vb3 = this.vb1.sub(this.vb2);
    this.Br = this.vb3.mag();

    this.vb3.mult(-1);

    this.BcosTheta = this.vb3.x/this.Br;

    this.BsinTheta = this.vb3.y/this.Br;

    this.findSumNumberB = 22-this.fredNumburB;
    this.sum = 0;
    for(var i = 0; i < this.fredRatioBuffer.length-this.findSumNumberB; i++ ){
      this.sum += this.fredRatioBuffer[i];
    }
    this.Bfred1R = this.Br * ((45.5-this.sum)/45.5);

    this.Bfred1X = this.Bfred1R * this.BcosTheta;

    this.Bfred1Y = this.Bfred1R * this.BsinTheta;

    if(this.fredNumburB==0){
      this.r = 0.00;
    }else if(this.fredNumburB>=1&&this.fredNumburB < 4){
      this.r = 21.00;
    }else if(this.fredNumburB==4){
      this.r = 20.55;
    }else if(this.fredNumburB==5){
      this.r = 20.10;
    }else if(this.fredNumburB==6||this.fredNumburB==7){
      this.r = 19.80;
    }else if(this.fredNumburB==8||this.fredNumburB==9){
      this.r = 19.20;
    }else if(this.fredNumburB==10){
      this.r = 19.05;
    }else if(this.fredNumburB==11){
      this.r = 18.90;
    }else if(this.fredNumburB==12||this.fredNumburB==13){
      this.r = 18.60;
    }else if(this.fredNumburB==14||this.fredNumburB==15){
      this.r = 18.30;
    }else if(this.fredNumburB==16){
      this.r = 18.15;
    }else if(this.fredNumburB==17){
      this.r = 18.00;
    }else if(this.fredNumburB==18||this.fredNumburB==19||this.fredNumburB==20){
      this.r = 17.85;
    }else if(this.fredNumburB==21){
      this.r = 17.55;
    }else if(this.fredNumburB==22){
      this.r = 17.40;
    }
    pop();
  };
  this.testBShow = function(){
    push();
    if(stringsIndex==2||keyCode==DELETE){
      this.fredNumburB = otoIndex;
    }
    translate(widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*2));

    if(this.fredNumburB == 0&&checkB==true){
      stroke(255,0,0);
    }else{
      noStroke();
    }
    if(this.fredNumburB>0&&this.fredNumburB < 23){
      stroke(255,50,25);
    }

    line(0,0,this.Bfred1X,this.Bfred1Y);
    if(this.sum==0&&checkB==true){
      noFill();
    }else{
      fill(25,50,255);
    }
    noStroke();
    ellipse(this.Bfred1X-7.5,this.Bfred1Y,this.r,this.r);

    this.BstringKeyBuffer = ["B2","C3","C#3","D3","D#3","E3","F3","F#3","G3","G#3","A3","A#3","B3","C4","C#4","D4","D#4","E4","F4","F#4","G4","G#4","A4"];
    if(this.fredNumburB==0){
      fill(0,240,180);
    }else{
      fill(255);
    }
    text(this.BstringKeyBuffer[this.fredNumburB],this.Bfred1X-15, this.Bfred1Y+3.75);
    pop();
  };
};

var TestG = function(){
  this.fredRatioBuffer = [3.4, 3.4, 3.4, 3.1, 2.8, 2.6, 2.6, 2.2, 2.2, 2.1, 2.0, 1.8, 1.8, 1.6, 1.6, 1.5, 1.4, 1.3, 1.3, 1.3, 1.1, 1];
  this.fredNumburG = 0;

  this.testGUpdate = function(){
    push();
    if(stringsIndex==3||keyCode==DELETE){
      this.fredNumburG = otoIndex;
    }
    this.vg1 = createVector(widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*3));
    this.vg2 = createVector(widthSpacing,(hei/2)-(topLength/2)+((topLength/7)*3));
    this.vg3 = this.vg1.sub(this.vg2);
    this.Gr = this.vg3.mag();

    this.vg3.mult(-1);

    this.GcosTheta = this.vg3.x/this.Gr;

    this.GsinTheta = this.vg3.y/this.Gr;

    this.findSumNumberG = 22-this.fredNumburG;
    this.sum = 0;
    for(var i = 0; i < this.fredRatioBuffer.length-this.findSumNumberG; i++ ){
      this.sum += this.fredRatioBuffer[i];
    }
    this.Gfred1R = this.Gr * ((45.5-this.sum)/45.5);

    this.Gfred1X = this.Gfred1R * this.GcosTheta;

    this.Gfred1Y = this.Gfred1R * this.GsinTheta;

    if(this.fredNumburG==0){
      this.r = 0.00;
    }else if(this.fredNumburG>=1&&this.fredNumburG < 4){
      this.r = 21.00;
    }else if(this.fredNumburG==4){
      this.r = 20.55;
    }else if(this.fredNumburG==5){
      this.r = 20.10;
    }else if(this.fredNumburG==6||this.fredNumburG==7){
      this.r = 19.80;
    }else if(this.fredNumburG==8||this.fredNumburG==9){
      this.r = 19.20;
    }else if(this.fredNumburG==10){
      this.r = 19.05;
    }else if(this.fredNumburG==11){
      this.r = 18.90;
    }else if(this.fredNumburG==12||this.fredNumburG==13){
      this.r = 18.60;
    }else if(this.fredNumburG==14||this.fredNumburG==15){
      this.r = 18.30;
    }else if(this.fredNumburG==16){
      this.r = 18.15;
    }else if(this.fredNumburG==17){
      this.r = 18.00;
    }else if(this.fredNumburG==18||this.fredNumburG==19||this.fredNumburG==20){
      this.r = 17.85;
    }else if(this.fredNumburG==21){
      this.r = 17.55;
    }else if(this.fredNumburG==22){
      this.r = 17.40;
    }
    pop();
  };

  this.testGShow = function(){
    push();
    if(stringsIndex==3||keyCode==DELETE){
      this.fredNumburG = otoIndex;
    }
    translate(widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*3));

    if(this.fredNumburG == 0&&checkG==true){
      stroke(255,0,0);
    }else{
      noStroke();
    }
    if(this.fredNumburG>0&&this.fredNumburG < 23){
      stroke(255,50,25);
    }

    line(0,0,this.Gfred1X,this.Gfred1Y);

    if(this.sum==0&&checkG==true){
      noFill();
    }else{
      fill(25,50,255);
    }
    noStroke();
    ellipse(this.Gfred1X-7.5,this.Gfred1Y,this.r,this.r);

    this.GstringKeyBuffer = ["G2","G#2","A2","A#2","B2","C3","C#3","D3","D#3","E3","F3","F#3","G3","G#3","A3","A#3","B3","C4","C#4","D4","D#4","E4","F4"];
    if(this.fredNumburG==0){
      fill(0,240,180);
    }else{
      fill(255);
    }
    text(this.GstringKeyBuffer[this.fredNumburG],this.Gfred1X-15, this.Gfred1Y+3.75);
    pop();
  };
};

var TestD = function(){
  this.fredRatioBuffer = [3.4, 3.4, 3.4, 3.1, 2.8, 2.6, 2.6, 2.2, 2.2, 2.1, 2.0, 1.8, 1.8, 1.6, 1.6, 1.5, 1.4, 1.3, 1.3, 1.3, 1.1, 1];
  this.fredNumburD = 0;

  this.testDUpdate = function(){
    push();
    if(stringsIndex==4||keyCode==DELETE){
      this.fredNumburD = otoIndex;
    }
    this.vd1 = createVector(widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*4));
    this.vd2 = createVector(widthSpacing,(hei/2)-(topLength/2)+((topLength/7)*4));
    this.vd3 = this.vd1.sub(this.vd2);
    this.Dr = this.vd3.mag();

    this.vd3.mult(-1);

    this.DcosTheta = this.vd3.x/this.Dr;

    this.DsinTheta = this.vd3.y/this.Dr;

    this.findSumNumberD = 22-this.fredNumburD;
    this.sum = 0;
    for(var i = 0; i < this.fredRatioBuffer.length-this.findSumNumberD; i++ ){
      this.sum += this.fredRatioBuffer[i];
    }
    this.Dfred1R = this.Dr * ((45.5-this.sum)/45.5);

    this.Dfred1X = this.Dfred1R * this.DcosTheta;

    this.Dfred1Y = this.Dfred1R * this.DsinTheta;

    if(this.fredNumburD==0){
      this.r = 0.00;
    }else if(this.fredNumburD>=1&&this.fredNumburD < 4){
      this.r = 21.00;
    }else if(this.fredNumburD==4){
      this.r = 20.55;
    }else if(this.fredNumburD==5){
      this.r = 20.10;
    }else if(this.fredNumburD==6||this.fredNumburD==7){
      this.r = 19.80;
    }else if(this.fredNumburD==8||this.fredNumburD==9){
      this.r = 19.20;
    }else if(this.fredNumburD==10){
      this.r = 19.05;
    }else if(this.fredNumburD==11){
      this.r = 18.90;
    }else if(this.fredNumburD==12||this.fredNumburD==13){
      this.r = 18.60;
    }else if(this.fredNumburD==14||this.fredNumburD==15){
      this.r = 18.30;
    }else if(this.fredNumburD==16){
      this.r = 18.15;
    }else if(this.fredNumburD==17){
      this.r = 18.00;
    }else if(this.fredNumburD==18||this.fredNumburD==19||this.fredNumburD==20){
      this.r = 17.85;
    }else if(this.fredNumburD==21){
      this.r = 17.55;
    }else if(this.fredNumburD==22){
      this.r = 17.40;
    }
    pop();
  };

  this.testDShow = function(){
    push();
    if(stringsIndex==4||keyCode==DELETE){
      this.fredNumburD = otoIndex;
    }
    translate(widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*4));

    if(this.fredNumburD == 0&&checkD==true){
      stroke(255,0,0);
    }else{
      noStroke();
    }
    if(this.fredNumburD>0&&this.fredNumburD < 23){
      stroke(255,50,25);
    }

    line(0,0,this.Dfred1X,this.Dfred1Y);

    if(this.sum==0&&checkD==true){
      noFill();
    }else{
      fill(25,50,255);
    }
    noStroke();
    ellipse(this.Dfred1X-7.5,this.Dfred1Y,this.r,this.r);

    this.DstringKeyBuffer = ["D2","D#2","E2","F2","F#2","G2","G#2","A2","A#2","B2","C3","C#3","D3","D#3","E3","F3","F#3","G3","G#3","A3","A#3","B3","C4"];
    if(this.fredNumburD==0){
      fill(0,240,180);
    }else{
      fill(255);
    }
    text(this.DstringKeyBuffer[this.fredNumburD],this.Dfred1X-15, this.Dfred1Y+3.75);
    pop();
  };
};

var TestA = function(){
  this.fredRatioBuffer = [3.4, 3.4, 3.4, 3.1, 2.8, 2.6, 2.6, 2.2, 2.2, 2.1, 2.0, 1.8, 1.8, 1.6, 1.6, 1.5, 1.4, 1.3, 1.3, 1.3, 1.1, 1];
  this.fredNumburD = 0;

  this.testAUpdate = function(){
    push();
    if(stringsIndex==5||keyCode==DELETE){
      this.fredNumburD = otoIndex;
    }
    this.vd1 = createVector(widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*5));
    this.vd2 = createVector(widthSpacing,(hei/2)-(topLength/2)+((topLength/7)*5));
    this.vd3 = this.vd1.sub(this.vd2);
    this.Dr = this.vd3.mag();

    this.vd3.mult(-1);

    this.DcosTheta = this.vd3.x/this.Dr;

    this.DsinTheta = this.vd3.y/this.Dr;

    this.findSumNumberD = 22-this.fredNumburD;
    this.sum = 0;
    for(var i = 0; i < this.fredRatioBuffer.length-this.findSumNumberD; i++ ){
      this.sum += this.fredRatioBuffer[i];
    }
    this.Dfred1R = this.Dr * ((45.5-this.sum)/45.5);

    this.Dfred1X = this.Dfred1R * this.DcosTheta;

    this.Dfred1Y = this.Dfred1R * this.DsinTheta;

    if(this.fredNumburD==0){
      this.r = 0.00;
    }else if(this.fredNumburD>=1&&this.fredNumburD < 4){
      this.r = 21.00;
    }else if(this.fredNumburD==4){
      this.r = 20.55;
    }else if(this.fredNumburD==5){
      this.r = 20.10;
    }else if(this.fredNumburD==6||this.fredNumburD==7){
      this.r = 19.80;
    }else if(this.fredNumburD==8||this.fredNumburD==9){
      this.r = 19.20;
    }else if(this.fredNumburD==10){
      this.r = 19.05;
    }else if(this.fredNumburD==11){
      this.r = 18.90;
    }else if(this.fredNumburD==12||this.fredNumburD==13){
      this.r = 18.60;
    }else if(this.fredNumburD==14||this.fredNumburD==15){
      this.r = 18.30;
    }else if(this.fredNumburD==16){
      this.r = 18.15;
    }else if(this.fredNumburD==17){
      this.r = 18.00;
    }else if(this.fredNumburD==18||this.fredNumburD==19||this.fredNumburD==20){
      this.r = 17.85;
    }else if(this.fredNumburD==21){
      this.r = 17.55;
    }else if(this.fredNumburD==22){
      this.r = 17.40;
    }
    pop();
  };

  this.testAShow = function(){
    push();
    if(stringsIndex==5||keyCode==DELETE){
      this.fredNumburD = otoIndex;
    }
    translate(widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*5));

    if(this.fredNumburD == 0&&checkA==true){
      stroke(255,0,0);
    }else{
      noStroke();
    }
    if(this.fredNumburD>0&&this.fredNumburD < 23){
      stroke(255,50,25);
    }

    line(0,0,this.Dfred1X,this.Dfred1Y);

    if(this.sum==0&&checkA==true){
      noFill();
    }else{
      fill(25,50,255);
    }
    noStroke();
    ellipse(this.Dfred1X-7.5,this.Dfred1Y,this.r,this.r);

    this.DstringKeyBuffer = ["A1","A#1","B1","C2","C#2","D2","D#2","E2","F2","F#2","G2","G#2","A2","A#2","B2","C3","C#3","D3","D#3","E3","F3","F#3","G3"];
    if(this.fredNumburD==0){
      fill(0,240,180);
    }else{
      fill(255);
    }
    text(this.DstringKeyBuffer[this.fredNumburD],this.Dfred1X-15, this.Dfred1Y+3.75);
    pop();
  };
};

var TestLowE = function(){

  this.fredRatioBuffer = [3.4, 3.4, 3.4, 3.1, 2.8, 2.6, 2.6, 2.2, 2.2, 2.1, 2.0, 1.8, 1.8, 1.6, 1.6, 1.5, 1.4, 1.3, 1.3, 1.3, 1.1, 1];
  this.fredNumburD = 0;

  this.testLowEUpdate = function(){
    push();

    if(stringsIndex==6||keyCode==DELETE){
      this.fredNumburD = otoIndex;
    }

    this.vd1 = createVector(widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*6));
    this.vd2 = createVector(widthSpacing,(hei/2)-(topLength/2)+((topLength/7)*6));
    this.vd3 = this.vd1.sub(this.vd2);
    this.Dr = this.vd3.mag();

    this.vd3.mult(-1);

    this.DcosTheta = this.vd3.x/this.Dr;

    this.DsinTheta = this.vd3.y/this.Dr;

    this.findSumNumberD = 22-this.fredNumburD;
    this.sum = 0;
    for(var i = 0; i < this.fredRatioBuffer.length-this.findSumNumberD; i++ ){
      this.sum += this.fredRatioBuffer[i];
    }
    this.Dfred1R = this.Dr * ((45.5-this.sum)/45.5);

    this.Dfred1X = this.Dfred1R * this.DcosTheta;

    this.Dfred1Y = this.Dfred1R * this.DsinTheta;

    if(this.fredNumburD==0){
      this.r = 0.00;
    }else if(this.fredNumburD>=1&&this.fredNumburD < 4){
      this.r = 21.00;
    }else if(this.fredNumburD==4){
      this.r = 20.55;
    }else if(this.fredNumburD==5){
      this.r = 20.10;
    }else if(this.fredNumburD==6||this.fredNumburD==7){
      this.r = 19.80;
    }else if(this.fredNumburD==8||this.fredNumburD==9){
      this.r = 19.20;
    }else if(this.fredNumburD==10){
      this.r = 19.05;
    }else if(this.fredNumburD==11){
      this.r = 18.90;
    }else if(this.fredNumburD==12||this.fredNumburD==13){
      this.r = 18.60;
    }else if(this.fredNumburD==14||this.fredNumburD==15){
      this.r = 18.30;
    }else if(this.fredNumburD==16){
      this.r = 18.15;
    }else if(this.fredNumburD==17){
      this.r = 18.00;
    }else if(this.fredNumburD==18||this.fredNumburD==19||this.fredNumburD==20){
      this.r = 17.85;
    }else if(this.fredNumburD==21){
      this.r = 17.55;
    }else if(this.fredNumburD==22){
      this.r = 17.40;
    }
    pop();
  };

  this.testLowEShow = function(){
    push();

    if(stringsIndex==6||keyCode==DELETE){
      this.fredNumburD = otoIndex;
    }

    translate(widthSpacing+threadLength,(hei/2)-(bottomLength/2)+((bottomLength/7)*6));

    if(this.fredNumburD == 0&&checkE==true){
      stroke(255,0,0);
    }else{
      noStroke();
    }
    if(this.fredNumburD>0&&this.fredNumburD < 23){
      stroke(255,50,25);
    }

    line(0,0,this.Dfred1X,this.Dfred1Y);

    if(this.sum==0&&checkE==true){
      noFill();
    }else{
      fill(25,50,255);
    }
    noStroke();
    ellipse(this.Dfred1X-7.5,this.Dfred1Y,this.r,this.r);

    this.DstringKeyBuffer = ["E1","F1","F#1","G1","G#1","A1","A#1","B1","C2","C#2","D2","D#2","E2","F2","F#2","G2","G#2","A2","A#2","B2","C3","C#3","D3"];
    if(this.fredNumburD==0){
      fill(0,240,180);
    }else{
      fill(255);
    }
    text(this.DstringKeyBuffer[this.fredNumburD],this.Dfred1X-15, this.Dfred1Y+3.75);

    pop();
  };
};

各ストリングを描画するためのクラスファイル郡です。名前の通りテスト用だったクラスファイルですので、同じ処理を何度も繰り返しています。 実際に使う際には1つに統合して、インスタンスを複数作るようにしたほうが良いですね、すんまそん。

Class file group for rendering each string. As the name implies, it's a class file for testing purposes, so I repeat the process over and over again. In practice, it's better to consolidate them into one and create multiple instances, right?

function keyPressed() {
  if(key=='p'||key=='P'){
    checke = true;
  }
  if(key=='o'||key=='O'){
    checkB = true;
  }
  if(key=='i'||key=='I'){
    checkG = true
  }
  if(key=='l'||key=='L'){
    checkD = true;
  }
  if(key=='k'||key=='K'){
    checkA = true;
  }
  if(key=='m'||key=='M'){
    checkE = true;
  }

  if(key=='j'||key=='J'){
    stringsIndex=6;
    otoIndex=0;
    checkE=false;
  }
  if(key=='h'||key=='H'){
    stringsIndex=5;
    otoIndex=0;
    checkA=false;
  }
  if(key=='g'||key=='G'){
    stringsIndex=4;
    otoIndex=0;
    checkD=false;
  }
  if(key=='u'||key=='U'){
    stringsIndex=3;
    otoIndex=0;
    checkG=false;
  }
  if(key=='y'||key=='Y'){
    stringsIndex=2;
    otoIndex=0;
    checkEB=false;
  }
  if(key=='t'||key=='T'){
    stringsIndex=1;
    otoIndex=0;
    checke=false;
  }

  if(keyCode == DELETE){
    setInterval(1000);

    stringsChara = '';
    otoChara = '';

    r1=r2=r3=r4=r5=r6=0;

    s1 = 1.2;
    s2 = 1.4;
    s3 = 1.6;
    s4 = 1.8;
    s5 = 2;
    s6 = 2.2;

    g1=g2=g3=g3=g4=g5=g6= 127;

    stringsIndex=0;
    otoIndex=0;

    //ADD
    teste = new TestHiE();
    stringsIndex = 1;
    otoIndex = 0;
    testb = new TestB();
    stringsIndex = 2;
    otoIndex = 0;
    testg = new TestG();
    stringsIndex = 3;
    otoIndex = 0;
    testd = new TestD();
    stringsIndex = 4;
    otoIndex = 0;
    testa = new TestA();
    stringsIndex = 5;
    otoIndex = 0;
    testE = new TestLowE();
    stringsIndex = 6;
    otoIndex = 0;

    checke = false;
    checkB = false;
    checkG = false;
    checkD = false;
    checkA = false;
    checkE = false;

    //ADD
    allClearAlpha = 200;

    console.log("All DELETED.");
  }
  if(keyCode==ENTER){
    stringsSearch();
    otoSearch();
    otoCheck();
  }
}

この関数はキーボードからでも操作できたら良いなというただの願望で用意された未完成の関数です。コメントアウトするなりしてください。

This is an unfinished function that is just a desire to be able to operate from the keyboard. Please comment it out.

function mousePressed(){
  editStringEnable();
  editString();
  clearStringEnable();
  clearString();

  doAllClear();
  doSavePng();
}

mousePressed()もP5が用意している関数です。名前の通り、マウスがクリックされた時呼び出される関数です。

mousePressed () is another P5 function. As the name suggests, it is a function that is called when the mouse is clicked.

function editString(){
  if(mouseX>stringOffsetXLeft[0][0]&&mouseX < stringOffsetXRight[0][0]&&mouseY>stringOffsetYUp[0][0]&&mouseY < stringOffsetYDown[0][0]&&editEnable==true&&editClear==false){
    checke = true;
  }
  if(mouseX>stringOffsetXLeft[1][0]&&mouseX < stringOffsetXRight[1][0]&&mouseY>stringOffsetYUp[1][0]&&mouseY < stringOffsetYDown[1][0]&&editEnable==true&&editClear==false){
    checkB = true;
  }
  if(mouseX>stringOffsetXLeft[2][0]&&mouseX < stringOffsetXRight[2][0]&&mouseY>stringOffsetYUp[2][0]&&mouseY < stringOffsetYDown[2][0]&&editEnable==true&&editClear==false){
    checkG = true; 
  }
  if(mouseX>stringOffsetXLeft[3][0]&&mouseX < stringOffsetXRight[3][0]&&mouseY>stringOffsetYUp[3][0]&&mouseY < stringOffsetYDown[3][0]&&editEnable==true&&editClear==false){
    checkD = true;
  }
  if(mouseX>stringOffsetXLeft[4][0]&&mouseX < stringOffsetXRight[4][0]&&mouseY>stringOffsetYUp[4][0]&&mouseY < stringOffsetYDown[4][0]&&editEnable==true&&editClear==false){
    checkA = true;
  }
  if(mouseX>stringOffsetXLeft[5][0]&&mouseX < stringOffsetXRight[5][0]&&mouseY>stringOffsetYUp[5][0]&&mouseY < stringOffsetYDown[5][0]&&editEnable==true&&editClear==false){
    checkE = true;
  }

  for(var i = 0; i < 6; i++){
    for(var j = 0; j < 23; j++){
      if(mouseX > stringOffsetXLeft[i][j]&&mouseX < stringOffsetXRight[i][j] && mouseY > stringOffsetYUp[i][j] && mouseY < stringOffsetYDown[i][j] && editEnable == true && editClea r== false){
        stringsIndex = i+1;
        otoIndex = j;
      }
    }
  }
}

マウスが各弦の各フレッドの位置でクリックされた時、音の記号を出すようにする関数です。これもクラスファイルにまとめたほうがいいでそう。

This function emits a sound symbol when the mouse is clicked at each Fred position on each chord. I'd better put this in a class file.

function clearString(){
  if(mouseX>stringOffsetXLeft[0][0]&&mouseX < stringOffsetXRight[0][0]&&mouseY>stringOffsetYUp[0][0]&&mouseY < stringOffsetYDown[0][0]&&editEnable==false&&editClear==true){
    stringsIndex=1;
    otoIndex=0;
    checke=false;
  }
  if(mouseX>stringOffsetXLeft[1][0]&&mouseX < stringOffsetXRight[1][0]&&mouseY>stringOffsetYUp[1][0]&&mouseY < stringOffsetYDown[1][0]&&editEnable==false&&editClear==true){
    stringsIndex=2;
    otoIndex=0;
    checkB=false;
  }
  if(mouseX>stringOffsetXLeft[2][0]&&mouseX < stringOffsetXRight[2][0]&&mouseY>stringOffsetYUp[2][0]&&mouseY < stringOffsetYDown[2][0]&&editEnable==false&&editClear==true){
    stringsIndex=3;
    otoIndex=0;
    checkG=false;
  }
  if(mouseX>stringOffsetXLeft[3][0]&&mouseX < stringOffsetXRight[3][0]&&mouseY > stringOffsetYUp[3][0]&&mouseY < stringOffsetYDown[3][0]&&editEnable==false&&editClear==true){
    stringsIndex=4;
    otoIndex=0;
    checkD=false;
  }if(mouseX>stringOffsetXLeft[4][0]&&mouseX < stringOffsetXRight[4][0]&&mouseY > stringOffsetYUp[4][0]&&mouseY < stringOffsetYDown[4][0]&&editEnable==false&&editClear==true){
    stringsIndex=5;
    otoIndex=0;
    checkA=false;
  }
  if(mouseX>stringOffsetXLeft[5][0]&&mouseX < stringOffsetXRight[5][0]&&mouseY>stringOffsetYUp[5][0]&&mouseY < stringOffsetYDown[5][0]&&editEnable==false&&editClear==true){
    stringsIndex=6;
    otoIndex=0;
    checkE=false;
  }
}

編集のリセットを弦毎に行う関数です。

This function resets the editing per string.

function editStringEnable(){
  if(mouseX>10&&mouseX < 70&&mouseY>10&&mouseY < 60){
    editEnable=true;
    editClear=false;
    editAlpha = enableAlpha;
    clearAlpha = disableAlpha;
  }
}

編集ボタンが押された時、タブ譜が作れるようになる関数です。

This function allows you to create tab notation when the edit button is pressed.

function clearStringEnable(){
  if(mouseX>120&&mouseX < 180&&mouseY>10&&mouseY < 60){
    editEnable=false;
    editClear=true;
    editAlpha = disableAlpha;
    clearAlpha = enableAlpha;
  }
}

各弦ごとにリセットをするためのボタンを有効にします。

Enables a reset button for each string.

function doAllClear(){
  if(mouseX>10&&mouseX < 70&&mouseY < 390&&mouseY > 330&&keyCode!=DELETE){ 
    setInterval(1000);

    stringsChara = '';
    otoChara = '';

    r1=r2=r3=r4=r5=r6=0;

    s1 = 1.2;
    s2 = 1.4;
    s3 = 1.6;
    s4 = 1.8;
    s5 = 2;
    s6 = 2.2;

    g1=g2=g3=g3=g4=g5=g6= 127;

    teste = new TestHiE();
    stringsIndex = 1;
    otoIndex = 0;
    testb = new TestB();
    stringsIndex = 2;
    otoIndex = 0;
    testg = new TestG();
    stringsIndex = 3;
    otoIndex = 0;
    testd = new TestD();
    stringsIndex = 4;
    otoIndex = 0;
    testa = new TestA();
    stringsIndex = 5;
    otoIndex = 0;
    testE = new TestLowE();
    stringsIndex = 6;
    otoIndex = 0;

    checke = false;
    checkB = false;
    checkG = false;
    checkD = false;
    checkA = false;
    checkE = false;


    allClearAlpha = 200;


    console.log("All have been reset.");
  }
}

全ての弦をリセットします。

Reset all strings.

function doSavePng(){
  if(mouseX>120&&mouseX < 180&&mouseY < 390&&mouseY>330){
    saveCanvas('tab_score', 'png');
    savePngDisableAlpha = 150;
    savePngAlpha = 200;
  }
}

キャンバスの画像をpngで保存する関数です。

This function saves a picture of the canvas in png.

function keyTyped(){
  if(key!=1&&key!=2&&key!=3&&key!=4&&key!=5&&key!=6&&key!='p'&&key!='P'&&key!='o'&&key!='O'&&key!='i'&&key!='I'&&key!='l'&&key!='L'&&key!='k'&&key!='K'&&key!='m'&&key!='M'&&keyCode!=DELETE&&keyCode!=ENTER&&keyCode!=SHIFT&&keyCode!=CONTROL){
    otoChara = key;
    console.log(key);
  }
  if(key==1||key==2||key==3||key==4||key==5||key==6){
    stringsChara = key;
    console.log(key);
  }
}

これはデバック用の関数です。コメントアウトで消してください。

This is a debugging function. Please comment it out.

function keyReleased() {
  if (keyCode == CONTROL) saveCanvas('tab_score', 'png');
}

Controlボタンが押された時にも保存できるようになっています。

You can also save when the Control button is pressed.

function otoSearch(){
  switch (otoChara) {
      case 'q':
      otoIndex = 1;
      break;
      case 'Q':
      otoIndex = 2;
      break;
      case 'a':
      otoIndex = 3;
      break;
      case 'A':
      otoIndex = 4;
      break;
      case 'z':
      otoIndex = 5;
      break;
      case 'Z':
      otoIndex = 6;
      break;
      case 'w':
      otoIndex = 7;
      break;
      case 'W':
      otoIndex = 8;
      break;
      case 's':
      otoIndex = 9;
      break;
      case 'S':
      otoIndex = 10;
      break;
      case 'x':
      otoIndex = 11;
      break;
      case 'X':
      otoIndex = 12;
      break;
      case 'e':
      otoIndex = 13;
      break;
      case 'E':
      otoIndex = 14;
      break;
      case 'd':
      otoIndex = 15;
      break;
      case 'D':
      otoIndex = 16;
      break;
      case 'c':
      otoIndex = 17;
      break;
      case 'C':
      otoIndex = 18;
      break;
      case 'r':
      otoIndex = 19;
      break;
      case 'R':
      otoIndex = 20;
      break;
      case 'f':
      otoIndex = 21;
      break;
      case 'F':
      otoIndex = 22;
      break;
  }
  var temp = str(otoIndex);
  console.log("otoIndex is : " + temp);
}

これもキーボードで操作できるようにしたかった未完成の関数です。コメントアウトしましょう。

This is also an incomplete function that I wanted to be able to do with the keyboard. Let's comment it out.

function stringsSearch(){
  switch (stringsChara) {
    case '1':
      stringsIndex = 1;
      break;
    case '2':
      stringsIndex = 2;
      break;
    case '3':
      stringsIndex = 3;
      break;
    case '4':
      stringsIndex = 4;
      break;
    case '5':
      stringsIndex = 5;
      break;
    case '6':
      stringsIndex = 6;
      break;
    }
  var temp = str(stringsIndex);
  console.log("stringsIndex is : " + temp);
}

今どの弦を操作しているのか探しだす関数です。だったっけな?ごめん覚えてない。

It is a function to find out which string is being manipulated now. .....Was it? Sorry, I don't remember.

function otoCheck(){
  var b1 = stringsIndex;
  var b2 = otoIndex;
  if((b1==1||b1==2||b1==3||b1==4||b1==5||b1==6)&&(b2==1||b2==2||b2==3||b2==4||b2==5||b2==6||b2==7||b2==8||b2==9||b2==10||b2==11||b2==12||b2==13||b2==14||b2==15||b2==16||b2==17||b2==18||b2==19||b2==20||b2==21||b2==22)){
    otoEnable = true;
  }else{
    otoEnable = false;
  }
  if(otoEnable){
    console.log("oto is : " + otoBuffer[stringsIndex-1][otoIndex-1]);
  }
}

これもデバッグ用です。コメントアウト。

This is also for debugging purposes. Comment out.


Androidのローカル環境での使用
Using Android in a Local Environment

続いてAndroidのローカル環境での使用です。

Next is the use of Android in local environment.

Android Studioなどの統合開発環境を使えばいいじゃないかと思うかもしれませんが、あくまで使ってるのはP5です。

You might think you should use an integrated development environment like Android Studio, but We're using P5.

ブラウザがあれば上のコードをそのまま実行するだけで簡単にできるのですが、例えばオフラインで使いたい場合はどうするかです。

If you have a browser, you can just run the code above, but what if you want to use it offline?

Android 4.1ぐらいまではHTMLファイルとJSファイルとクロームがあれば動きましたが、Android6以降だと何やら動かない仕様に変わっているみたいです。

Until Android 4.1, it worked with HTML files, JS files, and Chrome, but since Android 6, it doesn't work at all.

めんどくせーな、とか思って色々調べてみたら、Pydroid3というのがGoogle Playアプリストアに無料で置いてあるみたい。

So, I found Pydroid3 in the Google Play app store for free.

これがあればFlaskを使って簡単に表示できます。

This is easy to do with Flask.

さらにP5で全てのGUI部分やIO部分をまかなうことができれば、Androidアプリのように使えます。ちょっと面倒くさいですが。

And if P5 can handle all the GUI and IO parts, it can be used like an Android app. It's a little troublesome.

まず、Google Play StoreでPydroid3をダウンロードします。

First, download Pydroid3 from Google Play Store.


Responsive image

ダウンロードしたら開きます。そして左上のハンバーガーメニューをクリック。

Download and open. Then click the hamburger menu in the upper left.


Responsive image

Pipがあるのでクリック。

Click on Pip.


Responsive image

FlaskやFlask-Bootstrapなど今回使うライブラリをインストール。

Install Flask, Flask-Bootstrap.


Responsive image

次にパソコンでP5のコードを、sketch.jsとして保存して、以下のフォルダを作りその中のstaticフォルダにsketch.jsを格納します。

Next, save the code of P5 on your computer as sketch.js, create the following folder, and put sketch.js in the static folder inside.

言い忘れてました。HTMLファイルのIDとキャンバスを紐付ける為に、setup()関数のcreateCanvas()にParent()を追加してください。

I forgot to tell you. To associate the canvas with the ID of the contents of the HTML file, add Parent () to createCanvas () in the setup () function.

function setup(){
  createCanvas(wid,hei);

-->
function setup(){
  createCanvas(wid,hei).parent('canvasHolder');

次にP5のライブラリ(p5.dom.min.jsとp5.min.js)をhttps://p5js.org/download/からダウンロードして同じstaticフォルダに格納します。

Then download the P5 library (p5.dom.min.js and p5.min.js) from https://p5js.org/download/ and store it in the same static folder.

folder
     |
     |-static
           |-skecth.js
           |-p5.dom.min.js
           |-p5.min.js
     |-templates
           |-main.html
     |-app.py

続いてfloder/templates/main.htmlを作ります。

Next, create floder/templates/main.html.

{% extends "bootstrap/base.html" %}
{% block title %} guiterTabGenerator {% endblock title %}
{% block content %}
<div class="container">
  <div id="canvasHolder" align="center">
  </div>
</div>
{% endblock content %}
{% block head %}
{{ super() }}
<script src= {{ url_for( 'send_static' , path='p5.min.js') }}></script>
<script src= {{ url_for( 'send_static' , path='p5.dom.min.js') }}></script>
<script src= {{ url_for( 'send_static' , path='sketch.js') }}></script>
{% endblock head %}

bootstrap/base.htmlはFlask-Bootstrapが用意してくれます。続いてfloder/app.pyを作ります。

Flask-Bootstrap provides bootstrap/base.html. Next, create floder/app.py.

from flask import Flask, render_template, url_for, send_from_directory
from flask_bootstrap import Bootstrap


app = Flask(__name__)
bootstrap = Bootstrap(app)

@app.route('/')
def home():
    return render_template('main.html')


@app.route('/static/<path:path>')
def send_static(path):
    return send_from_directory('static', path)

if __name__=="__main__":
    app.run(debug=True)

作ったフォルダをUSBなりクラウドなりでAndroid実機の分かりやすい場所にコピーします。

You can copy the folder you made to a place where you can easily find the actual Android device by using USB or the cloud.

あとはPydroid3アプリからコピーしたFolderのapp.pyを実行させるだけです。

All you have to do is run app.py of Folder copied from Pydroid 3 app.


Responsive image


Responsive image


Responsive image


Responsive image


Responsive image

成功すれば以下のようになります。あとはご自由に画面サイズなど調整してください。

If successful, it will look like the image below. Also, please adjust the screen size freely.


Responsive image


Herokuにアップする
Upload to Heroku

続いてHerokuです。ここまでくれば簡単です。用意したフォルダをこの記事を参考にしてGunicornをインストール、Procfileとrequirements.txt、Heroku gitを駆使してマイアカウントからアップするだけです。

Next is Heroku. At this point, it's easy. Take a look at this blog post. Just install Gunicorn, use Procfile, requirements.txt, and Heroku Git to upload your folders from your Account.

これまでのファイルの作り方はこの方の記事の通りです。サンキューです!

This blog post explains how to create a file. Thank you!

それでは、長々とお付き合い頂きありがとうございます。

Thank you for reading this long blog.




See You Next Page!