M5Stackでできること 〜「M5Stack用MIDIシンセサイザユニット」の音色を確認する

スポンサーリンク
センサとの接続

先日、「M5Stack用MIDIシンセサイザユニット」というデバイスをつかって、マイコンデバイスからの制御で音を鳴らしてみました(記事は こちら)。


それなりの音質でさまざまな音色を鳴らすことができ、和音を鳴らすこともできたのですが、せっかくなので、このデバイスの音色や音階をいろいろ変えて、どんな音がするのかじっくりと聴いてみたいと思います。

ボタンを押して音色や音階を設定し、別のボタンを押すと設定した音が鳴るようなものをつくります。
なお、音の設定をしたり音を鳴らしたりするために、いくつかのボタンが必要になります。先日「M5Stack Core2」のタッチパネルで「タッチボタン」をつくりました(記事は こちら)ので、このボタンを活用しようと思います。


以下のようなものをつくります。

  • 「M5Stack Core2」を使う。
  • 「M5Stack用MIDIシンセサイザユニット」は「M5Stack Core2」のGROVEポート「PORT A」に接続する(今回使用している「M5Stack Core2 for AWS」にはGROVEポートが3つ搭載されていますが、今回は一般のCore2にも搭載されている「PORT A」を使います)。
  • タッチパネル左下にあるふたつのボタン(btn0, btn1)で、音色(snum)を「1〜128」の範囲で変動させる。
  • タッチパネル右下にあるふたつのボタン(btn2, btn3)で、音階(knum)を「23〜111」の範囲で変動させる。
  • タッチパネル左上にあるボタン(btn4)を押すと、音色が「119」(SynthDrum)、音階が「35」(SynthDrumでの最低値)に設定される。
  • タッチパネル上部に、設定されている音色と音階が表示される。
  • タッチパネルした中央にあるボタン(btn5)を押している間、設定されている音色と音階で音が鳴る。

スケッチは以下のとおりです。

#include <M5Unified.h>
#include "M5UnitSynth.h"

LGFX_Button btn0, btn1, btn2, btn3, btn4, btn5;
M5UnitSynth synth;

int    w, h;
int    snum = 1; 
int    knum = 60;
int    channel = 0;
String sound[129] = {
    "",
    "GrandPiano_1",
    "BrightPiano_2",
    "ElGrdPiano_3",
    "HonkyTonkPiano",
    "ElPiano1",
    "ElPiano2",
    "Harpsichord",
    "Clavi",
    "Celesta",
    "Glockenspiel",
    "MusicBox",
    "Vibraphone",
    "Marimba",
    "Xylophone",
    "TubularBells",
    "Santur",
    "DrawbarOrgan",
    "PercussiveOrgan",
    "RockOrgan",
    "ChurchOrgan",
    "ReedOrgan",
    "AccordionFrench",
    "Harmonica",
    "TangoAccordion",
    "AcGuitarNylon",
    "AcGuitarSteel",
    "AcGuitarJazz",
    "AcGuitarClean",
    "AcGuitarMuted",
    "OverdrivenGuitar",
    "DistortionGuitar",
    "GuitarHarmonics",
    "AcousticBass",
    "FingerBass",
    "PickedBass",
    "FretlessBass",
    "SlapBass1",
    "SlapBass2",
    "SynthBass1",
    "SynthBass2",
    "Violin",
    "Viola",
    "Cello",
    "Contrabass",
    "TremoloStrings",
    "PizzicatoStrings",
    "OrchestralHarp",
    "Timpani",
    "StringEnsemble1",
    "StringEnsemble2",
    "SynthStrings1",
    "SynthStrings2",
    "ChoirAahs",
    "VoiceOohs",
    "SynthVoice",
    "OrchestraHit",
    "Trumpet",
    "Trombone",
    "Tuba",
    "MutedTrumpet",
    "FrenchHorn",
    "BrassSection",
    "SynthBrass1",
    "SynthBrass2",
    "SopranoSax",
    "AltoSax",
    "TenorSax",
    "BaritoneSax",
    "Oboe",
    "EnglishHorn",
    "Bassoon",
    "Clarinet",
    "Piccolo",
    "Flute",
    "Recorder",
    "PanFlute",
    "BlownBottle",
    "Shakuhachi",
    "Whistle",
    "Ocarina",
    "Lead1Square",
    "Lead2Sawtooth",
    "Lead3Calliope",
    "Lead4Chiff",
    "Lead5Charang",
    "Lead6Voice",
    "Lead7Fifths",
    "Lead8BassLead",
    "Pad1Fantasia",
    "Pad2Warm",
    "Pad3PolySynth",
    "Pad4Choir",
    "Pad5Bowed",
    "Pad6Metallic",
    "Pad7Halo",
    "Pad8Sweep",
    "FX1Rain",
    "FX2Soundtrack",
    "FX3Crystal",
    "FX4Atmosphere",
    "FX5Brightness",
    "FX6Goblins",
    "FX7Echoes",
    "FX8SciFi",
    "Sitar",
    "Banjo",
    "Shamisen",
    "Koto",
    "Kalimba",
    "BagPipe",
    "Fiddle",
    "Shanai",
    "TinkleBell",
    "Agogo",
    "SteelDrums",
    "Woodblock",
    "TaikoDrum",
    "MelodicTom",
    "SynthDrum",
    "ReverseCymbal",
    "GtFretNoise",
    "BreathNoise",
    "Seashore",
    "BirdTweet",
    "TelephRing",
    "Helicopter",
    "Applause",
    "Gunshot"
};

