Nucleo F401REでFM音源を実装するやつ 外部DACとオペアンプを利用 現在はMCP4922とNJM2737

Dependencies:   AOTTrigon I2CEEPROM MCP4922 AQM0802A mbed

Fork of NuMidi401 by Yuu Kobayashi

NuFM401

Nucleo F401用の自作ソフトウェアMIDI音源

概要

だいたいそんなもんです。

特徴

  • ブレッドボードの上で組める程度には簡単な回路構成
  • 外部のDACにMCP4922を採用
  • 念のためのボルテージフォロアとしてNJM2737Dを採用
  • バンク用EEPROMに24FC1025を採用
  • シリアル経由でMIDIデータを受信することで操作

補足

シリアル <=> MIDI のドライバにはHairless-MIDISerialをオススメします。 仮想MIDIケーブルはとりあえずMIDI Yokeで。

FMOscillator/FMOscillator.cpp

Committer:
kb10uy
Date:
2015-01-31
Revision:
24:f93b49b4cd66
Parent:
23:deb76bdf6f03

File content as of revision 24:f93b49b4cd66:

#include "FMOscillator.h"

char sysexData[128];

FMOscillator::FMOscillator()
{

}

FMOscillator::FMOscillator(Timer *tim, Serial *ser, AOTTrigon *tri, I2C *i2clcd)
{
    master = tim;
    serial = ser;
    trigon = tri;

    lcd = new AQM0802A(*i2clcd);

    channels = new MIDIChannel*[16];
    for(int i = 0; i < 16; i++) {
        channels[i] = new MIDIChannel(lcd, master, trigon);
    }
    serial->baud(256000);
    serial->format();
    serial->attach(this, &FMOscillator::midiReceived);
    master->start();
    
    lcd->cls();
    lcd->printf("NuFM401\nFMDriver");
}

FMOscillator::~FMOscillator()
{
    for(int i = 0; i < 16; i++) {
        delete channels[i];
    }
    delete[] channels;
    delete lcd;
}

void FMOscillator::midiReceived()
{
    getMIDIMessage();
    while(serial->readable()) serial->getc();
}

void FMOscillator::getMIDIMessage()
{
    unsigned char st = serial->getc();
    switch(st >> 4) {
        case 0x8:
            midiNoteOff(st & 0xf, serial->getc(), serial->getc());
            break;
        case 0x9:
            midiNoteOn(st & 0xf, serial->getc(), serial->getc());
            break;
        case 0xa:
            midiPolyphonicKeyPressure(st & 0xf, serial->getc(), serial->getc());
            break;
        case 0xb:
            char b2 = serial->getc();
            if (b2 >= 120) {
                midiChannelMode(st & 0xf, b2, serial->getc());
            } else {
                midiControlChange(st & 0xf, b2, serial->getc());
            }
            break;
        case 0xc:
            midiProgramChange(st & 0xf, serial->getc());
            break;
        case 0xd:
            midiChannelPressure(st & 0xf, serial->getc());
            break;
        case 0xe:
            char LSB = serial->getc();
            char MSB = serial->getc();
            midiPitchBend(st & 0xf, ((LSB << 7) | (MSB << 7)) + 8192);
            break;
        case 0xf:
            int t2 = st & 0xf;
            if (t2 <= 7) {
                getMIDISystemCommonMessage(t2);
            } else {
                midiSystemRealtimeMessage(st);
            }
            break;
    }
}

void FMOscillator::getMIDISystemCommonMessage(char t2)
{
    switch(t2) {
        case 0:
            //もう面倒臭いから128byteのバッファに適当に放り込んでおこう
            sysexData[0] = 0xf0;
            int i = 1;
            char d = 0;
            do {
                d = serial->getc();
                sysexData[i]=d;
                i++;
            } while(d != 0xf7);

            break;
        case 1:
            serial->getc();
            break;
        case 2:
            serial->getc();
            serial->getc();
            break;
        case 3:
            serial->getc();
            break;
        case 4:
            break;
        case 5:
            break;
        case 6:
            break;
        case 7:
            //どうしろと
            break;
    }
}

