#include "Synth.h" double ADSR::Evaluate(double t, double duration) { if(t < delay) return 0; if(t > duration) { t -= duration; if(t > release) return 0; return sustain * (release - t) / release; } t -= delay; if(t < attack) return t / attack; t -= attack; if(t < decay) { return (sustain * t + decay - t) / decay; } return sustain; } struct FMSound : SoundGenerator, FMPatch { virtual bool Get(float *data, int len); double volume; double duration; double fc, fm1, fm2, fmf; int ti = 0; double noisedir = 0; double noiseval = 0; void SetVolume(double vol) { volume = vol; } void Set(double volume, double frequency, double duration, const FMPatch& m); FMSound(double volume, double frequency, double duration, const FMPatch& m) { Set(volume, frequency, duration, m); } }; void FMSound::Set(double volume, double frequency, double duration, const FMPatch& m) { (FMPatch&)*this = m; this->volume = volume; this->duration = duration; fc = frequency; fm1 = fc * m1; fm2 = fc * m2; fmf = fc * mf; } bool FMSound::Get(float *b, int len) { bool plays = true; double t; for(int i = 0; i < len; i++) { t = ti * (1.0 / 44200); double pt = M_2PI * t; static dword state = 1; state ^= state << 13; state ^= state >> 17; state ^= state << 5; double white = 2.0 / 4294967295.0 * state - 1; /* noisedir = clamp(noisedir + 0.0001 * fc * white, -0.08, 0.08); noiseval = noisedir; if(noiseval > 1) { noisedir = -abs(noisedir); noiseval = 1; } if(noiseval < 0) { noisedir = abs(noisedir); noiseval = -1; } *b++ = tanh(noiseval); */ *b++ = float(volume * adsr.Evaluate(t, duration) * sin(pt * fc + adsr1.Evaluate(t, duration) * beta1 * sin(pt * fm1 + betan * white + betaf * adsrf.Evaluate(t, duration) * sin(pt * fmf)) + adsr2.Evaluate(t, duration) * beta2 * sin(pt * fm2))); ti++; } return t < duration + adsr.release; } int64 Play(double volume, double frequency, double duration, const FMPatch& patch) { return AddSound(new FMSound(volume, frequency, duration, patch)); }