409db6dfd319d899acc994fcde19089688de1838
[goodguy/history.git] / cinelerra-5.1 / plugins / resamplert / resamplert.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2010-2016 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "bchash.h"
24 #include "filexml.h"
25 #include "language.h"
26 #include "resamplert.h"
27 #include "theme.h"
28 #include "transportque.h"
29
30 #include <string.h>
31
32
33
34
35
36
37
38 REGISTER_PLUGIN(ResampleRT);
39
40
41
42 ResampleRTConfig::ResampleRTConfig()
43 {
44         num = 1;
45         denom = 1;
46 }
47
48
49 int ResampleRTConfig::equivalent(ResampleRTConfig &src)
50 {
51         return fabs(num - src.num) < 0.0001 &&
52                 fabs(denom - src.denom) < 0.0001;
53 }
54
55 void ResampleRTConfig::copy_from(ResampleRTConfig &src)
56 {
57         this->num = src.num;
58         this->denom = src.denom;
59 }
60
61 void ResampleRTConfig::interpolate(ResampleRTConfig &prev,
62         ResampleRTConfig &next,
63         int64_t prev_frame,
64         int64_t next_frame,
65         int64_t current_frame)
66 {
67         this->num = prev.num;
68         this->denom = prev.denom;
69 }
70
71 void ResampleRTConfig::boundaries()
72 {
73         if(num < 0.0001) num = 0.0001;
74         if(denom < 0.0001) denom = 0.0001;
75 }
76
77
78
79
80 ResampleRTWindow::ResampleRTWindow(ResampleRT *plugin)
81  : PluginClientWindow(plugin,
82         210,
83         160,
84         200,
85         160,
86         0)
87 {
88         this->plugin = plugin;
89 }
90
91 ResampleRTWindow::~ResampleRTWindow()
92 {
93 }
94
95 void ResampleRTWindow::create_objects()
96 {
97         int x = plugin->get_theme()->window_border;
98         int y = plugin->get_theme()->window_border;
99
100         BC_Title *title;
101         add_subwindow(title = new BC_Title(x, y, _("Input samples:")));
102         y += title->get_h() + plugin->get_theme()->widget_border;
103         num = new ResampleRTNum(this, plugin, x, y);
104         num->create_objects();
105
106         y += num->get_h() + plugin->get_theme()->widget_border;
107         add_subwindow(title = new BC_Title(x, y, _("Output samples:")));
108         y += title->get_h() + plugin->get_theme()->widget_border;
109         denom = new ResampleRTDenom(this, plugin, x, y);
110         denom->create_objects();
111
112         show_window();
113 }
114
115
116
117
118
119
120 ResampleRTNum::ResampleRTNum(ResampleRTWindow *window,
121         ResampleRT *plugin,
122         int x,
123         int y)
124  : BC_TumbleTextBox(window,
125         plugin->config.num,
126         (float)0.0001,
127         (float)1000,
128         x,
129         y,
130         100)
131 {
132         this->plugin = plugin;
133         set_increment(0.001);
134 }
135
136 int ResampleRTNum::handle_event()
137 {
138         plugin->config.num = atof(get_text());
139         plugin->config.boundaries();
140         plugin->send_configure_change();
141         return 1;
142 }
143
144
145
146
147 ResampleRTDenom::ResampleRTDenom(ResampleRTWindow *window,
148         ResampleRT *plugin,
149         int x,
150         int y)
151  : BC_TumbleTextBox(window,
152         plugin->config.denom,
153         (float)0.0001,
154         (float)1000,
155         x,
156         y,
157         100)
158 {
159         this->plugin = plugin;
160         set_increment(0.001);
161 }
162
163 int ResampleRTDenom::handle_event()
164 {
165         plugin->config.denom = atof(get_text());
166         plugin->config.boundaries();
167         plugin->send_configure_change();
168         return 1;
169 }
170
171
172
173
174
175
176 ResampleRTResample::ResampleRTResample(ResampleRT *plugin)
177  : Resample()
178 {
179         this->plugin = plugin;
180 }
181
182 // To get the keyframes to work, resampling is always done in the forward
183 // direction with the plugin converting to reverse.
184 int ResampleRTResample::read_samples(Samples *buffer,
185         int64_t start,
186         int64_t len)
187 {
188         int result = plugin->read_samples(buffer,
189                 0,
190                 plugin->get_samplerate(),
191                 plugin->source_start,
192                 len);
193
194 //printf("ResampleRTResample::read_samples %lld %lld %lld %d\n", start, plugin->source_start, len, result);
195         if(plugin->get_direction() == PLAY_FORWARD)
196                 plugin->source_start += len;
197         else
198                 plugin->source_start -= len;
199
200         return result;
201 }
202
203
204
205
206
207
208 ResampleRT::ResampleRT(PluginServer *server)
209  : PluginAClient(server)
210 {
211         resample = 0;
212         need_reconfigure = 1;
213         prev_scale = 0;
214         dest_start = -1;
215 }
216
217
218 ResampleRT::~ResampleRT()
219 {
220         delete resample;
221 }
222
223 const char* ResampleRT::plugin_title() { return _("ResampleRT"); }
224 int ResampleRT::is_realtime() { return 1; }
225 int ResampleRT::is_synthesis() { return 1; }
226
227
228 NEW_WINDOW_MACRO(ResampleRT, ResampleRTWindow)
229
230 LOAD_CONFIGURATION_MACRO(ResampleRT, ResampleRTConfig)
231
232
233 int ResampleRT::process_buffer(int64_t size,
234         Samples *buffer,
235         int64_t start_position,
236         int sample_rate)
237 {
238         if(!resample) resample = new ResampleRTResample(this);
239
240         need_reconfigure |= load_configuration();
241
242
243         if(start_position != dest_start) need_reconfigure = 1;
244         dest_start = start_position;
245
246 // Get start position of the input.
247 // Sample 0 is the keyframe position
248         if(need_reconfigure)
249         {
250                 int64_t prev_position = edl_to_local(
251                         get_prev_keyframe(
252                                 get_source_position())->position);
253
254                 if(prev_position == 0)
255                 {
256                         prev_position = get_source_start();
257                 }
258
259                 source_start = (int64_t)((start_position - prev_position) *
260                         config.num / config.denom) + prev_position;
261
262                 resample->reset();
263                 need_reconfigure = 0;
264         }
265
266         resample->resample(buffer,
267                 size,
268                 (int)(65536 * config.num),
269                 (int)(65536 * config.denom),
270                 start_position,
271                 get_direction());
272
273         if(get_direction() == PLAY_FORWARD)
274                 dest_start += size;
275         else
276                 dest_start -= size;
277
278         return 0;
279 }
280
281 void ResampleRT::render_stop()
282 {
283         need_reconfigure = 1;
284 }
285
286
287
288
289 void ResampleRT::save_data(KeyFrame *keyframe)
290 {
291         FileXML output;
292
293 // cause data to be stored directly in text
294         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
295         output.tag.set_title("RESAMPLERT");
296         output.tag.set_property("SCALE", config.num);
297         output.tag.set_property("DENOM", config.denom);
298         output.append_tag();
299         output.tag.set_title("/RESAMPLERT");
300         output.append_tag();
301         output.append_newline();
302         output.terminate_string();
303 }
304
305 void ResampleRT::read_data(KeyFrame *keyframe)
306 {
307         FileXML input;
308
309         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
310
311         while(!input.read_tag())
312         {
313                 if(input.tag.title_is("RESAMPLERT"))
314                 {
315                         config.num = input.tag.get_property("SCALE", config.num);
316                         config.denom = input.tag.get_property("DENOM", config.denom);
317                 }
318         }
319 }
320
321 void ResampleRT::update_gui()
322 {
323         if(thread)
324         {
325                 if(load_configuration())
326                 {
327                         thread->window->lock_window("ResampleRT::update_gui");
328                         ((ResampleRTWindow*)thread->window)->num->update((float)config.num);
329                         ((ResampleRTWindow*)thread->window)->denom->update((float)config.denom);
330                         thread->window->unlock_window();
331                 }
332         }
333 }
334
335
336
337
338