1 /*
2  * Copyright (C) 2009, 2010, 2013 Hermann Meyer, James Warden, Andreas Degert
3  * Copyright (C) 2011 Pete Shorthose
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  * --------------------------------------------------------------------------
19  */
20 
21 #include "guitarix.h"                    // NOLINT
22 
23 namespace gx_jconv {
24 
25 /****************************************************************
26  ** Convolver Parameter Window
27  */
28 
29 /*
30 ** static class variables and functions
31 */
32 
create(const std::string & unit_id,Glib::RefPtr<Gdk::Pixbuf> icon,gx_engine::GxMachineBase & machine,Glib::RefPtr<Gtk::AccelGroup> accels,int nchan)33 IRWindow *IRWindow::create(const std::string& unit_id,
34 			   Glib::RefPtr<Gdk::Pixbuf> icon, gx_engine::GxMachineBase& machine,
35 			   Glib::RefPtr<Gtk::AccelGroup> accels, int nchan) {
36     Glib::RefPtr<gx_gui::GxBuilder> bld = gx_gui::GxBuilder::create_from_file(
37 	machine.get_options().get_builder_filepath(nchan == 1 ? "iredit_mono.glade" : "iredit.glade"), &machine);
38     Gtk::Widget *w;
39     if (!machine.get_jack()) {
40 	bld->find_widget("file_selector_box", w);
41 	//w->hide();
42 	//bld->find_widget("dir_combo:rack_button", w);
43 	//w->show();
44     }
45     gx_engine::JConvParameter *jcp = dynamic_cast<gx_engine::JConvParameter*>(&machine.get_parameter(unit_id+".convolver"));
46     assert(jcp);
47     return new IRWindow(bld, jcp, icon, machine, accels, nchan);
48 }
49 
50 /*
51  ** Constructor
52  */
53 
init_connect()54 void IRWindow::init_connect() {
55     builder->find_widget("iredit", wIredit);
56     wIredit->signal_delay_changed().connect(sigc::mem_fun(*this,
57                                             &IRWindow::on_delay_changed));
58     wIredit->signal_offset_changed().connect(sigc::mem_fun(*this,
59                                             &IRWindow::on_offset_changed));
60     wIredit->signal_length_changed().connect(sigc::mem_fun(*this,
61                                              &IRWindow::on_length_changed));
62     wIredit->signal_scale_max_reached().connect(sigc::mem_fun(*this,
63                                                 &IRWindow::on_max_scale_reached));
64     wIredit->signal_scale_min_reached().connect(sigc::mem_fun(*this,
65                                                 &IRWindow::on_min_scale_reached));
66 
67     builder->find_widget("file_combo:rack_button", wcombo);
68     wcombo->signal_changed().connect(
69 	sigc::mem_fun(*this, &IRWindow::on_combo_changed));
70     wcombo->set_model(model);
71 
72     builder->find_widget("dir_combo:rack_button", dircombo);
73     if (dircombo->is_visible()) {
74 	Gtk::TreeModelColumnRecord rec;
75 	Gtk::TreeModelColumn<std::string> fname_col;
76 	rec.add(fname_col);
77 	Gtk::TreeModelColumn<Glib::ustring> dname_col;
78 	rec.add(dname_col);
79 	Glib::RefPtr<Gtk::ListStore> st = Gtk::ListStore::create(rec);
80 	std::vector<gx_system::FileName> dirs;
81 	machine.load_impresp_dirs(dirs);
82 	for (std::vector<gx_system::FileName>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
83 	    Gtk::TreeIter j = st->append();
84 	    j->set_value(0, i->displayname);
85 	    j->set_value(1, i->filename);
86 	}
87 	dircombo->set_model(st);
88 	dircombo->signal_changed().connect(
89 	    sigc::mem_fun(*this, &IRWindow::on_dircombo_changed));
90     }
91 
92     if (nchan != 1) {
93 	builder->find_widget("left", wLeft);
94 	wLeft->signal_toggled().connect(sigc::mem_fun(*this, &IRWindow::on_left));
95 	builder->find_widget("right", wRight);
96 	wRight->signal_toggled().connect(sigc::mem_fun(*this, &IRWindow::on_right));
97 	builder->find_widget("sum", wSum);
98 	wSum->set_active(true);
99 	wSum->signal_toggled().connect(sigc::mem_fun(*this, &IRWindow::on_sum));
100     } else {
101 	wLeft = wRight = wSum = 0;
102     }
103 
104     builder->find_widget("log", wLog);
105     wLog->set_active(true);
106     builder->find_widget("linear", wLinear);
107     wLinear->signal_toggled().connect(sigc::mem_fun(*this, &IRWindow::on_linear));
108 
109     builder->find_widget("delay:show_always", wDelay);
110     wDelay->signal_value_changed().connect(sigc::mem_fun(*this,
111                                            &IRWindow::on_m_delay_changed));
112     builder->find_widget("offset:show_always", wOffset);
113     wOffset->signal_value_changed().connect(sigc::mem_fun(*this,
114                                             &IRWindow::on_m_offset_changed));
115     builder->find_widget("irlength:show_always", wLength);
116     wLength->signal_value_changed().connect(sigc::mem_fun(*this,
117                                             &IRWindow::on_m_length_changed));
118     builder->find_widget("delay_ms:show_always", wDelay_ms);
119     wDelay_ms->signal_value_changed().connect(sigc::mem_fun(*this,
120                                               &IRWindow::on_ms_delay_changed));
121     builder->find_widget("offset_ms:show_always", wOffset_ms);
122     wOffset_ms->signal_value_changed().connect(sigc::mem_fun(*this,
123                                                &IRWindow::on_ms_offset_changed));
124     builder->find_widget("irlength_ms:show_always", wLength_ms);
125     wLength_ms->signal_value_changed().connect(sigc::mem_fun(*this,
126                                                &IRWindow::on_ms_length_changed));
127 
128     if (nchan != 1) {
129 	builder->find_widget("delay_delta", wDelay_delta);
130 	wDelay_delta->signal_format_value().connect(sigc::mem_fun(*this,
131 								  &IRWindow::on_delay_delta_format_value));
132     }
133 
134     builder->find_widget("home", wHome);
135     wHome->signal_clicked().connect(sigc::mem_fun(*this, &IRWindow::on_home));
136     builder->find_widget("jump_zoom_mark", wJump_zoom_mark);
137     wJump_zoom_mark->signal_clicked().connect(sigc::mem_fun(*this,
138                                               &IRWindow::on_jump_zoom_mark));
139     builder->find_widget("incr", wIncr);
140     wIncr->signal_clicked().connect(sigc::mem_fun(*this, &IRWindow::on_incr));
141     builder->find_widget("decr", wDecr);
142     wDecr->signal_clicked().connect(sigc::mem_fun(*this, &IRWindow::on_decr));
143 
144     builder->find_widget("reset_button", wReset);
145     wReset->signal_clicked().connect(sigc::mem_fun(*this, &IRWindow::on_reset_clicked));
146     builder->find_widget("open_button", wOpen);
147     if (!machine.get_jack()) wOpen->set_sensitive(false);
148     wOpen->signal_clicked().connect(sigc::mem_fun(*this, &IRWindow::on_open));
149 
150     builder->find_widget("apply_button", wApply);
151     wApply->signal_clicked().connect(sigc::mem_fun(*this,
152                                      &IRWindow::on_apply_button_clicked));
153 
154     builder->find_widget("cancel_button", wCancel);
155     wCancel->signal_clicked().connect(sigc::mem_fun(*this,
156                                       &IRWindow::on_cancel_button_clicked));
157     builder->find_widget("ok_button", wOk);
158     wOk->signal_clicked().connect(sigc::mem_fun(*this,
159                                   &IRWindow::on_ok_button_clicked));
160 
161     builder->find_widget("gain_button", wGain_correction);
162     autogain_conn = wGain_correction->signal_toggled().connect(
163 	sigc::mem_fun(*this, &IRWindow::on_gain_button_toggled));
164 
165     builder->find_widget("length", wSamples);
166     builder->find_widget("samplerate", wSampleRate);
167     builder->find_widget("format", wFormat);
168     builder->find_widget("channels", wChan);
169     builder->find_widget("filename", wFilename);
170 
171     if (nchan == 1) {
172 	wChannelbox = 0;
173     } else {
174 	builder->find_widget("channelbox", wChannelbox);
175     }
176     Gtk::Button* button;
177     builder->find_widget("help_button", button);
178     button->signal_clicked().connect(sigc::mem_fun(*this, &IRWindow::on_help_clicked));
179     builder->find_widget("HelpIR", wHelp);
180     builder->find_widget("close_irhelp", button);
181     button->signal_clicked().connect(sigc::mem_fun(wHelp, &Gtk::Widget::hide));
182 
183     builder->find_widget("preset_button", button);
184     button->signal_clicked().connect(
185 	sigc::mem_fun(this, &IRWindow::on_preset_popup_clicked));
186 
187     gtk_window->signal_key_press_event().connect(
188 	sigc::mem_fun(this, &IRWindow::on_key_press_event));
189 }
190 
IRWindow(const Glib::RefPtr<gx_gui::GxBuilder> & bld,gx_engine::JConvParameter * jcp_,Glib::RefPtr<Gdk::Pixbuf> icon,gx_engine::GxMachineBase & machine_,Glib::RefPtr<Gtk::AccelGroup> accels,int nchan_)191 IRWindow::IRWindow(const Glib::RefPtr<gx_gui::GxBuilder>& bld, gx_engine::JConvParameter *jcp_,
192 		   Glib::RefPtr<Gdk::Pixbuf> icon, gx_engine::GxMachineBase& machine_,
193 		   Glib::RefPtr<Gtk::AccelGroup> accels, int nchan_)
194     : machine(machine_),
195       builder(bld),
196       filename(),
197       ms(0.0),
198       audio_buffer(0),
199       audio_size(0),
200       audio_chan(0),
201       jcp(jcp_),
202       gtk_window(0),
203       autogain_conn(),
204       nchan(nchan_),
205       //skipped all gtk widget pointers, will be set in init_connect()
206       columns(),
207       model(Gtk::TreeStore::create(columns)),
208       current_combo_dir() {
209     bld->get_toplevel("DisplayIR", gtk_window);
210 
211     init_connect();
212     gtk_window->set_icon(icon);
213     gtk_window->add_accel_group(accels);
214     jcp->signal_changed().connect(
215 	sigc::mem_fun(this, &IRWindow::load_state));
216     machine.signal_impresp_list().connect(
217 	sigc::mem_fun(this, &IRWindow::on_enumerate));
218 
219     // reset display
220     file_changed("", 0, 0, 0, "");
221     on_delay_changed(0, 0);
222     on_offset_changed(0, 0);
223     on_length_changed(0, 0);
224 }
225 
~IRWindow()226 IRWindow::~IRWindow() {
227     delete gtk_window;
228     delete audio_buffer;
229 }
230 
231 /*
232 ** helper functions
233 */
234 
set_val(Gxw::ControlParameter * sample_display,Gxw::ControlParameter * ms_display,double value,int fs)235 int IRWindow::set_val(Gxw::ControlParameter *sample_display,
236                       Gxw::ControlParameter *ms_display,
237                       double value, int fs) {
238     double s1, s2;
239     if (fs) {
240         s1 = value;
241         s2 = (value*1000.0)/fs;
242     } else {
243         s1 = 0;
244         s2 = 0;
245     }
246     ms_display->cp_set_value(s2);
247     sample_display->cp_set_value(s1);
248     return sample_display->cp_get_int_value();
249 }
250 
file_changed(Glib::ustring filename,int rate,int length,int channels,Glib::ustring format)251 void IRWindow::file_changed(Glib::ustring filename, int rate, int length,
252                             int channels, Glib::ustring format) {
253     Glib::ustring s_rate, s_length, s_channels;
254     if (filename.empty()) {
255         filename = "no file selected";
256         s_length = s_rate = format = s_channels = "--";
257     } else {
258         ms = rate/1000.0;
259         wDelay->set_range(0, 5*rate);
260         wDelay_ms->set_range(0, 5*1000);
261         wOffset->set_range(0, length-1);
262         wOffset_ms->set_range(0, (length-1)*1000.0/rate);
263         wLength->set_range(0, length);
264         wLength_ms->set_range(0, (length)*1000.0/rate);
265         s_length = (boost::format("%1%") % length).str();
266         s_rate = (boost::format("%1%") % rate).str();
267 	s_channels = (boost::format("%1%") % channels).str();
268     }
269     wSamples->set_text(s_length);
270     wSampleRate->set_text(s_rate);
271     wFormat->set_text(format);
272     wChan->set_text(s_channels);
273     if (nchan != 1) {
274 	wChannelbox->set_sensitive(channels >= 2);
275     }
276     wFilename->set_text(Glib::path_get_dirname(filename));
277 }
278 
load_state(const gx_engine::GxJConvSettings * jcs)279 void IRWindow::load_state(const gx_engine::GxJConvSettings* jcs) {
280     string path = jcs->getFullIRPath();
281     if (path.empty()) {
282 	wIredit->set_ir_data(0, 0, 0, 0);
283         return;
284     }
285     gx_engine::GxJConvSettings jc;
286     make_state(jc);
287     if (jc == *jcs) {
288 	return;
289     }
290     autogain_conn.block();
291     wGain_correction->set_active(jcs->getGainCor());
292     autogain_conn.unblock();
293     load_data(path, jcs->getOffset(), jcs->getDelay(), jcs->getLength(), jcs->getGainline());
294     reload_impresp_list();
295 }
296 
297 Gainline IRWindow::gain0 = Gainline();
298 
load_data(Glib::ustring f,int offset,int delay,int length,const Gainline & gain)299 bool IRWindow::load_data(Glib::ustring f, int offset, int delay, int length, const Gainline& gain) {
300     filename = f;
301     int audio_type, audio_form, audio_rate;
302     float *buffer;
303     if (!machine.read_audio(filename, &audio_size, &audio_chan, &audio_type, &audio_form, &audio_rate, &buffer)) {
304 	return false;
305     }
306     Glib::ustring enc;
307     switch (audio_type) {
308     case gx_engine::Audiofile::TYPE_OTHER: enc = "???"; break;
309     case gx_engine::Audiofile::TYPE_CAF: enc = "CAF"; break;
310     case gx_engine::Audiofile::TYPE_WAV: enc = "WAV"; break;
311     case gx_engine::Audiofile::TYPE_AIFF: enc = "AIFF"; break;
312     case gx_engine::Audiofile::TYPE_AMB: enc = "AMB"; break;
313     }
314     enc += " ";
315     switch (audio_form) {
316     case gx_engine::Audiofile::FORM_OTHER: enc += "?"; break;
317     case gx_engine::Audiofile::FORM_16BIT: enc += "16 bit"; break;
318     case gx_engine::Audiofile::FORM_24BIT: enc += "24 bit"; break;
319     case gx_engine::Audiofile::FORM_32BIT: enc += "32 bit"; break;
320     case gx_engine::Audiofile::FORM_FLOAT: enc += "float"; break;
321     }
322     delete[] audio_buffer;
323     audio_buffer = buffer;
324     file_changed(filename, audio_rate, audio_size, audio_chan, enc);
325     if (!length) {
326 	length = audio_size;
327     }
328     wIredit->set_state(audio_buffer, audio_chan, audio_size, audio_rate, offset, offset+length, delay-offset, gain);
329     if (wSum) {
330 	wSum->set_active(true);
331     }
332     wLog->set_active(true);
333     return true;
334 }
335 
calc_normalized_gain(int offset,int length,const Gainline & points)336 double IRWindow::calc_normalized_gain(int offset, int length, const Gainline& points) {
337     if (audio_chan == 0) {
338 	return 1.0;
339     }
340     double gain = 0.0;
341     unsigned int idx = 0; // current index in gainline point array
342     double gp = 0.0, fct = 0.0; // calculated parameter of interpolation line
343     if (points.size()) {
344         while (points[idx].i < offset) {
345             idx++;
346             assert(idx < points.size());
347         }
348         if (points[idx].i > offset) {
349             idx--;
350 	    gx_engine::GxConvolver::compute_interpolation(fct, gp, idx, points, 0);
351         }
352     }
353     for (int i = offset; i < offset+length; i++) {
354         if (idx+1 < points.size() && points[idx].i == i) {
355             gx_engine::GxConvolver::compute_interpolation(fct, gp, idx, points, 0);
356         }
357         double g = pow(10, gp + i*fct);
358         for (int j = 0; j < audio_chan; j++) {
359             double v = audio_buffer[i*audio_chan+j] * g;
360             gain += v*v;
361         }
362     }
363     gain = sqrt(gain / audio_chan);
364     if (gain != 0.0) {
365         gain = 1 / gain;
366     }
367     return gain;
368 }
369 
make_state(gx_engine::GxJConvSettings & jc)370 void IRWindow::make_state(gx_engine::GxJConvSettings& jc) {
371     Gainline gainline = wIredit->get_gain();
372     unsigned int offset = wIredit->get_offset();
373     unsigned int length = wIredit->get_length();
374     double gain = calc_normalized_gain(offset, length, gainline);
375     jc.setDelay(wIredit->get_delay());
376     jc.setOffset(offset);
377     jc.setLength(length);
378     jc.setFullIRPath(filename);
379     jc.setGainline(gainline);
380     jc.setGain(gain);
381     jc.setGainCor(wGain_correction->get_active());
382 }
383 
save_state()384 void IRWindow::save_state() {
385     gx_engine::GxJConvSettings jc;
386     make_state(jc);
387     jcp->set(jc);
388 }
389 
390 /**
391 ** signal functions
392 */
393 
on_combo_changed()394 void IRWindow::on_combo_changed() {
395     Gtk::TreeModel::iterator iter = wcombo->get_active();
396     if (iter) {
397         Gtk::TreeModel::Row row = *iter;
398         if (row) {
399             std::string fname = row[columns.filename];
400 	    if (fname != jcp->get_value().getIRFile()) {
401 		load_data(Glib::build_filename(current_combo_dir, fname));
402 		save_state();
403             }
404         }
405     }
406 }
407 
on_dircombo_changed()408 void IRWindow::on_dircombo_changed() {
409     Gtk::TreeModel::iterator iter = dircombo->get_active();
410     if (iter) {
411 	std::string dir;
412 	iter->get_value(1, dir);
413 	if (dir != current_combo_dir) {
414 	    machine.reload_impresp_list(dir);
415         }
416     }
417 }
418 
reload_impresp_list()419 void IRWindow::reload_impresp_list() {
420     std::string path = jcp->get_value().getIRDir();
421     if (path == "~/") {  // cruft in old files
422 	path = getenv("HOME");
423     }
424     string irfile = jcp->get_value().getIRFile();
425     if (current_combo_dir == path) {
426 	Gtk::TreeNodeChildren ch = model->children();
427 	for (Gtk::TreeIter i = ch.begin(); i != ch.end(); ++i) {
428 	    if (i->get_value(columns.filename) == irfile) {
429 		wcombo->set_active(i);
430 	    }
431 	}
432 	return;
433     }
434     machine.reload_impresp_list(path);
435 }
436 
437 // reload the treelist for the combobox
on_enumerate(const std::string & path,const std::vector<gx_system::FileName> & l)438 void IRWindow::on_enumerate(const std::string& path, const std::vector<gx_system::FileName>& l) {
439     if (current_combo_dir == path) {
440 	return;
441     }
442     current_combo_dir = path;
443     string irfile = jcp->get_value().getIRFile();
444     model->clear();
445     Gtk::TreeIter j;
446     wcombo->unset_model();
447     model->set_sort_column(Gtk::TreeSortable::DEFAULT_UNSORTED_COLUMN_ID, Gtk::SORT_ASCENDING);
448     for (std::vector<gx_system::FileName>::const_iterator f = l.begin(); f != l.end(); ++f) {
449 	Gtk::TreeIter i = model->append();
450 	i->set_value(columns.displayname, f->displayname);
451 	i->set_value(columns.filename, f->filename);
452 	if (f->filename == irfile) {
453 	    j = i;
454 	}
455     }
456     model->set_sort_column(columns.displayname, Gtk::SORT_ASCENDING);
457     wcombo->set_model(model);
458     if (j) {
459 	wcombo->set_active(j);
460     }
461     if (dircombo->is_visible()) {
462 	Gtk::TreeNodeChildren ch = dircombo->get_model()->children();
463 	for (Gtk::TreeIter di = ch.begin(); di != ch.end(); ++di) {
464 	    std::string p;
465 	    di->get_value(1, p);
466 	    if (p == current_combo_dir) {
467 		dircombo->set_active(di);
468 		break;
469 	    }
470 	}
471     }
472 }
473 
on_linear()474 void IRWindow::on_linear() {
475     wIredit->set_log(not wLinear->get_active());
476 }
477 
on_left()478 void IRWindow::on_left() {
479     if (wLeft->get_active()) {
480         wIredit->set_channel(0);
481     }
482 }
483 
on_right()484 void IRWindow::on_right() {
485     if (wRight->get_active()) {
486         wIredit->set_channel(1);
487     }
488 }
489 
on_sum()490 void IRWindow::on_sum() {
491     if (wSum->get_active()) {
492         wIredit->set_channel(-1);
493     }
494 }
495 
on_delay_changed(int delay,int fs)496 void IRWindow::on_delay_changed(int delay, int fs) {
497     int d = static_cast<int>(round(set_val(wDelay, wDelay_ms, delay, fs)));
498     if (d != delay) {
499         wIredit->set_delay(d);
500     }
501 }
502 
on_offset_changed(int offset,int fs)503 void IRWindow::on_offset_changed(int offset, int fs) {
504     set_val(wOffset, wOffset_ms, offset, fs);
505 }
506 
on_length_changed(int length,int fs)507 void IRWindow::on_length_changed(int length, int fs) {
508     set_val(wLength, wLength_ms, length, fs);
509 }
510 
on_reset_clicked()511 void IRWindow::on_reset_clicked() {
512     gx_engine::GxJConvSettings jc;
513     jc.setDelay(0);
514     jc.setOffset(0);
515     jc.setLength(audio_size);
516     jc.setFullIRPath(filename);
517     jc.setGainline(gain0);
518     jc.setGain(calc_normalized_gain(0, audio_size, gain0));
519     jc.setGainCor(true);
520     jcp->set(jc);
521     const char *params[] = {"jconv.balance", "jconv.diff_delay", "jconv.gain", "jconv.wet_dry", 0};
522     for (const char **p = params; *p; ++p) {
523 	gx_engine::Parameter& pm = machine.get_parameter(*p);
524 	pm.stdJSON_value();
525 	pm.setJSON_value();
526     }
527 }
528 
on_delay_delta_format_value(double v)529 Glib::ustring IRWindow::on_delay_delta_format_value(double v) {
530     Glib::ustring s = "";
531     if (v < 0.0) {
532         v = -v;
533         s = " R";
534     } else if (v > 0.0) {
535         s = " L";
536     }
537     // boost::format does not support "%*f"
538     Glib::ustring fmt = (boost::format("%%.%df%%s") % wDelay_delta->property_digits()).str();
539     return (boost::format(fmt) % v % s).str();
540 }
541 
on_max_scale_reached(bool v)542 void IRWindow::on_max_scale_reached(bool v) {
543     wIncr->set_sensitive(not v);
544 }
545 
on_min_scale_reached(bool v)546 void IRWindow::on_min_scale_reached(bool v) {
547     wDecr->set_sensitive(not v);
548 }
549 
on_open()550 void IRWindow::on_open() {
551     static Glib::ustring hostname = "localhost";
552     if (! machine.get_jack()) {
553         hostname = Gio::Resolver::get_default()->lookup_by_address
554           (Gio::InetAddress::create( machine.get_options().get_rpcaddress()));
555     }
556     Glib::ustring title = hostname + ": Select Impulse Response";
557     Gtk::FileChooserDialog d(*gtk_window, title);
558     d.set_local_only(false);
559     d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
560     d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
561     d.add_shortcut_folder_uri(Glib::filename_to_uri(GX_SOUND_BPA_DIR, hostname));
562     d.add_shortcut_folder_uri(Glib::filename_to_uri(GX_SOUND_BPB_DIR, hostname));
563     d.add_shortcut_folder_uri(Glib::filename_to_uri(string(getenv("HOME")) + string("/.config/guitarix/IR"), hostname));
564     auto wav = Gtk::FileFilter::create();
565     wav->set_name("WAV Files");
566     wav->add_mime_type("audio/x-wav");
567     wav->add_mime_type("audio/x-aiff");
568     d.add_filter(wav);
569     auto audio = Gtk::FileFilter::create();
570     audio->set_name("Audio Files");
571     audio->add_mime_type("audio/*");
572     d.add_filter(audio);
573     auto all = Gtk::FileFilter::create();
574     all->add_pattern("*");
575     all->set_name("All Files");
576     d.add_filter(all);
577     if (!filename.empty()) {
578         d.set_uri(Glib::filename_to_uri (filename, hostname));
579     } else {
580         d.set_current_folder_uri(Glib::filename_to_uri (string(getenv("HOME")) + string("/"), hostname));
581     }
582     if (d.run() != Gtk::RESPONSE_OK) {
583         return;
584     }
585     filename = Glib::filename_from_uri(d.get_uri(), hostname);
586     Gtk::RecentManager::Data data;
587     bool result_uncertain;
588     data.mime_type = Gio::content_type_guess(filename, "", result_uncertain);
589     data.app_name = "guitarix";
590     data.groups.push_back("impulseresponse");
591     Gtk::RecentManager::get_default()->add_item(d.get_uri(), data);
592     load_data(filename);
593     save_state();
594     reload_impresp_list();
595 }
596 
on_home()597 void IRWindow::on_home() {
598     wIredit->home();
599 }
600 
on_jump_zoom_mark()601 void IRWindow::on_jump_zoom_mark() {
602     wIredit->jump_zoom_mark();
603 }
604 
on_decr()605 void IRWindow::on_decr() {
606     wIredit->decr_scale(0.0);
607 }
608 
on_incr()609 void IRWindow::on_incr() {
610     wIredit->incr_scale(0.0);
611 }
612 
on_m_delay_changed()613 void IRWindow::on_m_delay_changed() {
614     wIredit->set_delay(wDelay->cp_get_int_value());
615 }
616 
on_ms_delay_changed()617 void IRWindow::on_ms_delay_changed() {
618     wIredit->set_delay(get_ms(wDelay_ms));
619 }
620 
on_m_offset_changed()621 void IRWindow::on_m_offset_changed() {
622     wIredit->set_offset(wOffset->cp_get_int_value());
623 }
624 
on_ms_offset_changed()625 void IRWindow::on_ms_offset_changed() {
626     wIredit->set_offset(get_ms(wOffset_ms));
627 }
628 
on_m_length_changed()629 void IRWindow::on_m_length_changed() {
630     wIredit->set_length(wLength->cp_get_int_value());
631 }
632 
on_ms_length_changed()633 void IRWindow::on_ms_length_changed() {
634     wIredit->set_length(get_ms(wLength_ms));
635 }
636 
on_apply_button_clicked()637 void IRWindow::on_apply_button_clicked() {
638     machine.pluginlist_lookup_plugin(jcp->group_id())->set_on_off(true);
639     save_state();
640 }
641 
destroy_self()642 void IRWindow::destroy_self() {
643     delete this;
644 }
645 
on_window_hide()646 void IRWindow::on_window_hide() {
647     Glib::signal_idle().connect(
648         sigc::bind_return(sigc::mem_fun(*this, &IRWindow::destroy_self), false));
649 }
650 
on_cancel_button_clicked()651 void IRWindow::on_cancel_button_clicked() {
652     gtk_window->hide();
653 }
654 
on_ok_button_clicked()655 void IRWindow::on_ok_button_clicked() {
656     save_state();
657     gtk_window->hide();
658 }
659 
on_preset_popup_clicked()660 void IRWindow::on_preset_popup_clicked() {
661     Glib::ustring name = Glib::path_get_basename(filename);
662     Glib::ustring::size_type n = name.find_last_of('.');
663     if (n != Glib::ustring::npos) {
664 	name.erase(n);
665     }
666     save_state();
667     new PluginPresetPopup(machine.pluginlist_lookup_plugin(jcp->group_id())->get_pdef(), machine, name);
668 }
669 
on_help_clicked()670 void IRWindow::on_help_clicked() {
671     wHelp->show();
672 }
673 
on_gain_button_toggled()674 void IRWindow::on_gain_button_toggled() {
675     save_state();
676 }
677 
on_key_press_event(GdkEventKey * event)678 bool IRWindow::on_key_press_event(GdkEventKey *event) {
679     if (event->keyval == GDK_KEY_Escape && (event->state & Gtk::AccelGroup::get_default_mod_mask()) == 0) {
680 	gtk_window->hide();
681 	return true;
682     }
683     return false;
684 }
685 
reload_and_show()686 void IRWindow::reload_and_show() {
687     if (gtk_window->get_visible() && !(gtk_window->get_window()->get_state() & Gdk::WINDOW_STATE_ICONIFIED)) {
688 	gtk_window->hide();
689     } else {
690 	load_state(&jcp->get_value());
691 	gtk_window->present();
692     }
693 }
694 
695 } // namespace gx_jconv
696