1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
2 
3 #include "smwavsetbuilder.hh"
4 #include "sminstencoder.hh"
5 #include "smbinbuffer.hh"
6 #include "sminstenccache.hh"
7 #include "smaudiotool.hh"
8 
9 #include <mutex>
10 
11 using namespace SpectMorph;
12 
13 using std::string;
14 using std::map;
15 using std::vector;
16 using std::max;
17 
WavSetBuilder(const Instrument * instrument,bool keep_samples)18 WavSetBuilder::WavSetBuilder (const Instrument *instrument, bool keep_samples) :
19   keep_samples (keep_samples)
20 {
21   wav_set = new WavSet();
22   wav_set->name = instrument->name();
23   wav_set->short_name = instrument->short_name();
24 
25   auto_volume = instrument->auto_volume();
26   auto_tune = instrument->auto_tune();
27   encoder_config = instrument->encoder_config();
28 
29   for (size_t i = 0; i < instrument->size(); i++)
30     {
31       Sample *sample = instrument->sample (i);
32       assert (sample);
33 
34       add_sample (sample);
35     }
36 }
37 
~WavSetBuilder()38 WavSetBuilder::~WavSetBuilder()
39 {
40   if (wav_set)
41     {
42       delete wav_set;
43       wav_set = nullptr;
44     }
45 }
46 
47 void
add_sample(const Sample * sample)48 WavSetBuilder::add_sample (const Sample *sample)
49 {
50   SampleData sd;
51 
52   sd.midi_note = sample->midi_note();
53   sd.shared = sample->shared();
54 
55   const double clip_adjust = std::max (0.0, sample->get_marker (MARKER_CLIP_START));
56 
57   sd.loop = sample->loop();
58   sd.loop_start_ms = sample->get_marker (MARKER_LOOP_START) - clip_adjust;
59   sd.loop_end_ms = sample->get_marker (MARKER_LOOP_END) - clip_adjust;
60   sd.clip_start_ms = sample->get_marker (MARKER_CLIP_START);
61   sd.clip_end_ms = sample->get_marker (MARKER_CLIP_END);
62 
63   sample_data_vec.push_back (sd);
64 }
65 
66 bool
killed()67 WavSetBuilder::killed()
68 {
69   return kill_function && kill_function();
70 }
71 
72 WavSet *
run()73 WavSetBuilder::run()
74 {
75   for (auto& sd : sample_data_vec)
76     {
77       /* clipping */
78       const WavData& wav_data = sd.shared->wav_data();
79       assert (wav_data.n_channels() == 1);
80 
81       /* if we have a loop, the loop end determines the real end of the recording */
82       int iclipend = wav_data.n_values();
83       if (sd.loop == Sample::Loop::NONE)
84         iclipend = sm_bound<int> (0, sm_round_positive (sd.clip_end_ms * wav_data.mix_freq() / 1000.0), wav_data.n_values());
85 
86       int iclipstart = sm_bound<int> (0, sm_round_positive (sd.clip_start_ms * wav_data.mix_freq() / 1000.0), iclipend);
87 
88 
89       WavSetWave new_wave;
90       new_wave.midi_note = sd.midi_note;
91       new_wave.channel = 0;
92       new_wave.velocity_range_min = 0;
93       new_wave.velocity_range_max = 127;
94       new_wave.audio = InstEncCache::the()->encode (cache_group, wav_data, sd.shared->wav_data_hash(), sd.midi_note, iclipstart, iclipend, encoder_config, kill_function);
95 
96       if (!new_wave.audio) // killed?
97         return nullptr;
98 
99       if (keep_samples)
100         new_wave.audio->original_samples = wav_data.samples(); // FIXME: clipping?
101 
102       wav_set->waves.push_back (new_wave);
103     }
104   apply_loop_settings();
105   apply_auto_volume();
106   apply_auto_tune();
107 
108   WavSet *result = wav_set;
109   wav_set = nullptr;
110 
111   return result;
112 }
113 
114 void
set_kill_function(const std::function<bool ()> & new_kill_function)115 WavSetBuilder::set_kill_function (const std::function<bool()>& new_kill_function)
116 {
117   kill_function = new_kill_function;
118 }
119 
120 void
apply_loop_settings()121 WavSetBuilder::apply_loop_settings()
122 {
123   // build index for sample data vector
124   map<int, SampleData*> note_to_sd;
125   for (auto& sd : sample_data_vec)
126     note_to_sd[sd.midi_note] = &sd;
127 
128   for (auto& wave : wav_set->waves)
129     {
130       SampleData *sd = note_to_sd[wave.midi_note];
131 
132       if (!sd)
133         {
134           printf ("warning: no to sd mapping %d failed\n", wave.midi_note);
135           continue;
136         }
137 
138       Audio *audio = wave.audio;
139 
140       const int last_frame        = audio->contents.size() ? (audio->contents.size() - 1) : 0;
141       const double zero_values_ms = audio->zero_values_at_start / audio->mix_freq * 1000.0;
142       const int loop_start        = sm_bound<int> (0, lrint ((zero_values_ms + sd->loop_start_ms) / audio->frame_step_ms), last_frame);
143       const int loop_end          = sm_bound<int> (0, lrint ((zero_values_ms + sd->loop_end_ms) / audio->frame_step_ms), last_frame);
144 
145       if (sd->loop == Sample::Loop::NONE)
146         {
147           audio->loop_type = Audio::LOOP_NONE;
148           audio->loop_start = 0;
149           audio->loop_end = 0;
150         }
151       else if (sd->loop == Sample::Loop::FORWARD)
152         {
153           audio->loop_type = Audio::LOOP_FRAME_FORWARD;
154           audio->loop_start = loop_start;
155           audio->loop_end = loop_end;
156         }
157       else if (sd->loop == Sample::Loop::PING_PONG)
158         {
159           audio->loop_type = Audio::LOOP_FRAME_PING_PONG;
160           audio->loop_start = loop_start;
161           audio->loop_end = loop_end;
162         }
163       else if (sd->loop == Sample::Loop::SINGLE_FRAME)
164         {
165           audio->loop_type = Audio::LOOP_FRAME_FORWARD;
166 
167           // single frame loop
168           audio->loop_start = loop_start;
169           audio->loop_end   = loop_start;
170         }
171     }
172 }
173 
174 void
apply_auto_volume()175 WavSetBuilder::apply_auto_volume()
176 {
177   if (!auto_volume.enabled)
178     return;
179 
180   for (auto& wave : wav_set->waves)
181     {
182       Audio& audio = *wave.audio;
183 
184       if (auto_volume.method == Instrument::AutoVolume::FROM_LOOP)
185         {
186           double energy = AudioTool::compute_energy (audio);
187 
188           AudioTool::normalize_energy (energy, audio);
189         }
190       if (auto_volume.method == Instrument::AutoVolume::GLOBAL)
191         {
192           AudioTool::normalize_factor (db_to_factor (auto_volume.gain), audio);
193         }
194     }
195 }
196 
197 void
apply_auto_tune()198 WavSetBuilder::apply_auto_tune()
199 {
200   if (!auto_tune.enabled)
201     return;
202 
203   for (auto& wave : wav_set->waves)
204     {
205       Audio& audio = *wave.audio;
206 
207       if (auto_tune.method == Instrument::AutoTune::SIMPLE)
208         {
209           double tune_factor;
210 
211           if (AudioTool::get_auto_tune_factor (audio, tune_factor))
212             AudioTool::apply_auto_tune_factor (audio, tune_factor);
213         }
214       if (auto_tune.method == Instrument::AutoTune::ALL_FRAMES)
215         {
216           for (auto& block : audio.contents)
217             {
218               const double est_freq = block.estimate_fundamental (auto_tune.partials);
219               const double tune_factor = 1.0 / est_freq;
220 
221               for (size_t p = 0; p < block.freqs.size(); p++)
222                 {
223                   const double freq = block.freqs_f (p) * tune_factor;
224                   block.freqs[p] = sm_freq2ifreq (freq);
225                 }
226             }
227         }
228       if (auto_tune.method == Instrument::AutoTune::SMOOTH)
229         {
230           AudioTool::auto_tune_smooth (audio, auto_tune.partials, auto_tune.time, auto_tune.amount);
231         }
232     }
233 }
234 
235 void
set_cache_group(InstEncCache::Group * group)236 WavSetBuilder::set_cache_group (InstEncCache::Group *group)
237 {
238   cache_group = group;
239 }
240