4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bcdisplayinfo.h"
28 #include "pluginaclient.h"
30 #include "transportque.h"
44 class LoopAudioSamples : public BC_TextBox
47 LoopAudioSamples(LoopAudio *plugin,
54 class LoopAudioWindow : public PluginClientWindow
57 LoopAudioWindow(LoopAudio *plugin);
59 void create_objects();
61 LoopAudioSamples *samples;
66 class LoopAudio : public PluginAClient
69 LoopAudio(PluginServer *server);
72 PLUGIN_CLASS_MEMBERS(LoopAudioConfig)
74 void save_data(KeyFrame *keyframe);
75 void read_data(KeyFrame *keyframe);
79 int process_buffer(int64_t size,
81 int64_t start_position,
91 REGISTER_PLUGIN(LoopAudio);
95 LoopAudioConfig::LoopAudioConfig()
104 LoopAudioWindow::LoopAudioWindow(LoopAudio *plugin)
105 : PluginClientWindow(plugin,
112 this->plugin = plugin;
115 LoopAudioWindow::~LoopAudioWindow()
119 void LoopAudioWindow::create_objects()
122 int ys10 = yS(10), ys20 = yS(20);
123 int x = xs10, y = ys10;
125 add_subwindow(new BC_Title(x, y, _("Samples to loop:")));
127 add_subwindow(samples = new LoopAudioSamples(plugin,
142 LoopAudioSamples::LoopAudioSamples(LoopAudio *plugin,
149 plugin->config.samples)
151 this->plugin = plugin;
155 int LoopAudioSamples::handle_event()
157 plugin->config.samples = atol(get_text());
158 plugin->config.samples = MAX(1, plugin->config.samples);
159 plugin->send_configure_change();
171 LoopAudio::LoopAudio(PluginServer *server)
172 : PluginAClient(server)
178 LoopAudio::~LoopAudio()
183 const char* LoopAudio::plugin_title() { return N_("Loop audio"); }
184 int LoopAudio::is_realtime() { return 1; }
185 int LoopAudio::is_synthesis() { return 1; }
189 NEW_WINDOW_MACRO(LoopAudio, LoopAudioWindow)
192 int LoopAudio::process_buffer(int64_t size,
194 int64_t start_position,
197 int64_t current_position = start_position;
198 int step = (get_direction() == PLAY_FORWARD) ? 1 : -1;
200 int64_t current_loop_end;
202 //printf("LoopAudio::process_buffer 1 %lld %d\n", start_position, size);
204 current_position = start_position;
206 for(int i = 0; i < size; i += fragment_size)
208 // Truncate to end of buffer
209 fragment_size = MIN(size - i, size);
211 int64_t current_loop_position;
213 // Truncate to next keyframe
214 if(get_direction() == PLAY_FORWARD)
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);
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);
228 // Get start of fragment in current loop
229 current_loop_position = prev_position +
230 ((current_position - prev_position) %
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;
235 // Truncate fragment to end of loop
236 current_loop_end = current_position -
237 current_loop_position +
240 fragment_size = MIN(current_loop_end - current_position,
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);
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);
256 current_loop_position = prev_position -
257 ((prev_position - current_position) %
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;
262 // Truncate fragment to end of loop
263 current_loop_end = current_position +
265 current_loop_position -
267 fragment_size = MIN(current_position - current_loop_end,
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);
279 current_loop_position,
281 buffer->set_offset(offset);
284 current_position += step * fragment_size;
294 int LoopAudio::load_configuration()
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;
304 void LoopAudio::save_data(KeyFrame *keyframe)
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);
313 output.tag.set_title("/LOOPAUDIO");
315 output.append_newline();
316 output.terminate_string();
319 void LoopAudio::read_data(KeyFrame *keyframe)
323 input.set_shared_input(keyframe->xbuf);
325 while(!input.read_tag())
327 if(input.tag.title_is("LOOPAUDIO"))
329 config.samples = input.tag.get_property("SAMPLES", config.samples);
334 void LoopAudio::update_gui()
338 load_configuration();
339 thread->window->lock_window();
340 ((LoopAudioWindow*)thread->window)->samples->update(config.samples);
341 thread->window->unlock_window();