diff --git a/lib/smmorphgridmodule.cc b/lib/smmorphgridmodule.cc index 2a999bc7..53acd23a 100644 --- a/lib/smmorphgridmodule.cc +++ b/lib/smmorphgridmodule.cc @@ -114,201 +114,6 @@ get_normalized_block (MorphGridModule::InputNode& input_node, size_t index, RTAu return MorphUtils::get_normalized_block (source, time_ms, out_audio_block); } -namespace -{ -struct MagData -{ - enum { - BLOCK_LEFT = 0, - BLOCK_RIGHT = 1 - } block; - size_t index; - uint16_t mag; -}; - -static bool -md_cmp (const MagData& m1, const MagData& m2) -{ - return m1.mag > m2.mag; // sort with biggest magnitude first -} - -static void -interp_mag_one (double interp, uint16_t *left, uint16_t *right) -{ - const uint16_t lmag_idb = max (left ? *left : 0, SM_IDB_CONST_M96); - const uint16_t rmag_idb = max (right ? *right : 0, SM_IDB_CONST_M96); - - const uint16_t mag_idb = sm_round_positive ((1 - interp) * lmag_idb + interp * rmag_idb); - - if (left) - *left = mag_idb; - if (right) - *right = mag_idb; -} - -static void -morph_scale (RTAudioBlock& out_block, const RTAudioBlock& in_block, double factor) -{ - const int ddb = sm_factor2delta_idb (factor); - - out_block.assign (in_block); - for (size_t i = 0; i < out_block.noise.size(); i++) - out_block.noise[i] = sm_bound (0, out_block.noise[i] + ddb, 65535); - - for (size_t i = 0; i < out_block.freqs.size(); i++) - interp_mag_one (factor, NULL, &out_block.mags[i]); -} - -} - -static bool -morph (RTAudioBlock& out_block, - bool have_left, const RTAudioBlock& left_block, - bool have_right, const RTAudioBlock& right_block, - double morphing) -{ - const double 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; - - if (!have_left) // nothing + interp * right = interp * right - { - morph_scale (out_block, right_block, interp); - return true; - } - if (!have_right) // (1 - interp) * left + nothing = (1 - interp) * left - { - morph_scale (out_block, left_block, 1 - interp); - return true; - } - - // set out_block capacity - const size_t max_partials = left_block.freqs.size() + right_block.freqs.size(); - out_block.freqs.set_capacity (max_partials); - out_block.mags.set_capacity (max_partials); - - // FIXME: lpc stuff - MagData mds[max_partials + AVOID_ARRAY_UB]; - size_t mds_size = 0; - for (size_t i = 0; i < left_block.freqs.size(); i++) - { - MagData& md = mds[mds_size]; - - md.block = MagData::BLOCK_LEFT; - md.index = i; - md.mag = left_block.mags[i]; - mds_size++; - } - for (size_t i = 0; i < right_block.freqs.size(); i++) - { - MagData& md = mds[mds_size]; - - md.block = MagData::BLOCK_RIGHT; - md.index = i; - md.mag = right_block.mags[i]; - mds_size++; - } - sort (mds, mds + mds_size, md_cmp); - - size_t left_freqs_size = left_block.freqs.size(); - size_t right_freqs_size = right_block.freqs.size(); - - MorphUtils::FreqState left_freqs[left_freqs_size + AVOID_ARRAY_UB]; - MorphUtils::FreqState right_freqs[right_freqs_size + AVOID_ARRAY_UB]; - - init_freq_state (left_block.freqs, left_freqs); - init_freq_state (right_block.freqs, right_freqs); - - for (size_t m = 0; m < mds_size; m++) - { - size_t i, j; - bool match = false; - if (mds[m].block == MagData::BLOCK_LEFT) - { - i = mds[m].index; - - if (!left_freqs[i].used) - match = MorphUtils::find_match (left_freqs[i].freq_f, right_freqs, right_freqs_size, &j); - } - else // (mds[m].block == MagData::BLOCK_RIGHT) - { - j = mds[m].index; - if (!right_freqs[j].used) - match = MorphUtils::find_match (right_freqs[j].freq_f, left_freqs, left_freqs_size, &i); - } - if (match) - { - /* prefer frequency of louder partial: - * - * if the magnitudes are similar, mfact will be close to 1, and freq will become approx. - * - * freq = (1 - interp) * lfreq + interp * rfreq - * - * if the magnitudes are very different, mfact will be close to 0, and freq will become - * - * 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; - - if (left_block.mags[i] > right_block.mags[j]) - { - const double 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); - - freq = rfreq + mfact * (1 - interp) * (lfreq - rfreq); - } - // FIXME: lpc - // FIXME: non-db - - const uint16_t lmag_idb = max (left_block.mags[i], SM_IDB_CONST_M96); - const uint16_t rmag_idb = max (right_block.mags[j], SM_IDB_CONST_M96); - const uint16_t mag_idb = sm_round_positive ((1 - interp) * lmag_idb + interp * rmag_idb); - - out_block.freqs.push_back (freq); - out_block.mags.push_back (mag_idb); - - left_freqs[i].used = 1; - right_freqs[j].used = 1; - } - } - for (size_t i = 0; i < left_freqs_size; i++) - { - if (!left_freqs[i].used) - { - out_block.freqs.push_back (left_block.freqs[i]); - out_block.mags.push_back (left_block.mags[i]); - - interp_mag_one (interp, &out_block.mags.back(), NULL); - } - } - for (size_t i = 0; i < right_freqs_size; i++) - { - if (!right_freqs[i].used) - { - out_block.freqs.push_back (right_block.freqs[i]); - out_block.mags.push_back (right_block.mags[i]); - - interp_mag_one (interp, NULL, &out_block.mags.back()); - } - } - out_block.noise.set_capacity (left_block.noise.size()); - for (size_t i = 0; i < left_block.noise.size(); i++) - out_block.noise.push_back (sm_factor2idb ((1 - interp) * left_block.noise_f (i) + interp * right_block.noise_f (i))); - - out_block.sort_freqs(); - return true; -} - - namespace { @@ -364,6 +169,7 @@ MorphGridModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_block { const double x_morphing = module->apply_modulation (module->cfg->x_morphing_mod); const double y_morphing = module->apply_modulation (module->cfg->y_morphing_mod); + const MorphUtils::MorphMode morph_mode = MorphUtils::MorphMode::DB_LINEAR; const LocalMorphParams x_morph_params = global_to_local_params (x_morphing, module->cfg->width); const LocalMorphParams y_morph_params = global_to_local_params (y_morphing, module->cfg->height); @@ -383,7 +189,7 @@ MorphGridModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_block bool have_a = get_normalized_block (node_a, index, audio_block_a); bool have_b = get_normalized_block (node_b, index, audio_block_b); - bool have_ab = morph (out_block, have_a, audio_block_a, have_b, audio_block_b, x_morph_params.morphing); + bool have_ab = MorphUtils::morph (out_block, have_a, audio_block_a, have_b, audio_block_b, x_morph_params.morphing, morph_mode); if (have_ab) { double delta_db = morph_delta_db (node_a.delta_db, node_b.delta_db, x_morph_params.morphing); @@ -414,7 +220,7 @@ MorphGridModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_block bool have_a = get_normalized_block (node_a, index, audio_block_a); bool have_b = get_normalized_block (node_b, index, audio_block_b); - bool have_ab = morph (out_block, have_a, audio_block_a, have_b, audio_block_b, y_morph_params.morphing); + bool have_ab = MorphUtils::morph (out_block, have_a, audio_block_a, have_b, audio_block_b, y_morph_params.morphing, morph_mode); if (have_ab) { double delta_db = morph_delta_db (node_a.delta_db, node_b.delta_db, y_morph_params.morphing); @@ -452,9 +258,9 @@ MorphGridModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_block bool have_c = get_normalized_block (node_c, index, audio_block_c); bool have_d = get_normalized_block (node_d, index, audio_block_d); - bool have_ab = morph (audio_block_ab, have_a, audio_block_a, have_b, audio_block_b, x_morph_params.morphing); - bool have_cd = morph (audio_block_cd, have_c, audio_block_c, have_d, audio_block_d, x_morph_params.morphing); - bool have_abcd = morph (out_block, have_ab, audio_block_ab, have_cd, audio_block_cd, y_morph_params.morphing); + bool have_ab = MorphUtils::morph (audio_block_ab, have_a, audio_block_a, have_b, audio_block_b, x_morph_params.morphing, morph_mode); + bool have_cd = MorphUtils::morph (audio_block_cd, have_c, audio_block_c, have_d, audio_block_d, x_morph_params.morphing, morph_mode); + bool have_abcd = MorphUtils::morph (out_block, have_ab, audio_block_ab, have_cd, audio_block_cd, y_morph_params.morphing, morph_mode); if (have_abcd) { diff --git a/lib/smmorphlinearmodule.cc b/lib/smmorphlinearmodule.cc index 75ff5fcc..64c26d01 100644 --- a/lib/smmorphlinearmodule.cc +++ b/lib/smmorphlinearmodule.cc @@ -93,262 +93,39 @@ MorphLinearModule::MySource::audio() return &module->audio; } -static void -dump_block (size_t index, const char *what, const RTAudioBlock& block) -{ - if (DEBUG) - { - for (size_t i = 0; i < block.freqs.size(); i++) - sm_printf ("%zd:%s %.17g %.17g\n", index, what, block.freqs_f (i), block.mags_f (i)); - } -} - -static void -dump_line (size_t index, const char *what, double start, double end) -{ - if (DEBUG) - { - sm_printf ("%zd:%s %.17g %.17g\n", index, what, start, end); - } -} - -struct MagData -{ - enum { - BLOCK_LEFT = 0, - BLOCK_RIGHT = 1 - } block; - size_t index; - uint16_t mag; -}; - -static bool -md_cmp (const MagData& m1, const MagData& m2) -{ - return m1.mag > m2.mag; // sort with biggest magnitude first -} - -void -MorphLinearModule::MySource::interp_mag_one (double interp, uint16_t *left, uint16_t *right) -{ - if (module->cfg->db_linear) - { - const uint16_t lmag_idb = max (left ? *left : 0, SM_IDB_CONST_M96); - const uint16_t rmag_idb = max (right ? *right : 0, SM_IDB_CONST_M96); - - const uint16_t mag_idb = sm_round_positive ((1 - interp) * lmag_idb + interp * rmag_idb); - - if (left) - *left = mag_idb; - if (right) - *right = mag_idb; - } - else - { - if (left) - *left = sm_factor2idb ((1 - interp) * sm_idb2factor (*left)); - if (right) - *right = sm_factor2idb (interp * sm_idb2factor (*right)); - } -} - bool MorphLinearModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_audio_block) { bool have_left = false, have_right = false; const double morphing = module->apply_modulation (module->cfg->morphing_mod); - const double interp = (morphing + 1) / 2; /* examples => 0: only left; 0.5 both equally; 1: only right */ const double time_ms = index; // 1ms frame step + const auto morph_mode = module->cfg->db_linear ? MorphUtils::MorphMode::DB_LINEAR : MorphUtils::MorphMode::LINEAR; RTAudioBlock left_block (module->rt_memory_area()), right_block (module->rt_memory_area()); - Audio *left_audio = nullptr; - Audio *right_audio = nullptr; if (module->left_mod && module->left_mod->source()) { have_left = MorphUtils::get_normalized_block (module->left_mod->source(), time_ms, left_block); - left_audio = module->left_mod->source()->audio(); } if (module->right_mod && module->right_mod->source()) { have_right = MorphUtils::get_normalized_block (module->right_mod->source(), time_ms, right_block); - right_audio = module->right_mod->source()->audio(); } if (module->have_left_source) { have_left = MorphUtils::get_normalized_block (&module->left_source, time_ms, left_block); - left_audio = module->left_source.audio(); } if (module->have_right_source) { have_right = MorphUtils::get_normalized_block (&module->right_source, time_ms, right_block); - right_audio = module->right_source.audio(); - } - - if (have_left && have_right) // true morph: both sources present - { - assert (left_audio && right_audio); - - const size_t max_partials = left_block.freqs.size() + right_block.freqs.size(); - out_audio_block.freqs.set_capacity (max_partials); - out_audio_block.mags.set_capacity (max_partials); - - dump_block (index, "A", left_block); - dump_block (index, "B", right_block); - - MagData mds[max_partials + AVOID_ARRAY_UB]; - size_t mds_size = 0; - for (size_t i = 0; i < left_block.freqs.size(); i++) - { - MagData& md = mds[mds_size]; - - md.block = MagData::BLOCK_LEFT; - md.index = i; - md.mag = left_block.mags[i]; - mds_size++; - } - for (size_t i = 0; i < right_block.freqs.size(); i++) - { - MagData& md = mds[mds_size]; - - md.block = MagData::BLOCK_RIGHT; - md.index = i; - md.mag = right_block.mags[i]; - mds_size++; - } - sort (mds, mds + mds_size, md_cmp); - - size_t left_freqs_size = left_block.freqs.size(); - size_t right_freqs_size = right_block.freqs.size(); - - MorphUtils::FreqState left_freqs[left_freqs_size + AVOID_ARRAY_UB]; - MorphUtils::FreqState right_freqs[right_freqs_size + AVOID_ARRAY_UB]; - - init_freq_state (left_block.freqs, left_freqs); - init_freq_state (right_block.freqs, right_freqs); - - for (size_t m = 0; m < mds_size; m++) - { - size_t i, j; - bool match = false; - if (mds[m].block == MagData::BLOCK_LEFT) - { - i = mds[m].index; - - if (!left_freqs[i].used) - match = MorphUtils::find_match (left_freqs[i].freq_f, right_freqs, right_freqs_size, &j); - } - else // (mds[m].block == MagData::BLOCK_RIGHT) - { - j = mds[m].index; - if (!right_freqs[j].used) - match = MorphUtils::find_match (right_freqs[j].freq_f, left_freqs, left_freqs_size, &i); - } - if (match) - { - double freq; - - /* prefer frequency of louder partial */ - const double lfreq = left_block.freqs[i]; - const double rfreq = right_block.freqs[j]; - - if (left_block.mags[i] > right_block.mags[j]) - { - const double 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); - - freq = rfreq + mfact * (1 - interp) * (lfreq - rfreq); - } - - double mag; - if (module->cfg->db_linear) - { - // FIXME: this could be faster if we avoided db conversion (see grid morph) - - double lmag_db = db_from_factor (left_block.mags_f (i), -100); - double rmag_db = db_from_factor (right_block.mags_f (j), -100); - - double mag_db = (1 - interp) * lmag_db + interp * rmag_db; - - mag = db_to_factor (mag_db); - } - else - { - mag = (1 - interp) * left_block.mags_f (i) + interp * right_block.mags_f (j); - } - out_audio_block.freqs.push_back (freq); - out_audio_block.mags.push_back (sm_factor2idb (mag)); - - dump_line (index, "L", left_block.freqs[i], right_block.freqs[j]); - left_freqs[i].used = 1; - right_freqs[j].used = 1; - } - } - for (size_t i = 0; i < left_block.freqs.size(); i++) - { - if (!left_freqs[i].used) - { - out_audio_block.freqs.push_back (left_block.freqs[i]); - out_audio_block.mags.push_back (left_block.mags[i]); - - interp_mag_one (interp, &out_audio_block.mags.back(), NULL); - } - } - for (size_t i = 0; i < right_block.freqs.size(); i++) - { - if (!right_freqs[i].used) - { - out_audio_block.freqs.push_back (right_block.freqs[i]); - out_audio_block.mags.push_back (right_block.mags[i]); - - interp_mag_one (interp, NULL, &out_audio_block.mags.back()); - } - } - assert (left_block.noise.size() == right_block.noise.size()); - - out_audio_block.noise.set_capacity (left_block.noise.size()); - for (size_t i = 0; i < left_block.noise.size(); i++) - out_audio_block.noise.push_back (sm_factor2idb ((1 - interp) * left_block.noise_f (i) + interp * right_block.noise_f (i))); - - out_audio_block.sort_freqs(); - - return true; } - else if (have_left) // only left source output present - { - out_audio_block.assign (left_block); - for (size_t i = 0; i < out_audio_block.noise.size(); i++) - out_audio_block.noise[i] = sm_factor2idb (out_audio_block.noise_f (i) * (1 - interp)); - for (size_t i = 0; i < out_audio_block.mags.size(); i++) - interp_mag_one (interp, &out_audio_block.mags[i], NULL); + return MorphUtils::morph (out_audio_block, have_left, left_block, have_right, right_block, morphing, morph_mode); - return true; - } - else if (have_right) // only right source output present - { - out_audio_block.assign (right_block); - - for (size_t i = 0; i < out_audio_block.noise.size(); i++) - out_audio_block.noise[i] = sm_factor2idb (out_audio_block.noise_f (i) * interp); - for (size_t i = 0; i < out_audio_block.mags.size(); i++) - interp_mag_one (interp, NULL, &out_audio_block.mags[i]); - - return true; - } - else - { - return false; - } } LiveDecoderSource * diff --git a/lib/smmorphlinearmodule.hh b/lib/smmorphlinearmodule.hh index 23f0b859..cecab953 100644 --- a/lib/smmorphlinearmodule.hh +++ b/lib/smmorphlinearmodule.hh @@ -29,7 +29,6 @@ class MorphLinearModule : public MorphOperatorModule { MorphLinearModule *module; - void interp_mag_one (double interp, uint16_t *left, uint16_t *right); void retrigger (int channel, float freq, int midi_velocity) override; Audio* audio() override; bool rt_audio_block (size_t index, RTAudioBlock& block) override; diff --git a/lib/smmorphutils.cc b/lib/smmorphutils.cc index 48daa5bb..ff8d96ae 100644 --- a/lib/smmorphutils.cc +++ b/lib/smmorphutils.cc @@ -6,7 +6,9 @@ #include using std::vector; +using std::sort; using std::min; +using std::max; namespace SpectMorph { @@ -14,13 +16,35 @@ namespace SpectMorph namespace MorphUtils { +struct MagData +{ + enum { + BLOCK_LEFT = 0, + BLOCK_RIGHT = 1 + } block; + size_t index; + uint16_t mag; +}; + +static inline bool +md_cmp (const MagData& m1, const MagData& m2) +{ + return m1.mag > m2.mag; // sort with biggest magnitude first +} + +struct FreqState +{ + float freq_f; + int used; +}; + static bool fs_cmp (const FreqState& fs1, const FreqState& fs2) { return fs1.freq_f < fs2.freq_f; } -bool +static bool find_match (float freq, const FreqState *freq_state, size_t freq_state_size, size_t *index) { const float freq_start = freq - 0.5; @@ -54,17 +78,34 @@ find_match (float freq, const FreqState *freq_state, size_t freq_state_size, siz return false; } -void -init_freq_state (const vector& fint, FreqState *freq_state) +static size_t +init_mag_data (MagData *mds, const RTAudioBlock& left_block, const RTAudioBlock& right_block) { - for (size_t i = 0; i < fint.size(); i++) + size_t mds_size = 0; + for (size_t i = 0; i < left_block.freqs.size(); i++) { - freq_state[i].freq_f = sm_ifreq2freq (fint[i]); - freq_state[i].used = 0; + MagData& md = mds[mds_size]; + + md.block = MagData::BLOCK_LEFT; + md.index = i; + md.mag = left_block.mags[i]; + mds_size++; + } + for (size_t i = 0; i < right_block.freqs.size(); i++) + { + MagData& md = mds[mds_size]; + + md.block = MagData::BLOCK_RIGHT; + md.index = i; + md.mag = right_block.mags[i]; + mds_size++; } + sort (mds, mds + mds_size, md_cmp); + return mds_size; } -void + +static void init_freq_state (const RTVector& fint, FreqState *freq_state) { for (size_t i = 0; i < fint.size(); i++) @@ -74,6 +115,43 @@ init_freq_state (const RTVector& fint, FreqState *freq_state) } } +static void +interp_mag_one (double interp, uint16_t *left, uint16_t *right, MorphMode mode) +{ + if (mode == MorphMode::DB_LINEAR) + { + const uint16_t lmag_idb = max (left ? *left : 0, SM_IDB_CONST_M96); + const uint16_t rmag_idb = max (right ? *right : 0, SM_IDB_CONST_M96); + + const uint16_t mag_idb = sm_round_positive ((1 - interp) * lmag_idb + interp * rmag_idb); + + if (left) + *left = mag_idb; + if (right) + *right = mag_idb; + } + else + { + if (left) + *left = sm_factor2idb ((1 - interp) * sm_idb2factor (*left)); + if (right) + *right = sm_factor2idb (interp * sm_idb2factor (*right)); + } +} + +static void +morph_scale (RTAudioBlock& out_block, const RTAudioBlock& in_block, double factor, MorphUtils::MorphMode mode) +{ + const int ddb = sm_factor2delta_idb (factor); + + out_block.assign (in_block); + for (size_t i = 0; i < out_block.noise.size(); i++) + out_block.noise[i] = sm_bound (0, out_block.noise[i] + ddb, 65535); + + for (size_t i = 0; i < out_block.freqs.size(); i++) + interp_mag_one (factor, NULL, &out_block.mags[i], mode); +} + bool get_normalized_block (LiveDecoderSource *source, double time_ms, RTAudioBlock& out_audio_block) { @@ -112,6 +190,142 @@ get_normalized_block (LiveDecoderSource *source, double time_ms, RTAudioBlock& o return source->rt_audio_block (source_index, out_audio_block); } +bool +morph (RTAudioBlock& out_block, + bool have_left, const RTAudioBlock& left_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 */ + + if (!have_left && !have_right) // nothing + nothing = nothing + return false; + + if (!have_left) // nothing + interp * right = interp * right + { + MorphUtils::morph_scale (out_block, right_block, interp, morph_mode); + return true; + } + if (!have_right) // (1 - interp) * left + nothing = (1 - interp) * left + { + MorphUtils::morph_scale (out_block, left_block, 1 - interp, morph_mode); + return true; + } + + // set out_block capacity + const size_t max_partials = left_block.freqs.size() + right_block.freqs.size(); + out_block.freqs.set_capacity (max_partials); + out_block.mags.set_capacity (max_partials); + + MagData mds[max_partials + AVOID_ARRAY_UB]; + + size_t mds_size = MorphUtils::init_mag_data (mds, left_block, right_block); + size_t left_freqs_size = left_block.freqs.size(); + size_t right_freqs_size = right_block.freqs.size(); + + MorphUtils::FreqState left_freqs[left_freqs_size + AVOID_ARRAY_UB]; + MorphUtils::FreqState right_freqs[right_freqs_size + AVOID_ARRAY_UB]; + + init_freq_state (left_block.freqs, left_freqs); + init_freq_state (right_block.freqs, right_freqs); + + for (size_t m = 0; m < mds_size; m++) + { + size_t i, j; + bool match = false; + if (mds[m].block == MagData::BLOCK_LEFT) + { + i = mds[m].index; + + if (!left_freqs[i].used) + match = MorphUtils::find_match (left_freqs[i].freq_f, right_freqs, right_freqs_size, &j); + } + else // (mds[m].block == MagData::BLOCK_RIGHT) + { + j = mds[m].index; + if (!right_freqs[j].used) + match = MorphUtils::find_match (right_freqs[j].freq_f, left_freqs, left_freqs_size, &i); + } + if (match) + { + /* prefer frequency of louder partial: + * + * if the magnitudes are similar, mfact will be close to 1, and freq will become approx. + * + * freq = (1 - interp) * lfreq + interp * rfreq + * + * if the magnitudes are very different, mfact will be close to 0, and freq will become + * + * 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; + + if (left_block.mags[i] > right_block.mags[j]) + { + const double 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); + + freq = rfreq + mfact * (1 - interp) * (lfreq - rfreq); + } + + uint16_t mag_idb; + if (morph_mode == MorphUtils::MorphMode::DB_LINEAR) + { + const uint16_t lmag_idb = max (left_block.mags[i], SM_IDB_CONST_M96); + const uint16_t rmag_idb = max (right_block.mags[j], SM_IDB_CONST_M96); + + mag_idb = sm_round_positive ((1 - interp) * lmag_idb + interp * rmag_idb); + } + else + { + mag_idb = sm_factor2idb ((1 - interp) * left_block.mags_f (i) + interp * right_block.mags_f (j)); + } + out_block.freqs.push_back (freq); + out_block.mags.push_back (mag_idb); + + left_freqs[i].used = 1; + right_freqs[j].used = 1; + } + } + for (size_t i = 0; i < left_block.freqs.size(); i++) + { + if (!left_freqs[i].used) + { + out_block.freqs.push_back (left_block.freqs[i]); + out_block.mags.push_back (left_block.mags[i]); + + interp_mag_one (interp, &out_block.mags.back(), NULL, morph_mode); + } + } + for (size_t i = 0; i < right_block.freqs.size(); i++) + { + if (!right_freqs[i].used) + { + out_block.freqs.push_back (right_block.freqs[i]); + out_block.mags.push_back (right_block.mags[i]); + + interp_mag_one (interp, NULL, &out_block.mags.back(), morph_mode); + } + } + assert (left_block.noise.size() == right_block.noise.size()); + + out_block.noise.set_capacity (left_block.noise.size()); + for (size_t i = 0; i < left_block.noise.size(); i++) + out_block.noise.push_back (sm_factor2idb ((1 - interp) * left_block.noise_f (i) + interp * right_block.noise_f (i))); + + out_block.sort_freqs(); + + return true; +} + } } diff --git a/lib/smmorphutils.hh b/lib/smmorphutils.hh index 72a31bfd..2f255af8 100644 --- a/lib/smmorphutils.hh +++ b/lib/smmorphutils.hh @@ -17,17 +17,16 @@ namespace SpectMorph namespace MorphUtils { -struct FreqState -{ - float freq_f; - int used; +enum class MorphMode { + LINEAR, + DB_LINEAR }; -bool find_match (float freq, const FreqState *freq_state, size_t freq_state_size, size_t *index); -void init_freq_state (const std::vector& fint, FreqState *freq_state); -void init_freq_state (const RTVector& fint, FreqState *freq_state); +bool morph (RTAudioBlock& out_block, + bool have_left, const RTAudioBlock& left_block, + bool have_right, const RTAudioBlock& right_block, + double morphing, MorphUtils::MorphMode morph_mode); -AudioBlock* get_normalized_block_ptr (LiveDecoderSource *source, double time_ms); bool get_normalized_block (LiveDecoderSource *source, double time_ms, RTAudioBlock& out_audio_block); }