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で。

Committer:
kb10uy
Date:
Sat Jan 31 10:54:13 2015 +0000
Revision:
24:f93b49b4cd66
Parent:
21:e3014c1bdf9c
NRPN 20h xxh???

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kb10uy 13:e11380ceb460 1 #include "FMOperator.h"
kb10uy 7:439c57c20593 2
kb10uy 7:439c57c20593 3 static const float pi2 = 6.283185307179586476925286766559f;
kb10uy 12:7408b85fba39 4 inline float getFloatRate(char cr);
kb10uy 7:439c57c20593 5
kb10uy 10:0ffdefe75566 6 FMOperator::FMOperator()
kb10uy 10:0ffdefe75566 7 {
kb10uy 10:0ffdefe75566 8 attack = 0.0f;
kb10uy 12:7408b85fba39 9 decay = 0.0f;
kb10uy 12:7408b85fba39 10 sustain = 1.0f;
kb10uy 12:7408b85fba39 11 sustainRate = 0.0f;
kb10uy 12:7408b85fba39 12 release = 0.0f;
kb10uy 12:7408b85fba39 13
kb10uy 12:7408b85fba39 14 frequencyMultiple = 1.0f;
kb10uy 12:7408b85fba39 15 totalLevel = 1.0f;
kb10uy 12:7408b85fba39 16 modulation = 0.0f;
kb10uy 12:7408b85fba39 17
kb10uy 12:7408b85fba39 18 startTime = 0.0;
kb10uy 12:7408b85fba39 19 releaseTime = 0.0;
kb10uy 12:7408b85fba39 20 baseFrequency = 1.0f;
kb10uy 12:7408b85fba39 21 feedback = 0.0f;
kb10uy 12:7408b85fba39 22 prev = 0.0f;
kb10uy 12:7408b85fba39 23 released = false;
kb10uy 12:7408b85fba39 24 }
kb10uy 12:7408b85fba39 25
kb10uy 12:7408b85fba39 26 FMOperator::FMOperator(Timer *tm, AOTTrigon *t)
kb10uy 12:7408b85fba39 27 {
kb10uy 12:7408b85fba39 28 attack = 0.0f;
kb10uy 12:7408b85fba39 29 decay = 0.0f;
kb10uy 10:0ffdefe75566 30 sustain = 0.0f;
kb10uy 10:0ffdefe75566 31 sustainRate = 1.0f;
kb10uy 10:0ffdefe75566 32 release = 0.0f;
kb10uy 10:0ffdefe75566 33
kb10uy 10:0ffdefe75566 34 frequencyMultiple = 1.0f;
kb10uy 10:0ffdefe75566 35 totalLevel = 1.0f;
kb10uy 12:7408b85fba39 36 modulation = 1.0f;
kb10uy 7:439c57c20593 37
kb10uy 9:12a54d2ea8fc 38 tri = t;
kb10uy 7:439c57c20593 39 master = tm;
kb10uy 7:439c57c20593 40 startTime = 0.0;
kb10uy 7:439c57c20593 41 releaseTime = 0.0;
kb10uy 7:439c57c20593 42 baseFrequency = 1.0f;
kb10uy 12:7408b85fba39 43 feedback = 0.0f;
kb10uy 12:7408b85fba39 44 prev = 0.0f;
kb10uy 12:7408b85fba39 45 released = false;
kb10uy 7:439c57c20593 46 }
kb10uy 7:439c57c20593 47
kb10uy 21:e3014c1bdf9c 48 float FMOperator::calculate(float fmIn) {
kb10uy 7:439c57c20593 49 if (startTime == 0.0) return 0.0f;
kb10uy 7:439c57c20593 50 float pos = (pi2 * baseFrequency * frequencyMultiple);
kb10uy 12:7408b85fba39 51 double abt = master->read_us() / 1000000.0;
kb10uy 12:7408b85fba39 52 double nt = abt - startTime;
kb10uy 12:7408b85fba39 53 float e;
kb10uy 12:7408b85fba39 54 if (released) {
kb10uy 12:7408b85fba39 55 e = getEnvelopeReleaseRate(abt - releaseTime,getEnvelopeRate(nt));
kb10uy 12:7408b85fba39 56 } else {
kb10uy 12:7408b85fba39 57 e = getEnvelopeRate(nt);
kb10uy 12:7408b85fba39 58 }
kb10uy 12:7408b85fba39 59 if (feedback != 0.0f) {
kb10uy 12:7408b85fba39 60 return prev = tri->sin((float)(pos * nt) + prev * feedback) * e * totalLevel * modulation;
kb10uy 12:7408b85fba39 61 }
kb10uy 12:7408b85fba39 62 return tri->sin(fmIn + (float)(pos * nt)) * e * totalLevel * modulation;
kb10uy 12:7408b85fba39 63 }
kb10uy 12:7408b85fba39 64
kb10uy 12:7408b85fba39 65 void FMOperator::attackNote(float freq, double time) {
kb10uy 12:7408b85fba39 66 baseFrequency = freq;
kb10uy 12:7408b85fba39 67 startTime = time;
kb10uy 12:7408b85fba39 68 released = false;
kb10uy 7:439c57c20593 69 }
kb10uy 7:439c57c20593 70
kb10uy 12:7408b85fba39 71 void FMOperator::releaseNote(double time) {
kb10uy 12:7408b85fba39 72 releaseTime = time;
kb10uy 12:7408b85fba39 73 released = true;
kb10uy 7:439c57c20593 74 }
kb10uy 7:439c57c20593 75
kb10uy 12:7408b85fba39 76 float FMOperator::getEnvelopeRate(double reltime) {
kb10uy 12:7408b85fba39 77 //アタック・ディケイ・リリースに要する時間は
kb10uy 12:7408b85fba39 78 //127の時0s、0のとき1s
kb10uy 12:7408b85fba39 79 if (attack != 0.0f && reltime <= attack) {
kb10uy 12:7408b85fba39 80 return reltime * (1.0f / attack);
kb10uy 12:7408b85fba39 81 }
kb10uy 12:7408b85fba39 82 if (decay != 0.0f && reltime <= (attack + decay)) {
kb10uy 12:7408b85fba39 83 reltime -= attack;
kb10uy 12:7408b85fba39 84 return 1.0f - reltime * (1.0f - sustain) / (decay);
kb10uy 12:7408b85fba39 85 }
kb10uy 12:7408b85fba39 86 return (sustainRate != 0.0f) ? sustain - (reltime - decay) * (sustain / sustainRate) : sustain;
kb10uy 12:7408b85fba39 87 }
kb10uy 12:7408b85fba39 88
kb10uy 12:7408b85fba39 89 float FMOperator::getEnvelopeReleaseRate(double rlst,float orate) {
kb10uy 12:7408b85fba39 90 //どう考えても無音・1回も鳴らしてない・リリースなし
kb10uy 12:7408b85fba39 91 //ってどれが一番頻度高いかね
kb10uy 12:7408b85fba39 92 if (rlst >= (attack + decay + release) || release == 0.0f || startTime == 0.0) {
kb10uy 12:7408b85fba39 93 return 0;
kb10uy 12:7408b85fba39 94 } else {
kb10uy 12:7408b85fba39 95 return orate - rlst * (orate / release);
kb10uy 12:7408b85fba39 96 }
kb10uy 12:7408b85fba39 97 }
kb10uy 12:7408b85fba39 98