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

FMOscillator/FMOperator.cpp

Committer:
kb10uy
Date:
2015-01-31
Revision:
24:f93b49b4cd66
Parent:
21:e3014c1bdf9c

File content as of revision 24:f93b49b4cd66:

#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(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);
    }
}