1100円で作るTR-808/909 サンプルプレイヤードラムモジュール-モジュラーシンセ自作
Arduinoプログラミングに挑戦しつつ、モジュラーシンセサイザー TR-808/909 サンプルプレイヤードラムモジュールを自作したので、その備忘録。
背景
コードの書けないシステムエンジニア脱却のために始めたプログラミングの15作品目。前回はkickを。前々回はハイハットを作成し、ドラムモジュールが揃ってきた。
残りを補完するスネア、ハンドクラップモジュールを作成したいと思っていた。
音色をシンセサイズする方法を検討したが難しかったため、WAV playerで実現することとなった。ドラムマシンの王者であるRoland TR-808、TR-909のサンプリング音源を収録した。
TR-808/909への思い入れ
正直なところ、実機は触ったことすら無い。SH-32というRolandのデスクトップシンセサイザーにドラム音色が内蔵されており、それで鳴らしたことがある程度だ。
日本に居ると、いろんなイベントでTR-808や909の開発話(例えば、808の初期型は低音が大きくチューニングされてるとか、YMOが使用している試作品はハンドクラップのディケイが量産品と異なるとか)を聞く機会も多く、漠然とした憧れを抱いていた。
TR-808はアナログ回路でドラム音源を再現し、そして再現にとどまらずオリジナルとしての魅力もあり、今もなお、お茶の間で聞かない日が無い高い汎用性は、楽器として100点満点だと思う。
TR-909の事は、正直よく知らない。でも、音は使いやすいよね。その程度の思い入れ。
私が好きなTR-808を使用した曲は飯島真理「Love Sick」とYellow Magic Orchestra「Music plans」だ。TR-808とProphet5の組み合わせっていいよね。
制作物のスペック
ユーロラック規格 3U 6HPサイズ
電源:30mA ( at 5V ) / 20mA ( at12V )
5V単電源で動作可能。または12V単電源で動作可能。
CH1~CH4のトリガーを受けたら、各CHに割り当てられたドラムサンプルを再生する。サンプルの種類はTR-808から9音色、TR-909から9音色の、合計18音色から選択する。
ドラムサンプルは4音源同時出力可能で、それぞれのCHで音量を設定できる。
サンプルのピッチ変更可能。ただし、4CH全てのピッチが同時に変わってしまう。(CH1を低く、CH2を高くといった設定は不可能)
設定データはセーブ可能。電源を切っても、セーブ時の設定を起動時に読み出してくれる。
入出力
トリガー入力:CH1 ~ CH4の全4CH
入力に連動して4つのLEDが点灯する。
オーディオ出力:-2.5 ~ +2.5VのVp-p 5V。DCカップリング。
OLED(有機ELパネル):音色と音量、設定を表示。
マイコン処理の都合上、演奏中は操作不可能。
トグルスイッチ:音色の選択、及び演奏を切り替え。
上記の通り、マイコン処理の都合で、音色変更と音声出力が同時にできないため、このスイッチで切り替える。
タッチセンサー:合計3つのボタンがタッチセンサーとして機能する。
左右選択で2ボタン、パラメータ切り替え1ボタンだ。
制作費
総額1100円
Seeeduino xiao 550円
OLED 180円
オペアンプ100円
電源モジュール(12V to 5V) 70円
パネル 150円
etc
ボタンはタッチパネルを採用することでコストダウン。
安価な中国製電源モジュールを使用し、電源回路をコストダウン。
ほぼ全ての部品をAliexpressから調達している。
プログラミング
-Seeeduino xiao
今回は大量の音声データを扱うので、Arduino nanoでは容量が不足する。
そのため、Arduino IDEが使用可能で、安価小型なSeeeduino xiaoを使用した。
Seeeduino xiaoの使い勝手は良く、Arduinoに慣れている人ならば簡単に扱えるようになる。相性の悪いライブラリはあるだろうが、Seeeduino向けに多くのライブラリが公開されているため、困ることはなかった。
-音声出力(内蔵DAC)
音声出力はSeeeduino xiao内蔵のDACを使用している。DAC分解能は10bitだが、メモリ容量の都合で8bitで使用した。
音声サンプリングは16bit 16kHzよりも、8bit 32kHzのほうが高音質に聞こえる。
-音色メモリ
音色は全18種類、各サンプルは0.3sec以下にすることで容量を確保。
サンプリングレートは8bit 32kHz。
18サンプル * 8bit * 32kHz * 0.3 = 172k byteで、メモリ256k byteに収まる。
wavデータをバイナリに変換する方法は下記リンクを参照。
mp3データをバイナリデータに変換するサービスはいくつかあるが、mp3を出力する際に、0.5secくらいの無音が頭に挿入されてしまった。(理由は調べてないが、データ変換の都合があるらしい)
そのため、wavデータからの書き換えをする手段を選んだ。
Audacityで0.3sec以下のサンプルを作成し、RAWデータ出力。その後、下記のリンクの「PROGMEM作蔵さん」を用いれば、簡単にArduinoテーブル形式のバイナリデータを吐き出してくれる。
-EEPROM(Flash memory)
EEPROMを搭載していないが、Flash memoryを書き換えることで、EEPROMの様な使い方ができる。メモリ使用量が90%を超えているとコンパイルに成功するが書き込みに失敗したため、注意が必要。
ライブラリは下記リンク参照。
-タッチセンサー
Seeeduino xiaoはタッチセンサに対応している。Adafruit_FreeTouch.hというライブラリを使用。判定閾値や、サンプリング回数をチューニングすることで高い精度でタッチセンサを使用することができる。
欠点として、制御の実行に時間がかかり、音声再生に影響を与えることがある。そのため、音声再生中はタッチセンサの機能を殺している。
詳細な使い方は下記参照。
-OLED(有機ELパネル)
OLEDの使用はArduino nanoと同じで、特別なケアは必要なかった。
OLED表示の制御に時間がかかり、音声再生に影響をあたえるので、音声再生中はOLED表示を切り替えないようにしている。
ハードウェア
-電源回路
Arduino nanoは12V to 5Vのレギュレータを内蔵していたが、Seeeduino xiaoは5V to 3.3Vのレギュレータを内蔵している。12Vを印加すると壊れてしまうので、モジュラーシンセ電源の12V to 5Vに変換する手段が必要だった。
(モジュラーシンセの5V電源に繋げば解決するのだが、モジュラーシンセにおいて5Vは貴重なリソースなので消費したくない。多くの電源モジュールは12Vは1A流せても、5Vは150mA程度しか流せない。)
Aliexpressで70円で購入した12V to 5VのDCDCコンバータを使用した。1kHzのスイッチングノイズがあるが、100uFの電解コンデンサを入れたら落ち着いた。
-OLED
厄介なことに、大きなノイズを発する。オーディオ出力に大きなノイズがあるため、対策が必要だ。ノイズ源はOLEDモジュールに内蔵されたチャージポンプが原因と思われる。
対策として220uFの電解コンデンサを2個、VCCとGND間に挿入している。
また、OLEDの表示領域が広いほどノイズも大きいので、表示領域を小さくするオプションを用意し、OLEDの見栄えを犠牲にする代わりにノイズを低減する手段を準備した。
ハードで対策できなければ、ソフトや運用で対策する。世の中の製品の多くが取る手段だ。
-入力回路
Seeeduino xiaoはINPUT回路にPULLDOWN抵抗のオプションがある。
pinMode(pin number , INPUT_PULLDOWN)の関数を用いると、マイコン内部のプルダウン抵抗が使える。
データシートを調べたところ、プルダウン抵抗の値は40kohm。これを用いることで、外付けの抵抗を削減した。
-その他
DACのOUTPUT電圧が3.3Vp-pなので、非反転増幅回路で5Vp-pに変換している。
入力回路のLEDはGNDに直に落としている。LEDの順方向電圧Vfによっては、Seeeduino xiaoが正しくトリガー入力を検出できないので、注意。その場合はLEDとINPUT端子の間に抵抗をいれればOK。
宣伝:オープンソースプロジェクトの支援をお願いします
DIYモジュラーシンセのオープンソースプロジェクトを継続するために、patreonというサービスでパトロンを募集しています。
コーヒー一杯の支援をいただけると嬉しいです。
また、パトロン限定のコンテンツも配信しています。
ソースコード
粗末だが公開する。悪い点があれば教えてもらえると勉強になる。
音色データはblogの文字数上限の都合でソースコードから削除している。自分で用意してほしい。
下記のテーブルに18個のサンプルデータを入れればよい。
const static byte smpl[18][9900] PROGMEM = {//wav raw data
// sample data , Data deleted due to copyright reasons
};
もしくは、オリジナルのソースコードをpatreonで公開しているので、そちらでDLしてほしい。
https://www.patreon.com/posts/81414536?pr=true
#include <FlashAsEEPROM.h>//flash memory use as eeprom
#include <Adafruit_FreeTouch.h>//touch sensor
//OLED setting
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#define OLED_ADDRESS 0x3C
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#include <Wire.h>//for I2C
#include <avr/pgmspace.h>
// ディスプレイ変数の宣言
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
byte mode = 0;//display serect , sample 0-3 and amp 4-7 , pitch 8 , display 9 ,save 10
bool disp_ratch = 0;//1=display change , 0 = no change , for reduce i2c frequency.
bool disp_sw = 1; //1=display update on , 0 = no update for play sound.counter measure of delay by update display and reduce audio noise from display power supply.
bool old_disp_sw = 0;
bool disp_set = 1;//1=font size big but have noise , 0 = font size small due to reduce noise.
//touch
Adafruit_FreeTouch qt_1 = Adafruit_FreeTouch(A7, OVERSAMPLE_32, RESISTOR_0, FREQ_MODE_NONE);
Adafruit_FreeTouch qt_2 = Adafruit_FreeTouch(A8, OVERSAMPLE_32, RESISTOR_0, FREQ_MODE_NONE);
Adafruit_FreeTouch qt_3 = Adafruit_FreeTouch(A9, OVERSAMPLE_32, RESISTOR_0, FREQ_MODE_NONE);
int qt1 = 0;//read touch sensor ,use as select button
int qt2 = 0;//read touch sensor ,use as up button
int qt3 = 0;//read touch sensor ,use as down button
byte qt1_ratch = 0;//0=no signal,1=with signal,2=countermeasure of continuous signal
byte qt2_ratch = 0;
byte qt3_ratch = 0;
//sample setting
int slct_smpl1 = 0;
int slct_smpl2 = 0;
int slct_smpl3 = 0;
int slct_smpl4 = 0;
const static char* smpl_name[] PROGMEM = {//display sample name
"808 BD ", "808 SD ", "808 TOM", "808 RIM", "808 HC ", "808 CB ", "808 CH ", "808 OH ", "909 BD1", "909 BD2", "909 SD1", "909 SD2", "909 TOM", "909 RIM", "909 HC1", "909 HC2", "909 CH ", "909 OH "
};
const static byte smpl[18][9900] PROGMEM = {//wav raw data
// sample data , Data deleted due to copyright reasons
};
byte pitch = 15;// 31usec = 1sec / 32kHz(sampling rate) ,Adjust by processing delay.
byte ch1_amp = 8;//sample default volume
byte ch2_amp = 8;
byte ch3_amp = 8;
byte ch4_amp = 8;
//ch1 setting
word ch1_i = 0;//Reference binary data of the sample to be played
bool ch1_ratch = 0;//0=no play sample , 1 = play sample
int ch1_sample = 0;//Referenced binary data of the sample to be played
bool ch1_in = 0;//external trig input
bool old_ch1_in = 0;//old external trig input
//ch2 setting
word ch2_i = 0;
bool ch2_ratch = 0;
int ch2_sample = 0;
bool ch2_in = 0;
bool old_ch2_in = 0;
//ch3 setting
word ch3_i = 0;
bool ch3_ratch = 0;
int ch3_sample = 0;
bool ch3_in = 0;
bool old_ch3_in = 0;
//ch4 setting
word ch4_i = 0;
bool ch4_ratch = 0;
int ch4_sample = 0;
bool ch4_in = 0;
bool old_ch4_in = 0;
void setup() {
if(EEPROM.isValid()==1){//already writed eeprom
slct_smpl1 = EEPROM.read(1);
slct_smpl2 = EEPROM.read(2);
slct_smpl3 = EEPROM.read(3);
slct_smpl4 = EEPROM.read(4);
ch1_amp = EEPROM.read(5);
ch2_amp = EEPROM.read(6);
ch3_amp = EEPROM.read(7);
ch4_amp = EEPROM.read(8);
pitch = EEPROM.read(9);
}
else if ( EEPROM.isValid()==0){//no eeprom data , setting any number to eeprom
slct_smpl1 = 10;
slct_smpl2 = 5;
slct_smpl3 = 18;
slct_smpl4 = 19;
ch1_amp = 8;
ch2_amp = 8;
ch3_amp = 8;
ch4_amp = 8;
pitch = 13;
}
// ディスプレイの初期化
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay(); // ディスプレイをクリア
OLED_display();
analogWriteResolution(8);
analogReadResolution(10);
pinMode(1, INPUT_PULLDOWN);//pull-down resistance typ40kohm
pinMode(2, INPUT_PULLDOWN);
pinMode(3, INPUT_PULLDOWN);
pinMode(6, INPUT_PULLDOWN);
pinMode(10, INPUT_PULLUP); //for development
// Initialize touch sensor
if (! qt_1.begin())
Serial.println("Failed to begin qt on pin A7");
if (! qt_2.begin())
Serial.println("Failed to begin qt on pin A8");
if (! qt_3.begin())
Serial.println("Failed to begin qt on pin A9");
}
void loop() {
old_disp_sw = disp_sw;
disp_sw = digitalRead(10);
if (old_disp_sw == 1 && disp_sw == 0) { //switch on to off , mode 9 setting update
// mode = 0;
OLED_display();
}
if (old_disp_sw == 0 && disp_sw == 1) { //switch off to on , mode 9 setting update
// mode = 0;
ch1_ratch = 0;
ch2_ratch = 0;
ch3_ratch = 0;
ch4_ratch = 0;
OLED_display();
}
if (disp_sw == 1 && ch1_ratch == 0 && ch2_ratch == 0 && ch3_ratch == 0 && ch4_ratch == 0 ) {
// touch sensor input
qt1 = qt_1.measure();
qt2 = qt_2.measure();
qt3 = qt_3.measure();
//qtx_ratch == 0 is countermeasure of
if (qt1 > 930 && qt1_ratch == 0) {
qt1_ratch = 1;
disp_ratch = 1;
}
if (qt2 > 930 && qt2_ratch == 0) {
qt2_ratch = 1;
disp_ratch = 1;
}
if (qt3 > 930 && qt3_ratch == 0) {
qt3_ratch = 1;
disp_ratch = 1;
}
if (qt1 <= 930) {
qt1_ratch = 0;
}
if (qt2 <= 930) {
qt2_ratch = 0;
}
if (qt3 <= 930) {
qt3_ratch = 0;
}
if (qt1_ratch == 1) {
mode ++;
qt1_ratch = 2;
if (mode >= 11) {
mode = 0;
}
else if (mode < 0) {
mode = 10;
}
}
//select sample
if (mode == 0) { //select CH1 sample
if (qt2_ratch == 1) {
slct_smpl1 ++;
qt2_ratch = 2;
ch1_ratch = 1;//one shot sample play
}
else if (qt3_ratch == 1) {
slct_smpl1 --;
qt3_ratch = 2;
ch1_ratch = 1;//one shot sample play
}
if (slct_smpl1 >= 18) {
slct_smpl1 = 0;
}
else if (slct_smpl1 < 0) {
slct_smpl1 = 17;
}
}
else if (mode == 1) { //select CH2 sample
if (qt2_ratch == 1) {
slct_smpl2 ++;
qt2_ratch = 2;
ch2_ratch = 1;//one shot sample play
}
else if (qt3_ratch == 1) {
slct_smpl2 --;
qt3_ratch = 2;
ch2_ratch = 1;//one shot sample play
}
if (slct_smpl2 >= 18) {
slct_smpl2 = 0;
}
else if (slct_smpl2 < 0) {
slct_smpl2 = 17;
}
}
else if (mode == 2) { //select CH3 sample
if (qt2_ratch == 1) {
slct_smpl3 ++;
qt2_ratch = 2;
ch3_ratch = 1;//one shot sample play
}
else if (qt3_ratch == 1) {
slct_smpl3 --;
qt3_ratch = 2;
ch3_ratch = 1;//one shot sample play
}
if (slct_smpl3 >= 18) {
slct_smpl3 = 0;
}
else if (slct_smpl3 < 0) {
slct_smpl3 = 17;
}
}
else if (mode == 3) { //select CH4 sample
if (qt2_ratch == 1) {
slct_smpl4 ++;
qt2_ratch = 2;
ch4_ratch = 1;//one shot sample play
}
else if (qt3_ratch == 1) {
slct_smpl4 --;
qt3_ratch = 2;
ch4_ratch = 1;//one shot sample play
}
if (slct_smpl4 >= 18) {
slct_smpl4 = 0;
}
else if (slct_smpl4 < 0) {
slct_smpl4 = 17;
}
}
//----------------control each ch volume-----------------------
if (mode == 4) { //select CH1 sample
if (qt2_ratch == 1) {
ch1_amp ++;
qt2_ratch = 2;
ch1_ratch = 1;//one shot sample play
}
else if (qt3_ratch == 1) {
ch1_amp --;
qt3_ratch = 2;
ch1_ratch = 1;//one shot sample play
}
if (ch1_amp >= 10) {
ch1_amp = 10;
}
else if (ch1_amp < 1) {
ch1_amp = 1;
}
}
else if (mode == 5) { //change CH2 volume
if (qt2_ratch == 1) {
ch2_amp ++;
qt2_ratch = 2;
ch2_ratch = 1;//one shot sample play
}
else if (qt3_ratch == 1) {
ch2_amp --;
qt3_ratch = 2;
ch2_ratch = 1;//one shot sample play
}
if (ch2_amp >= 10) {
ch2_amp = 10;
}
else if (ch2_amp < 1) {
ch2_amp = 1;
}
}
else if (mode == 6) { //change CH3 volume
if (qt2_ratch == 1) {
ch3_amp ++;
qt2_ratch = 2;
ch3_ratch = 1;//one shot sample play
}
else if (qt3_ratch == 1) {
ch3_amp --;
qt3_ratch = 2;
ch3_ratch = 1;//one shot sample play
}
if (ch3_amp >= 10) {
ch3_amp = 10;
}
else if (ch3_amp < 1) {
ch1_amp = 1;
}
}
else if (mode == 7) { //change CH4 volume
if (qt2_ratch == 1) {
ch4_amp ++;
qt2_ratch = 2;
ch4_ratch = 1;//one shot sample play
}
else if (qt3_ratch == 1) {
ch4_amp --;
qt3_ratch = 2;
ch4_ratch = 1;//one shot sample play
}
if (ch4_amp >= 10) {
ch4_amp = 10;
}
else if (ch4_amp < 1) {
ch4_amp = 1;
}
}
//----------------pitch control and display andSAVE-----------------------
else if (mode == 8) { //pitch control
if (qt2_ratch == 1) {
pitch ++;
qt2_ratch = 2;
ch1_ratch = 1;//one shot sample play
}
else if (qt3_ratch == 1) {
pitch --;
qt3_ratch = 2;
ch1_ratch = 1;//one shot sample play
}
if (pitch >= 52) {
pitch = 52;
}
else if (pitch < 5) {
pitch = 5;
}
}
else if (mode == 9) { //save
if (qt2_ratch == 1) {
qt2_ratch = 2;
disp_set = 1;
}
else if (qt3_ratch == 1) {
qt3_ratch = 2;
disp_set = 0;
}
}
else if (mode == 10) { //save
if (qt2_ratch == 1) {
qt2_ratch = 2;
save();
}
else if (qt3_ratch == 1) {
qt3_ratch = 2;
save();
}
}
if ( disp_ratch == 1) {
OLED_display();
disp_ratch = 0;
delay(100);//countermeasure of touch sensor continuous input
}
if (ch1_ratch == 1 || ch2_ratch == 1 || ch3_ratch == 1 || ch4_ratch == 1 ) {
soundout();
}
}
else if (disp_sw == 0) {
//----------------signal input--------------------------
old_ch1_in = ch1_in;
old_ch2_in = ch2_in;
old_ch3_in = ch3_in;
old_ch4_in = ch4_in;
ch1_in = digitalRead(1);
ch2_in = digitalRead(2);
ch3_in = digitalRead(3);
ch4_in = digitalRead(6);
soundout();
}
else {
soundout();
}
}
void soundout() {
if (ch1_i > 9500) {
ch1_i = 0;
ch1_ratch = 0;
ch1_sample = 127;
}
if (ch2_i > 9500) {
ch2_i = 0;
ch2_ratch = 0;
ch2_sample = 127;
}
if (ch3_i > 9500) {
ch3_i = 0;
ch3_ratch = 0;
ch3_sample = 127;
}
if (ch4_i > 9500) {
ch4_i = 0;
ch4_ratch = 0;
ch4_sample = 127;
}
if (old_ch1_in == 0 && ch1_in == 1) {
ch1_ratch = 1;
ch1_i = 0;
}
if (old_ch2_in == 0 && ch2_in == 1) {
ch2_ratch = 1;
ch2_i = 0;
}
if (old_ch3_in == 0 && ch3_in == 1) {
ch3_ratch = 1;
ch3_i = 0;
}
if (old_ch4_in == 0 && ch4_in == 1) {
ch4_ratch = 1;
ch4_i = 0;
}
if (ch1_ratch == 1) {
ch1_i ++;
}
if (ch2_ratch == 1) {
ch2_i ++;
}
if (ch3_ratch == 1) {
ch3_i ++;
}
if (ch4_ratch == 1) {
ch4_i ++;
}
//Read sample data and volume setting.
ch1_sample = ((pgm_read_byte(&(smpl[slct_smpl1][ch1_i])) - 127) * ch1_amp / 6) + 127;
ch2_sample = ((pgm_read_byte(&(smpl[slct_smpl2][ch2_i])) - 127) * ch2_amp / 6) + 127;
ch3_sample = ((pgm_read_byte(&(smpl[slct_smpl3][ch3_i])) - 127) * ch3_amp / 6) + 127;
ch4_sample = ((pgm_read_byte(&(smpl[slct_smpl4][ch4_i])) - 127) * ch4_amp / 6) + 127;
if (ch1_ratch == 1 || ch2_ratch == 1 || ch3_ratch == 1 || ch4_ratch == 1 ) {
analogWrite(A0, ch1_sample + ch2_sample + ch3_sample + ch4_sample);
}
delayMicroseconds(pitch);
}
void save() {//save setting data to flash memory
delay(100);
EEPROM.write(1, slct_smpl1);
EEPROM.write(2, slct_smpl2);
EEPROM.write(3, slct_smpl3);
EEPROM.write(4, slct_smpl4);
EEPROM.write(5, ch1_amp);
EEPROM.write(6, ch2_amp);
EEPROM.write(7, ch3_amp);
EEPROM.write(8, ch4_amp);
EEPROM.write(9, pitch);
EEPROM.commit();
display.clearDisplay(); // clear display
display.setTextSize(disp_set + 1);
if (disp_sw == 1) {
display.setTextSize(2);
}
display.setTextColor(BLACK, WHITE);
display.setCursor(0, 32);
display.print("SAVEED");
display.display();
delay(1000);
}
void OLED_display() {
display.clearDisplay();
display.setTextSize(disp_set + 1);
if (disp_sw == 1) {
display.setTextSize(2);
}
display.setTextColor(WHITE);
if ( mode <= 7) {
//sample display
display.setCursor(0, 0);
display.print(smpl_name[slct_smpl1]);
display.setCursor(0, 16);
display.print(smpl_name[slct_smpl2]);
display.setCursor(0, 32);
display.print(smpl_name[slct_smpl3]);
display.setCursor(0, 48);
display.print(smpl_name[slct_smpl4]);
//amp display
display.drawRect(95, 0, ch1_amp * 3, 15, WHITE);
display.drawRect(95, 16, ch2_amp * 3, 15, WHITE);
display.drawRect(95, 32, ch3_amp * 3, 15, WHITE);
display.drawRect(95, 48, ch4_amp * 3, 15, WHITE);
//mode display
if (mode < 4 && disp_sw == 1) {
display.drawTriangle(92, 2 + mode * 16, 92, 10 + mode * 16, 86, 6 + mode * 16, WHITE);
}
else if (mode >= 4 && disp_sw == 1) {
display.drawTriangle(86, 2 + (mode - 4) * 16, 86, 10 + (mode - 4) * 16, 92, 6 + (mode - 4) * 16, WHITE);
}
}
else if (mode >= 8) {
display.setCursor(0, 0);
display.print("PITCH");
display.setCursor(70, 0);
display.print(pitch);
display.setCursor(0, 16);
display.print("NOISE");
display.setCursor(70, 16);
if (disp_set == 1) {
display.print("MID");
}
else if (disp_set == 0) {
display.print("LOW");
}
display.setCursor(0, 32);
display.print("SAVE");
display.drawTriangle(114, 2 + (mode - 8) * 16, 114, 10 + (mode - 8) * 16, 108, 6 + (mode - 8) * 16, WHITE);
}
display.display();
}