// ------------------------------------------------------------------------ // interface.cpp: Main user interface widget for ecamegapedal // Copyright (C) 2001-2004 Kai Vehmanen (kai.vehmanen@wakkanet.fi) // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // ------------------------------------------------------------------------ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include /* POSIX: getpid() */ #include /* POSIX: getpid() */ #ifdef ECA_COMPILE_JACK #include #endif #include #include #include #include #include "dbc.h" #include "version.h" #include "qeaudiotrap.h" #include "qevumeter.h" #include "qebuttonrow.h" #include "qechainoperatorinput.h" #include "interface.h" QEInterface::QEInterface(QWidget *parent, const char *name) : QWidget(parent, name) { setCaption("Ecamegapedal v" + QString(ecamegapedal_version) + " - the real audio processor!"); qApp->setMainWidget(this); accel_repp = new QAccel(this); copinput_repp = 0; esession_repp = new ECA_SESSION(); ectrl_repp = new ECA_CONTROL(esession_repp); input_rep = "/dev/dsp"; output_rep = "/dev/dsp"; io_changed_rep = true; /* to trigger full_stop if start is issued without first calling initialize() */ srate_rep = 0; bufsize_rep = 0; fetch_defaults_from_jack(); init_layout(); } QEInterface::~QEInterface(void) { delete ectrl_repp; delete esession_repp; } #ifdef ECA_COMPILE_JACK static void ecamegapedal_jack_error_callback(const char *desc) { // fprintf(stderr, "libjack error: %s.\n", desc); } #endif void QEInterface::fetch_defaults_from_jack(void) { #ifdef ECA_COMPILE_JACK int pid = getpid(); string cname = "ecamegapedal-ctrl-" + kvu_numtostr(pid); jack_set_error_function(ecamegapedal_jack_error_callback); bool env_changed = false; char* oldenv = getenv("JACK_NO_START_SERVER"); if (oldenv == NULL) { env_changed = true; setenv("JACK_NO_START_SERVER", "yes", 1); } jack_client_t *client = jack_client_new (cname.c_str()); if (client != 0) { srate_rep = jack_get_sample_rate(client); bufsize_rep = static_cast(jack_get_buffer_size(client)); jack_client_close(client); client = 0; /* FIXME: add a check that makes sure also ecasound is configured * with JACK enabled */ input_rep = "jack_alsa"; output_rep = "jack_alsa"; } if (env_changed == true) { unsetenv("JACK_NO_START_SERVER"); } DBC_CHECK(client == 0); #endif } void QEInterface::init_layout(void) { toplayout_repp = new QVBoxLayout( this ); QBoxLayout* bottomrow = new QHBoxLayout(); init_buttons(); init_io_rows(); copinput_repp = new QEChainOperatorInput(this, "qechainop"); QObject::connect(copinput_repp, SIGNAL(parameters_changed()), this, SLOT(update_processing_parameters())); QObject::connect(copinput_repp, SIGNAL(operator_changed()), this, SLOT(update_processing_operator())); toplayout_repp->addWidget(copinput_repp, 2); toplayout_repp->addLayout(io_rows_repp, 0); toplayout_repp->addWidget(buttonrow_repp, 0); vumeter_repp = new QEVUMeter(this, 0); vumeter_repp->setDelay(500); toplayout_repp->addWidget(vumeter_repp, 1); init_bottomrow(bottomrow); toplayout_repp->addLayout(bottomrow,0); } void QEInterface::init_bottomrow(QBoxLayout* bottomrow) { init_statusbar(); bottomrow->addWidget(statusbar_repp, 2, 0); } void QEInterface::init_statusbar(void) { statusbar_repp = new QStatusBar(this, "qsbar"); statusbar_repp->message(QString("Ecamegapedal v") + QString(ecamegapedal_version) + QString(" ready.")); QTimer *timer = new QTimer( this ); connect( timer, SIGNAL(timeout()), this, SLOT(update_statusbar())); timer->start( 500, false); } void QEInterface::update_statusbar(void) { static string last_epstatus; string new_epstatus = ectrl_repp->engine_status(); position_update(); // if (new_epstatus == last_epstatus) return; // else last_epstatus = new_epstatus; string pos = kvu_numtostr(curpos_rep, 3); statusbar_repp->message(QString(" [ ") + last_epstatus.c_str() + ", " + QString(pos.c_str()) + "sec ] . (C) 2001-2004 Kai Vehmanen"); } void QEInterface::init_io_rows(void) { io_rows_repp = new QGridLayout(0, 2, 4, 2, -1, "io_grid"); QLabel* tmp = new QLabel("&Input: ", this, 0); io_rows_repp->addWidget(tmp, 0, 0); inputrow_name_repp = new QLineEdit(this, "inputrow_name"); inputrow_name_repp->setText(input_rep.c_str()); io_rows_repp->addWidget(inputrow_name_repp, 0, 1); tmp->setBuddy(inputrow_name_repp); // get shortcut from label -artham // inputrow_format_repp = new QLineEdit(this, "inputrow_format"); // io_rows_repp->addWidget(inputrow_format_repp, 0, 2); QPushButton* inputrow_browse = new QPushButton("&Browse", this, 0); io_rows_repp->addWidget(inputrow_browse, 0, 3); tmp = new QLabel("&Output: ", this, 0); io_rows_repp->addWidget(tmp, 1, 0); outputrow_name_repp = new QLineEdit(this, "outputrow_name"); outputrow_name_repp->setText(output_rep.c_str()); io_rows_repp->addWidget(outputrow_name_repp, 1, 1); tmp->setBuddy(outputrow_name_repp); // get shortcut from label -artham // outputrow_format_repp = new QLineEdit(this, "outputrow_format"); // io_rows_repp->addWidget(outputrow_format_repp, 1, 2); QPushButton* outputrow_browse = new QPushButton("Bro&wse", this, 0); io_rows_repp->addWidget(outputrow_browse, 1, 3); io_rows_repp->setMargin(5); QObject::connect(inputrow_browse, SIGNAL(clicked()), this, SLOT(button_input_browse())); QObject::connect(inputrow_name_repp, SIGNAL(textChanged(const QString&)), this, SLOT(set_input_name(const QString&))); QObject::connect(outputrow_browse, SIGNAL(clicked()), this, SLOT(button_output_browse())); QObject::connect(outputrow_name_repp, SIGNAL(textChanged(const QString&)), this, SLOT(set_output_name(const QString&))); // remove automatic alt-* shortcuts -artham // fixme: should remove from labels too... outputrow_browse->setAccel(0); inputrow_browse->setAccel(0); accel_repp->connectItem(accel_repp->insertItem(CTRL+Key_B), this, SLOT(button_input_browse())); accel_repp->connectItem(accel_repp->insertItem(CTRL+Key_W), this, SLOT(button_output_browse())); accel_repp->connectItem(accel_repp->insertItem(CTRL+Key_I), inputrow_name_repp, SLOT(setFocus())); accel_repp->connectItem(accel_repp->insertItem(CTRL+Key_O), outputrow_name_repp, SLOT(setFocus())); } void QEInterface::init_buttons(void) { buttonrow_repp = new QEButtonRow(this, "buttonrow"); QButton* tmp = new QPushButton("Begin", buttonrow_repp); tmp->setPixmap(QPixmap(QString(PACKAGE_DATA_DIR) + "/pixmaps/begin_idx.png")); QToolTip::add(tmp, "Rewind begin (ctrl-g)"); buttonrow_repp->add_button(tmp, CTRL+Key_G, this, SLOT(button_rewind_begin())); tmp = new QPushButton("Rewind", buttonrow_repp); tmp->setPixmap(QPixmap(QString(PACKAGE_DATA_DIR) + "/pixmaps/rewind_idx.png")); //QToolTip::add(tmp, "Rewind (<)"); buttonrow_repp->add_button(tmp, Key_Less, this, SLOT(button_rewind())); tmp = new QPushButton("Start", buttonrow_repp); tmp->setPixmap(QPixmap(QString(PACKAGE_DATA_DIR) + "/pixmaps/start_idx.png")); //QToolTip::add(tmp, "Start (ctrl-t)"); buttonrow_repp->add_button(tmp, CTRL+Key_T, this, SLOT(start_processing())); tmp = new QPushButton("Stop", buttonrow_repp); tmp->setPixmap(QPixmap(QString(PACKAGE_DATA_DIR) + "/pixmaps/stop_idx.png")); //QToolTip::add(tmp, "Stop (ctrl-s)"); buttonrow_repp->add_button(tmp, CTRL+Key_S, this, SLOT(stop_processing())); tmp = new QPushButton("Forward", buttonrow_repp); tmp->setPixmap(QPixmap(QString(PACKAGE_DATA_DIR) + "/pixmaps/forward_idx.png")); //QToolTip::add(tmp, "Forward (>)"); buttonrow_repp->add_button(tmp, SHIFT+Key_Greater, this, SLOT(button_forward())); tmp = new QPushButton("Quit", buttonrow_repp); tmp->setPixmap(QPixmap(QString(PACKAGE_DATA_DIR) + "/pixmaps/quit_idx.png")); //QToolTip::add(tmp, "Quit (ctrl-q)"); buttonrow_repp->add_button(tmp, CTRL+Key_Q, qApp, SLOT(closeAllWindows())); } void QEInterface::initialize(void) { /* make sure we're not running */ if (ectrl_repp->is_connected() == true) stop_processing(); /* clear out the previous chainsetup */ if (ectrl_repp->selected_chainsetup() == "ecamegapedal") { ectrl_repp->remove_chainsetup(); } /* initialize a new chainsetup */ ectrl_repp->add_chainsetup("ecamegapedal"); #ifdef ECA_COMPILE_JACK ectrl_repp->command("cs-set-param -G:jack,ecamegapedal,sendrecv"); #endif ectrl_repp->set_chainsetup_parameter("-B:rtlowlatency"); if (bufsize_rep > 0) ectrl_repp->set_chainsetup_buffersize(bufsize_rep); if (srate_rep > 0) { ECA_AUDIO_FORMAT afmt = ectrl_repp->default_audio_format(); afmt.set_samples_per_second(srate_rep); ectrl_repp->set_default_audio_format(afmt); } ectrl_repp->add_chain("ecamegapedal"); ectrl_repp->add_audio_input(input_rep); ectrl_repp->add_audio_output(output_rep); io_changed_rep = false; } void QEInterface::start_processing(bool onlyengine) { bool full_stop = false; if (io_changed_rep == true || ectrl_repp->is_connected() != true) full_stop = true; if (ectrl_repp->is_running() == true) ectrl_repp->stop_on_condition(); if (full_stop == true) initialize(); ectrl_repp->select_chainsetup("ecamegapedal"); ectrl_repp->select_chain("ecamegapedal"); ectrl_repp->clear_chains(); /* create a new audiotrap object, ownership of the object is transfered to libecasound */ QEAudioTrap* atrap = new QEAudioTrap(this, 0, vumeter_repp); if (copinput_repp != 0) { copinput_repp->update_results(); const OPERATOR* c = dynamic_cast(copinput_repp->result()); if (c != 0) { OPERATOR* new_c = c->new_expr(); for(int n = 0; n < new_c->number_of_params(); n++) new_c->set_parameter(n + 1, c->get_parameter(n + 1)); ectrl_repp->add_chain_operator(dynamic_cast(new_c)); } } ectrl_repp->add_chain_operator(dynamic_cast(atrap)); if (full_stop == true) ectrl_repp->connect_chainsetup(); if (ectrl_repp->is_connected() == true && ectrl_repp->is_running() != true) { if (onlyengine == true) { ectrl_repp->command("engine-launch"); if (ectrl_repp->last_type() == "e") { /* libecasound v9 or older */ ectrl_repp->command("start"); } } else { ectrl_repp->command("start"); } } else { QMessageBox* mbox = new QMessageBox(this, "mbox"); mbox->information(this, "ecamegapedal", "Unable to start processing!",0); io_changed_rep = true; } } void QEInterface::check_size(void) { QWidget *d = dynamic_cast(QApplication::desktop()); int h = d->height(); // cerr << "desktop height: " << h << endl; // cerr << "my height: " << height() << endl; if (h - 40 < height()) { resize(minimumSizeHint()); toplayout_repp->invalidate(); updateGeometry(); // cerr << "my new height: " << height() << endl; } } void QEInterface::update_processing_operator(void) { if (ectrl_repp->is_running() == true) { start_processing(false); } check_size(); } void QEInterface::update_processing_parameters(void) { if (ectrl_repp->is_running() == true) { if (copinput_repp != 0) { /* get the chainop controller by the GUI controls */ copinput_repp->update_results(); const CHAIN_OPERATOR* newcop = copinput_repp->result(); if (newcop != 0) { /* select the current setup */ ectrl_repp->select_chainsetup("ecamegapedal"); ectrl_repp->select_chain("ecamegapedal"); /* get the active chainop from the engine */ ectrl_repp->select_chain_operator(1); const CHAIN_OPERATOR* cop = 0; cop = ectrl_repp->get_chain_operator(); if (cop != 0) { for(int n = 0; n < cop->number_of_params(); n++) { ectrl_repp->select_chain_operator_parameter(n + 1); ectrl_repp->set_chain_operator_parameter(newcop->get_parameter(n + 1)); } } } } } check_size(); } void QEInterface::stop_processing(void) { if (ectrl_repp->is_running() == true) ectrl_repp->stop_on_condition(); if (ectrl_repp->is_connected() == true) ectrl_repp->disconnect_chainsetup(); } void QEInterface::close_session(void) { } void QEInterface::button_input_browse(void) { QFileDialog* fdialog = new QFileDialog(0, 0, true); fdialog->setMode(QFileDialog::ExistingFile); fdialog->setCaption("Selecting an input file..."); fdialog->setDir(current_dir_rep.c_str()); fdialog->exec(); QString fname = fdialog->selectedFile(); if (!fname.isEmpty()) { current_dir_rep = string(fdialog->dirPath().latin1()); inputrow_name_repp->setText(fname); } } void QEInterface::button_output_browse(void) { QFileDialog* fdialog = new QFileDialog(0, 0, true); fdialog->setMode(QFileDialog::AnyFile); fdialog->setCaption("Selecting an output file..."); fdialog->setDir(current_dir_rep.c_str()); fdialog->exec(); QString fname = fdialog->selectedFile(); if (!fname.isEmpty()) { current_dir_rep = string(fdialog->dirPath().latin1()); outputrow_name_repp->setText(fname); } } void QEInterface::button_rewind_begin(void) { ectrl_repp->command("setpos 0"); } void QEInterface::button_rewind(void) { ectrl_repp->command("rw 5"); } void QEInterface::button_forward(void) { ectrl_repp->command("fw 5"); } const string& QEInterface::input_name(void) const { return(input_rep); } const string& QEInterface::output_name(void) const { return(output_rep); } void QEInterface::set_input_name(const QString& q) { string s (q.latin1()); if (s != input_rep) { input_rep = s; io_changed_rep = true; inputrow_name_repp->setText(q); } } void QEInterface::set_output_name(const QString& q) { string s (q.latin1()); if (s != output_rep) { output_rep = s; io_changed_rep = true; outputrow_name_repp->setText(q); } } void QEInterface::position_update(void) { curpos_rep = ectrl_repp->position_in_seconds_exact(); } void QEInterface::not_implemented(void) { QMessageBox* mbox = new QMessageBox(this, "mbox"); mbox->information(this, "ecamegapedal", "This feature is not implemented...",0); }