LoginSignup
3
3

More than 5 years have passed since last update.

Siv3D の MIDI メッセージ送信ユーティリティ

Last updated at Posted at 2015-12-13

Siv3D Advent Calendar 2015 13 日目の記事です。
Siv3D June 2015 から、MIDI の再生に対応した環境では MIDI メッセージを直接送信して音楽演奏ができるようになりました。しかし、MIDI メッセージの規格 に従って適切な数値を送信しなければならないので、MIDI に慣れていない場合には少し扱いづらいです。

今日は、MIDI メッセージの送信を補助するユーティリティヘッダを公開します。
この機能は Siv3D January 2016 に標準で実装される予定です。

MidiUtility.hpp
//-----------------------------------------------
//
//  This file is part of the Siv3D Engine.
//
//  Copyright (C) 2008-2015 Ryo Suzuki
//
//  Licensed under the MIT License.
//
//-----------------------------------------------

# pragma once
# include <Siv3D.hpp>

namespace s3d
{
    /// <summary>
    /// 音階
    /// </summary>
    enum class PitchName : uint8
    {
        C_1 = 0,
        CS_1,
        DF_1 = CS_1,
        D_1,
        DS_1,
        EF_1 = DS_1,
        E_1,
        FF_1 = E_1,
        F_1,
        ES_1 = F_1,
        FS_1,
        GF_1 = FS_1,
        G_1,
        GS_1,
        AF_1 = GS_1,
        A_1,
        AS_1,
        BF_1 = AS_1,
        B_1,

        CF0 = B_1,
        C0,
        BS_1 = C0,
        CS0,
        DF0 = CS0,
        D0,
        DS0,
        EF0 = DS0,
        E0,
        FF0 = E0,
        F0,
        ES0 = F0,
        FS0,
        GF0 = FS0,
        G0,
        GS0,
        AF0 = GS0,
        A0,
        AS0,
        BF0 = AS0,
        B0,

        CF1 = B0,
        C1,
        BS0 = C1,
        CS1,
        DF1 = CS1,
        D1,
        DS1,
        EF1 = DS1,
        E1,
        FF1 = E1,
        F1,
        ES1 = F1,
        FS1,
        GF1 = FS1,
        G1,
        GS1,
        AF1 = GS1,
        A1,
        AS1,
        BF1 = AS1,
        B1,

        CF2 = B1,
        C2,
        BS1 = C2,
        CS2,
        DF2 = CS2,
        D2,
        DS2,
        EF2 = DS2,
        E2,
        FF2 = E2,
        F2,
        ES2 = F2,
        FS2,
        GF2 = FS2,
        G2,
        GS2,
        AF2 = GS2,
        A2,
        AS2,
        BF2 = AS2,
        B2,

        CF3 = B2,
        C3,
        BS2 = C3,
        CS3,
        DF3 = CS3,
        D3,
        DS3,
        EF3 = DS3,
        E3,
        FF3 = E3,
        F3,
        ES3 = F3,
        FS3,
        GF3 = FS3,
        G3,
        GS3,
        AF3 = GS3,
        A3,
        AS3,
        BF3 = AS3,
        B3,

        CF4 = B3,
        C4,
        BS3 = C4,
        CS4,
        DF4 = CS4,
        D4,
        DS4,
        EF4 = DS4,
        E4,
        FF4 = E4,
        F4,
        ES4 = F4,
        FS4,
        GF4 = FS4,
        G4,
        GS4,
        AF4 = GS4,
        A4,
        AS4,
        BF4 = AS4,
        B4,

        CF5 = B4,
        C5,
        BS4 = C5,
        CS5,
        DF5 = CS5,
        D5,
        DS5,
        EF5 = DS5,
        E5,
        FF5 = E5,
        F5,
        ES5 = F5,
        FS5,
        GF5 = FS5,
        G5,
        GS5,
        AF5 = GS5,
        A5,
        AS5,
        BF5 = AS5,
        B5,

