1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
2 
3 #include "smmorphutils.hh"
4 #include "smmath.hh"
5 
6 #include <algorithm>
7 
8 using std::vector;
9 using std::min;
10 
11 namespace SpectMorph
12 {
13 
14 namespace MorphUtils
15 {
16 
17 static bool
fs_cmp(const FreqState & fs1,const FreqState & fs2)18 fs_cmp (const FreqState& fs1, const FreqState& fs2)
19 {
20   return fs1.freq_f < fs2.freq_f;
21 }
22 
23 bool
find_match(float freq,const FreqState * freq_state,size_t freq_state_size,size_t * index)24 find_match (float freq, const FreqState *freq_state, size_t freq_state_size, size_t *index)
25 {
26   const float freq_start = freq - 0.5;
27   const float freq_end   = freq + 0.5;
28 
29   double min_diff = 1e20;
30   size_t best_index = 0; // initialized to avoid compiler warning
31 
32   FreqState start_freq_state = {freq_start, 0};
33   const FreqState *start_ptr = std::lower_bound (freq_state, freq_state + freq_state_size, start_freq_state, fs_cmp);
34   size_t i = start_ptr - freq_state;
35 
36   while (i < freq_state_size && freq_state[i].freq_f < freq_end)
37     {
38       if (!freq_state[i].used)
39         {
40           double diff = fabs (freq - freq_state[i].freq_f);
41           if (diff < min_diff)
42             {
43               best_index = i;
44               min_diff = diff;
45             }
46         }
47       i++;
48     }
49   if (min_diff < 0.5)
50     {
51       *index = best_index;
52       return true;
53     }
54   return false;
55 }
56 
57 void
init_freq_state(const vector<uint16_t> & fint,FreqState * freq_state)58 init_freq_state (const vector<uint16_t>& fint, FreqState *freq_state)
59 {
60   for (size_t i = 0; i < fint.size(); i++)
61     {
62       freq_state[i].freq_f = sm_ifreq2freq (fint[i]);
63       freq_state[i].used   = 0;
64     }
65 }
66 
67 AudioBlock*
get_normalized_block_ptr(LiveDecoderSource * source,double time_ms)68 get_normalized_block_ptr (LiveDecoderSource *source, double time_ms)
69 {
70   if (!source)
71     return nullptr;
72 
73   Audio *audio = source->audio();
74   if (!audio)
75     return nullptr;
76 
77   if (audio->loop_type == Audio::LOOP_TIME_FORWARD)
78     {
79       const double loop_start_ms = audio->loop_start * 1000.0 / audio->mix_freq;
80       const double loop_end_ms   = audio->loop_end   * 1000.0 / audio->mix_freq;
81 
82       if (loop_start_ms >= loop_end_ms)
83         {
84           /* loop_start_index usually should be less than loop_end_index, this is just
85            * to handle corner cases and pathological cases
86            */
87           time_ms = min (time_ms, loop_start_ms);
88         }
89       else if (time_ms > loop_end_ms)
90         {
91           /* compute loop position: ensure that time_ms is in [loop_start_ms, loop_end_ms] */
92           time_ms = fmod (time_ms - loop_start_ms, loop_end_ms - loop_start_ms) + loop_start_ms;
93         }
94     }
95 
96   int source_index = sm_round_positive (time_ms / audio->frame_step_ms);
97   if (audio->loop_type == Audio::LOOP_FRAME_FORWARD || audio->loop_type == Audio::LOOP_FRAME_PING_PONG)
98     {
99       source_index = LiveDecoder::compute_loop_frame_index (source_index, audio);
100     }
101 
102   return source->audio_block (source_index);
103 }
104 
105 bool
get_normalized_block(LiveDecoderSource * source,double time_ms,AudioBlock & out_audio_block)106 get_normalized_block (LiveDecoderSource *source, double time_ms, AudioBlock& out_audio_block)
107 {
108   AudioBlock *block_ptr = MorphUtils::get_normalized_block_ptr (source, time_ms);
109   if (!block_ptr)
110     return false;
111 
112   out_audio_block.noise  = block_ptr->noise;
113   out_audio_block.mags   = block_ptr->mags;
114   out_audio_block.freqs  = block_ptr->freqs;
115 
116   return true;
117 }
118 
119 }
120 
121 }
122