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