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で。
Operator.cpp
- Committer:
- kb10uy
- Date:
- 2014-12-30
- Revision:
- 12:7408b85fba39
- Parent:
- 10:0ffdefe75566
File content as of revision 12:7408b85fba39:
#include "Operator.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); } }