correct kfrm span maskauto update_params, avoid zero w/h draw_refresh segv
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / timestretchrt / timestretchrt.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2011 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 "theme.h"
27 #include "../timestretch/timestretchengine.h"
28 #include "timestretchrt.h"
29 #include "transportque.h"
30
31 #include <string.h>
32
33
34
35
36
37
38
39 REGISTER_PLUGIN(TimeStretchRT);
40
41
42
43 TimeStretchRTConfig::TimeStretchRTConfig()
44 {
45 //      scale = 1;
46         num = 1;
47         denom = 1;
48         size = 40;
49 }
50
51
52 int TimeStretchRTConfig::equivalent(TimeStretchRTConfig &src)
53 {
54 //      return fabs(scale - src.scale) < 0.0001 && size == src.size;
55         return fabs(num - src.num) < 0.0001 &&
56                 fabs(denom - src.denom) < 0.0001 && 
57                 size == src.size;
58 }
59
60 void TimeStretchRTConfig::copy_from(TimeStretchRTConfig &src)
61 {
62         this->num = src.num;
63         this->denom = src.denom;
64 //      this->scale = src.scale;
65         this->size = src.size;
66 }
67
68 void TimeStretchRTConfig::interpolate(TimeStretchRTConfig &prev,
69         TimeStretchRTConfig &next,
70         int64_t prev_frame,
71         int64_t next_frame,
72         int64_t current_frame)
73 {
74         this->num = prev.num;
75         this->denom = prev.denom;
76 //      this->scale = prev.scale;
77         this->size = prev.size;
78         boundaries();
79 }
80
81 void TimeStretchRTConfig::boundaries()
82 {
83         if(num < 0.0001) num = 0.0001;
84         if(denom < 0.0001) denom = 0.0001;
85 //      if(fabs(scale) < 0.01) scale = 0.01;
86 //      if(fabs(scale) > 100) scale = 100;
87         if(size < 10) size = 10;
88         if(size > 1000) size = 1000;
89 }
90
91
92
93
94 TimeStretchRTWindow::TimeStretchRTWindow(TimeStretchRT *plugin)
95  : PluginClientWindow(plugin,
96         210, 
97         200, 
98         200, 
99         210,
100         0)
101 {
102         this->plugin = plugin;
103 }
104
105 TimeStretchRTWindow::~TimeStretchRTWindow()
106 {
107 }
108
109 void TimeStretchRTWindow::create_objects()
110 {
111         int x = 10, y = 10;
112         int margin = plugin->get_theme()->widget_border;
113
114         BC_Title *title = 0;
115         add_subwindow(title = new BC_Title(x, y, _("Input samples:")));
116         y += title->get_h() + plugin->get_theme()->widget_border;
117         num = new TimeStretchRTScale(this,
118                 plugin, 
119                 x, 
120                 y,
121                 &plugin->config.num);
122         num->create_objects();
123         y += num->get_h() + margin;
124
125         add_subwindow(title = new BC_Title(x, y, _("Output samples:")));
126         y += title->get_h() + plugin->get_theme()->widget_border;
127         denom = new TimeStretchRTScale(this,
128                 plugin, 
129                 x, 
130                 y,
131                 &plugin->config.denom);
132         denom->create_objects();
133
134         y += denom->get_h() + margin;
135         add_subwindow(title = new BC_Title(x, y, _("Window size (ms):")));
136         y += title->get_h() + margin;
137         size = new TimeStretchRTSize(this,
138                 plugin,
139                 x,
140                 y);
141         size->create_objects();
142
143         show_window();
144 }
145
146
147
148
149
150
151 TimeStretchRTScale::TimeStretchRTScale(TimeStretchRTWindow *window,
152         TimeStretchRT *plugin,
153         int x,
154         int y,
155         double *value)
156  : BC_TumbleTextBox(window,
157         (float)*value,
158         (float)0.0001,
159         (float)1000,
160         x,
161         y,
162         100)
163 {
164         this->plugin = plugin;
165         this->value = value;
166         set_increment(0.01);
167 }
168
169 int TimeStretchRTScale::handle_event()
170 {
171         *value = atof(get_text());
172         plugin->config.boundaries();
173         plugin->send_configure_change();
174         return 1;
175 }
176
177
178
179
180 TimeStretchRTSize::TimeStretchRTSize(TimeStretchRTWindow *window,
181         TimeStretchRT *plugin,
182         int x,
183         int y)
184  : BC_TumbleTextBox(window,
185         plugin->config.size,
186         10,
187         1000,
188         x,
189         y,
190         100)
191 {
192         this->plugin = plugin;
193         set_increment(10);
194 }
195
196 int TimeStretchRTSize::handle_event()
197 {
198         plugin->config.size = atoi(get_text());
199         plugin->send_configure_change();
200         return 1;
201 }
202
203
204
205
206
207
208
209
210 TimeStretchRT::TimeStretchRT(PluginServer *server)
211  : PluginAClient(server)
212 {
213         need_reconfigure = 1;
214         dest_start = -1;
215         source_start = -1;
216         engine = 0;
217 }
218
219
220 TimeStretchRT::~TimeStretchRT()
221 {
222         delete engine;
223 }
224
225 const char* TimeStretchRT::plugin_title() { return N_("Time Stretch RT"); }
226 int TimeStretchRT::is_realtime() { return 1; }
227 int TimeStretchRT::is_synthesis() { return 1; }
228
229
230 NEW_WINDOW_MACRO(TimeStretchRT, TimeStretchRTWindow)
231
232 LOAD_CONFIGURATION_MACRO(TimeStretchRT, TimeStretchRTConfig)
233
234
235 int TimeStretchRT::process_buffer(int64_t size,
236         Samples *buffer,
237         int64_t start_position,
238         int sample_rate)
239 {
240         need_reconfigure = load_configuration();
241
242         if(!engine) engine = new TimeStretchEngine(config.denom / config.num, 
243                 sample_rate,
244                 config.size);
245
246         if(start_position != dest_start) need_reconfigure = 1;
247         dest_start = start_position;
248
249 // Get start position of the input.
250 // Sample 0 is the keyframe position
251         if(need_reconfigure)
252         {
253                 int64_t prev_position = edl_to_local(
254                         get_prev_keyframe(
255                                 get_source_position())->position);
256
257                 if(prev_position == 0)
258                 {
259                         prev_position = get_source_start();
260                 }
261
262                 source_start = (int64_t)((start_position - prev_position) * 
263                         config.num / config.denom) + prev_position;
264
265                 engine->reset();
266                 engine->update(config.denom / config.num, sample_rate, config.size);
267                 need_reconfigure = 0;
268 // printf("TimeStretchRT::process_buffer %d start_position=%lld prev_position=%lld scale=%f source_start=%lld\n", 
269 // __LINE__, 
270 // start_position,
271 // prev_position,
272 // config.scale,
273 // source_start);
274         }
275
276 // process buffers until output length is reached
277         int error = 0;
278         while(!error && engine->get_output_size() < size)
279         {
280
281 // printf("TimeStretchRT::process_buffer %d buffer=%p size=%lld source_start=%lld\n",
282 // __LINE__,
283 // buffer,
284 // size,
285 // source_start);
286                 read_samples(buffer,
287                         0,
288                         sample_rate,
289                         source_start,
290                         size);
291
292
293                 if(get_direction() == PLAY_FORWARD)
294                         source_start += size;
295                 else
296                         source_start -= size;
297
298 //printf("TimeStretchRT::process_buffer %d size=%d\n", __LINE__, size);
299                 engine->process(buffer, size);
300 //printf("TimeStretchRT::process_buffer %d\n", __LINE__);
301
302         }
303 //printf("TimeStretchRT::process_buffer %d\n", __LINE__);
304
305
306         engine->read_output(buffer, size);
307
308 //printf("TimeStretchRT::process_buffer %d\n", __LINE__);
309         if(get_direction() == PLAY_FORWARD)
310                 dest_start += size;
311         else
312                 dest_start -= size;
313
314         return 0;
315 }
316
317
318
319
320
321 void TimeStretchRT::save_data(KeyFrame *keyframe)
322 {
323         FileXML output;
324
325 // cause data to be stored directly in text
326         output.set_shared_output(keyframe->xbuf);
327         output.tag.set_title("TIMESTRETCHRT");
328         output.tag.set_property("NUM", config.num);
329         output.tag.set_property("DENOM", config.denom);
330         output.tag.set_property("SIZE", config.size);
331         output.append_tag();
332         output.tag.set_title("/TIMESTRETCHRT");
333         output.append_tag();
334         output.append_newline();
335         output.terminate_string();
336 }
337
338 void TimeStretchRT::read_data(KeyFrame *keyframe)
339 {
340         FileXML input;
341
342         input.set_shared_input(keyframe->xbuf);
343
344         while(!input.read_tag())
345         {
346                 if(input.tag.title_is("TIMESTRETCHRT"))
347                 {
348                         config.num = input.tag.get_property("NUM", config.num);
349                         config.denom = input.tag.get_property("DENOM", config.denom);
350                         config.size = input.tag.get_property("SIZE", config.size);
351                 }
352         }
353 }
354
355 void TimeStretchRT::update_gui()
356 {
357         if(thread)
358         {
359                 if(load_configuration())
360                 {
361
362                         thread->window->lock_window("TimeStretchRT::update_gui");
363                         ((TimeStretchRTWindow*)thread->window)->num->update((float)config.num);
364                         ((TimeStretchRTWindow*)thread->window)->denom->update((float)config.denom);
365                         ((TimeStretchRTWindow*)thread->window)->size->update((int64_t)config.size);
366                         thread->window->unlock_window();
367                 }
368         }
369 }
370
371
372
373
374