1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Arduino Nano 33 IoTのBLEとIMUでBLE MIDIコントローラーを作ってみよう

Posted at

概要

この記事に続き、Arduino nano 33 IoTBLEIMUを使ってMIDIコントローラーを作ってみます。

今回のデモの音源も、iOSアプリの KORG Gadget 2 で、制御するのは、"Phenix"のPitch(Pitch)とVolume(CC7)です。

ボードをX軸に倒すとPitchが変わり、Y軸に倒すとVolumeが変わる、というものになります。

KORG Gadget2のシンセの中で、"Phonix"だけPitchBendのレンジ変えられるので、このシンセを選びました。

このボードにはユーザーボタンがないので、音を出すのは、"Phonix"のキーボードを押すか、シーケンスを組むかで音を出してください。

開発環境準備

Arduino IDEで下記をインストールしてください。

ボードマネージャー

ライブラリ

昔に比べて、ArduinoのWebページ、かなり分かりやすくなってますね。

ソース

Theramin_AN33IOT.ino
#include <ArduinoBLE.h>
#include <Arduino_LSM6DS3.h>

 // BLE MIDI Service
BLEService midiService("03B80E5A-EDE8-4B33-A751-6CE34EC4C700");

// BLE MIDI OUT Characteristic
BLECharacteristic midiOutChar("7772E5DB-3868-4112-A1A9-F2669D106BF3",
    BLERead | BLENotify, 5);

//MIDI Buff
uint8_t midiPayload[] = {0x80, 0x80, 0xB0, 0x01, 0x64};

//CC Buff
int i;
uint8_t cc[128];

//Pitch Buff
uint16_t pitch;

//IMU Buff
float x, y, z;
uint16_t midiX, midiY;

void setup() {
  // initialize serial communication
  Serial.begin(9600); 

  // initialize the built-in LED pin to indicate when a central is connected  
  pinMode(LED_BUILTIN, OUTPUT);

  //Buff initialize
  for(i = 0; i < 128; i++)
  {
    cc[128] = 64;
  }

  pitch = 8192;

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");
    while (1);
  }

  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }

  //BLE Initialize
  BLE.setLocalName("AN33IoT");
  BLE.setAdvertisedService(midiService);

  midiService.addCharacteristic(midiOutChar);
  BLE.addService(midiService);

  // start advertising
  Serial.println("Bluetooth device active, waiting for connections...");
  BLE.advertise();
}

void loop() {
  // wait for a BLE central
  BLEDevice central = BLE.central();

  if (central) {
    Serial.print("Connected to central: ");
    Serial.println(central.address());
    digitalWrite(LED_BUILTIN, HIGH);

    while (central.connected()) {
      if (IMU.accelerationAvailable()) {
        IMU.readAcceleration(x, y, z);

        midiX = mapAndLimit((int)(x * 16384.0), -8192, 8191, 0, 16383);
        midiY = mapAndLimit((int)(y * 1000.0), 500, -500, 0, 127);            

        notifyPitch(midiX, 1);
        notifyCC(7, (uint8_t)midiY, 1);            

        delay(1);
      }
    }

    // when the central disconnects, turn off the LED:
    digitalWrite(LED_BUILTIN, LOW);
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
  }
}

//NotifyCC
void notifyCC(uint8_t ccNum, uint8_t midiValue, uint8_t sensitivity)
{
    if(abs(cc[ccNum] - midiValue) > sensitivity)
    {
        cc[ccNum] = midiValue;

        //Send Note
        midiPayload[2] = 0xb0;
        midiPayload[3] = ccNum;
        midiPayload[4] = midiValue;

        Serial.print("CC");
        Serial.print(ccNum);
        Serial.print(":");
        Serial.println(midiValue);

        //Notify MIDI Data        
        midiOutChar.writeValue(midiPayload, 5);
    }
}

//NotifyPitch
void notifyPitch(int value, int sensitivity)
{
  if(abs(pitch - value) > sensitivity)
  {
    //元情報にデータを入れておく
    pitch = value;

    //valueをCC(ccNum)のデータにする
    midiPayload[2] = 0xe0;
    midiPayload[3] = value & 127;      
    midiPayload[4] = value >> 7;

    Serial.print("Pitch");
    Serial.print(":");
    Serial.println(value);

    //Notify MIDI Data        
    midiOutChar.writeValue(midiPayload, 5);
  }
}

//Map and Limit
uint16_t mapAndLimit(int inputValue, int fromLow, int fromHigh, int toLow, int toHigh)
{
    int tmp, minValue, maxValue;    

    if(toLow < toHigh)
    {
        minValue = toLow;
        maxValue = toHigh;
    }
    else
    {
        minValue = toHigh;
        maxValue = toLow;
    }

    tmp = inputValue - fromLow;
    tmp = (int)((double)tmp * (double)(toHigh - toLow) / (double)(fromHigh - fromLow));    
    tmp += toLow;
    tmp = tmp < minValue ? minValue : tmp;
    tmp = tmp > maxValue ? maxValue : tmp;

    return (uint16_t)tmp;        
}

動作所感

相変わらずPitchはガタガタですが、ESP32のBLEでも綺麗に動いてくれました。

M5StickCとの違い

1. コンパイル、アップロードが速い

M5StickCも大分速度上がってましたが、このボードは、もうワンランク、コンパイル、アップロードが速かったですね。流石、純正ですね。

2.アナログ入力が8つある

今、自分が作りたいのは、 KORG Gadget 2 の"Chicago"のTB-303の上の6つのノブに当たるCCを可変抵抗で操作するものです。このボードには、アナログ入力が8端子あるので、簡単に作成できます(できたら、また記事上げます。)。
IMUで新しい音作りが出来るか期待したんですが、303系の音作りはやっぱりノブですね。
Wavetable系は、まだIMUで面白いことできる気もしますが...

まとめ

ようやく日本の技適の通ったArduino nano 33 IoTを使えば、簡単にBLE MIDIコントローラーを作れることが分かりました。皆さんも、お気に入りのMIDIコントローラを作ってみてはいかがでしょうか?

ノブ6つのコントローラでいいなら、nanoKEY Studio買った方が速いんですけどね...
これならWinでも動くし...
ただ、コンパクトなのが欲しいんですよね...

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?