2018-10-27に更新

電子リコーダーができた

リコーダー型のMIDIコントローラがついに出来上がってきた。

とりあえず圧電スピーカは洗濯バサミで上にくっつけている。
接続はピンソケット2つで行っているので、
つばで汚れたら新しいものに付け替えることができるようにしている。

もう普通に演奏できる。
まだファームウェア書き換えでは試してないので
音を鳴らす方法は下記のまま。
http://program.alphabrend.com/?p=150

ただちょっと遅延があって演奏しづらいので、
可能な箇所があればプログラムや回路の見直しと、
ASIOドライバというものを導入してみたいと考えている。

最終的にはアクリルを筒状っぽくしてそれっぽい入れものに入れてみたい。
とりあえずは段ボールでケースでもつくろかな…。

arduino

|c|

include <MIDI.h>

define NO_VOLUME_CHANGE

const int BUTTON_MIN = 2;
const int BUTTON_MAX = 12;
const int BREATH = 0;
const int BASE_PITCH = 53;
const int BREATH_CUT = 670;
const int MIN_BREATH = 300;
const int MAX_DIFF = 3;
const int BREATH_DELAY = 70000;

int playing = -1;
unsigned long lastHigh = micros();
unsigned long lastVelo = micros();
byte currentVelocity = 0;
char* notes[] = {
"01111110011",
"01111110110",
"01111110010",
"01111111000",
"01111110000",
"01111100000",
"01111010010",
"01111000000",
"01110111000",
"01110000000",
"01101100000",
"01100000000",
"01010000000",
"00110000000",
"00010000000",
"00111110010",
"10111110000",
"10111100000",
"10111010000",
"10111000000",
"10110100000",
"10110000000",
"10110010010",
"10110110000",
"10100110000",
"10101100011",
"10101100010",
};
int noteCount = sizeof(notes) / sizeof(notes[0]);

void setup() {
for (int i = BUTTON_MIN; i <= BUTTON_MAX; i++) {
pinMode(i, INPUT_PULLUP);
}
MIDI.begin();
}

void loop() {
char currentValue[] = "00000000000";
int exist = 0;
for (int i = BUTTON_MIN; i <= BUTTON_MAX; i++) {
if (digitalRead(i) == LOW) {
currentValue[i - BUTTON_MIN] = '1';
exist = 1;
} else {
currentValue[i - BUTTON_MIN] = '0';
}
}

if (exist == 1) {
short breath = analogRead(BREATH);
breath = abs(breath - BREATH_CUT);
if (breath > MIN_BREATH) {
for (int i = 0; i < noteCount; i++) {
if (strcmp(currentValue, notes[i]) == 0) {

ifdef NO_VOLUME_CHANGE

      breath = 127;

else

      breath = map(breath, MIN_BREATH, 1023 - BREATH_CUT, 64, 127);

endif

      if (i != playing) {
        if (playing > -1) {
          MIDI.sendNoteOff(BASE_PITCH + playing, 0, 1);
        }
        playing = i;
        MIDI.sendNoteOn(BASE_PITCH + playing, breath, 1);
        currentVelocity = breath;
      } else {
        if (micros() - lastVelo > BREATH_DELAY) {
          if (breath > currentVelocity) {
            short plus = min(MAX_DIFF, breath - currentVelocity);
            if (plus + (short)currentVelocity > 127) {
              plus = 127 - currentVelocity;
            }
            currentVelocity += plus;
            MIDI.sendControlChange(7, currentVelocity, 1);
          } else if (breath &lt; currentVelocity) {
            short minus = min(MAX_DIFF, currentVelocity - breath);
            if (minus > currentVelocity) {
              minus = currentVelocity;
            }
            currentVelocity -= minus;
            MIDI.sendControlChange(7, currentVelocity, 1);
          }
        }
      }
      lastVelo = micros();
      break;
    }
  }
  lastHigh = micros();
} else {
  if (micros() - lastHigh > BREATH_DELAY) {
    noteOff();
  }
}

} else {
noteOff();
}
}

void noteOff() {
if (playing > -1) {
MIDI.sendNoteOff(BASE_PITCH + playing, 0, 1);
playing = -1;
}
}
||

processing

|c|
import processing.serial.*;
import themidibus.*; //Import the library

MidiBus myBus; // The MidiBus
Serial port;
int[] val = new int[3];
int valno = 0;
int lastInput = 0;

void setup() {
size(400, 400);
background(0);

MidiBus.list(); // List all available Midi devices on STDOUT. This will show each device's index and name.
myBus = new MidiBus(this, -1, "loopMIDI Port"); // Create a new MidiBus with no input device and the default Java Sound Synthesizer as the output device.
String portName = Serial.list()[0];
port=new Serial(this, portName, 31250);
}

void draw() {
while (port.available() > 0) {
int inByte = port.read();
println(inByte);
if (valno == 0) {
if (inByte >= 128) {
val[0] = inByte;
valno++;
} else if (lastInput > 0) {
val[0] = lastInput;
val[1] = inByte;
valno += 2;
}
} else {
val[valno++] = inByte;
if (valno == 3) {
valno = 0;
if (val[0] == 128) {
println(val);
myBus.sendNoteOff(0, val[1], val[2]);
lastInput = 0;
} else if (val[0] == 144) {
// println(val);
setVolume(val[2]);
myBus.sendNoteOn(0, val[1], /val[2]/127);
lastInput = val[0];
} else if (val[0] == 176) {
setVolume(val[2]);
// println(val);
lastInput = val[0];
}
}
}
}
}

void setVolume(int velocity) {
if (velocity < 64) {
velocity = 64;
}
myBus.sendControllerChange(0, 7, velocity);
}
||

とりあえずボリュームはマックス固定にしている。
変動を試したい場合はNO_VOLUME_CHANGEをコメントアウト。
多少安定はしてきたが、あんまりいいかんじではない。
ビブラートも上手くは再現できないので。

このあとのASIO対応やファームウェア書き換えでまた
上手く動かなくなってつまづきそうだがとりあえず一段落。

ツイッターでシェア
みんなに共有、忘れないようにメモ

だら@Crieit開発者

Crieitの開発者です。 Webエンジニアです(在宅)。大体10年ちょい。 記事でわかりにくいところがあればDMで質問していただくか、案件発注してください。 業務依頼、同業種の方からのコンタクトなどお気軽にご連絡ください。 業務経験有:PHP, MySQL, Laravel, React, Flutter, Vue.js, Node, RoR 趣味:Elixir, Phoenix, Nuxt, Express, GCP, AWS等色々 PHPフレームワークちいたんの作者

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント