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