photo credit: Maschine via photopin (license)
photo credit: Maschine via photopin (license)

MIDIとはなんぞやというのをアプリプログラマ的に説明してみる

こんにちは、おひろです。

今日もReMINEの開発で得たノウハウについて書こうと思います。

ReMINEはMIDIコントローラなんですが、そもそもMIDIコンのMIDIって何?というところを書こうかなと思います。
今さら書かずともググればなんぼでも情報はありますけどね。。

MIDIとは

MIDIはMusical Instrument Digital Interfaceの略で、狭義の意味では通信規約とそれに伴うデータの「規格」です。広義の意味で言うとその規格に沿って作られたハードウェア(コントローラ)だったり、ファイルデータも含むようです。
規格なので、それに沿って作られたものは互いを知らなくても連携できるということです。
MIDI自体は30年以上も前からあります。過去の資産を無駄にしないためかもしれませんが、いまだに使い続けられているのは驚異だと思います。

それで何をやり取りするかというと、「演奏データ」です。
例えばピアノアプリを作ることを想定して説明してみます。
シンプルに鍵盤を叩いたら音がでる、というものを作ろうと思ったら以下のような感じになると思います。

image

例えばドの鍵盤(ボタン)を叩いたらドの音を再生する、レならレ、という感じでアクションに対して紐づく音がなるように作ればピアノアプリになりますね。
「ドの音」だと抽象的なので鍵盤ボタンと音に数字(タグ)を振ってみます。例えばドは0として、ドのボタンに0番を振り、ボタンを押したときにモデルに渡す。モデルは0番を受けたらドを鳴らす、としましょう。


// ViewController
class ViewController: UIViewController {
    @IBOutlet weak var buttonDo: UIButton!
    @IBOutlet weak var buttonRe: UIButton!

    private let model = Model()

    override func viewDidLoad() {
        super.viewDidLoad()

        // 鍵盤ボタンに数字を振っておきます
        self.buttonDo.tag = 0
        self.buttonRe.tag = 1
    }

    @IBAction func pushKey(sender: UIButton) {
        // 鍵盤ボタンがおされたので数字をモデルに渡して再生!
        model.play(sender.tag)
    }
}

// Model
class Model {
    func play(number: Int) {
        switch number {
        case 0:
            // ドの音を再生
            play("piano_do.aac") // 音声ファイルを再生する関数の実装については割愛
        case 1:
            // レの音を再生
            play("piano_re.aac")
        default:
            break
        }
    }
}

はい、これMIDIの基本です。

もう少し突っ込んで考えてみます。

こんな感じでモデルを鳴らしたい音の番号を渡せば鳴るように作っておけば、鍵盤を叩かずとも例えばテキストファイルに「0」と書いて、それを読み込んで渡しても「ド」と鳴るよなぁ、ということでやってみると、

//
// テキストファイルから音を鳴らすようにViewControllerを変えてみる
//
class ViewController: UIViewController {
    private let model = Model()

    override func viewDidLoad() {
        super.viewDidLoad()

        // 0とだけ書かれたテキストファイルがあったとして、
        // それを読み込んだら書いてる文字が得られるloadという関数がある前提
        // (loadの実装自体は割愛)
        let playText: String = load("playText.txt")

        model.play(Int(playText)!) // これでドがなる
    }
}

今度はモデルを拡張して、モデルに音源の種類を設けよう。音と番号の紐づけは変えずに音色だけ変えよう。
そうすれば鍵盤を叩いたりテキストを読み込んで再生する部分は変えずに音色だけ変わるようになるなぁ。

//
// 音色を変えられるようにModelに音色の種類を実装してみる
//
class Model {

    // 音色のタイプ
    enum ToneType {
        case Piano
        case Organ
    }

    private var type: ToneType

    // 例えばということで初期化時にセットしているが
    // 実際はViewに切り替えボタンがあったら良いと思う
    init(toneType: ToneType) {
        type = toneType
    }

    func play(number: Int) {
        switch type {
        case .Piano:
            // ピアノの音を再生
            playPiano(number)
        case .Organ:
            // オルガンの音を再生
            playOrgan(number)
        }
    }