void FMOscillator::midiSystemRealtimeMessage(char mes)
{

}


void FMOscillator::midiNoteOn(char ch, char note, char vel)
{
    lcd->cls();
    lcd->printf("Note On\n");
    lcd->printf("%1x: %2x,%2x", ch, note, vel);
    if (vel==0) {
        channels[ch]->noteOff(note, master->read_us() / 1000000.0);
    } else {
        channels[ch]->noteOn(note, vel, master->read_us() / 1000000.0);
    }
}

void FMOscillator::midiNoteOff(char ch, char note, char vel)
{
    lcd->cls();
    lcd->printf("Note Off\n");
    lcd->printf("%1x: %2x,%2x", ch, note, vel);
    channels[ch]->noteOff(note, master->read_us() / 1000000.0);
}

void FMOscillator::midiPolyphonicKeyPressure(char ch, char note, char vel)
{

}

void FMOscillator::midiControlChange(char ch, char ctrl, char data)
{
    switch(ctrl) {
            //bank select
        case 0x00:
            break;
        case 0x20:
            break;

            //modulation
        case 0x01:
            lcd->cls();
            lcd->printf("CC:MODUL\nCh%1x:  %2x", ch, data);

            channels[ch]->setModulationMSB(data);
            break;
        case 0x21:
            //channels[ch]->setModulationLSB(data);
            break;

            //portamento time
        case 0x05:
            lcd->cls();
            lcd->printf("CC:PORTM\nCh%1x:  %2x", ch, data);

            channels[ch]->setPortamentoTime(data);
            break;
        case 0x25:
            break;

            //Volume
        case 0x07:
            lcd->cls();
            lcd->printf("CC:VOL\nCh%1x:  %2x", ch, data);
        
            channels[ch]->setVolume(data);
            break;
        case 0x37:
            break;

            //balance
        case 0x08:
            break;
        case 0x28:
            break;

            //panpot
        case 0x0a:
            lcd->cls();
            lcd->printf("CC:PANPT\nCh%1x:  %2x", ch, data);
            channels[ch]->setPanpot(data);
            break;
        case 0x2a:
            break;

            //expression
        case 0x0b:
            lcd->cls();
            lcd->printf("CC:EXPRS\nCh%1x:  %2x", ch, data);
            
            channels[ch]->setExpression(data);
            break;
        case 0x2b:
            break;

            //hold1
        case 0x40:
            lcd->cls();
            lcd->printf("CC:HOLD1\nCh%1x:  %2x", ch, data);
            
            if (data > 0x40) {
                channels[ch]->startHold1();
            } else {
                channels[ch]->endHold1();
            }
            break;

            //portamento
        case 0x41:
            lcd->cls();
            lcd->printf("CC:PORTS\nCh%1x:  %2x", ch, data);
            
            channels[ch]->setPortamentoSwitch(data > 0x40);
            break;

            //data entry
        case 0x06:
            channels[ch]->setDataEntryMSB(data);
            break;
        case 0x26:
            channels[ch]->setDataEntryLSB(data);
            break;

            //nrpn
        case 0x63:
            channels[ch]->setNRPNMSB(data);
            break;
        case 0x62:
            channels[ch]->setNRPNLSB(data);
            break;

            //rpn
        case 0x65:
            channels[ch]->setRPNMSB(data);
            break;
        case 0x64:
            channels[ch]->setRPNLSB(data);
            break;
    }
}

void FMOscillator::midiChannelMode(char ch, char ctrl, char data)
{
    switch(ctrl) {
        case 0x78:
            channels[ch]->allSoundOff();
            break;

        case 0x7b:
        case 0x7c:
        case 0x7d:
            channels[ch]->allNoteOff();
            break;
    }
}

void FMOscillator::midiProgramChange(char ch, char prg)
{

}

void FMOscillator::midiChannelPressure(char ch, char pres)
{

}

void FMOscillator::midiPitchBend(char ch, short pb)
{

}

void FMOscillator::midiSystemExclusiveMessage()
{

}