add timecode units/alignment/probe, add prefs auto_rotate,
[goodguy/cinelerra.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         xS(180),
83         yS(110),
84         xS(180),
85         yS(110),
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, int64_t len, int direction)
186 {
187         int result = plugin->read_samples(buffer,
188                 0,
189                 plugin->get_samplerate(),
190                 plugin->source_start,
191                 len);
192
193 //printf("ResampleRTResample::read_samples %lld %lld %lld %d\n", start, plugin->source_start, len, result);
194         if(plugin->get_direction() == PLAY_FORWARD)
195                 plugin->source_start += len;
196         else
197                 plugin->source_start -= len;
198
199         return result;
200 }
201
202
203
204
205
206
207 ResampleRT::ResampleRT(PluginServer *server)
208  : PluginAClient(server)
209 {
210         resample = 0;
211         need_reconfigure = 1;
212         prev_scale = 0;
213         dest_start = -1;
214 }
215
216
217 ResampleRT::~ResampleRT()
218 {
219         delete resample;
220 }
221
222 const char* ResampleRT::plugin_title() { return N_("ResampleRT"); }
223 int ResampleRT::is_realtime() { return 1; }
224 int ResampleRT::is_synthesis() { return 1; }
225
226
227 NEW_WINDOW_MACRO(ResampleRT, ResampleRTWindow)
228
229 LOAD_CONFIGURATION_MACRO(ResampleRT, ResampleRTConfig)
230
231
232 int ResampleRT::process_buffer(int64_t size,
233         Samples *buffer,
234         int64_t start_position,
235         int sample_rate)
236 {
237         if(!resample) resample = new ResampleRTResample(this);
238
239         need_reconfigure |= load_configuration();
240
241
242         if(start_position != dest_start) need_reconfigure = 1;
243         dest_start = start_position;
244
245 // Get start position of the input.
246 // Sample 0 is the keyframe position
247         if(need_reconfigure)
248         {
249                 int64_t prev_position = edl_to_local(
250                         get_prev_keyframe(
251                                 get_source_position())->position);
252
253                 if(prev_position == 0)
254                 {
255                         prev_position = get_source_start();
256                 }
257
258                 source_start = (int64_t)((start_position - prev_position) *
259                         config.num / config.denom) + prev_position;
260
261                 resample->reset();
262                 need_reconfigure = 0;
263         }
264
265         resample->resample(buffer,
266                 size,
267                 (int)(65536 * config.num),
268                 (int)(65536 * config.denom),
269                 start_position,
270                 get_direction());
271
272         if(get_direction() == PLAY_FORWARD)
273                 dest_start += size;
274         else
275                 dest_start -= size;
276
277         return 0;
278 }
279
280 void ResampleRT::render_stop()
281 {
282         need_reconfigure = 1;
283 }
284
285
286
287
288 void ResampleRT::save_data(KeyFrame *keyframe)
289 {
290         FileXML output;
291
292 // cause data to be stored directly in text
293         output.set_shared_output(keyframe->xbuf);
294         output.tag.set_title("RESAMPLERT");
295         output.tag.set_property("SCALE", config.num);
296         output.tag.set_property("DENOM", config.denom);
297         output.append_tag();
298         output.tag.set_title("/RESAMPLERT");
299         output.append_tag();
300         output.append_newline();
301         output.terminate_string();
302 }
303
304 void ResampleRT::read_data(KeyFrame *keyframe)
305 {
306         FileXML input;
307
308         input.set_shared_input(keyframe->xbuf);
309
310         while(!input.read_tag())
311         {
312                 if(input.tag.title_is("RESAMPLERT"))
313                 {
314                         config.num = input.tag.get_property("SCALE", config.num);
315                         config.denom = input.tag.get_property("DENOM", config.denom);
316                 }
317         }
318 }
319
320 void ResampleRT::update_gui()
321 {
322         if(thread)
323         {
324                 if(load_configuration())
325                 {
326                         thread->window->lock_window("ResampleRT::update_gui");
327                         ((ResampleRTWindow*)thread->window)->num->update((float)config.num);
328                         ((ResampleRTWindow*)thread->window)->denom->update((float)config.denom);
329                         thread->window->unlock_window();
330                 }
331         }
332 }
333
334
335
336
337