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: Operator.cpp
- Revision:
- 12:7408b85fba39
- Parent:
- 10:0ffdefe75566
--- a/Operator.cpp Mon Dec 29 12:48:44 2014 +0000 +++ b/Operator.cpp Tue Dec 30 05:53:06 2014 +0000 @@ -1,54 +1,98 @@ #include "Operator.h" static const float pi2 = 6.283185307179586476925286766559f; +inline float getFloatRate(char cr); FMOperator::FMOperator() { attack = 0.0f; - delay = 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; - - startTime = 0.0; - releaseTime = 0.0; - baseFrequency = 1.0f; -} - -FMOperator::FMOperator(Timer *tm, AOTTrigon *t) -{ - attack = 0.0f; - delay = 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(float fmIn) { +float FMOperator::calculate(double time, float fmIn) { if (startTime == 0.0) return 0.0f; float pos = (pi2 * baseFrequency * frequencyMultiple); - double nt = (master->read_us() / 1000000.0) - startTime; - return tri->sin(fmIn + (float)(pos * nt)); + 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::attackNote(float freq) { - baseFrequency = freq; - startTime = master->read_us() / 1000000.0; +void FMOperator::releaseNote(double time) { + releaseTime = time; + released = true; } -void FMOperator::releaseNote() { - startTime = 0.0; - releaseTime = master->read_us() / 1000000.0; -} \ No newline at end of file +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); + } +} +