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()
123 add_subwindow(new BC_Title(x, y, _("Samples to loop:")));
125 add_subwindow(samples = new LoopAudioSamples(plugin,
140 LoopAudioSamples::LoopAudioSamples(LoopAudio *plugin,
147 plugin->config.samples)
149 this->plugin = plugin;
153 int LoopAudioSamples::handle_event()
155 plugin->config.samples = atol(get_text());
156 plugin->config.samples = MAX(1, plugin->config.samples);
157 plugin->send_configure_change();
169 LoopAudio::LoopAudio(PluginServer *server)
170 : PluginAClient(server)
176 LoopAudio::~LoopAudio()
181 const char* LoopAudio::plugin_title() { return _("Loop audio"); }
182 int LoopAudio::is_realtime() { return 1; }
183 int LoopAudio::is_synthesis() { return 1; }
187 NEW_WINDOW_MACRO(LoopAudio, LoopAudioWindow)
190 int LoopAudio::process_buffer(int64_t size,
192 int64_t start_position,
195 int64_t current_position = start_position;
196 int step = (get_direction() == PLAY_FORWARD) ? 1 : -1;
198 int64_t current_loop_end;
200 //printf("LoopAudio::process_buffer 1 %lld %d\n", start_position, size);
202 current_position = start_position;
204 for(int i = 0; i < size; i += fragment_size)
206 // Truncate to end of buffer
207 fragment_size = MIN(size - i, size);
209 int64_t current_loop_position;
211 // Truncate to next keyframe
212 if(get_direction() == PLAY_FORWARD)
214 KeyFrame *next_keyframe = get_next_keyframe(current_position);
215 int64_t next_position = edl_to_local(next_keyframe->position);
216 if(next_position > current_position)
217 fragment_size = MIN(fragment_size, next_position - current_position);
219 // Get start of current loop
220 KeyFrame *prev_keyframe = get_prev_keyframe(current_position);
221 int64_t prev_position = edl_to_local(prev_keyframe->position);
222 if(prev_position == 0)
223 prev_position = get_source_start();
224 read_data(prev_keyframe);
226 // Get start of fragment in current loop
227 current_loop_position = prev_position +
228 ((current_position - prev_position) %
230 while(current_loop_position < prev_position) current_loop_position += config.samples;
231 while(current_loop_position >= prev_position + config.samples) current_loop_position -= config.samples;
233 // Truncate fragment to end of loop
234 current_loop_end = current_position -
235 current_loop_position +
238 fragment_size = MIN(current_loop_end - current_position,
243 KeyFrame *next_keyframe = get_prev_keyframe(current_position);
244 int64_t next_position = edl_to_local(next_keyframe->position);
245 if(next_position < current_position)
246 fragment_size = MIN(fragment_size, current_position - next_position);
248 KeyFrame *prev_keyframe = get_next_keyframe(current_position);
249 int64_t prev_position = edl_to_local(prev_keyframe->position);
250 if(prev_position == 0)
251 prev_position = get_source_start() + get_total_len();
252 read_data(prev_keyframe);
254 current_loop_position = prev_position -
255 ((prev_position - current_position) %
257 while(current_loop_position <= prev_position - config.samples) current_loop_position += config.samples;
258 while(current_loop_position > prev_position) current_loop_position -= config.samples;
260 // Truncate fragment to end of loop
261 current_loop_end = current_position +
263 current_loop_position -
265 fragment_size = MIN(current_position - current_loop_end,
270 // printf("LoopAudio::process_buffer 100 %lld %lld %lld %d\n",
271 // current_position, current_loop_position, current_loop_end, fragment_size);
272 int offset = buffer->get_offset();
273 buffer->set_offset(offset + i);
277 current_loop_position,
279 buffer->set_offset(offset);
282 current_position += step * fragment_size;
292 int LoopAudio::load_configuration()
294 KeyFrame *prev_keyframe;
295 int64_t old_samples = config.samples;
296 prev_keyframe = get_prev_keyframe(get_source_position());
297 read_data(prev_keyframe);
298 return old_samples != config.samples;
302 void LoopAudio::save_data(KeyFrame *keyframe)
306 // cause data to be stored directly in text
307 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
308 output.tag.set_title("LOOPAUDIO");
309 output.tag.set_property("SAMPLES", config.samples);
311 output.tag.set_title("/LOOPAUDIO");
313 output.append_newline();
314 output.terminate_string();
317 void LoopAudio::read_data(KeyFrame *keyframe)
321 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
323 while(!input.read_tag())
325 if(input.tag.title_is("LOOPAUDIO"))
327 config.samples = input.tag.get_property("SAMPLES", config.samples);
332 void LoopAudio::update_gui()
336 load_configuration();
337 thread->window->lock_window();
338 ((LoopAudioWindow*)thread->window)->samples->update(config.samples);
339 thread->window->unlock_window();