void setup() {
  auto cfg = M5.config();
  M5.begin(cfg);

  w = M5.Display.width();
  h = M5.Display.height();
  M5.Display.setTextColor(TFT_WHITE);
  M5.Display.fillScreen(TFT_BLACK);
  
  btn0.initButton(&M5.Display, w/8*1, h/8*5, w/4-4, h/4-4, TFT_DARKGREEN, TFT_DARKGREEN, TFT_WHITE, "UP",   2);
  btn1.initButton(&M5.Display, w/8*1, h/8*7, w/4-4, h/4-4, TFT_DARKGREEN, TFT_DARKGREEN, TFT_WHITE, "DOWN", 2);
  btn2.initButton(&M5.Display, w/8*7, h/8*5, w/4-4, h/4-4, TFT_DARKGREEN, TFT_DARKGREEN, TFT_WHITE, "UP",   2);
  btn3.initButton(&M5.Display, w/8*7, h/8*7, w/4-4, h/4-4, TFT_DARKGREEN, TFT_DARKGREEN, TFT_WHITE, "DOWN", 2);
  btn4.initButton(&M5.Display, w/8*1,h/16*5, w/4-4, h/8-4, TFT_DARKGREEN, TFT_DARKGREEN, TFT_WHITE, "DRUM", 2);
  btn5.initButton(&M5.Display, w/8*4, h/8*6, w/2-4, h/2-4, TFT_DARKGREEN, TFT_DARKGREEN, TFT_WHITE, "PLAY", 2);
  
  btn0.drawButton();
  btn1.drawButton();
  btn2.drawButton();
  btn3.drawButton();
  btn4.drawButton();
  btn5.drawButton();

  M5.Display.setTextDatum(BC_DATUM);
  M5.Display.drawString("SOUND", w/8*1, h/8*4, 2);
  M5.Display.drawString("KEY",   w/8*7, h/8*4, 2);
  M5.Display.setTextDatum(MC_DATUM);
  M5.Display.drawString(String(snum) + " : " + sound[snum], w/8*4, h/8*1, 4);
  M5.Display.drawNumber(knum, w/8*4, h/8*3, 4);

  synth.begin(&Serial2, UNIT_SYNTH_BAUD, 33, 32);
  synth.setInstrument(0, channel, snum);
}

void loop() {
  M5.update();
  auto t = M5.Touch.getDetail();
  if(t.wasPressed()) {
    if(btn0.contains(t.x, t.y)) {
      if(snum<128) snum++;
      M5.Display.fillRect(0, 0, w, h/4, TFT_BLACK);
      M5.Display.drawString(String(snum) + " : " + sound[snum], w/8*4, h/8*1, 4);
      if(snum==119) channel = 9; else channel = 0;
      synth.setInstrument(0, channel, snum);
    }
    if(btn1.contains(t.x, t.y)) {
      if(snum>1) snum--;
      M5.Display.fillRect(0, 0, w, h/4, TFT_BLACK);
      M5.Display.drawString(String(snum) + " : " + sound[snum], w/8*4, h/8*1, 4);
      if(snum==119) channel = 9; else channel = 0;
      synth.setInstrument(0, channel, snum);
    }
    if(btn2.contains(t.x, t.y)) {
      if(knum<111) knum++;
      M5.Display.fillRect(w/4, h/4, w/2, h/4, TFT_BLACK);
      M5.Display.drawNumber(knum, w/8*4, h/8*3, 4);
    }
    if(btn3.contains(t.x, t.y)) {
      if(knum>23) knum--;
      M5.Display.fillRect(w/4, h/4, w/2, h/4, TFT_BLACK);
      M5.Display.drawNumber(knum, w/8*4, h/8*3, 4);
    }
    if(btn4.contains(t.x, t.y)) {
      snum=119;
      knum=35;
      channel=9;
      M5.Display.fillRect(0, 0, w, h/4, TFT_BLACK);
      M5.Display.drawString(String(snum) + " : " + sound[snum], w/8*4, h/8*1, 4);
      M5.Display.fillRect(w/4, h/4, w/2, h/4, TFT_BLACK);
      M5.Display.drawNumber(knum, w/8*4, h/8*3, 4);
      synth.setInstrument(0, channel, snum);
    }
    if(btn5.contains(t.x, t.y)) {
      synth.setNoteOn(channel, knum, 127);
    }
  }
  if(t.wasReleased()) {
    synth.setAllNotesOff(channel);
  }
}

なお、「M5Stack用MIDIシンセサイザユニット」では、音色のうち「119:SynthDrum」のみ別扱いになっており、「synth.setInstrument()」で設定するチャンネル番号を「9」にしなければいけないようです。また、その他の音色は「9」以外のチャンネル番号にしなければいけません。
よって「snum==119」かどうかでチャンネル番号を切り替える処理を入れています。

これを「M5Stack Core2」に書き込むと、ディスプレイに以下のように表示されます。
各ボタンを押すと、音色や音階を変更でき、音を鳴らすこともできました。

特に「119:SynthDrum」の各ノート番号(楽器)について、このデバイスでは実際にどのような音が鳴るのかを確認したかったのですが、この仕組みを使うことでじっくり聴くことができました。

 

なお、私がM5Stack、M5StickCの使い方を習得するのにあたっては、以下の書籍を参考にさせていただきました。


ごく基本的なところから、かなり複雑なスケッチや、ネットワーク接続など、比較的高度なものまで、つまづかずに読み進めていけるような構成になっており、大変わかりやすい本です。