5974c90ec5a0f631a073b454dd3e0185066b1b6d
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / loopaudio / loopaudio.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 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 "clip.h"
24 #include "bchash.h"
25 #include "filexml.h"
26 #include "guicast.h"
27 #include "language.h"
28 #include "pluginaclient.h"
29 #include "samples.h"
30 #include "transportque.h"
31
32 #include <string.h>
33
34 class LoopAudio;
35
36 class LoopAudioConfig
37 {
38 public:
39         LoopAudioConfig();
40         int64_t samples;
41 };
42
43
44 class LoopAudioSamples : public BC_TextBox
45 {
46 public:
47         LoopAudioSamples(LoopAudio *plugin,
48                 int x,
49                 int y);
50         int handle_event();
51         LoopAudio *plugin;
52 };
53
54 class LoopAudioWindow : public PluginClientWindow
55 {
56 public:
57         LoopAudioWindow(LoopAudio *plugin);
58         ~LoopAudioWindow();
59         void create_objects();
60         LoopAudio *plugin;
61         LoopAudioSamples *samples;
62 };
63
64
65
66 class LoopAudio : public PluginAClient
67 {
68 public:
69         LoopAudio(PluginServer *server);
70         ~LoopAudio();
71
72         PLUGIN_CLASS_MEMBERS(LoopAudioConfig)
73
74         void save_data(KeyFrame *keyframe);
75         void read_data(KeyFrame *keyframe);
76         void update_gui();
77         int is_realtime();
78         int is_synthesis();
79         int process_buffer(int64_t size,
80                 Samples *buffer,
81                 int64_t start_position,
82                 int sample_rate);
83 };
84
85
86
87
88
89
90
91 REGISTER_PLUGIN(LoopAudio);
92
93
94
95 LoopAudioConfig::LoopAudioConfig()
96 {
97         samples = 48000;
98 }
99
100
101
102
103
104 LoopAudioWindow::LoopAudioWindow(LoopAudio *plugin)
105  : PluginClientWindow(plugin,
106         xS(210),
107         yS(160),
108         xS(200),
109         yS(160),
110         0)
111 {
112         this->plugin = plugin;
113 }
114
115 LoopAudioWindow::~LoopAudioWindow()
116 {
117 }
118
119 void LoopAudioWindow::create_objects()
120 {
121         int xs10 = xS(10);
122         int ys10 = yS(10), ys20 = yS(20);
123         int x = xs10, y = ys10;
124
125         add_subwindow(new BC_Title(x, y, _("Samples to loop:")));
126         y += ys20;
127         add_subwindow(samples = new LoopAudioSamples(plugin,
128                 x,
129                 y));
130         show_window();
131         flush();
132 }
133
134
135
136
137
138
139
140
141
142 LoopAudioSamples::LoopAudioSamples(LoopAudio *plugin,
143         int x,
144         int y)
145  : BC_TextBox(x,
146         y,
147         xS(100),
148         1,
149         plugin->config.samples)
150 {
151         this->plugin = plugin;
152         set_precision(2);
153 }
154
155 int LoopAudioSamples::handle_event()
156 {
157         plugin->config.samples = atol(get_text());
158         plugin->config.samples = MAX(1, plugin->config.samples);
159         plugin->send_configure_change();
160         return 1;
161 }
162
163
164
165
166
167
168
169
170
171 LoopAudio::LoopAudio(PluginServer *server)
172  : PluginAClient(server)
173 {
174
175 }
176
177
178 LoopAudio::~LoopAudio()
179 {
180
181 }
182
183 const char* LoopAudio::plugin_title() { return N_("Loop audio"); }
184 int LoopAudio::is_realtime() { return 1; }
185 int LoopAudio::is_synthesis() { return 1; }
186
187
188
189 NEW_WINDOW_MACRO(LoopAudio, LoopAudioWindow)
190
191
192 int LoopAudio::process_buffer(int64_t size,
193         Samples *buffer,
194         int64_t start_position,
195         int sample_rate)
196 {
197         int64_t current_position = start_position;
198         int step = (get_direction() == PLAY_FORWARD) ? 1 : -1;
199         int fragment_size;
200         int64_t current_loop_end;
201
202 //printf("LoopAudio::process_buffer 1 %lld %d\n", start_position, size);
203
204         current_position = start_position;
205
206         for(int i = 0; i < size; i += fragment_size)
207         {
208 // Truncate to end of buffer
209                 fragment_size = MIN(size - i, size);
210
211                 int64_t current_loop_position;
212
213 // Truncate to next keyframe
214                 if(get_direction() == PLAY_FORWARD)
215                 {
216                         KeyFrame *next_keyframe = get_next_keyframe(current_position);
217                         int64_t next_position = edl_to_local(next_keyframe->position);
218                         if(next_position > current_position)
219                                 fragment_size = MIN(fragment_size, next_position - current_position);
220
221 // Get start of current loop
222                         KeyFrame *prev_keyframe = get_prev_keyframe(current_position);
223                         int64_t prev_position = edl_to_local(prev_keyframe->position);
224                         if(prev_position == 0)
225                                 prev_position = get_source_start();
226                         read_data(prev_keyframe);
227
228 // Get start of fragment in current loop
229                         current_loop_position = prev_position +
230                                 ((current_position - prev_position) %
231                                         config.samples);
232                         while(current_loop_position < prev_position) current_loop_position += config.samples;
233                         while(current_loop_position >= prev_position + config.samples) current_loop_position -= config.samples;
234
235 // Truncate fragment to end of loop
236                         current_loop_end = current_position -
237                                 current_loop_position +
238                                 prev_position +
239                                 config.samples;
240                         fragment_size = MIN(current_loop_end - current_position,
241                                 fragment_size);
242                 }
243                 else
244                 {
245                         KeyFrame *next_keyframe = get_prev_keyframe(current_position);
246                         int64_t next_position = edl_to_local(next_keyframe->position);
247                         if(next_position < current_position)
248                                 fragment_size = MIN(fragment_size, current_position - next_position);
249
250                         KeyFrame *prev_keyframe = get_next_keyframe(current_position);
251                         int64_t prev_position = edl_to_local(prev_keyframe->position);
252                         if(prev_position == 0)
253                                 prev_position = get_source_start() + get_total_len();
254                         read_data(prev_keyframe);
255
256                         current_loop_position = prev_position -
257                                 ((prev_position - current_position) %
258                                           config.samples);
259                         while(current_loop_position <= prev_position - config.samples) current_loop_position += config.samples;
260                         while(current_loop_position > prev_position) current_loop_position -= config.samples;
261
262 // Truncate fragment to end of loop
263                         current_loop_end = current_position +
264                                 prev_position -
265                                 current_loop_position -
266                                 config.samples;
267                         fragment_size = MIN(current_position - current_loop_end,
268                                 fragment_size);
269                 }
270
271
272 // printf("LoopAudio::process_buffer 100 %lld %lld %lld %d\n",
273 // current_position, current_loop_position, current_loop_end, fragment_size);
274                 int offset = buffer->get_offset();
275                 buffer->set_offset(offset + i);
276                 read_samples(buffer,
277                         0,
278                         sample_rate,
279                         current_loop_position,
280                         fragment_size);
281                 buffer->set_offset(offset);
282
283
284                 current_position += step * fragment_size;
285         }
286
287
288         return 0;
289 }
290
291
292
293
294 int LoopAudio::load_configuration()
295 {
296         KeyFrame *prev_keyframe;
297         int64_t old_samples = config.samples;
298         prev_keyframe = get_prev_keyframe(get_source_position());
299         read_data(prev_keyframe);
300         return old_samples != config.samples;
301 }
302
303
304 void LoopAudio::save_data(KeyFrame *keyframe)
305 {
306         FileXML output;
307
308 // cause data to be stored directly in text
309         output.set_shared_output(keyframe->xbuf);
310         output.tag.set_title("LOOPAUDIO");
311         output.tag.set_property("SAMPLES", config.samples);
312         output.append_tag();
313         output.tag.set_title("/LOOPAUDIO");
314         output.append_tag();
315         output.append_newline();
316         output.terminate_string();
317 }
318
319 void LoopAudio::read_data(KeyFrame *keyframe)
320 {
321         FileXML input;
322
323         input.set_shared_input(keyframe->xbuf);
324
325         while(!input.read_tag())
326         {
327                 if(input.tag.title_is("LOOPAUDIO"))
328                 {
329                         config.samples = input.tag.get_property("SAMPLES", config.samples);
330                 }
331         }
332 }
333
334 void LoopAudio::update_gui()
335 {
336         if(thread)
337         {
338                 load_configuration();
339                 thread->window->lock_window();
340                 ((LoopAudioWindow*)thread->window)->samples->update(config.samples);
341                 thread->window->unlock_window();
342         }
343 }
344
345
346
347
348