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