Skip to content

Commit

Permalink
Merge branch 'perf-use-float'
Browse files Browse the repository at this point in the history
* perf-use-float:
  TESTS: adapt tests to double->float changes
  LIB: MorphUtils: use floats for freq/mag representation
  LIB: RTVector: double->float for accessors
  LIB: change more math functions: double->float for factors/freqs
  TESTS: testifftsynth: adapt threshold
  LIB: Random: provide method to generate random float in range
  LIB: LiveDecoder: consistently use floats for freq/mag/phase
  IFFTSynth: use floats for freq/mag/phase

Signed-off-by: Stefan Westerfeld <[email protected]>
  • Loading branch information
swesterfeld committed Jun 6, 2024
2 parents ef4cf6f + 5383aaa commit d1926e5
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 64 deletions.
22 changes: 11 additions & 11 deletions lib/smifftsynth.hh
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ class IFFTSynth

int zero_padding;
size_t block_size;
double mix_freq;
double freq256_factor;
double mag_norm;
float mix_freq;
float freq256_factor;
float mag_norm;

float *fft_in;
float *fft_out;
Expand Down Expand Up @@ -58,11 +58,11 @@ public:
return fft_out;
}

inline void render_partial (double freq, double mag, double phase);
inline void render_partial (float freq, float mag, float phase);
void get_samples (float *samples, OutputMode output_mode = REPLACE);
void precompute_tables();

inline double quantized_freq (double freq);
inline float quantized_freq (float freq);
};

struct IFFTSynthTable
Expand All @@ -76,7 +76,7 @@ struct IFFTSynthTable
* phase can be in range [-2*pi..2*pi]
*/
inline void
IFFTSynth::render_partial (double mf_freq, double mag, double phase)
IFFTSynth::render_partial (float mf_freq, float mag, float phase)
{
const int range = 4;

Expand All @@ -92,7 +92,7 @@ IFFTSynth::render_partial (double mf_freq, double mag, double phase)
/* the following block computes sincos (phase + phase_adjust)
* - we add 2 * SIN_TABLE_SIZE here to support negative phases
*/
int iarg = sm_round_positive (phase * (SIN_TABLE_SIZE / (2 * M_PI)) + 2 * SIN_TABLE_SIZE);
int iarg = sm_round_positive (phase * float (SIN_TABLE_SIZE / (2 * M_PI)) + 2 * SIN_TABLE_SIZE);

// adjust phase to get the same output like vector sin (smmath.hh)
// phase_adjust = freq256 * (M_PI / 256.0) - M_PI / 2;
Expand Down Expand Up @@ -148,12 +148,12 @@ IFFTSynth::render_partial (double mf_freq, double mag, double phase)
}
}

inline double
IFFTSynth::quantized_freq (double mf_freq)
inline float
IFFTSynth::quantized_freq (float mf_freq)
{
const int freq256 = sm_round_positive (mf_freq * freq256_factor);
const double qfreq = freq256 * (1 / 256.0);
const double mf_qfreq = qfreq / block_size * mix_freq;
const float qfreq = freq256 * float (1 / 256.0);
const float mf_qfreq = qfreq / block_size * mix_freq;

return mf_qfreq;
}
Expand Down
54 changes: 27 additions & 27 deletions lib/smlivedecoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,19 @@ init_aa_filter()
}
}

static inline double
fmatch (double f1, double f2)
static inline float
fmatch (float f1, float f2)
{
return f2 < (f1 * 1.05) && f2 > (f1 * 0.95);
return f2 < (f1 * 1.05f) && f2 > (f1 * 0.95f);
}

static inline double
truncate_phase (double phase)
static inline float
truncate_phase (float phase)
{
// truncate phase to interval [-2*pi:2*pi]; like fmod (phase, 2 * M_PI) but faster
phase *= 1 / (2 * M_PI);
phase *= float (1 / (2 * M_PI));
phase -= int (phase);
phase *= 2 * M_PI;
phase *= float (2 * M_PI);

return phase;
}
Expand Down Expand Up @@ -305,22 +305,22 @@ LiveDecoder::gen_sines (float freq_in)

