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, 250, 100, 250, 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()
145 add_subwindow(level_title=new EchoTitle(5, y + 10, _("Level: "),
146 plugin->db.fromdb(plugin->config.level)));
147 add_subwindow(level = new EchoLevel(this, x, y)); y += 25;
148 add_subwindow(atten_title=new EchoTitle(5, y + 10, _("Atten: "),
149 plugin->db.fromdb(plugin->config.atten)));
150 add_subwindow(atten = new EchoAtten(this, x + 35, y)); y += 25;
151 add_subwindow(offset_title=new EchoTitle(5, y + 10, _("Offset: "),
152 (int)plugin->config.offset));
153 add_subwindow(offset = new EchoOffset(this, x, y)); y += 25;
157 int EchoWindow::resize_event(int w, int h)
162 void EchoWindow::update_gui()
164 level->update(plugin->config.level);
165 double l = plugin->db.fromdb(plugin->config.level);
166 level_title->update(l);
167 atten->update(plugin->config.atten);
168 double g = plugin->db.fromdb(plugin->config.atten);
170 offset->update(plugin->config.offset);
171 int ofs = plugin->config.offset;
172 offset_title->update(ofs);
176 void Echo::update_gui()
178 if( !thread ) return;
179 EchoWindow *window = (EchoWindow*)thread->get_window();
180 window->lock_window("Echo::update_gui");
181 if( load_configuration() )
182 window->update_gui();
183 window->unlock_window();
186 Echo::Echo(PluginServer *server)
187 : PluginAClient(server)
210 const char* Echo::plugin_title() { return _("Echo"); }
211 int Echo::is_realtime() { return 1; }
212 int Echo::is_multichannel() { return 1; }
214 void Echo::delete_buffers()
216 for( int ch=0; ch<nch; ++ch ) {
220 delete [] ibfr; ibfr = 0;
221 delete [] rbfr; rbfr = 0;
225 void Echo::alloc_buffers(int nch, int isz, int rsz)
227 // allocate reflection buffers
228 ibfr = new double *[nch];
229 rbfr = new ring_buffer *[nch];
230 for( int ch=0; ch<nch; ++ch ) {
231 ibfr[ch] = new double[isz];
232 rbfr[ch] = new ring_buffer(rsz);
239 int Echo::process_buffer(int64_t size, Samples **buffer, int64_t start_position, int sample_rate)
241 load_configuration();
243 double level = db.fromdb(config.level);
244 double atten = db.fromdb(config.atten);
245 int ofs = config.offset * sample_rate/1000.;
246 int len = size * ((ofs + size-1) / size);
248 if( nch != total_in_buffers || isz != size || rsz != len )
251 alloc_buffers(total_in_buffers, size, len);
254 if( bfr_pos != start_position ) { // reset reflection
255 bfr_pos = start_position;
256 for( int ch=0; ch<nch; ++ch ) rbfr[ch]->clear();
260 for( int ch=0; ch<nch; ++ch ) { // read samples * level
261 read_samples(buffer[ch], ch, sample_rate, start_position, size);
262 double *bp = buffer[ch]->get_data(), *cp = ibfr[ch];
263 for( int ch=0; ch<size; ++ch ) *cp++ = *bp++ * level;
268 for( int ch=0; ch<nch; ++ch ) {
269 ring_buffer *rp = rbfr[ch];
270 rp->iseek(rpos); rp->oseek(rpos+ofs);
271 double *bp = ibfr[ch];
272 for( int i=n; --i>=0; ) // add front to end reflection
273 rp->onxt() = atten * (rp->inxt() + *bp++);
275 double *op = buffer[ch]->get_data(), *ip = ibfr[ch];
277 for( int i=size; --i>=0; ) // output reflection + input
278 *op++ = rp->inxt() + *ip++;
281 for( int i=size-n; --i>=0; ) // add end to front reflection
282 rp->onxt() = atten * (rp->inxt() + *bp++);
291 NEW_WINDOW_MACRO(Echo, EchoWindow)
294 int Echo::load_configuration()
296 KeyFrame *prev_keyframe = get_prev_keyframe(get_source_position());
297 EchoConfig old_config;
298 old_config.copy_from(config);
299 read_data(prev_keyframe);
300 return !old_config.equivalent(config) ? 1 : 0;
303 void Echo::read_data(KeyFrame *keyframe)
307 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
309 while(!(result = input.read_tag()) ) {
310 if( !input.tag.title_is("ECHO")) continue;
311 config.level = input.tag.get_property("LEVEL", config.level);
312 config.atten = input.tag.get_property("ATTEN", config.atten);
313 config.offset = input.tag.get_property("OFFSET", config.offset);
314 if( !is_defaults() ) continue;
318 void Echo::save_data(KeyFrame *keyframe)
321 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
323 output.tag.set_title("ECHO");
324 output.tag.set_property("LEVEL", config.level);
325 output.tag.set_property("ATTEN", config.atten);
326 output.tag.set_property("OFFSET", config.offset);
328 output.tag.set_title("/ECHO");
330 output.append_newline();
331 output.terminate_string();