Nucleo F401REでFM音源を実装するやつ 外部DACとオペアンプを利用 現在はMCP4922とNJM2737
Dependencies: AOTTrigon I2CEEPROM MCP4922 AQM0802A mbed
Fork of NuMidi401 by
NuFM401
Nucleo F401用の自作ソフトウェアMIDI音源
概要
だいたいそんなもんです。
特徴
- ブレッドボードの上で組める程度には簡単な回路構成
- 外部のDACにMCP4922を採用
- 念のためのボルテージフォロアとしてNJM2737Dを採用
- バンク用EEPROMに24FC1025を採用
- シリアル経由でMIDIデータを受信することで操作
補足
シリアル <=> MIDI のドライバにはHairless-MIDISerialをオススメします。 仮想MIDIケーブルはとりあえずMIDI Yokeで。
FMOscillator/FMOscillator.cpp
- Committer:
- kb10uy
- Date:
- 2015-01-29
- Revision:
- 21:e3014c1bdf9c
- Parent:
- 20:8278e607a687
- Child:
- 23:deb76bdf6f03
File content as of revision 21:e3014c1bdf9c:
#include "FMOscillator.h" char sysexData[128]; FMOscillator::FMOscillator() { } FMOscillator::FMOscillator(int opc, Timer *tim, Serial *ser, AOTTrigon *tri, I2C *i2clcd) { master = tim; serial = ser; trigon = tri; opcount = opc; lcd = new AQM0802A(*i2clcd); operators = new FMOperator*[opcount]; for(int i = 0; i < opcount; i++) { operators[i] = new FMOperator(master, trigon); } channels = new MIDIChannel*[16]; for(int i = 0; i < 16; i++) { channels[i] = new MIDIChannel(lcd); } serial->baud(256000); serial->format(); serial->attach(this, &FMOscillator::midiReceived); master->start(); lcd->cls(); lcd->printf("Welcome\n to "); wait_ms(1000); lcd->cls(); lcd->printf("NuFM401\nFMDriver"); wait_ms(1000); lcd->cls(); lcd->printf("FMOpe\n%dbytes",sizeof(FMOperator)*opcount); wait_ms(1000); lcd->cls(); lcd->printf("FMOsc\n%dbytes",sizeof(FMOscillator)); wait_ms(1000); lcd->cls(); lcd->printf("MIDICh\n%dbytes",sizeof(MIDIChannel)*16); wait_ms(1000); lcd->cls(); lcd->printf("NuFM401\nSTAND BY"); } FMOscillator::~FMOscillator() { for(int i = 0; i < opcount; i++) { delete operators[i]; } for(int i = 0; i < 16; i++) { delete channels[i]; } delete[] operators; 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() { }