if (sines_enabled)
{
const double phase_factor = block_size * M_PI / mix_freq;
const double filter_fact = 18000.0 / 44100.0; // for 44.1 kHz, filter at 18 kHz (higher mix freq => higher filter)
const double filter_min_freq = filter_fact * mix_freq;
const float phase_factor = block_size * M_PI / mix_freq;
const float filter_fact = 18000.0 / 44100.0; // for 44.1 kHz, filter at 18 kHz (higher mix freq => higher filter)
const float filter_min_freq = filter_fact * mix_freq;

size_t old_partial = 0;
for (size_t partial = 0; partial < audio_block.freqs.size(); partial++)
{
const double freq = audio_block.freqs_f (partial) * current_freq;
const float freq = audio_block.freqs_f (partial) * current_freq;

// anti alias filter:
double mag = audio_block.mags_f (partial);
float mag = audio_block.mags_f (partial);

const double portamento_freq = audio_block.freqs_f (partial) * freq_in;
const float portamento_freq = audio_block.freqs_f (partial) * freq_in;
if (portamento_freq > filter_min_freq)
{
double norm_freq = portamento_freq / mix_freq;
float norm_freq = portamento_freq / mix_freq;
if (norm_freq > 0.5)
{
// above nyquist freq -> since partials are sorted, there is nothing more to do for this frame
Expand All @@ -329,7 +329,7 @@ LiveDecoder::gen_sines (float freq_in)
else
{
// between filter_fact and 0.5 (db linear filter)
int index = sm_round_positive (ANTIALIAS_FILTER_TABLE_SIZE * (norm_freq - filter_fact) / (0.5 - filter_fact));
int index = sm_round_positive (ANTIALIAS_FILTER_TABLE_SIZE * (norm_freq - filter_fact) / (0.5f - filter_fact));
if (index >= 0)
{
if (index < ANTIALIAS_FILTER_TABLE_SIZE)
Expand All @@ -350,11 +350,11 @@ LiveDecoder::gen_sines (float freq_in)
bool freq_match = false;
if (!old_pstate.empty())
{
double best_fdiff = fabs (old_pstate[old_partial].freq - freq);
float best_fdiff = std::abs (old_pstate[old_partial].freq - freq);

while ((old_partial + 1) < old_pstate.size())
{
double fdiff = fabs (old_pstate[old_partial + 1].freq - freq);
float fdiff = std::abs (old_pstate[old_partial + 1].freq - freq);
if (fdiff < best_fdiff)
{
old_partial++;
Expand All @@ -365,20 +365,20 @@ LiveDecoder::gen_sines (float freq_in)
break;
}
}
const double lfreq = old_pstate[old_partial].freq;
const float lfreq = old_pstate[old_partial].freq;
freq_match = fmatch (lfreq, freq);
}
if (DEBUG)
printf ("%d:F %.17g %.17g\n", int (env_pos), freq, mag);

double phase = 0;
float phase = 0;
if (unison_voices == 1)
{
if (freq_match)
{
// matching freq -> compute new phase
const double lfreq = old_pstate[old_partial].freq;
const double lphase = old_pstate[old_partial].phase;
const float lfreq = old_pstate[old_partial].freq;
const float lphase = old_pstate[old_partial].phase;

phase = truncate_phase (lphase + ifft_synth.quantized_freq (lfreq * old_portamento_stretch) * phase_factor);

Expand All @@ -388,7 +388,7 @@ LiveDecoder::gen_sines (float freq_in)
else
{
if (start_phase_rand_enabled)
phase = phase_random_gen.random_double_range (0, 2 * M_PI); // randomize start phase
phase = phase_random_gen.random_float_range (0, 2 * M_PI); // randomize start phase
}
}
else
Expand All @@ -399,14 +399,14 @@ LiveDecoder::gen_sines (float freq_in)
{
if (freq_match)
{
const double lfreq = old_pstate[old_partial].freq;
const double lphase = unison_old_phases[old_partial * unison_voices + i];
const float lfreq = old_pstate[old_partial].freq;
const float lphase = unison_old_phases[old_partial * unison_voices + i];

phase = truncate_phase (lphase + ifft_synth.quantized_freq (lfreq * old_portamento_stretch * unison_freq_factor[i]) * phase_factor);
}
else
{
phase = phase_random_gen.random_double_range (0, 2 * M_PI); // always randomize start phase for unison
phase = phase_random_gen.random_float_range (0, 2 * M_PI); // always randomize start phase for unison
}
unison_new_phases.push_back (phase);
}
Expand All @@ -427,7 +427,7 @@ LiveDecoder::gen_sines (float freq_in)
{
ifft_synth.clear_partials();

auto render_old_partial = [&] (double freq, double mag, double phase)
auto render_old_partial = [&] (float freq, float mag, float phase)
{
// bandlimiting: do not render partials above nyquist frequency
if (freq * portamento_stretch > 0.495 * mix_freq)
Expand Down Expand Up @@ -991,7 +991,7 @@ LiveDecoder::set_unison_voices (int voices, float detune)
{
/* since the position of the partials changed, randomization is really
* the best we can do here */
phase = phase_random_gen.random_double_range (0, 2 * M_PI);
phase = phase_random_gen.random_float_range (0, 2 * M_PI);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions lib/smmath.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ sm_factor2idbs (float *factors, uint n_factors, uint16_t *out)
out[i] = sm_round_positive (tmp[i] * factor + float (512 * 64));
}

#define FAC 6000.0
#define FAC 6000.0f
#define ADD (3 * FAC)

uint16_t
sm_freq2ifreq (double freq)
sm_freq2ifreq (float freq)
{
return sm_bound (0, sm_round_positive (log (freq) * FAC + ADD), 65535);
return sm_bound (0, sm_round_positive (std::log (freq) * FAC + ADD), 65535);
}

#define FAC_LOG2F 4158.88308335967f
Expand Down
6 changes: 3 additions & 3 deletions lib/smmath.hh
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ double sm_idb2factor_slow (uint16_t idb);

void sm_math_init();

uint16_t sm_freq2ifreq (double freq);
uint16_t sm_freq2ifreq (float freq);
double sm_ifreq2freq_slow (uint16_t ifreq);
void sm_freq2ifreqs (float *freqs, uint n_freqs, uint16_t *out);

Expand All @@ -512,15 +512,15 @@ sm_ifreq2freq (uint16_t ifreq)
}

inline uint16_t
sm_factor2idb (double factor)
sm_factor2idb (float factor)
{
/* 1e-25 is about the smallest factor we can properly represent as integer, as
*
* 20 * log10(1e-25) = 20 * -25 = -500 db
*
* so we map every factor that is smaller, like 0, to this value
*/
const double db = 20 * log10 (std::max (factor, 1e-25));
const float db = 20 * std::log10 (std::max (factor, 1e-25f));

return sm_round_positive (db * 64 + 512 * 64);
}
Expand Down
18 changes: 9 additions & 9 deletions lib/smmorphutils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ find_match (float freq, const FreqState *freq_state, size_t freq_state_size, siz
const float freq_start = freq - 0.5;
const float freq_end = freq + 0.5;

double min_diff = 1e20;
float min_diff = 1e20;
size_t best_index = 0; // initialized to avoid compiler warning

FreqState start_freq_state = {freq_start, 0};
Expand All @@ -61,7 +61,7 @@ find_match (float freq, const FreqState *freq_state, size_t freq_state_size, siz
{
if (!freq_state[i].used)
{
double diff = fabs (freq - freq_state[i].freq_f);
float diff = std::abs (freq - freq_state[i].freq_f);
if (diff < min_diff)
{
best_index = i;
Expand Down Expand Up @@ -116,7 +116,7 @@ init_freq_state (const RTVector<uint16_t>& fint, FreqState *freq_state)
}

static void
interp_mag_one (double interp, uint16_t *left, uint16_t *right, MorphMode mode)
interp_mag_one (float interp, uint16_t *left, uint16_t *right, MorphMode mode)
{
if (mode == MorphMode::DB_LINEAR)
{
Expand Down Expand Up @@ -196,7 +196,7 @@ morph (RTAudioBlock& out_block,
bool have_right, const RTAudioBlock& right_block,
double morphing, MorphUtils::MorphMode morph_mode)
{
const double interp = (morphing + 1) / 2; /* examples => 0: only left; 0.5 both equally; 1: only right */
const float interp = (morphing + 1) / 2; /* examples => 0: only left; 0.5 both equally; 1: only right */

if (!have_left && !have_right) // nothing + nothing = nothing
return false;
Expand Down Expand Up @@ -259,19 +259,19 @@ morph (RTAudioBlock& out_block,
* freq ~= lfreq // if left partial is louder
* freq ~= rfreq // if right partial is louder
*/
const double lfreq = left_block.freqs[i];
const double rfreq = right_block.freqs[j];
double freq;
const float lfreq = left_block.freqs[i];
const float rfreq = right_block.freqs[j];
float freq;

if (left_block.mags[i] > right_block.mags[j])
{
const double mfact = right_block.mags_f (j) / left_block.mags_f (i);
const float mfact = right_block.mags_f (j) / left_block.mags_f (i);

freq = lfreq + mfact * interp * (rfreq - lfreq);
}
else
{
const double mfact = left_block.mags_f (i) / right_block.mags_f (j);
const float mfact = left_block.mags_f (i) / right_block.mags_f (j);

freq = rfreq + mfact * (1 - interp) * (lfreq - rfreq);
}
Expand Down
21 changes: 16 additions & 5 deletions lib/smrandom.hh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ namespace SpectMorph
class Random
{
Pcg32Rng rand_gen;
template<class T>
inline T
random_real_range (T begin, T end)
{
const uint32_t rand_max = 0xffffffff; // Pcg32Rng output: complete 32-bit values
const uint32_t r = random_uint32();
const T scale = 1 / (T (rand_max) + 1);

return r * scale * (end - begin) + begin;
}
public:
Random();

Expand All @@ -22,11 +32,12 @@ public:
inline double
random_double_range (double begin, double end)
{
const uint32_t rand_max = 0xffffffff; // Pcg32Rng output: complete 32-bit values
const uint32_t r = random_uint32();
const double scale = 1.0 / (double (rand_max) + 1.0);

return r * scale * (end - begin) + begin;
return random_real_range<double> (begin, end);
}
inline float
random_float_range (float begin, float end)
{
return random_real_range<float> (begin, end);
}
inline uint32_t
random_uint32()
Expand Down
6 changes: 3 additions & 3 deletions lib/smrtmemory.hh
Original file line number Diff line number Diff line change
Expand Up @@ -170,19 +170,19 @@ public:
RTVector<uint16_t> mags;
RTVector<uint16_t> noise;

double
float
freqs_f (size_t i) const
{
return sm_ifreq2freq (freqs[i]);
}

double
float
mags_f (size_t i) const
{
return sm_idb2factor (mags[i]);
}

double
float
noise_f (size_t i) const
{
return sm_idb2factor (noise[i]);
Expand Down
2 changes: 1 addition & 1 deletion tests/testconvperf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
using namespace SpectMorph;
using std::vector;

double global_var;
float global_var;
int global_int;

int
Expand Down
2 changes: 1 addition & 1 deletion tests/testidb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ main (int argc, char **argv)

// printf ("%f %f %d %f %f\n", factor, db_from_factor (factor, -500), idb, xfactor, error);
}
const double bound = 0.0009;
const double bound = 0.00091;
printf ("representation error%%: [%.6f, %.6f] bound %.6f\n", emin * 100, emax * 100, bound * 100);

const double small_bound = 5e-16;
Expand Down
Loading

0 comments on commit d1926e5

Please sign in to comment.