    func playPiano(number: Int) {
        switch number {
        case 0:
            // ドの音を再生
            play("piano_do.aac") // 音声ファイルを再生する関数の実装については割愛
        case 1:
            // レの音を再生
            play("piano_re.aac")
        default:
            break
        }
    }

    func playOrgan(number: Int) {
        switch number {
        case 0:
            // ドの音を再生
            play("organ_do.aac")
        case 1:
            // レの音を再生
            play("organ_re.aac")
        default:
            break
        }
    }
}

つまり音を鳴らす音源の部分と、演奏するコントローラの部分を分離して、演奏データ(上記の例で言えば音と番号の紐づけ)だけやり取り(通信)しあう、という構成にすればコントローラを変えたり音源を変えたりしても動作するということです。
コントローラでなくても上記の例のようにデータファイルでも良いのです。実際にそういう使われ方もします。

そしてこの演奏データやそのやり取りについて規格を定めたものがMIDIです。
ここで説明したことはごく一部の話で、実際は非常に細かいルールがあります。そりゃもうなんでそんなにいろいろあるの、もっとシンプルにできねぇのかよってくらいに。

MIDIコントローラ

MIDIコントローラというのは、上記の話で出た「演奏するコントローラの部分」の役割を持ち、名前の通りそれはMIDIの規格に準拠しています。
ソフトウェアでもいいんですけど、一般にMIDIコンというとハードウェアを指す事が多いと思います。
音を鳴らす音源の部分を搭載していないので、音源と組み合わせて使わないと音はなりません。

「おい、MIDIキーボードとかいうピアノ買ってきたらよ、音鳴らねーじゃねーかよ。壊れてんのかよ。ちょっと店行ってブチ切れてくるわ!」
もしこのようなことがあっても決してブチ切れてはなりません。とても恥をかくことになります。
※MIDIキーボードとは鍵盤型のMIDIコントローラのことです。

音源

音源となるのは、ReMINEのケースでいうと、iOSの音楽系のアプリになります。ピアノアプリとかサンプラーアプリとか。

最近では音源はソフトウェアが多いんじゃないかと思いますが、もちろんハードウェアの音源というのもあって、昔はそれが活躍してたんじゃないですかね。
ローランドのSCシリーズなんか有名じゃないでしょうか。私もだいぶ昔ですがSC-8820というハード音源を持っていたのですけど、当時はMIDIを理解してなかったのでまぁ全く意味がわかりませんでした。
音楽制作自体は付属のソフトで行うため、これなんのためにいるんやろうって思いつつひとまず説明書通りにセットアップ。MIDIキーボードなんて存在も知らず、ソフトを使ってポチポチ楽譜を書いて作ってました。

で、やっとできた!と思って保存して別のPCで聞いたら全然音が違うんです。保存したデータというのはあくまで「演奏データ」だったわけです。
ギターで作ってたのにピアノの音になってるとかね。仕方ないことです、そのPCにはSC-8820をつけていなかったのでOSの標準の音源が使われてたわけです。
同じ音色で再生するにはSC-8820を接続し音の割り当て設定をちゃんとしてやらないといけなかったのです。

でもはぁ!?ってなりました。MIDIのこと知らなかったらそうなるでしょう。。それ以降SC-8820君は引き出しの奥に眠ることとなります。。高いのに。。南無。。
この場合、mp3などの音楽ファイルとして書き出してやればどのPCで聞いても同じ音になるんですけど、そんなことは発想になかったし、ソフトにそんな機能があったかも不明です。

話がそれました。

iOSの音楽系アプリは音源の役割のみしか持たないものは稀で、実際は鍵盤とかのUIが付いているので単体で完結はしています。
でもタッチパネルの平面での操作はしづらいのでやっぱり物理的なMIDIコンは欲しくなるわけで、iOSデバイスとLightningコネクタ経由で接続できるように最近のMIDIコンは作られています。
有線接続だけでなく無線で接続できるコントローラも徐々に出てきています。ReMINEも無線なのでその流れに乗りたいぜ!

そしてMIDIコンから送られてきたMIDI信号を受け取り、音源となるアプリでそれをフックする仕組みがiOS側にも備わっています。(Androidも6.0から正式にサポートされたようです)
次回はそのiOS関連の話を書こうかなと思います。

ではでは。

★★★ツイッターでも情報発信していきますのでフォローお願いします!★★★

Pocket