Published Date : 2020年2月24日9:01
YouTubeにアップした動画、「Part 7 - 前半 - Adding sound to apps created with Processing」の補足説明の記事です。
Here's a little more about the "Part 7 - first half - Adding sound to apps created with Processing" video I uploaded to YouTube.
まずは上の動画の趣旨を軽く説明します。 Processingを使用してギターのフレットボードから簡単なTAB譜を描画するアプリケーションを作成します。 このアプリケーションの利点は、ギターの弦と音階の関係をギターフレットボードから直接理解でき、1つずつ画像ファイルとして保存できることです。
First, let me briefly explain the purpose of the video above. Create an application to draw a simple TAB notation from a guitar fretboard with Processing. The advantage of this application is that you can understand the relationship between guitar strings and musical scales directly from the guitar fretboard and save them one by one as image files.
簡単に誰でもすぐに作れます。 今回はおまけとして、前回のアプリに音を出す機能を加えていくための下準備をします。 ギターの音はSunvoxというロシア製のフリーのDTMソフトを使用します。 このソフトはかなり高機能で、無料で使用できるのに、本格的なDTMに使用できます。是非使ってみてください。
This time, as a bonus, I'm going to prepare for adding sound to the previous app. I use a free Russian DTM software called Sunvox for the guitar sound. This software is quite advanced, and although it can be used for free, it can be used for full-fledged DTM. Please try it.
全体の説明は動画に任せるとして、補足が必要だろうと思われる部分を説明していきMASU。
I'll leave the entire explanation to the video, but I'll explain the parts that I think need to be supplemented.
過去に似たアプリをP5.jsとPythonを使ってブラウザに表示させるものを作ったのでこちらの記事も参考にしてみてくだちぃ。
I've created a similar app in the past that uses P5.js and Python to display in the browser, so check out this post.
目次
Table of Contents
まずSunvoxをダウンロード、インストールして、ギターの音を1音ずつWAVEファイルで保存していきます。
First, download and install Sunvox, and save the guitar notes one by one as WAVE files.
そこから、Processingのプロジェクトを作成し、DATAフォルダとスケッチファイルを作成して、WAVEファイルをDATAフォルダに移動します。
From there, create a Processing project, create a DATA folder and sketch file, and move the WAVE file to the DATA folder.
ProcessingのSoundライブラリを使用してテスト用コードを作成し、ギターの音と音の長さをインタラクティブに調整できることを確認します。
Create test code using the Processing Sound library to ensure that you can interactively adjust the guitar sound and the note length.
後はそのテスト用のコードのロジックをこれまでに作ったアプリに適用するだけです。
All you have to do is apply the logic of the test code to the apps we've written.
ブラウザでSunvoxを検索
Search Sunvox in browser
ダウンロードしたフォルダを開き、Sunvoxという名前のフォルダーを開きます。
Open the downloaded folder and open the folder named Sunvox.
それぞれ使用しているOS用のフォルダを開きます。
Open the folder for the OS you are using.
そこに入っている実行ファイルを開きます。
Open the executable file contained there.
左上のSunvoxのロゴマークボタンを押すと様々な設定ができます。
If you press the logo button of Sunvox in the upper left, you can make various settings.
今回はNewProjectを選びます。
Select NewProject this time.
Emptyを選択してOutputモジュールのみにします。
Choose Empty to make it the Output module only.
Sunvoxにはエレキギターの音が既に用意されてます。
Sunvox already has electric guitar sounds.
それをロードするためにはまずモジュールウィンドウのハンバーガーメニューをクリックして開きます。
To load that, you need to click the hamburger menu in the module window.
メニューを開いたら、Load ー> Instrumental ー> guitar ー> electric_guitar ー> OKの順に選択していきます。
Open the menu and choose Load - > Instrumental - > guitar - > electric _ guitar - > OK.
Guitarモジュールが用意されたら、ハンバーガーメニューの横にあるコネクトボタンをクリックすると画面が緑色に変わるので、Guitarモジュールが選択されている状態でOutputモジュールをクリックします。
When the Guitar module is ready, click the Connect button next to the hamburger menu and the screen will turn green. With the Guitar module selected, click the Output module.
するとGuitarモジュールの音が出るようになるので、キーボードのどれか一つをクリックすると音が確認できます。
So, You can then hear the Guitar module sound by clicking on one of the keyboards.
キーボードのオクターブを変化させるにはキーボード横にあるプラスマイナスボタンを押します。
To change the octave on the keyboard, press the Plus/Minus button next to the keyboard.
パターンプロパティの設定を変えるには、タイムラインウィンドウのハンバーガーメニューを開きます。
To change the pattern property settings, open the Hamburger menu in a Timeline window.
BPM等の設定はProject propertiesからできます。
Settings such as BPM can be made from Project properties.
編集モードのままキーボードを押すと、音が表記されます。
Press the keyboard while in edit mode to display the note.
Import/Exportメニューから音をWAVEファイルやMIDIファイルにエクスポートできます。
You can export sounds to wave and MIDI files from the Import/Export menu.
エクスポートしたい場所を選び、名前を決めてOKボタンを押します。
Select the location you want to export, choose a name, and press the OK button.
テスト用プロジェクトのファイル構成は以下になります。
The file structure of the test project is as follows.
processingAudioTest data e1.wav f1.wav fs1.wav . . . . d5.wav processingAudioTest.pde
サウンドライブラリを読み込みます。
Import the sound library
import processing.sound.*;
続いてですが、同じような名前の変数や配列があるのでわかりにくいので上から順番に変数の役割を説明します。
Next, since there are variables and arrays with similar names, it is difficult to understand, so I will explain the roles of variables in order from the top.
String[] musicalNote = {"e", "f", "fs", "g", "gs", "a", "as", "b", "c", "cs", "d", "ds"}; String[] musicalNotes; String[] noteLength = {"W", "H", "Q", "E", "16"}; SoundFile[] notes; String currentNote; String currentNoteLength; float[] durationsRatio; float currentDuration;
まず、ファイル名を特定するための配列があり、 続いて、拡張子を除いた音名だけの配列、 そして、音の長さを識別するための配列、 さらに、SoundFileオブジェクトを格納するための配列、 もういっちょ、現在鳴っている音の名前を画面に表示させるために必要な変数、 あともう少し、同様に現在の音の長さを表す配列、 ラス手前、音の長さの時間の比率が格納される配列、 そして最後は、キーボードによって音の長さを切り替えた時に、現在の音の長さが一時的に記録される変数です。
First, there is an array to identify the filenames. followed by an array containing only the names of the notes without the extension, and an array for identifying the length of the note, and an array for storing SoundFile objects, and the variables needed to display the name of the current note on the screen. and similarly an array representing the length of the current note, an array in which the ratio of time to sound length is stored; And finally, when you switch the note length by keyboard, the current note length is temporarily recorded.
続いて、setup関数内の説明です。
This is followed by a description in the setup function.
void setup(){ size(640,360); currentNote = ""; currentNoteLength = "W"; currentDuration = 0; notes = new SoundFile[47]; durationsRatio = new float[noteLength.length]; musicalNotes = new String[47];
まず、先程定義した配列や変数を初期化していきます。
First, we initialize the array and variables we defined earlier.
for (int i = 1; i < 5; i++) { int offset = 12; for (int j = 0; j < musicalNote.length; j++) { if (i == 1) { offset = i * j; } else { offset = 12 * (i-1) + j; } if (j <= 7) { notes[offset] = new SoundFile(this, musicalNote[j] + i + ".wav"); musicalNotes[offset] = musicalNote[j] + i; } else { if (i==4 && j==11) { break; } else { notes[offset] = new SoundFile(this, musicalNote[j] + str(i+1) + ".wav"); musicalNotes[offset] = musicalNote[j] + str(i+1); } } } }
最初のFor文でオクターブの数字の分だけループさせます。 数字は1から5まであります。 次に、オクターブは12音で切り替わるので、一時的な変数Offsetには12の数をいれます。 そして次のFor文で1オクターブ目の数、つまり12回ループさせます。 そのループの中で、もしiが1なら、そのままiに0から11までの数を掛けてOffset変数に格納します。 すると、最初の配列に0から11までの12個分のWAVEファイルとNote名がそのまま格納されていきます。 それ以外、つまりiが2から4までなら一回のループで12個分増えるように計算していきます。 そしてオクターブはCで切り替わるので、それを(j <= 7)で判定します。 例えば、EFF#GG#AA#Bまでの8個の音のオクターブ記号が1なら、次のCから2に切り替わります。 最後にエラーの原因となった47個しか入らない配列に48個目のオブジェクトや変数を入れようとするのを回避するためにループ処理の一番最後をBreak文でスキップさせます。
The first For statement loops through the octave numbers. Numbers range from 1 to 5. Next, the octave is switched with 12 syllables, so the temporary variable Offset should contain a number of 12. Then, in the following For statement, we loop the number of 1 octave, or 12. In the loop, if i is 1, we simply multiply i by a number between 0 and 11 and store it in the Offset variable. The first array will contain exactly 12 WAVE files and Note names from 0 to 11. Otherwise, if i is between 2 and 4, add 12 more in one loop. And the octave is switched by C, so it is judged by (j < = 7). For example, if the octave symbol for eight notes up to EFF#GG#AA#B is 1, it switches from C to 2. The Break statement skips the end of the loop to avoid trying to put the 48th object or variable in the array that only holds 47 that caused the error.
for (int k = 0; k < noteLength.length; k++) { durationsRatio[k] = notes[0].duration() * (pow(2, k)-1)/pow(2, k); } }
そして最後に、音の長さの比率をdurationメソッドから取り出した基本となる音の長さから算出していきます。
Finally, the ratio of the note length is calculated from the base note length extracted from the duration method.
音の長さは単純計算をすると2分の1、4分の1としていけばいいのですが、ProcessingのSoundライブラリを使って表現するのが難しいです。 何故なら、この後にでてくる音の長さを変えるcueメソッドは再生場所を変えることによって音の長さを変えているからです。 つまり2秒が長さのベースとなっている音なら 2分の1は1秒後から再生させればいいのですが、4分の1の長さを表現するには、1.5秒後から再生させなければいけません。 なので、音の長さは元の音の長さに2分の1、4分の3、8分の7、16分の15を掛けていけば算出できるようになっています。
For simple calculations, the sound length can be 1/2 or 1/4, but it is difficult to express using the Processing Sound library. This is because the cue method, which changes the length of the subsequent sound, changes the length of the sound by changing the playback location. So if two seconds is the base sound of the length, 1/2 should play after 1 second, but to represent 1/4 length, you have to play after 1.5 seconds. So you can calculate the length by multiplying 1/2, 3/4, 7/8, 15/16 of the original length.
続いてのDraw関数はシンプルです。
The Draw function that follows is simple.
void draw() { background(255); textSize(21); textAlign(CENTER,CENTER); fill(0); text("currentNote: " + currentNote, width/2, height/2 - 20); text("currentNoteLength: " + currentNoteLength, width/2, height/2 + 20); }
画面に現在のノート名と現在のノートの長さを表示させるだけです。
Just display the current note name and the current note length on the screen.
次は音と音の長さをインタラクティブに切り替えて再生させるためのKeyPressed関数内の説明です。
The following is a description of the KeyPressed function, which lets you interactively switch between sound and sound length for playback.
沢山コードが書かれていますが、考え方はシンプルです。
There's a lot of code, but the idea is simple.
void keyPressed() { switch (key) { case '1': // whole note currentNoteLength = noteLength[0]; currentDuration = durationsRatio[0]; break; case '2': // half note currentNoteLength = noteLength[1]; currentDuration = durationsRatio[1]; break; case '3': // Quarter note currentNoteLength = noteLength[2]; currentDuration = durationsRatio[2]; break; case '4': // 8th note currentNoteLength = noteLength[3]; currentDuration = durationsRatio[3]; break; case '5': // 16th note currentNoteLength = noteLength[4]; currentDuration = durationsRatio[4]; break; // Assign pitches to the open strings pitches as E,A,D,G,B and E for guitar standard tunings. /* 6th string -> E 5th string -> A 4th string -> D 3rd string -> G 2nd string -> B 1st string -> E */ case 'a': currentNote = musicalNotes[0]; notes[0].cue(currentDuration); notes[0].play(1.0, 1.0); break; case 's': currentNote = musicalNotes[5]; notes[5].cue(currentDuration); notes[5].play(1.0, 1.0); break; case 'd': currentNote = musicalNotes[10]; notes[10].cue(currentDuration); notes[10].play(1.0, 1.0); break; case 'f': currentNote = musicalNotes[15]; notes[15].cue(currentDuration); notes[15].play(1.0, 1.0); break; case 'g': currentNote = musicalNotes[19]; notes[19].cue(currentDuration); notes[19].play(1.0, 1.0); break; case 'h': currentNote = musicalNotes[24]; notes[24].cue(currentDuration); notes[24].play(1.0, 1.0); break; /*test chord Am DownStroke is expressed by shifting the sound from 6th strings to 1st string by 6 millisecond. UpStroke is expressed by shifting the sound from 1st strings to 6th string by 6 millisecond. 1000 millisecond -> 1 second. */ case 'j': // 5th string, Open string. currentNote = musicalNotes[5]; notes[5].cue(currentDuration); notes[5].play(1.0, 1.0); delay(6); // 4th string, 2 fret. currentNote = musicalNotes[10+2]; notes[10+2].cue(currentDuration); notes[10+2].play(1.0, 1.0); delay(6); // 3rd String, 2fret. currentNote = musicalNotes[15+2]; notes[15+2].cue(currentDuration); notes[15+2].play(1.0, 1.0); delay(6); // 2nd string, 1 fret currentNote = musicalNotes[19+1]; notes[19+1].cue(currentDuration); notes[19+1].play(1.0, 1.0); delay(6); // 1st string, open string. currentNote = musicalNotes[24]; notes[24].cue(currentDuration); notes[24].play(1.0, 1.0); break; // up stroke case 'k': // 1st string, open string. currentNote = musicalNotes[24]; notes[24].cue(currentDuration); notes[24].play(1.0, 1.0); delay(6); // 2nd string, 1 fret currentNote = musicalNotes[19+1]; notes[19+1].cue(currentDuration); notes[19+1].play(1.0, 1.0); delay(6); // 3rd String, 2fret. currentNote = musicalNotes[15+2]; notes[15+2].cue(currentDuration); notes[15+2].play(1.0, 1.0); delay(6); // 4th string, 2 fret. currentNote = musicalNotes[10+2]; notes[10+2].cue(currentDuration); notes[10+2].play(1.0, 1.0); delay(6); // 5th string, Open string. currentNote = musicalNotes[5]; notes[5].cue(currentDuration); notes[5].play(1.0, 1.0); break; } }
キーボードの1から5までを押すことで、音の長さを切り替えます。 そして、適当なキーボードに鳴らしたい音を配置して再生させるようにするだけです。 先程説明したCueメソッドの他にPlayメソッドがあります。 これは引数に何も指定しなければデフォルトの音の速さや大きさで再生されます。 「1.0」は元の音の速さや大きさを表す数値です。 詳しくはProcessingのリファレンスを見てください。 ダウンストロークやアップストロークはDelay関数を使って再生する時間を少しだけ遅らせて表現しています。
Press 1 to 5 on the keyboard to switch the sound length. All you have to do is place the sound you want on the appropriate keyboard and let it play. There is a Play method in addition to the Cue method described earlier. This will play at the default speed and volume if no argument is given. "1.0" is a numerical value representing the speed and magnitude of the original sound. See the Processing reference for more information. Downstrokes and upstrokes use the Delay function to delay the playback time slightly.
後は、キーボードで割り当てていた再生機能を、アプリの機能に合わせるだけです。
All you have to do is adjust the playback function assigned by the keyboard to the function of the application.
この動画とアプリは現在進行形で作っています。
This video and the app are in progress.
P5.jsの時より、機能が複雑になっていきそうなので多少時間がかかる可能性があります。
It may take some time since the functions seem to be more complicated than in P5.js.
ま、兎に角長くなってしまったので次回へ続きます。
In any case, since the blog post is long, so continues on to next time.