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で。
Diff: FMOscillator/FMOperator.cpp
- Revision:
- 13:e11380ceb460
- Parent:
- 12:7408b85fba39
- Child:
- 21:e3014c1bdf9c
diff -r 7408b85fba39 -r e11380ceb460 FMOscillator/FMOperator.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FMOscillator/FMOperator.cpp Sat Jan 17 03:57:58 2015 +0000 @@ -0,0 +1,98 @@ +#include "FMOperator.h" + +static const float pi2 = 6.283185307179586476925286766559f; +inline float getFloatRate(char cr); + +FMOperator::FMOperator() +{ + attack = 0.0f; + decay = 0.0f; + sustain = 1.0f; + sustainRate = 0.0f; + release = 0.0f; + + frequencyMultiple = 1.0f; + totalLevel = 1.0f; + modulation = 0.0f; + + startTime = 0.0; + releaseTime = 0.0; + baseFrequency = 1.0f; + feedback = 0.0f; + prev = 0.0f; + released = false; +} + +FMOperator::FMOperator(Timer *tm, AOTTrigon *t) +{ + attack = 0.0f; + decay = 0.0f; + sustain = 0.0f; + sustainRate = 1.0f; + release = 0.0f; + + frequencyMultiple = 1.0f; + totalLevel = 1.0f; + modulation = 1.0f; + + tri = t; + master = tm; + startTime = 0.0; + releaseTime = 0.0; + baseFrequency = 1.0f; + feedback = 0.0f; + prev = 0.0f; + released = false; +} + +float FMOperator::calculate(double time, float fmIn) { + if (startTime == 0.0) return 0.0f; + float pos = (pi2 * baseFrequency * frequencyMultiple); + double abt = master->read_us() / 1000000.0; + double nt = abt - startTime; + float e; + if (released) { + e = getEnvelopeReleaseRate(abt - releaseTime,getEnvelopeRate(nt)); + } else { + e = getEnvelopeRate(nt); + } + if (feedback != 0.0f) { + return prev = tri->sin((float)(pos * nt) + prev * feedback) * e * totalLevel * modulation; + } + return tri->sin(fmIn + (float)(pos * nt)) * e * totalLevel * modulation; +} + +void FMOperator::attackNote(float freq, double time) { + baseFrequency = freq; + startTime = time; + released = false; +} + +void FMOperator::releaseNote(double time) { + releaseTime = time; + released = true; +} + +float FMOperator::getEnvelopeRate(double reltime) { + //アタック・ディケイ・リリースに要する時間は + //127の時0s、0のとき1s + if (attack != 0.0f && reltime <= attack) { + return reltime * (1.0f / attack); + } + if (decay != 0.0f && reltime <= (attack + decay)) { + reltime -= attack; + return 1.0f - reltime * (1.0f - sustain) / (decay); + } + return (sustainRate != 0.0f) ? sustain - (reltime - decay) * (sustain / sustainRate) : sustain; +} + +float FMOperator::getEnvelopeReleaseRate(double rlst,float orate) { + //どう考えても無音・1回も鳴らしてない・リリースなし + //ってどれが一番頻度高いかね + if (rlst >= (attack + decay + release) || release == 0.0f || startTime == 0.0) { + return 0; + } else { + return orate - rlst * (orate / release); + } +} +