4 * Copyright (C) 1997-2011 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"
32 #include "transportque.inc"
43 EchoConfig::EchoConfig()
50 int EchoConfig::equivalent(EchoConfig &that)
52 return EQUIV(level, that.level) &&
53 atten == that.atten &&
54 offset == that.offset;
57 void EchoConfig::copy_from(EchoConfig &that)
64 void EchoConfig::interpolate(EchoConfig &prev, EchoConfig &next,
65 int64_t prev_frame, int64_t next_frame, int64_t current_frame)
67 double frames = next_frame - prev_frame;
68 double next_scale = (current_frame - prev_frame) / frames;
69 double prev_scale = (next_frame - current_frame) / frames;
70 level = prev.level * prev_scale + next.level * next_scale;
71 atten = prev.atten * prev_scale + next.atten * next_scale;
72 offset = prev.offset * prev_scale + next.offset * next_scale;
78 EchoWindow::EchoWindow(Echo *plugin)
79 : PluginClientWindow(plugin, xS(250), yS(100), xS(250), yS(100), 0)
81 this->plugin = plugin;
84 EchoWindow::~EchoWindow()
89 EchoLevel::EchoLevel(EchoWindow *window, int x, int y)
90 : BC_FPot(x, y, window->plugin->config.level, INFINITYGAIN, MAXGAIN)
92 this->window = window;
94 EchoLevel::~EchoLevel()
97 int EchoLevel::handle_event()
99 Echo *plugin = (Echo *)window->plugin;
100 plugin->config.level = get_value();
101 plugin->send_configure_change();
102 double l = plugin->db.fromdb(plugin->config.level);
103 window->level_title->update(l);
107 EchoAtten::EchoAtten(EchoWindow *window, int x, int y)
108 : BC_FPot(x, y, window->plugin->config.atten,INFINITYGAIN,-0.1)
110 this->window = window;
112 EchoAtten::~EchoAtten()
115 int EchoAtten::handle_event()
117 Echo *plugin = (Echo *)window->plugin;
118 plugin->config.atten = get_value();
119 plugin->send_configure_change();
120 double g = plugin->db.fromdb(plugin->config.atten);
121 window->atten_title->update(g);
125 EchoOffset::EchoOffset(EchoWindow *window, int x, int y)
126 : BC_FPot(x, y, window->plugin->config.offset, 1, 999)
128 this->window = window;
130 EchoOffset::~EchoOffset()
133 int EchoOffset::handle_event()
135 Echo *plugin = (Echo *)window->plugin;
136 plugin->config.offset = get_value();
137 plugin->send_configure_change();
138 window->offset_title->update((int)plugin->config.offset);
142 void EchoWindow::create_objects()
144 int xs5 = xS(5), xs35 = xS(35);
145 int ys10 = yS(10), ys25 = yS(25);
146 int x = xS(170), y = yS(10);
147 add_subwindow(level_title=new EchoTitle(xs5, y + ys10, _("Level: "),
148 plugin->db.fromdb(plugin->config.level)));
149 add_subwindow(level = new EchoLevel(this, x, y)); y += ys25;
150 add_subwindow(atten_title=new EchoTitle(xs5, y + ys10, _("Atten: "),
151 plugin->db.fromdb(plugin->config.atten)));
152 add_subwindow(atten = new EchoAtten(this, x + xs35, y)); y += ys25;
153 add_subwindow(offset_title=new EchoTitle(xs5, y + ys10, _("Offset: "),
154 (int)plugin->config.offset));
155 add_subwindow(offset = new EchoOffset(this, x, y)); y += ys25;
159 int EchoWindow::resize_event(int w, int h)
164 void EchoWindow::update_gui()
166 level->update(plugin->config.level);
167 double l = plugin->db.fromdb(plugin->config.level);
168 level_title->update(l);
169 atten->update(plugin->config.atten);
170 double g = plugin->db.fromdb(plugin->config.atten);
172 offset->update(plugin->config.offset);
173 int ofs = plugin->config.offset;
174 offset_title->update(ofs);
178 void Echo::update_gui()
180 if( !thread ) return;
181 EchoWindow *window = (EchoWindow*)thread->get_window();
182 window->lock_window("Echo::update_gui");
183 if( load_configuration() )
184 window->update_gui();
185 window->unlock_window();
188 Echo::Echo(PluginServer *server)
189 : PluginAClient(server)
212 const char* Echo::plugin_title() { return N_("Echo"); }
213 int Echo::is_realtime() { return 1; }
214 int Echo::is_multichannel() { return 1; }
216 void Echo::delete_buffers()
218 for( int ch=0; ch<nch; ++ch ) {
222 delete [] ibfr; ibfr = 0;
223 delete [] rbfr; rbfr = 0;
227 void Echo::alloc_buffers(int nch, int isz, int rsz)
229 // allocate reflection buffers
230 ibfr = new double *[nch];
231 rbfr = new ring_buffer *[nch];
232 for( int ch=0; ch<nch; ++ch ) {
233 ibfr[ch] = new double[isz];
234 rbfr[ch] = new ring_buffer(rsz);
241 int Echo::process_buffer(int64_t size, Samples **buffer, int64_t start_position, int sample_rate)
243 load_configuration();
245 double level = db.fromdb(config.level);
246 double atten = db.fromdb(config.atten);
247 int ofs = config.offset * sample_rate/1000.;
248 int len = size * ((ofs + size-1) / size);
250 if( nch != total_in_buffers || isz != size || rsz != len )
253 alloc_buffers(total_in_buffers, size, len);
256 if( bfr_pos != start_position ) { // reset reflection
257 bfr_pos = start_position;
258 for( int ch=0; ch<nch; ++ch ) rbfr[ch]->clear();
262 for( int ch=0; ch<nch; ++ch ) { // read samples * level
263 read_samples(buffer[ch], ch, sample_rate, start_position, size);
264 double *bp = buffer[ch]->get_data(), *cp = ibfr[ch];
265 for( int ch=0; ch<size; ++ch ) *cp++ = *bp++ * level;
270 for( int ch=0; ch<nch; ++ch ) {
271 ring_buffer *rp = rbfr[ch];
272 rp->iseek(rpos); rp->oseek(rpos+ofs);
273 double *bp = ibfr[ch];
274 for( int i=n; --i>=0; ) // add front to end reflection
275 rp->onxt() = atten * (rp->inxt() + *bp++);
277 double *op = buffer[ch]->get_data(), *ip = ibfr[ch];
279 for( int i=size; --i>=0; ) // output reflection + input
280 *op++ = rp->inxt() + *ip++;
283 for( int i=size-n; --i>=0; ) // add end to front reflection
284 rp->onxt() = atten * (rp->inxt() + *bp++);
293 NEW_WINDOW_MACRO(Echo, EchoWindow)
296 int Echo::load_configuration()
298 KeyFrame *prev_keyframe = get_prev_keyframe(get_source_position());
299 EchoConfig old_config;
300 old_config.copy_from(config);
301 read_data(prev_keyframe);
302 return !old_config.equivalent(config) ? 1 : 0;
305 void Echo::read_data(KeyFrame *keyframe)
309 input.set_shared_input(keyframe->xbuf);
311 while(!(result = input.read_tag()) ) {
312 if( !input.tag.title_is("ECHO")) continue;
313 config.level = input.tag.get_property("LEVEL", config.level);
314 config.atten = input.tag.get_property("ATTEN", config.atten);
315 config.offset = input.tag.get_property("OFFSET", config.offset);
316 if( !is_defaults() ) continue;
320 void Echo::save_data(KeyFrame *keyframe)
323 output.set_shared_output(keyframe->xbuf);
325 output.tag.set_title("ECHO");
326 output.tag.set_property("LEVEL", config.level);
327 output.tag.set_property("ATTEN", config.atten);
328 output.tag.set_property("OFFSET", config.offset);
330 output.tag.set_title("/ECHO");
332 output.append_newline();
333 output.terminate_string();