From 41e804913cce963126a92372f530686338d180d8 Mon Sep 17 00:00:00 2001 From: Stefan Westerfeld Date: Fri, 19 Jan 2024 11:36:12 +0100 Subject: [PATCH 01/11] LIB: MagData: move struct to MorphUtils Signed-off-by: Stefan Westerfeld --- lib/smmorphgridmodule.cc | 17 ++--------------- lib/smmorphlinearmodule.cc | 18 ++---------------- lib/smmorphutils.hh | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/lib/smmorphgridmodule.cc b/lib/smmorphgridmodule.cc index 2a999bc7..3165597e 100644 --- a/lib/smmorphgridmodule.cc +++ b/lib/smmorphgridmodule.cc @@ -17,6 +17,8 @@ using std::max; using std::vector; using std::string; using std::sort; +using SpectMorph::MorphUtils::md_cmp; +using SpectMorph::MorphUtils::MagData; static LeakDebugger leak_debugger ("SpectMorph::MorphGridModule"); @@ -116,21 +118,6 @@ get_normalized_block (MorphGridModule::InputNode& input_node, size_t index, RTAu 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) diff --git a/lib/smmorphlinearmodule.cc b/lib/smmorphlinearmodule.cc index 75ff5fcc..ffd902e1 100644 --- a/lib/smmorphlinearmodule.cc +++ b/lib/smmorphlinearmodule.cc @@ -20,6 +20,8 @@ using std::vector; using std::min; using std::max; using std::sort; +using SpectMorph::MorphUtils::md_cmp; +using SpectMorph::MorphUtils::MagData; static LeakDebugger leak_debugger ("SpectMorph::MorphLinearModule"); @@ -112,22 +114,6 @@ dump_line (size_t index, const char *what, double start, double 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) { diff --git a/lib/smmorphutils.hh b/lib/smmorphutils.hh index 72a31bfd..57374451 100644 --- a/lib/smmorphutils.hh +++ b/lib/smmorphutils.hh @@ -17,6 +17,22 @@ 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; From 808f5d1559504322a1c4a769bb9d3a56ccfef6e3 Mon Sep 17 00:00:00 2001 From: Stefan Westerfeld Date: Fri, 19 Jan 2024 11:47:16 +0100 Subject: [PATCH 02/11] LIB: move linear/grid morph mag data initialization to MorphUtils Signed-off-by: Stefan Westerfeld --- lib/smmorphgridmodule.cc | 26 +++----------------------- lib/smmorphlinearmodule.cc | 25 +++---------------------- lib/smmorphutils.cc | 28 ++++++++++++++++++++++++++++ lib/smmorphutils.hh | 1 + 4 files changed, 35 insertions(+), 45 deletions(-) diff --git a/lib/smmorphgridmodule.cc b/lib/smmorphgridmodule.cc index 3165597e..02a66220 100644 --- a/lib/smmorphgridmodule.cc +++ b/lib/smmorphgridmodule.cc @@ -175,31 +175,11 @@ morph (RTAudioBlock& out_block, 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(); + 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]; diff --git a/lib/smmorphlinearmodule.cc b/lib/smmorphlinearmodule.cc index ffd902e1..def65cc6 100644 --- a/lib/smmorphlinearmodule.cc +++ b/lib/smmorphlinearmodule.cc @@ -187,29 +187,10 @@ MorphLinearModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_aud 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(); + 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]; diff --git a/lib/smmorphutils.cc b/lib/smmorphutils.cc index 48daa5bb..6b89ab8a 100644 --- a/lib/smmorphutils.cc +++ b/lib/smmorphutils.cc @@ -6,6 +6,7 @@ #include using std::vector; +using std::sort; using std::min; namespace SpectMorph @@ -54,6 +55,33 @@ find_match (float freq, const FreqState *freq_state, size_t freq_state_size, siz return false; } +size_t +init_mag_data (MagData *mds, const RTAudioBlock& left_block, const RTAudioBlock& right_block) +{ + 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); + return mds_size; +} + + void init_freq_state (const vector& fint, FreqState *freq_state) { diff --git a/lib/smmorphutils.hh b/lib/smmorphutils.hh index 57374451..a4c7fe7e 100644 --- a/lib/smmorphutils.hh +++ b/lib/smmorphutils.hh @@ -40,6 +40,7 @@ struct FreqState }; bool find_match (float freq, const FreqState *freq_state, size_t freq_state_size, size_t *index); +size_t init_mag_data (MagData *mds, const RTAudioBlock& left_block, const RTAudioBlock& right_block); void init_freq_state (const std::vector& fint, FreqState *freq_state); void init_freq_state (const RTVector& fint, FreqState *freq_state); From 2b07fe030d5874c9dd9c4d56ac89e883125dc4f5 Mon Sep 17 00:00:00 2001 From: Stefan Westerfeld Date: Fri, 19 Jan 2024 12:03:03 +0100 Subject: [PATCH 03/11] LIB: MorphLinearModule: use optimized db linear morphing Signed-off-by: Stefan Westerfeld --- lib/smmorphlinearmodule.cc | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/smmorphlinearmodule.cc b/lib/smmorphlinearmodule.cc index def65cc6..9234718f 100644 --- a/lib/smmorphlinearmodule.cc +++ b/lib/smmorphlinearmodule.cc @@ -236,24 +236,20 @@ MorphLinearModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_aud freq = rfreq + mfact * (1 - interp) * (lfreq - rfreq); } - double mag; + uint16_t mag_idb; if (module->cfg->db_linear) { - // FIXME: this could be faster if we avoided db conversion (see grid morph) + 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); - 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); + mag_idb = sm_round_positive ((1 - interp) * lmag_idb + interp * rmag_idb); } else { - mag = (1 - interp) * left_block.mags_f (i) + interp * right_block.mags_f (j); + mag_idb = sm_factor2idb ((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)); + out_audio_block.mags.push_back (mag_idb); dump_line (index, "L", left_block.freqs[i], right_block.freqs[j]); left_freqs[i].used = 1; From 5745756427ec6083bfb6e22719aedf79efeec624 Mon Sep 17 00:00:00 2001 From: Stefan Westerfeld Date: Fri, 19 Jan 2024 12:35:17 +0100 Subject: [PATCH 04/11] LIB: move interp_mag_one to MorphUtils Signed-off-by: Stefan Westerfeld --- lib/smmorphgridmodule.cc | 27 +++++++-------------------- lib/smmorphlinearmodule.cc | 33 +++++---------------------------- lib/smmorphlinearmodule.hh | 1 - lib/smmorphutils.cc | 26 ++++++++++++++++++++++++++ lib/smmorphutils.hh | 7 +++++++ 5 files changed, 45 insertions(+), 49 deletions(-) diff --git a/lib/smmorphgridmodule.cc b/lib/smmorphgridmodule.cc index 02a66220..ccfcf13d 100644 --- a/lib/smmorphgridmodule.cc +++ b/lib/smmorphgridmodule.cc @@ -120,21 +120,7 @@ namespace { 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) +morph_scale (RTAudioBlock& out_block, const RTAudioBlock& in_block, double factor, MorphUtils::MorphMode mode) { const int ddb = sm_factor2delta_idb (factor); @@ -143,7 +129,7 @@ morph_scale (RTAudioBlock& out_block, const RTAudioBlock& in_block, double facto 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]); + interp_mag_one (factor, NULL, &out_block.mags[i], mode); } } @@ -155,18 +141,19 @@ morph (RTAudioBlock& out_block, double morphing) { const double interp = (morphing + 1) / 2; /* examples => 0: only left; 0.5 both equally; 1: only right */ + const MorphUtils::MorphMode morph_mode = MorphUtils::MorphMode::DB_LINEAR; 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); + morph_scale (out_block, right_block, interp, morph_mode); return true; } if (!have_right) // (1 - interp) * left + nothing = (1 - interp) * left { - morph_scale (out_block, left_block, 1 - interp); + morph_scale (out_block, left_block, 1 - interp, morph_mode); return true; } @@ -254,7 +241,7 @@ morph (RTAudioBlock& out_block, 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); + interp_mag_one (interp, &out_block.mags.back(), NULL, morph_mode); } } for (size_t i = 0; i < right_freqs_size; i++) @@ -264,7 +251,7 @@ morph (RTAudioBlock& out_block, 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()); + interp_mag_one (interp, NULL, &out_block.mags.back(), morph_mode); } } out_block.noise.set_capacity (left_block.noise.size()); diff --git a/lib/smmorphlinearmodule.cc b/lib/smmorphlinearmodule.cc index 9234718f..ffeaebce 100644 --- a/lib/smmorphlinearmodule.cc +++ b/lib/smmorphlinearmodule.cc @@ -114,30 +114,6 @@ dump_line (size_t index, const char *what, double start, double end) } } -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) { @@ -146,6 +122,7 @@ MorphLinearModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_aud 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()); @@ -263,7 +240,7 @@ MorphLinearModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_aud 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); + interp_mag_one (interp, &out_audio_block.mags.back(), NULL, morph_mode); } } for (size_t i = 0; i < right_block.freqs.size(); i++) @@ -273,7 +250,7 @@ MorphLinearModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_aud 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()); + interp_mag_one (interp, NULL, &out_audio_block.mags.back(), morph_mode); } } assert (left_block.noise.size() == right_block.noise.size()); @@ -293,7 +270,7 @@ MorphLinearModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_aud 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); + interp_mag_one (interp, &out_audio_block.mags[i], NULL, morph_mode); return true; } @@ -304,7 +281,7 @@ MorphLinearModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_aud 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]); + interp_mag_one (interp, NULL, &out_audio_block.mags[i], morph_mode); return true; } 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 6b89ab8a..65e034e3 100644 --- a/lib/smmorphutils.cc +++ b/lib/smmorphutils.cc @@ -8,6 +8,7 @@ using std::vector; using std::sort; using std::min; +using std::max; namespace SpectMorph { @@ -102,6 +103,31 @@ init_freq_state (const RTVector& fint, FreqState *freq_state) } } +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)); + } +} + + bool get_normalized_block (LiveDecoderSource *source, double time_ms, RTAudioBlock& out_audio_block) { diff --git a/lib/smmorphutils.hh b/lib/smmorphutils.hh index a4c7fe7e..c2909ce5 100644 --- a/lib/smmorphutils.hh +++ b/lib/smmorphutils.hh @@ -39,10 +39,17 @@ struct FreqState 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); size_t init_mag_data (MagData *mds, const RTAudioBlock& left_block, const RTAudioBlock& right_block); void init_freq_state (const std::vector& fint, FreqState *freq_state); void init_freq_state (const RTVector& fint, FreqState *freq_state); +void interp_mag_one (double interp, uint16_t *left, uint16_t *right, MorphMode mode); AudioBlock* get_normalized_block_ptr (LiveDecoderSource *source, double time_ms); bool get_normalized_block (LiveDecoderSource *source, double time_ms, RTAudioBlock& out_audio_block); From 2a437d4e7c67bc302dd36476d685bff06c264a77 Mon Sep 17 00:00:00 2001 From: Stefan Westerfeld Date: Fri, 19 Jan 2024 12:49:10 +0100 Subject: [PATCH 05/11] LIB: move morph_scale function to MorphUtils Signed-off-by: Stefan Westerfeld --- lib/smmorphgridmodule.cc | 17 ++--------------- lib/smmorphlinearmodule.cc | 16 ++-------------- lib/smmorphutils.cc | 12 ++++++++++++ lib/smmorphutils.hh | 1 + 4 files changed, 17 insertions(+), 29 deletions(-) diff --git a/lib/smmorphgridmodule.cc b/lib/smmorphgridmodule.cc index ccfcf13d..f51cdac6 100644 --- a/lib/smmorphgridmodule.cc +++ b/lib/smmorphgridmodule.cc @@ -119,19 +119,6 @@ get_normalized_block (MorphGridModule::InputNode& input_node, size_t index, RTAu namespace { -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); -} - } static bool @@ -148,12 +135,12 @@ morph (RTAudioBlock& out_block, if (!have_left) // nothing + interp * right = interp * right { - morph_scale (out_block, right_block, interp, morph_mode); + MorphUtils::morph_scale (out_block, right_block, interp, morph_mode); return true; } if (!have_right) // (1 - interp) * left + nothing = (1 - interp) * left { - morph_scale (out_block, left_block, 1 - interp, morph_mode); + MorphUtils::morph_scale (out_block, left_block, 1 - interp, morph_mode); return true; } diff --git a/lib/smmorphlinearmodule.cc b/lib/smmorphlinearmodule.cc index ffeaebce..ea2371fe 100644 --- a/lib/smmorphlinearmodule.cc +++ b/lib/smmorphlinearmodule.cc @@ -265,24 +265,12 @@ MorphLinearModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_aud } 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, morph_mode); - + MorphUtils::morph_scale (out_audio_block, left_block, 1 - interp, 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], morph_mode); - + MorphUtils::morph_scale (out_audio_block, right_block, interp, morph_mode); return true; } else diff --git a/lib/smmorphutils.cc b/lib/smmorphutils.cc index 65e034e3..a55c0acd 100644 --- a/lib/smmorphutils.cc +++ b/lib/smmorphutils.cc @@ -127,6 +127,18 @@ interp_mag_one (double interp, uint16_t *left, uint16_t *right, MorphMode mode) } } +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) diff --git a/lib/smmorphutils.hh b/lib/smmorphutils.hh index c2909ce5..b4c6ade9 100644 --- a/lib/smmorphutils.hh +++ b/lib/smmorphutils.hh @@ -50,6 +50,7 @@ size_t init_mag_data (MagData *mds, const RTAudioBlock& left_block, const RTAudi void init_freq_state (const std::vector& fint, FreqState *freq_state); void init_freq_state (const RTVector& fint, FreqState *freq_state); void interp_mag_one (double interp, uint16_t *left, uint16_t *right, MorphMode mode); +void morph_scale (RTAudioBlock& out_block, const RTAudioBlock& in_block, double factor, MorphMode mode); AudioBlock* get_normalized_block_ptr (LiveDecoderSource *source, double time_ms); bool get_normalized_block (LiveDecoderSource *source, double time_ms, RTAudioBlock& out_audio_block); From f4b2040e779b0db6a172b252de67e111f7809360 Mon Sep 17 00:00:00 2001 From: Stefan Westerfeld Date: Fri, 19 Jan 2024 13:07:23 +0100 Subject: [PATCH 06/11] LIB: MorphLinearModule: move morphing into morph() function Signed-off-by: Stefan Westerfeld --- lib/smmorphlinearmodule.cc | 103 +++++++++++++++---------------------- 1 file changed, 41 insertions(+), 62 deletions(-) diff --git a/lib/smmorphlinearmodule.cc b/lib/smmorphlinearmodule.cc index ea2371fe..88cc5b95 100644 --- a/lib/smmorphlinearmodule.cc +++ b/lib/smmorphlinearmodule.cc @@ -95,74 +95,19 @@ MorphLinearModule::MySource::audio() return &module->audio; } -static void -dump_block (size_t index, const char *what, const RTAudioBlock& block) +static bool +morph (RTAudioBlock& out_audio_block, + bool have_left, const RTAudioBlock& left_block, + bool have_right, const RTAudioBlock& right_block, + double morphing, MorphUtils::MorphMode morph_mode) { - 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); - } -} - -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 = MorphUtils::init_mag_data (mds, left_block, right_block); @@ -214,7 +159,7 @@ MorphLinearModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_aud } uint16_t mag_idb; - if (module->cfg->db_linear) + 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); @@ -228,7 +173,6 @@ MorphLinearModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_aud out_audio_block.freqs.push_back (freq); out_audio_block.mags.push_back (mag_idb); - dump_line (index, "L", left_block.freqs[i], right_block.freqs[j]); left_freqs[i].used = 1; right_freqs[j].used = 1; } @@ -279,6 +223,41 @@ MorphLinearModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_aud } } +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 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()); + + if (module->left_mod && module->left_mod->source()) + { + have_left = MorphUtils::get_normalized_block (module->left_mod->source(), time_ms, left_block); + } + + if (module->right_mod && module->right_mod->source()) + { + have_right = MorphUtils::get_normalized_block (module->right_mod->source(), time_ms, right_block); + } + + if (module->have_left_source) + { + have_left = MorphUtils::get_normalized_block (&module->left_source, time_ms, left_block); + } + + if (module->have_right_source) + { + have_right = MorphUtils::get_normalized_block (&module->right_source, time_ms, right_block); + } + + return morph (out_audio_block, have_left, left_block, have_right, right_block, morphing, morph_mode); + +} + LiveDecoderSource * MorphLinearModule::source() { From e1176c57b0255aa57d735058ae79cc1a710d9f32 Mon Sep 17 00:00:00 2001 From: Stefan Westerfeld Date: Fri, 19 Jan 2024 17:45:04 +0100 Subject: [PATCH 07/11] LIB: MorphLinearModule: move special cases handling in morph() function Signed-off-by: Stefan Westerfeld --- lib/smmorphlinearmodule.cc | 188 ++++++++++++++++++------------------- 1 file changed, 93 insertions(+), 95 deletions(-) diff --git a/lib/smmorphlinearmodule.cc b/lib/smmorphlinearmodule.cc index 88cc5b95..0b59575b 100644 --- a/lib/smmorphlinearmodule.cc +++ b/lib/smmorphlinearmodule.cc @@ -102,125 +102,123 @@ morph (RTAudioBlock& out_audio_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) // true morph: both sources present + + if (!have_left && !have_right) // nothing + nothing = nothing + return false; + + if (!have_left) // nothing + interp * right = interp * right + { + MorphUtils::morph_scale (out_audio_block, right_block, interp, morph_mode); + return true; + } + if (!have_right) // (1 - interp) * left + nothing = (1 - interp) * left { - 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); + MorphUtils::morph_scale (out_audio_block, left_block, 1 - interp, morph_mode); + return true; + } - MagData mds[max_partials + AVOID_ARRAY_UB]; + 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); - 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(); + MagData mds[max_partials + AVOID_ARRAY_UB]; - MorphUtils::FreqState left_freqs[left_freqs_size + AVOID_ARRAY_UB]; - MorphUtils::FreqState right_freqs[right_freqs_size + 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(); - init_freq_state (left_block.freqs, left_freqs); - init_freq_state (right_block.freqs, right_freqs); + MorphUtils::FreqState left_freqs[left_freqs_size + AVOID_ARRAY_UB]; + MorphUtils::FreqState right_freqs[right_freqs_size + AVOID_ARRAY_UB]; - for (size_t m = 0; m < mds_size; m++) + 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) { - size_t i, j; - bool match = false; - if (mds[m].block == MagData::BLOCK_LEFT) - { - i = mds[m].index; + 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); - } - - 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_audio_block.freqs.push_back (freq); - out_audio_block.mags.push_back (mag_idb); - - left_freqs[i].used = 1; - right_freqs[j].used = 1; - } + if (!left_freqs[i].used) + match = MorphUtils::find_match (left_freqs[i].freq_f, right_freqs, right_freqs_size, &j); } - for (size_t i = 0; i < left_block.freqs.size(); i++) + else // (mds[m].block == MagData::BLOCK_RIGHT) { - if (!left_freqs[i].used) + 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]) { - out_audio_block.freqs.push_back (left_block.freqs[i]); - out_audio_block.mags.push_back (left_block.mags[i]); + const double mfact = right_block.mags_f (j) / left_block.mags_f (i); - interp_mag_one (interp, &out_audio_block.mags.back(), NULL, morph_mode); + freq = lfreq + mfact * interp * (rfreq - lfreq); } - } - for (size_t i = 0; i < right_block.freqs.size(); i++) - { - if (!right_freqs[i].used) + else { - out_audio_block.freqs.push_back (right_block.freqs[i]); - out_audio_block.mags.push_back (right_block.mags[i]); + const double mfact = left_block.mags_f (i) / right_block.mags_f (j); - interp_mag_one (interp, NULL, &out_audio_block.mags.back(), morph_mode); + freq = rfreq + mfact * (1 - interp) * (lfreq - rfreq); } - } - 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))); + 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); - out_audio_block.sort_freqs(); + 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_audio_block.freqs.push_back (freq); + out_audio_block.mags.push_back (mag_idb); - return true; - } - else if (have_left) // only left source output present - { - MorphUtils::morph_scale (out_audio_block, left_block, 1 - interp, morph_mode); - return true; + left_freqs[i].used = 1; + right_freqs[j].used = 1; + } } - else if (have_right) // only right source output present + for (size_t i = 0; i < left_block.freqs.size(); i++) { - MorphUtils::morph_scale (out_audio_block, right_block, interp, morph_mode); - return true; + 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, morph_mode); + } } - else + for (size_t i = 0; i < right_block.freqs.size(); i++) { - return false; + 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(), morph_mode); + } } + 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; } bool From f3a1b924827eb038fa7cbf6ddcc5dd6f4ff282b4 Mon Sep 17 00:00:00 2001 From: Stefan Westerfeld Date: Fri, 19 Jan 2024 17:48:30 +0100 Subject: [PATCH 08/11] LIB: MorphLinearModule: cleanup morph() function Signed-off-by: Stefan Westerfeld --- lib/smmorphlinearmodule.cc | 48 +++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/lib/smmorphlinearmodule.cc b/lib/smmorphlinearmodule.cc index 0b59575b..e5d1f119 100644 --- a/lib/smmorphlinearmodule.cc +++ b/lib/smmorphlinearmodule.cc @@ -96,7 +96,7 @@ MorphLinearModule::MySource::audio() } static bool -morph (RTAudioBlock& out_audio_block, +morph (RTAudioBlock& out_block, bool have_left, const RTAudioBlock& left_block, bool have_right, const RTAudioBlock& right_block, double morphing, MorphUtils::MorphMode morph_mode) @@ -108,18 +108,19 @@ morph (RTAudioBlock& out_audio_block, if (!have_left) // nothing + interp * right = interp * right { - MorphUtils::morph_scale (out_audio_block, right_block, interp, morph_mode); + 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_audio_block, left_block, 1 - interp, morph_mode); + 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_audio_block.freqs.set_capacity (max_partials); - out_audio_block.mags.set_capacity (max_partials); + out_block.freqs.set_capacity (max_partials); + out_block.mags.set_capacity (max_partials); MagData mds[max_partials + AVOID_ARRAY_UB]; @@ -152,11 +153,20 @@ morph (RTAudioBlock& out_audio_block, } if (match) { - double freq; - - /* prefer frequency of louder partial */ + /* 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]) { @@ -183,8 +193,8 @@ morph (RTAudioBlock& out_audio_block, { mag_idb = sm_factor2idb ((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 (mag_idb); + out_block.freqs.push_back (freq); + out_block.mags.push_back (mag_idb); left_freqs[i].used = 1; right_freqs[j].used = 1; @@ -194,29 +204,29 @@ morph (RTAudioBlock& out_audio_block, { 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]); + out_block.freqs.push_back (left_block.freqs[i]); + out_block.mags.push_back (left_block.mags[i]); - interp_mag_one (interp, &out_audio_block.mags.back(), NULL, morph_mode); + 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_audio_block.freqs.push_back (right_block.freqs[i]); - out_audio_block.mags.push_back (right_block.mags[i]); + out_block.freqs.push_back (right_block.freqs[i]); + out_block.mags.push_back (right_block.mags[i]); - interp_mag_one (interp, NULL, &out_audio_block.mags.back(), morph_mode); + interp_mag_one (interp, NULL, &out_block.mags.back(), morph_mode); } } assert (left_block.noise.size() == right_block.noise.size()); - out_audio_block.noise.set_capacity (left_block.noise.size()); + out_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_block.noise.push_back (sm_factor2idb ((1 - interp) * left_block.noise_f (i) + interp * right_block.noise_f (i))); - out_audio_block.sort_freqs(); + out_block.sort_freqs(); return true; } From f077dccde1d789edd39cf4265781d096bbacb746 Mon Sep 17 00:00:00 2001 From: Stefan Westerfeld Date: Fri, 19 Jan 2024 17:55:44 +0100 Subject: [PATCH 09/11] LIB: move merge morph() function into MorphUtils::morph() Signed-off-by: Stefan Westerfeld --- lib/smmorphgridmodule.cc | 145 ++----------------------------------- lib/smmorphlinearmodule.cc | 138 +---------------------------------- lib/smmorphutils.cc | 136 ++++++++++++++++++++++++++++++++++ lib/smmorphutils.hh | 4 + 4 files changed, 147 insertions(+), 276 deletions(-) diff --git a/lib/smmorphgridmodule.cc b/lib/smmorphgridmodule.cc index f51cdac6..4d960b50 100644 --- a/lib/smmorphgridmodule.cc +++ b/lib/smmorphgridmodule.cc @@ -116,140 +116,6 @@ get_normalized_block (MorphGridModule::InputNode& input_node, size_t index, RTAu return MorphUtils::get_normalized_block (source, time_ms, out_audio_block); } -namespace -{ - -} - -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 */ - const MorphUtils::MorphMode morph_mode = MorphUtils::MorphMode::DB_LINEAR; - - 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); - } - // 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, morph_mode); - } - } - 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(), morph_mode); - } - } - 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 { @@ -305,6 +171,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); @@ -324,7 +191,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); @@ -355,7 +222,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); @@ -393,9 +260,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 e5d1f119..be4f58bc 100644 --- a/lib/smmorphlinearmodule.cc +++ b/lib/smmorphlinearmodule.cc @@ -95,142 +95,6 @@ MorphLinearModule::MySource::audio() return &module->audio; } -static 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; -} - bool MorphLinearModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_audio_block) { @@ -262,7 +126,7 @@ MorphLinearModule::MySource::rt_audio_block (size_t index, RTAudioBlock& out_aud have_right = MorphUtils::get_normalized_block (&module->right_source, time_ms, right_block); } - return morph (out_audio_block, have_left, left_block, have_right, right_block, morphing, morph_mode); + return MorphUtils::morph (out_audio_block, have_left, left_block, have_right, right_block, morphing, morph_mode); } diff --git a/lib/smmorphutils.cc b/lib/smmorphutils.cc index a55c0acd..703c3ea0 100644 --- a/lib/smmorphutils.cc +++ b/lib/smmorphutils.cc @@ -178,6 +178,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 b4c6ade9..a3036fec 100644 --- a/lib/smmorphutils.hh +++ b/lib/smmorphutils.hh @@ -51,6 +51,10 @@ void init_freq_state (const std::vector& fint, FreqState *freq_state); void init_freq_state (const RTVector& fint, FreqState *freq_state); void interp_mag_one (double interp, uint16_t *left, uint16_t *right, MorphMode mode); void morph_scale (RTAudioBlock& out_block, const RTAudioBlock& in_block, double factor, MorphMode mode); +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); From e3d3b5bc6e35938d15cbe3e598e45771c40b900d Mon Sep 17 00:00:00 2001 From: Stefan Westerfeld Date: Fri, 19 Jan 2024 18:00:29 +0100 Subject: [PATCH 10/11] LIB: MorphUtils: remove some function from public API Signed-off-by: Stefan Westerfeld --- lib/smmorphgridmodule.cc | 2 -- lib/smmorphlinearmodule.cc | 2 -- lib/smmorphutils.cc | 38 +++++++++++++++++++++++++------------- lib/smmorphutils.hh | 27 --------------------------- 4 files changed, 25 insertions(+), 44 deletions(-) diff --git a/lib/smmorphgridmodule.cc b/lib/smmorphgridmodule.cc index 4d960b50..53acd23a 100644 --- a/lib/smmorphgridmodule.cc +++ b/lib/smmorphgridmodule.cc @@ -17,8 +17,6 @@ using std::max; using std::vector; using std::string; using std::sort; -using SpectMorph::MorphUtils::md_cmp; -using SpectMorph::MorphUtils::MagData; static LeakDebugger leak_debugger ("SpectMorph::MorphGridModule"); diff --git a/lib/smmorphlinearmodule.cc b/lib/smmorphlinearmodule.cc index be4f58bc..64c26d01 100644 --- a/lib/smmorphlinearmodule.cc +++ b/lib/smmorphlinearmodule.cc @@ -20,8 +20,6 @@ using std::vector; using std::min; using std::max; using std::sort; -using SpectMorph::MorphUtils::md_cmp; -using SpectMorph::MorphUtils::MagData; static LeakDebugger leak_debugger ("SpectMorph::MorphLinearModule"); diff --git a/lib/smmorphutils.cc b/lib/smmorphutils.cc index 703c3ea0..df768a1d 100644 --- a/lib/smmorphutils.cc +++ b/lib/smmorphutils.cc @@ -16,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; @@ -56,7 +78,7 @@ find_match (float freq, const FreqState *freq_state, size_t freq_state_size, siz return false; } -size_t +static size_t init_mag_data (MagData *mds, const RTAudioBlock& left_block, const RTAudioBlock& right_block) { size_t mds_size = 0; @@ -83,17 +105,7 @@ init_mag_data (MagData *mds, const RTAudioBlock& left_block, const RTAudioBlock& } -void -init_freq_state (const vector& fint, FreqState *freq_state) -{ - for (size_t i = 0; i < fint.size(); i++) - { - freq_state[i].freq_f = sm_ifreq2freq (fint[i]); - freq_state[i].used = 0; - } -} - -void +static void init_freq_state (const RTVector& fint, FreqState *freq_state) { for (size_t i = 0; i < fint.size(); i++) diff --git a/lib/smmorphutils.hh b/lib/smmorphutils.hh index a3036fec..bc93de2e 100644 --- a/lib/smmorphutils.hh +++ b/lib/smmorphutils.hh @@ -17,38 +17,11 @@ 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; -}; - - enum class MorphMode { LINEAR, DB_LINEAR }; -bool find_match (float freq, const FreqState *freq_state, size_t freq_state_size, size_t *index); -size_t init_mag_data (MagData *mds, const RTAudioBlock& left_block, const RTAudioBlock& right_block); -void init_freq_state (const std::vector& fint, FreqState *freq_state); -void init_freq_state (const RTVector& fint, FreqState *freq_state); void interp_mag_one (double interp, uint16_t *left, uint16_t *right, MorphMode mode); void morph_scale (RTAudioBlock& out_block, const RTAudioBlock& in_block, double factor, MorphMode mode); bool morph (RTAudioBlock& out_block, From 69ee659908f98f5119951a47e8e4817b9476ab5e Mon Sep 17 00:00:00 2001 From: Stefan Westerfeld Date: Fri, 19 Jan 2024 18:03:59 +0100 Subject: [PATCH 11/11] LIB: MorphUtils: cleanup MorphUtils API a bit more Signed-off-by: Stefan Westerfeld --- lib/smmorphutils.cc | 4 ++-- lib/smmorphutils.hh | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/smmorphutils.cc b/lib/smmorphutils.cc index df768a1d..ff8d96ae 100644 --- a/lib/smmorphutils.cc +++ b/lib/smmorphutils.cc @@ -115,7 +115,7 @@ init_freq_state (const RTVector& fint, FreqState *freq_state) } } -void +static void interp_mag_one (double interp, uint16_t *left, uint16_t *right, MorphMode mode) { if (mode == MorphMode::DB_LINEAR) @@ -139,7 +139,7 @@ interp_mag_one (double interp, uint16_t *left, uint16_t *right, MorphMode mode) } } -void +static void morph_scale (RTAudioBlock& out_block, const RTAudioBlock& in_block, double factor, MorphUtils::MorphMode mode) { const int ddb = sm_factor2delta_idb (factor); diff --git a/lib/smmorphutils.hh b/lib/smmorphutils.hh index bc93de2e..2f255af8 100644 --- a/lib/smmorphutils.hh +++ b/lib/smmorphutils.hh @@ -22,14 +22,11 @@ enum class MorphMode { DB_LINEAR }; -void interp_mag_one (double interp, uint16_t *left, uint16_t *right, MorphMode mode); -void morph_scale (RTAudioBlock& out_block, const RTAudioBlock& in_block, double factor, MorphMode mode); 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); }