        CF6 = B5,
        C6,
        BS5 = C6,
        CS6,
        DF6 = CS6,
        D6,
        DS6,
        EF6 = DS6,
        E6,
        FF6 = E6,
        F6,
        ES6 = F6,
        FS6,
        GF6 = FS6,
        G6,
        GS6,
        AF6 = GS6,
        A6,
        AS6,
        BF6 = AS6,
        B6,

        CF7 = B6,
        C7,
        BS6 = C7,
        CS7,
        DF7 = CS7,
        D7,
        DS7,
        EF7 = DS7,
        E7,
        FF7 = E7,
        F7,
        ES7 = F7,
        FS7,
        GF7 = FS7,
        G7,
        GS7,
        AF7 = GS7,
        A7,
        AS7,
        BF7 = AS7,
        B7,

        CF8 = B7,
        C8,
        BS7 = C8,
        CS8,
        DF8 = CS8,
        D8,
        DS8,
        EF8 = DS8,
        E8,
        FF8 = E8,
        F8,
        ES8 = F8,
        FS8,
        GF8 = FS8,
        G8,
        GS8,
        AF8 = GS8,
        A8,
        AS8,
        BF8 = AS8,
        B8,

        CF9 = B8,
        C9,
        BS8 = C9,
        CS9,
        DF9 = CS9,
        D9,
        DS9,
        EF9 = DS9,
        E9,
        FF9 = E9,
        F9,
        ES9 = F9,
        FS9,
        GF9 = FS9,
        G9,
    };

    /// <summary>
    /// GM 音色
    /// </summary>
    enum class GMInstrument : uint8
    {
        // Piano
        Piano1,
        Piano2,
        Piano3,
        Piano4,
        ElectricPiano1,
        ElectricPiano2,
        Harpsichord,
        Clavinet,

        // Chromatic Percussion
        Celesta,
        Glockenspiel,
        MusicBox,
        Vibraphone,
        Marimba,
        Xylophone,
        TubularBells,
        Dulcimer,

        // Organ
        DrawbarOrgan,
        PercussiveOrgan,
        RockOrgan,
        ChurchOrgan,
        ReedOrgan,
        Accordion,
        Harmonica,
        TangoAccordion,

        //Guitar
        NylonGuitar,
        SteelGuitar,
        JazzGuitar,
        CleanGuitar,
        MutedGuitar,
        OverdrivenGuitar,
        DistortionGuitar,
        GuitarHarmonics,

        // Bass
        AcousticBass,
        FingeredBass,
        PickedBass,
        FretlessBass,
        SlapBass1,
        SlapBass2,
        SynthBass1,
        SynthBass2,

        // Strings
        Violin,
        Viola,
        Cello,
        Contrabass,
        TremoloStrings,
        PizzicatoStrings,
        OrchestralHarp,
        Timpani,

        // Ensemble
        StringEnsemble1,
        StringEnsemble2,
        SynthStrings1,
        SynthStrings2,
        ChoirAahs,
        VoiceOohs,
        SynthChoir,
        OrchestraHit,

        // Brass
        Trumpet,
        Trombone,
        Tuba,
        MutedTrumpet,
        FrenchHorn,
        BrassSection,
        SynthBrass1,
        SynthBrass2,

        // Reed
        SopranoSax,
        AltoSax,
        TenorSax,
        BaritoneSax,
        Oboe,
        EnglishHorn,
        Bassoon,
        Clarinet,

        // Pipe
        Piccolo,
        Flute,
        Recorder,
        PanFlute,
        Blownbottle,
        Shakuhachi,
        Whistle,
        Ocarina,

        // Synth Lead
        SquareWave,
        SawWave,
        SynCalliope,
        ChifferLead,
        Charang,
        SoloVox,
        FifthSawWave,
        BassAndLead,

        // Synth Pad
        Fantasia,
        WarmPad,
        Polysynth,
        SpaceVoice,
        BowedGlass,
        MetalPad,
        HaloPad,
        SweepPad,

        // Synth Effects
        IceRain,
        Soundtrack,
        Crystal,
        Atmosphere,
        Brightness,
        Goblin,
        EchoDrops,
        StarTheme,

