mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
157 lines
3.6 KiB
C++
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;
|
|
}
|