読者です 読者をやめる 読者になる 読者になる
一人もくもく会 α verでサービス開始しました。

電子リコーダーができた

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

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

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

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

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

arduino

#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 < 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

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対応やファームウェア書き換えでまた
上手く動かなくなってつまづきそうだがとりあえず一段落。