        // Ethnic
        Sitar,
        Banjo,
        Shamisen,
        Koto,
        Kalimba,
        Bagpipe,
        Fiddle,
        Shanai,

        // Percussive
        TinkleBell,
        Agogo,
        SteelDrums,
        Woodblock,
        TaikoDrum,
        MelodicTom,
        SynthDrum,
        ReverseCymbal,

        // Sound effects
        GuitarFretNoise,
        BreathNoise,
        Seashore,
        BirdTweet,
        TelephoneRing,
        Helicopter,
        Applause,
        Gunshot,
    };

    /// <summary>
    /// MIDI メッセージ・ユーティリティ
    /// </summary>
    namespace MidiMessage
    {
        /// <summary>
        /// 音色を変更する MIDI メッセージを作成します。
        /// </summary>
        /// <param name="ch">
        /// チャンネル [0, 15]
        /// </param>
        /// <param name="instrument">
        /// 音色
        /// </param>
        /// <returns>
        /// 音色を変更する MIDI メッセージ
        /// </returns>
        inline Array<uint8> SetInstrument(uint32 ch, uint32 instrument)
        {
            return{ uint8(0xC0 | (ch & 0xF)), uint8(instrument & 0x7F) };
        }

        /// <summary>
        /// 音色を変更する MIDI メッセージを作成します。
        /// </summary>
        /// <param name="ch">
        /// チャンネル [0, 15]
        /// </param>
        /// <param name="instrument">
        /// 音色
        /// </param>
        /// <returns>
        /// 音色を変更する MIDI メッセージ
        /// </returns>
        inline Array<uint8> SetInstrument(uint32 ch, GMInstrument instrument)
        {
            return{ uint8(0xC0 | (ch & 0xF)), uint8(static_cast<uint8>(instrument) & 0x7F) };
        }

        /// <summary>
        /// ノート・オンの MIDI メッセージを作成します。
        /// </summary>
        /// <param name="ch">
        /// チャンネル [0, 15]
        /// </param>
        /// <param name="note">
        /// ノート番号
        /// </param>
        /// <param name="velocity">
        /// ベロシティ
        /// </param>
        /// <returns>
        /// ノート・オンの MIDI メッセージ
        /// </returns>
        inline Array<uint8> NoteOn(uint32 ch, uint32 note, uint8 velocity = 64)
        {
            return{ uint8(0x90 | (ch & 0xF)), uint8(note & 0x7F), velocity };
        }

        /// <summary>
        /// ノート・オンの MIDI メッセージを作成します。
        /// </summary>
        /// <param name="ch">
        /// チャンネル [0, 15]
        /// </param>
        /// <param name="note">
        /// ノート番号
        /// </param>
        /// <param name="velocity">
        /// ベロシティ
        /// </param>
        /// <returns>
        /// ノート・オンの MIDI メッセージ
        /// </returns>
        inline Array<uint8> NoteOn(uint32 ch, PitchName note, uint8 velocity = 64)
        {
            return{ uint8(0x90 | (ch & 0xF)), uint8(static_cast<uint8>(note) & 0x7F), velocity };
        }

        /// <summary>
        /// ノート・オフの MIDI メッセージを作成します。
        /// </summary>
        /// <param name="ch">
        /// チャンネル [0, 15]
        /// </param>
        /// <param name="note">
        /// ノート番号
        /// </param>
        /// <param name="velocity">
        /// ベロシティ
        /// </param>
        /// <returns>
        /// ノート・オフの MIDI メッセージ
        /// </returns>
        inline Array<uint8> NoteOff(uint32 ch, uint32 note, uint8 velocity = 64)
        {
            return{ uint8(0x80 | (ch & 0xF)), uint8(note & 0x7F), velocity };
        }

