ultimatepp/examples/Synth/Gen.cpp
cxl 376df036cd .examples
git-svn-id: svn://ultimatepp.org/upp/trunk@12698 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2019-01-22 09:33:28 +00:00

157 lines
3.6 KiB
C++

#include "Synth.h"
#include "sample.i"
double waveform_table[9][4096];
INITBLOCK {
for(int i = 0; i < 4096; i++) {
double arg = M_2PI * i / 4096;
waveform_table[WAVEFORM_SIN][i] = sin(arg);
waveform_table[WAVEFORM_SQUARE][i] = sgn(waveform_table[WAVEFORM_SIN][i]);
waveform_table[WAVEFORM_TRIANGLE][i] = abs(2048 - i) / 1024.0 - 1;
waveform_table[WAVEFORM_SAWTOOTH][i] = 2 * i / 4096.0 - 1;
}
for(int i = 0; i < 4096; i++) {
waveform_table[4][i] = wave_saxophone[i];
waveform_table[5][i] = wave_violin[i];
waveform_table[6][i] = wave_doublebass[i];
waveform_table[7][i] = wave_banjo[i];
waveform_table[8][i] = wave_trumpet[i];
}
}
double Rate(double x)
{
return pow(10, (6 * x / 100 - 6));
}
void SoundGen::FMOPGen::Comp()
{
attack = 1 + Rate(attack);
decay = 1 - Rate(decay);
release = 1 - Rate(release);
duration = 44100 * duration / 1000;
fdrift = exp2(fdrift / 12 / 44100);
if(volume > 0)
volume = pow(10, (volume - 100) / 40);
if(sustain > 0)
sustain = pow(10, (sustain - 100) / 40);
wave_tab = waveform_table[clamp(waveform, 0, (int)WAVEFORM_LASTSAMPLE)];
}
String SoundGen::FMOPGen::ToString() const
{
return String() << "Volume: " << volume << ", phase: " << p << ", ADSR volume: " << v;
}
force_inline
double SoundGen::FMOPGen::Evaluate(int t, double mf, double mod, double& cv)
{
if(volume == 0)
return 0;
if(t >= duration) {
v *= release;
cv = v;
}
else
switch(p) {
case 0:
v *= attack;
if(v >= 1.0) {
v = 1.0;
p = 1;
}
cv = v > 0;
break;
case 1:
v *= decay;
if(v < sustain) {
v = sustain;
p = 2;
}
cv = v;
break;
default:
cv = v = sustain;
}
cv *= volume;
f *= fdrift;
double fn;
if(findarg(waveform, WAVEFORM_BROWN, WAVEFORM_WHITE) >= 0) {
static dword state = 1;
state ^= state << 13;
state ^= state >> 17;
state ^= state << 5;
fn = 2.0 / 4294967295.0 * state - 1;
if(waveform == WAVEFORM_BROWN)
fn = n = clamp(n + 0.06 * fn, -1.0, 1.0);
}
else {
#if 0
double arg = mf * f * t + mod;
if(waveform == WAVEFORM_SIN)
fn = sin(arg);
else {
arg = fmod(arg, M_2PI);
fn = waveform == WAVEFORM_SQUARE ? sgn(abs(M_PI - arg) / (M_PI / 2) - 1) :
waveform == WAVEFORM_TRIANGLE ? abs(M_PI - arg) / (M_PI / 2) - 1 :
waveform == WAVEFORM_SAWTOOTH ? arg / M_PI - 1 :
0;
}
#else
double arg = mf * f * t + mod;
fn = wave_tab[dword((4096 / M_2PI) * arg) & 4095];
#endif
}
return volume * v * fn;
}
void SoundGen::Start(const Sound& s)
{
for(int i = 0; i < OPCOUNT; i++) {
(FMOP&)op[i] = s.op[i];
op[i].Comp();
op[i].Start();
}
f = s.f / 22100 * M_PI;
lpan = (float)s.pan;
rpan = (float)(1 - s.pan);
for(int i = 3; i <= 4; i++) // vibrato, tremolo
op[i].f = op[i].f / 22100 * M_PI;
t = 0;
memset(feedback, 0, sizeof(feedback));
current_volume = 1;
lfo_mod = Randomf() * M_2PI;
}
float SoundGen::Get()
{
#if 0
float r = op[0].Evaluate(t, f, 0, current_volume);
#else
if(current_volume < 0.001)
return 0;
double dummy;
double lfo1 = op[3].Evaluate(t, 1, lfo_mod, dummy);
double lfo2 = op[4].Evaluate(t, 1, lfo_mod, dummy);
double v = (1 - op[4].volume + lfo2);
float r =
(float)(v *
op[0].Evaluate(t, f, op[1].Evaluate(t, f, lfo1, dummy) + op[2].Evaluate(t, f, lfo1, dummy) + lfo1, current_volume)
);
#endif
t++;
return r;
}
String SoundGen::ToString() const
{
String r;
r << "----- Current volume: " << current_volume << ", time: " << t << '\n';
for(int i = 0; i < OPCOUNT; i++)
r << i << ": " << op[i] << '\n';
return r;
}