        /// <summary>
        /// ノート・オフの MIDI メッセージを作成します。
        /// </summary>
        /// <param name="ch">
        /// チャンネル [0, 15]
        /// </param>
        /// <param name="note">
        /// ノート番号
        /// </param>
        /// <param name="velocity">
        /// ベロシティ
        /// </param>
        /// <returns>
        /// ノート・オフの MIDI メッセージ
        /// </returns>
        inline Array<uint8> NoteOff(uint32 ch, PitchName note, uint8 velocity = 64)
        {
            return{ uint8(0x80 | (ch & 0xF)), uint8(static_cast<uint8>(note) & 0x7F), velocity };
        }

        /// <summary>
        /// 音量を変更する MIDI メッセージを作成します。
        /// </summary>
        /// <param name="ch">
        /// チャンネル [0, 15]
        /// </param>
        /// <param name="volume">
        /// 音量 [0.0, 1.0]
        /// </param>
        /// <returns>
        /// 音量を変更する MIDI メッセージ
        /// </returns>
        inline Array<uint8> SetVolume(uint32 ch, double volume)
        {
            return{ uint8(0xB0 | (ch & 0xF)), uint8(0x07), static_cast<uint8>(Clamp(255 * volume, 0.0, 255.0)) };
        }

        /// <summary>
        /// パンポットを変更する MIDI メッセージを作成します。
        /// </summary>
        /// <param name="ch">
        /// チャンネル [0, 15]
        /// </param>
        /// <param name="panpot">
        /// パンポット [-1.0, 1.0]
        /// </param>
        /// <returns>
        /// パンポットを変更する MIDI メッセージ
        /// </returns>
        inline Array<uint8> SetPanpot(uint32 ch, double panpot)
        {
            return{ uint8(0xB0 | (ch & 0xF)), uint8(0x0A), static_cast<uint8>(Clamp(64 + 63.5 * panpot, 0.0, 127.0)) };
        }

        /// <summary>
        /// 全てのノートをオフにする MIDI メッセージを作成します。
        /// </summary>
        /// <param name="ch">
        /// チャンネル [0, 15]
        /// </param>
        /// <returns>
        /// 全てのノートをオフにする MIDI メッセージ
        /// </returns>
        inline Array<uint8> AllSoundOff(uint32 ch)
        {
            return{ uint8(0xB0 | (ch & 0xF)), uint8(0x78), uint8(0x00) };
        }
    }
}

使用例

Main.cpp
// This is free and unencumbered software released into the public domain.
// For more information, please refer to <http://unlicense.org/>

# include <Siv3D.hpp>
# include "MidiUtility.hpp"

void Main()
{
    const Array<std::pair<Key, GMInstrument>> instruments
    {
        { Input::Key1, GMInstrument::Piano1 },
        { Input::Key2, GMInstrument::Marimba },
        { Input::Key3, GMInstrument::Harmonica },
        { Input::Key4, GMInstrument::JazzGuitar },
        { Input::Key5, GMInstrument::Violin },
        { Input::Key6, GMInstrument::VoiceOohs },
        { Input::Key7, GMInstrument::FrenchHorn },
        { Input::Key8, GMInstrument::SquareWave },
    };

    const Array<std::pair<Key, PitchName>> keys
    {
        { Input::KeyA, PitchName::C4 },
        { Input::KeyS, PitchName::D4 },
        { Input::KeyD, PitchName::E4 },
        { Input::KeyF, PitchName::F4 },
        { Input::KeyG, PitchName::G4 },
        { Input::KeyH, PitchName::A4 },
        { Input::KeyJ, PitchName::B4 },
        { Input::KeyK, PitchName::C5 },
    };

    while (System::Update())
    {
        for (const auto& instrument : instruments)
        {
            if (instrument.first.clicked)
            {
                Midi::SendMessage(MidiMessage::SetInstrument(0, instrument.second));
            }
        }

        for (const auto& key : keys)
        {
            if (key.first.clicked)
            {
                Midi::SendMessage(MidiMessage::NoteOn(0, key.second));
            }
            else if (key.first.released)
            {
                Midi::SendMessage(MidiMessage::NoteOff(0, key.second));
            }
        }
    }
}

明日の記事は @matsu7874 さんです。
よろしくお願いします。

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