Logo Search packages:      
Sourcecode: ardour version File versions

ksi.cc

/*
    Copyright (C) 2001 Paul Davis
    
    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., 675 Mass Ave, Cambridge, MA 02139, USA.

    $Id: ksi.cc,v 1.79 2004/11/29 13:40:03 pauld Exp $
*/

#include <string>
#include <algorithm>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cerrno>
#include <sys/socket.h>
#include <netinet/in.h>
#include <cstdlib>
#include <string>
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>

#include <pbd/error.h>
#include <pbd/failed_constructor.h>
#include <pbd/lockmonitor.h>
#include <pbd/undo.h>

#include <sigc++/signal_system.h>
#include <sigc++/bind.h>

#include <ardour/ardour.h>
#include <ardour/audioengine.h>
#include <ardour/session.h>
#include <ardour/session_route.h>
#include <ardour/configuration.h>
#include <ardour/ladspa_plugin.h>
#include <ardour/plugin_manager.h>
#include <ardour/diskstream.h>
#include <ardour/route.h>
#include <ardour/audio_track.h>
#include <ardour/insert.h>

#include "physical_keyboard.h"
#include "ksi.h"
#include "opts.h"

#include "i18n.h"

using namespace SigC;
using namespace KSI_ARDOUR;
using namespace ARDOUR;
using namespace std;

sigset_t KSI::signals;
bool KSI::_die;
bool KSI::_saveable;
PBD::Lock KSI::die_lock;
PBD::NonBlockingLock KSI::screen_lock;
extern void die (void);
extern void die_gracefully (void);


void *
KSI::butler_thread (void *arg)

{
      struct sched_param sp;
      static KSI *ksi = (KSI *) arg;

            memset (&sp, 0, sizeof sp);
            sp.sched_priority = 0;
            if (sched_setscheduler(0, SCHED_OTHER, &sp) != 0) {
                  error << _("KSI_BUTLER: can't give up RT scheduling") << endmsg;
            }
            
                /* we are now ready to start. */
            {
                  PBD::LockMonitor lm(ksi->butler_lock, __LINE__, __FILE__);
                  pthread_cond_signal (&ksi->cond);
            }

            while (1) {
                  char buf[12];
                  struct timespec req;
                  SMPTE_Time smpte;
                  
                  memset(&req, 0, sizeof req);
                  memset (&buf, 0, 12);
                  req.tv_sec = 0;
                  req.tv_nsec = 100000000; // 100 ms
                  if (int err = nanosleep(&req, NULL) != 0) {
                        error << _("BUTLER: nanosleep failed...exiting") << strerror(err) << endmsg;
                        return 0;
                  }
                  mvwaddstr (ksi->lower_window, 4, 0, "Session Time: ");
                  
                  ksi->session->smpte_time(smpte);
                  if (smpte.negative) {
                        sprintf (buf, "-%02ld:%02ld:%02ld:%02ld", smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
                  } else {
                        sprintf (buf, "%02ld:%02ld:%02ld:%02ld", smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
                  }
                  mvwaddstr(ksi->lower_window, 4, 14, buf);
                  ksi->redraw_screen(false, true);
            }
}

void *
KSI::signal_thread (void *arg)

{
      int sig;
      int err;

      err = sigwait (&KSI::signals, &sig);

      if (err) {
            exit (1);
      }

      if (sig == 2) { // we got an interrupt
            fprintf(stderr, "INTERRUPT!\n");
            die_gracefully();
            /*NOTREACHED*/
            return 0;
      } else {
            fprintf (stderr, "SIGNAL %d CAUGHT!\n", sig);
            die ();
            /*NOTREACHED*/
            return 0;
      }
}

int
KSI::smpte_time_str(char *buf, jack_nframes_t when) {

      if (session) {
            SMPTE_Time smpte;

            session->smpte_time(when, smpte);
            if (smpte.negative) {
                  sprintf (buf, "-%02ld:%02ld:%02ld:%02ld", smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
            } else {
                  sprintf (buf, "%02ld:%02ld:%02ld:%02ld", smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
            }
            return 0;
      }
      return -1;
}

KSI::KSI (AudioEngine &eng, const string& server)
      : engine (eng),
        selection ("selection"),
        _track("track_group")

{
      string host;
      int port;
      
      pthread_cond_init(&cond, 0);
      _die = false;
      _saveable = false;
      _yn = false;
      display_is_remote = false;
      session = 0;
      scrub_speed = 1.00;
      _scrubbing = false;
      _location_page = 0;
      _location_cnt = 0;
      selection_cnt = 0;
      group_cnt = 0;
      p_amount = 0;
      g_amount = 0;

      if (server.length()) {

            int socket;
            string::size_type n;
            
            if ((n = server.find (':')) != string::npos) {
                  host = server.substr (0, n);
                  port = atoi (server.substr (n+1).c_str());
            } else {
                  struct servent *srv;


                  host = server;
                  if ((srv = getservbyname("remote_kbd", "tcp")) != 0) {
                        port = ntohs(srv->s_port);
                        free(srv);
                  } else {
                        port = 9763;
                  }
            }

            if ((socket = tcp_connect (host, port)) < 0) {
                  error << compose(_("cannot connect to %1"), server) << endmsg;
                  throw failed_constructor();
            }
            
            try {
                  keyboard = new PhysicalKeyboard (socket);
            }
            
            catch (failed_constructor& err) {
                  error << _("could not create proxy keyboard object") << endmsg;
                  throw err;
            }

            display_is_remote = true;
            if (catch_signals ()) {
                  throw failed_constructor ();
            }
            
            if (dup2 (socket, 1) < 0) {
                  error << compose(_("cannot reopen stdout as socket (%1"), strerror (errno)) << endmsg;
                  endwin ();
                  throw failed_constructor();
            }

            if (initialize_ui ()) {
                  throw failed_constructor ();
            }

      } else {

            if (initialize_ui ()) {
                  throw failed_constructor ();
            }
            
            try {
                  keyboard = new PhysicalKeyboard;
            }
            
            catch (failed_constructor& err) {
                  error << _("could not create direct keyboard object") << endmsg;
                  endwin ();
                  throw err;
            }

            if (catch_signals ()) {
                  throw failed_constructor ();
            }
      }

      push_selection_mode (Route);

      current_group = 0;
      paused = false;
      route_start = 0;
      io_start = 0;
      editing_insert = 0;

      keyboard->key_press.connect (slot (this, &KSI::key_press_handler));

      string::size_type commapos;

      if ((commapos = master_outs.find (',')) == string::npos) {
            error << compose(_("bad format for master outputs [%1]"), master_outs) << endmsg;
            throw failed_constructor();
      }

      /* allow user to use start-at-one channel ids */

      master_lr_channels.push_back (master_outs.substr (0, commapos));
      master_lr_channels.push_back (master_outs.substr (commapos+1));

      if ((commapos = control_outs.find (',')) == string::npos) {
            error << compose(_("bad format for control outputs [%1]"), control_outs) << endmsg;
            throw failed_constructor();
      }

      control_lr_channels.push_back (control_outs.substr (0, commapos));
      control_lr_channels.push_back (control_outs.substr (commapos+1));

      if (control_lr_channels[0] != master_lr_channels[0] ||
          control_lr_channels[1] != master_lr_channels[1]) {
            need_control_room_outs = true;
      } else {
            need_control_room_outs = false;
      }

      update_channel_range_display ();
      update_selection_mode_display ();
}

KSI::~KSI ()

{
      if (session) {
            if (safe_to_save()) {
                  fprintf (stderr, "saving session state.\n");
                  session->save_state("default");
            } else {
                  fprintf (stderr, "WARNING! session state saving disallowed!\n");
                  }
            delete session;
      }

      /* XXX problems here with the remote keyboard: we shut 
         the socket and so the UI dies. Need to keep stdout
         around as a different file descriptor, then
         switch back to it, or something.
      */

      engine.stop ();
      delete keyboard;
      endwin ();
}

int
KSI::run ()
{
      string spath = session_path;
      string sname;
      string::size_type pos;
      
      if ((pos = spath.find_last_of ('/')) == string::npos) {
            sname = spath;
      } else {
            sname = spath.substr(pos+1);
      }

      try { 
//          string path, name;
//          tokenize_fullpath(session_path, path, name);
            session = new Session (engine, spath, "default", 0);
      }
      
      catch (failed_constructor& err) {
            error << _("could not load new session") << endmsg;
            return -1;
      }

        // if we're not running, we lose! we cant tell how many output channels there are.

      info << _("starting engine") << endmsg;
      engine.start ();

      unsigned long limit = max (engine.n_physical_outputs(), session->nroutes());

      session->set_input_auto_connect(true);
      for (unsigned long n = 0; n < limit; ++n) {

            char buf[32];
            bool want_signals_and_paints = true;

            sprintf (buf, "Audio %lu", n+1);     /* XXX gack. this naming is private to the session */

                /* JHALL * * * W A R N I N G * * *
             *
             * renaming these initially created routes might cause a population explosion 
             */
            
            ARDOUR::Route* route = session->route_by_name (buf);
            ARDOUR::AudioTrack* track = 0;

            if (route == 0) {
                  route = new_route(with_diskstreams);
/* JHALL: to delete
                  if (with_diskstreams) {
                        route = session->new_audio_track ();
                        track = dynamic_cast<AudioTrack*> (route);
                  } else {
                        route = session->new_audio_route ();
                  }
*/
                  want_signals_and_paints = false;
            }
                  if (with_diskstreams)
                        track = dynamic_cast<AudioTrack*> (route);

            if (route != 0 && want_signals_and_paints) {
                  paint_channel_gain (n, route);
                  paint_channel_mute (n, route);
                  paint_channel_solo (n, route);

                  if (with_diskstreams) {
                        paint_channel_record_enable (n, track);
                        track->record_enable_changed.connect 
                              (bind (slot (this, &KSI::route_record_enable_changed), track, n));
                  }

                  route->solo_changed.connect (bind (slot (this, &KSI::route_solo_changed), route, n));
                  route->mute_changed.connect (bind (slot (this, &KSI::route_mute_changed), route, n));
                  route->gain_changed.connect (bind (slot (this, &KSI::route_gain_changed), route, n));
            }

            want_signals_and_paints = true;
      }
      
      if (need_control_room_outs) {

            if ((control_route = session->new_audio_route (0, 0)) == 0) {
                  error << _("ERROR unable to create control room bus") << endmsg;
                  throw failed_constructor();
            } 

            control_route->set_name ("CONTROL ROUTE", this);
      
            while (control_route->n_inputs() < 2) {
                  control_route->add_input_port ("", this);
            }

            while (control_route->n_outputs() < 2) {
                  control_route->add_output_port ("", this);
            }
      
            control_route->connect_output (control_route->output (0), control_lr_channels[0], this);
            control_route->connect_output (control_route->output (1), control_lr_channels[1], this);
      }
      
      session->mix_group_added.connect (slot (this, &KSI::add_group));
      session->RecordEnabled.connect (slot (this, &KSI::session_record_enable_changed));
      session->RecordDisabled.connect (slot (this, &KSI::session_record_enable_changed));
      session->TransportStateChange.connect (slot (this, &KSI::session_transport_state_change));
//    session->save_state ("default");

      /* set up 10 mix groups */

      for (guint32 x = 0; x < 10; x++) {
            char buf[32];
            
            sprintf (buf, "Group %u", x + 1);
            if (session->mix_group_by_name(buf) == 0) {
                  session->add_mix_group (buf);
            }
      }
      session->set_auto_play (false);

      update_transport_state_display ();
      start_butler_thread();
      Config->set_use_hardware_monitoring(false);

      return keyboard->main ();
}

int
KSI::catch_signals (void)

{
      pthread_t thread_id;

      sigemptyset (&signals);
      sigaddset(&signals, SIGALRM);
      sigaddset(&signals, SIGHUP);
      sigaddset(&signals, SIGINT);
      sigaddset(&signals, SIGQUIT);
      sigaddset(&signals, SIGILL);
      sigaddset(&signals, SIGTRAP);
      sigaddset(&signals, SIGABRT);
      sigaddset(&signals, SIGIOT);
      sigaddset(&signals, SIGFPE);
      sigaddset(&signals, SIGKILL);
      sigaddset(&signals, SIGUSR1);
      sigaddset(&signals, SIGSEGV);
      sigaddset(&signals, SIGUSR2);
      sigaddset(&signals, SIGPIPE);
      sigaddset(&signals, SIGTERM);
      sigaddset(&signals, SIGCHLD);
      sigaddset(&signals, SIGCONT);
      sigaddset(&signals, SIGSTOP);
      sigaddset(&signals, SIGTSTP);
      sigaddset(&signals, SIGTTIN);
      sigaddset(&signals, SIGTTOU);

      /* all child threads will inherit this mask */

      pthread_sigmask (SIG_BLOCK, &signals, 0);

      /* start a thread to wait for signals */

      if (pthread_create (&thread_id, 0, KSI::signal_thread, 0)) {
            error << _("cannot create signal catching thread") << endmsg;
            return -1;
      }

      pthread_detach (thread_id);

      return 0;
}

void
KSI::route_selected (guint32 which, SelectionType type, RouteGroup *grp)
{
      ARDOUR::Route *route;
      
      if (grp == &selection) {
            which += route_start;
      }
      
      char buf[32];
      snprintf (buf, sizeof(buf)-1, "Audio %u", which + 1);

      if ((route = session->route_by_name (buf)) != 0) {

            if (type == Replace) {
                  grp->clear ();
                  grp->add (route);
            } else if (type == Remove) {
                  grp->remove (route);
            } else {
                  grp->add (route);
                        // JHALL: should this be a set?
            }
            
            if ((grp == &selection) || (grp == &_track)) {
                  update_selection_display(grp);
            } else {
                  update_group_content_display (grp);
            }
            
      } else {
            info << compose(_("no such route %1"), which) << endmsg;
      }

}

void
KSI::plugin_selected (guint32 which, SelectionType type)

{
      ARDOUR::Route *mx = get_first_selected_route ();
      
      pop_selection_mode ();

      if (mx == 0) {
            return;
      }

      switch (type) {
      case Add:
      case Replace:
            add_plugin (mx, which + (plugin_page * selection_size));
            break;
            
      case Remove:
//          remove_plugin(mx, which);
            break;
      } 
}

void
KSI::insert_selected (guint32 which, SelectionType type)
{
      Redirect *redirect;

      ARDOUR::Route *mx = get_first_selected_route ();

      if (mx == 0) {
            return;
      }

      redirect = mx->nth_redirect (which);

      if (redirect == 0) {
            editing_insert = 0;
            info << compose(_("no such insert (%1)"), which) << endmsg;
            return;
      }
      
      if ((editing_insert = dynamic_cast<ARDOUR::PluginInsert *> (redirect)) == 0) {
            error << _("the selected insert is actually a send!") << endmsg;
            return;
      }

      info << compose(_("selected insert %1"), which + 1) << endmsg;
      
      switch (type) {
      case Remove:
            mx->remove_redirect (editing_insert, this);
            editing_insert = 0;
            insert_page = 0;
            show_inserts (insert_page, true);
            break;

      default:
            ensure_selection_mode (Parameter);
            parameter_page = 0;
            show_parameters (parameter_page, editing_insert);
      }
}

void
KSI::remove_location() 
{
      ARDOUR::Location *loc;

      if (session == 0) return;
      loc = session->locations()->current();
      if (loc == 0) {
            error << _("unable to remove location") << endmsg;
            return;
      }
      session->locations()->remove(loc);
}

void
KSI::add_location() {
      
      if (session) {
            ARDOUR::Location *loc;
            jack_nframes_t now = session->audible_frame();

            loc = new ARDOUR::Location (now, now, "UNNAMED");
            session->locations()->add(loc, true);
      }
      return;
}

void
KSI::remove_insert (ARDOUR::Route *mx, guint32 which)
{
}

void
KSI::start_insert_activate ()

{
}

void
KSI::start_insert_edit ()
{
      ensure_selection_mode (Insert);
      insert_page = 0;
      show_inserts (insert_page, true);
}

void
KSI::start_insert_add ()

{
      ensure_selection_mode (Plugin);
      plugin_page = 0;
      show_possible_plugins (plugin_page);
}

void
KSI::remove_inserts ()

{
      ARDOUR::Route *mx = get_first_selected_route ();

      if (mx == 0) {
            return;
      }

      mx->clear_redirects (this);

      /* XXX what will update the display if we're looking
         at this particular Route's insert list ?
      */
}

void
KSI::set_insert_state (bool yn)
{
      if (editing_insert == 0) {
            /* XXX programming error */
            return;
      }

      editing_insert->set_active (yn, this);
}

/* JHALL: make sure that insert_cnt == 0 before calling this function */

void
KSI::show_insert (Redirect *redirect)

{
      ARDOUR::PluginInsert *insert;

      if ((insert = dynamic_cast<ARDOUR::PluginInsert *> (redirect)) == 0) {
            /* XXX should handle sends one day */
            return;
      }

      wprintw (inserts_window, "%d %s %s\n", ++insert_cnt, 
             insert->active() ? " (ON)" : " (OFF)",
             insert->name().c_str());
}

int
KSI::show_inserts (guint32 page, bool show_active)
{
      ARDOUR::Route *mx = get_first_selected_route ();

      if (mx == 0) {
            return -1;
      }

      mvwaddstr (inserts_box, 0, 15, mx->name().c_str());
      werase (inserts_window);

      insert_cnt = 0;
      mx->foreach_redirect (this, &KSI::show_insert);

      redraw_screen ();
      return 0;
}

void
KSI::location_selected(guint32 which) {

      _location_cnt = which;
      if (session) {
                  session->locations()->apply(*this, &KSI::_location_selected);
            }
}

void
KSI::show_locations() {

      if (session) {
            session->locations()->apply(*this, &KSI::update_locations_display);
      }
}

int
KSI::update_current_location_display ()
{
      ARDOUR::Location *loc;
      char s_buf[12];

      if (session == 0) return -1;

      loc = session->locations()->current();

      if (loc == 0) {
            error << _("ERROR cannot use the current location") << endmsg;
            return -1;
      }

      mvwaddstr (locations_box, 0, 15, loc->name().c_str());
      werase (locations_window);

      if (smpte_time_str(s_buf, loc->start()) < 0) {
            error << _("PROGRAMMER ERROR! no session!") << endmsg;
            return -1;
      }
      mvwprintw(locations_window, 0, 0, "Start: %s", s_buf);
      if (smpte_time_str(s_buf, loc->end()) < 0) {
            error << _("PROGRAMMER ERROR! no session!") << endmsg;
            return -1;
      }
      mvwprintw(locations_window, 1, 0, "ENd: %s", s_buf);
      mvwprintw(locations_window, 2, 0, "CD marker: %s", loc->is_cd_marker() ? "Yes" : "No");
      mvwprintw(locations_window, 3, 0, "AutoLoop: %s", loc->is_auto_loop() ? "Yes" : "No");
      mvwprintw (locations_window, 4, 0, "AutoPunch: %s", loc->is_auto_punch() ? "Yes" : "No");
      mvwprintw (locations_window, 5, 0, "Name: %s",loc->name().c_str());

      redraw_screen ();
      return 0;
}

void
KSI::add_plugin (ARDOUR::Route *mx, guint32 which)
{
      list<PluginInfo *>& pluginfo = ARDOUR::PluginManager::the_manager()->ladspa_plugin_info ();
      list<PluginInfo *>::iterator infoiter;
      ARDOUR::PluginInsert *insert;
      LadspaPlugin *plugin;
      guint32 n;

      for (n = 0, infoiter = pluginfo.begin(); ((infoiter != pluginfo.end()) && (n < which)); n++, infoiter++);

      info << compose(_("loading plugin %1"), (*infoiter)->name) << endmsg;

      try {
            plugin = dynamic_cast<LadspaPlugin*> (ARDOUR::PluginManager::the_manager()->load (*session, *infoiter));
      }
      
      catch (failed_constructor& err) {
            info << compose(_("could not load plugin module for %1"), (*infoiter)->name) << endmsg;
            return;
      }
      
      insert = new ARDOUR::PluginInsert (*session, *plugin, PreFader);
      mx->add_redirect (insert, this);
      insert->set_active (true, this);
      
      insert_cnt = 0;
      mx->foreach_redirect (this, &KSI::show_insert);
      
      redraw_screen ();
}

void
KSI::update_record_display(ARDOUR::Route *rt) {

      ensure_selection_mode(RecordParameter);
      mvwprintw (record_box, 4, 0, " Route %s", rt->name().c_str());
      wclrtoeol(record_box);
      werase(record_window);
      mvwprintw(record_window, 0, 0, "Route: %s", rt->active() ? "On" : "Off");
      mvwprintw(record_window, 1, 0, "Record Enabled: %s", rt->record_enabled() ? "Yes" : "No");
      mvwprintw(record_window, 2, 0, "Automation Record Enable: %s", rt->gain_automation_recording() ? "Yes" : "No");
      mvwprintw (record_window, 3, 0, "Automation Playing Enable: %s", rt->gain_automation_playback() ? "Yes" : "No");
      mvwprintw (record_window, 4, 0, "Phase Inverter: %s", rt->phase_invert() ? "On" : "Off");
      mvwprintw(record_window, 5, 0, "Mute Affects Pre-Fader: %s", rt->get_mute_config (ARDOUR::PRE_FADER) ? "Yes" : "No");
      mvwprintw(record_window, 6, 0, "Mute Affects Post-Fader: %s", rt->get_mute_config (ARDOUR::POST_FADER) ? "Yes" : "No");
      mvwprintw(record_window, 7, 0, "Mute Affects Control Outs: %s", rt->get_mute_config (ARDOUR::CONTROL_OUTS) ? "Yes" : "No");
      mvwprintw(record_window, 8, 0, "Mute Affects Main Outs: %s", rt->get_mute_config (ARDOUR::MAIN_OUTS) ? "Yes" : "No");
      mvwprintw (record_window, 9, 0, "10: Create New Playlist");
      ensure_panel_on_top(record_panel);
      redraw_screen();
}

void
KSI::record_selected (guint32 which, SelectionType type, OpType op)

{
      char buf[32];
      ARDOUR::Route *rt;
      ARDOUR::AudioTrack* at;
      bool yn;
      
      /* XXX gack, this is supposed to be private to the session */

      snprintf (buf, sizeof(buf)-1, "Audio %u", which+1);
      
      if (selection_mode() == RecordParameter) {
            rt = _record_routeptr;
      } else {
            rt = session->route_by_name (buf);
            _record_routeptr = rt;
      }
      
      if (rt == 0) {
            error << compose(_("Channel %1not found!"), which + 1) << endmsg;
            pop_selection_mode ();
            return;
      }

      if ((at = dynamic_cast<AudioTrack*>(rt)) == 0) {
            error << compose(_("Channel %1 is not an audio track"), which+1) << endmsg;
            pop_selection_mode ();
            return;
      }

      switch (type) {
      case Add:
            at->set_record_enable (true, this);
            pop_selection_mode ();
            break;

      case Replace:
            
                // JHALL: oh yeah, like THIS isn't overloading a function

            if (selection_mode() == KSI::Record) {
                  update_record_display (at);
                  return;
            } else if (selection_mode() != KSI::RecordParameter) {
                  error << compose(_("PROGRAMMER ERROR! %1called but selection_mode is not Record or RecordParameter"), __PRETTY_FUNCTION__) << endmsg;
                  return;
            }

            switch (op) {
                  case increment:
                        yn = true;
                  break;
                  case decrement:
                        yn = false;
                  break;
                  default:
                        return;
                  }

            switch((which % selection_size) + 1) {
            case 1:
                  at->set_active(yn);
                  break;
            case 2:
                  at->set_record_enable(yn, this);
                  break;
            case 3:
                  at->set_gain_automation_state ((yn ? Write : Off));
                  break;
            case 4:
                  at->set_gain_automation_state(yn ? Play : Off);
                  break;
            case 5:
                  at->set_phase_invert(yn, this);
                  break;
            case 6:
                  at->set_mute_config(ARDOUR::PRE_FADER, yn, this);
                  break;
            case 7:
                  at->set_mute_config(ARDOUR::POST_FADER, yn, this);
                  break;
            case 8:
                  rt->set_mute_config(ARDOUR::CONTROL_OUTS, yn, this);
                  break;
            case 9:
                  rt->set_mute_config(ARDOUR::MAIN_OUTS, yn, this);
                  break;
            case 10:
                  at->disk_stream().use_new_playlist();
                  break;
            }
            
            break;

      case Remove:
            at->set_record_enable (false, this);
            pop_selection_mode ();
            break;
      } 
}

void
KSI::process_selection (guint32 which, SelectionType type, OpType op)
{
      RouteGroup *grp;

      grp = &selection;

      switch (selection_mode()) {
      case Group:
            grp = current_group;
            /* fallthru */
      case Route:
            route_selected (which, type, grp);
            break;

      case IO:
            io_selected (which + io_start, type);
            break;

      case Plugin:
            plugin_selected (which, type);
            break;

      case Insert:
            insert_selected (which, type);
            break;

      case RecordParameter:
      case Record:
            record_selected(route_start + which, type, op);
            break;

      case Parameter:
            /* do nothing */
            break;
      case Locations:
            location_selected ((_location_page * selection_size) + which);
            break;
            case Location:
                  // do nothing
            break;
      }
}

void
KSI::transport_rewind ()
{
      float current_transport_speed;
 
            if (session) {
            current_transport_speed = session->transport_speed();
            
            if (current_transport_speed > 0.0f) {
                  /* reset to regular reverse speed */
                  session->request_transport_speed (-1.0f);
            } else if (current_transport_speed == 0.0f) {
                  session->request_transport_speed (-1.2f);
            } else {
                  /* speed up */
//                session->request_transport_speed (current_transport_speed * 1.2f);
            session->request_transport_speed (max((double) -25, current_transport_speed - 0.25));
            }
      }
}

void
KSI::transport_forward ()
{
      float current_transport_speed;
      
      if (session) {
            current_transport_speed = session->transport_speed();
            
            if (current_transport_speed < 0.0f) {
                  /* reset to regular forward speed */
                  session->request_transport_speed (1.0f);
            } else if (current_transport_speed == 0.0f) {
                  session->request_transport_speed (1.2f);
            } else {
                  /* speed up */
//                session->request_transport_speed (current_transport_speed * 1.2f);
            session->request_transport_speed (min ((double) 25, current_transport_speed + 0.25));
            }
      }
}

int
KSI::key_press_handler (int keyboard_state, int key)
{

      double amount;
      guint32 which = 0;
      bool group = false;
      bool yn;
      bool save = false;
      OpType op = none;

        //keyboard->print_key(key);

      switch (key) {

      case 27: /* Esc */
            pop_selection_mode ();
            break;

      case 28: /* PrintScreen/SysRq */
            if ((keyboard_state & PhysicalKeyboard::Control) &&
                (keyboard_state & PhysicalKeyboard::Shift)) {

                  /* Ctrl-Alt-28: We're done */

                  return 1;
            }

            totally_redraw_screen ();
            break;

      case K_ENTER:
            if (keyboard_state & PhysicalKeyboard::Shift_L) {
                  /* unsolo all but current selection */
            } else if (keyboard_state & PhysicalKeyboard::Shift_R) {
                  /* resolo all previously soloed */
            } else if (keyboard_state & PhysicalKeyboard::Control) {
                  set_solo (false);
                  save = true;
            } else {
                  set_solo (true);
                  save = true;
            }
            break;
            
      case ' ':
            if (session->transport_rolling()) {
                  
                  if (session->get_record_enabled() == false)
                        session->set_auto_play (false);
                  session->request_stop();
                  
                  if (_scrubbing) {
                        session->request_transport_speed (0.0);
                        _scrubbing = false;
                  }
            } else {
                  if (session->get_record_enabled() == false)
                  session->set_auto_play (true);            
                  session->request_transport_speed (1.0);
            }
            break;

      case '\\':
            shift_selection_right ();
            break;

      case '\t':
            shift_selection_left ();
            break;

      case '[':
            if (keyboard_state & PhysicalKeyboard::Shift) {
                  if (keyboard_state & PhysicalKeyboard::Control) {
                        pan_left (0.25);
                  } else {
                        pan_hard_left ();
                  } 
            } else {
                  if (keyboard_state & PhysicalKeyboard::Alt) {
                        pan_left (0.5);
                  } else {
                        pan_left (0.05);
                  }
            }
            save = true;
            break;

      case ']':
            if (keyboard_state & PhysicalKeyboard::Shift) {
                  if (keyboard_state & PhysicalKeyboard::Control) {
                        pan_right (0.25);
                  } else {
                        pan_hard_right ();
                  } 
            } else {
                  if (keyboard_state & PhysicalKeyboard::Alt) {
                        pan_right (0.5);
                  } else {
                        pan_right (0.05);
                  }
            }
            save = true;
            break;

      /* increase the relevant channel */

      case 'q':
            which = 0;
            op = increment;
            break;
      case 'w':
            which = 1;
            op = increment;
            break;
      case 'e':
            which = 2;
            op = increment;
            break;
      case 'r':
            if (keyboard_state & PhysicalKeyboard::Alt) {
                  if (keyboard_state & PhysicalKeyboard::Shift) {
                        session->maybe_enable_record();
                        save = true;
                  } else if (keyboard_state & PhysicalKeyboard::Control) {
                        session->disable_record();
                        save = true;
                  }
                  goto save_state;
            }
            which = 3;
            op = increment;
            break;
      case 't':
            if (keyboard_state & PhysicalKeyboard::Alt) {
//                start_io_selection ();
                  error << _("ERROR IO selection not possible yet.") << endmsg;
                  goto save_state;
            }
            which = 4;
            op = increment;
            break;
      case 'y':
            which = 5;
            op = increment;
            break;
      case 'u':
            if (keyboard_state & PhysicalKeyboard::Alt) {
                  if (keyboard_state & PhysicalKeyboard::Shift) {
                        session->begin_reversible_command("SESSION::Roll");
                        //session->add_undo((UndoAction)bind(slot(this, &KSI::request_transport_state),ARDOUR::Session::Stopped));
                        //session->add_redo((UndoAction)bind(slot(this, &KSI::request_transport_state),ARDOUR::Session::Roll));
                        session->commit_reversible_command();
                        }
                  } else {
            which = 6;
            op = increment;
            }
            break;
      case 'i':
            if (keyboard_state & PhysicalKeyboard::Alt) {
                  inputs_selected();
                  selection.clear();
                  save = true;
                  goto save_state;
            }
            which = 7;
            op = increment;
            break;
      case 'o':
            if (keyboard_state & PhysicalKeyboard::Alt) {
                  outputs_selected();
                  selection.clear();
                  save = true;
                  goto save_state;
            }
            which = 8;
            op = increment;
            break;
      case 'p':
            which = 9;
            op = increment;
            break;

        /* reset the relevant channel */

      case 'a':
            which = 0;
            op = reset;
            break;
      case 's':
            if (keyboard_state & PhysicalKeyboard::Alt) {
                  session->save_state("default");
            } else {
            which = 1;
            op = reset;
            }
            break;
      case 'd':
            which = 2;
            op = reset;
            break;
      case 'f':
            which = 3;
            op = reset;
            break;
      case 'g':
            which = 4;
            op = reset;
            break;
      case 'h':
            op = reset;
            which = 5;
            break;
      case 'j':
            op = reset;
            which = 6;
            break;
      case 'k':
            op = reset;
            which = 7;
            break;
      case 'l':
            if (keyboard_state & PhysicalKeyboard::Alt) {
                  if (keyboard_state & PhysicalKeyboard::Shift) {
                        add_location();
                  save = true;
                  goto save_state;
                  } else if (keyboard_state & PhysicalKeyboard::Control) {
                        remove_location();
                  save = true;
                  goto save_state;
                  } else {
                        ensure_selection_mode(Locations);
                  } // ctrl_shift
                  break;
                  } // alt
            op = reset;
            which = 8;
            break;

      case ';':
            op = reset;
            which = 9;
            break;

        /* decrease the relevant channel */

      case 'z':
            op = decrement;
            which = 0;
            break;
      case 'x':
            op = decrement;
            which = 1;
            break;
      case 'c':
            op = decrement;
            which = 2;
            break;
      case 'v':
            op = decrement;
            which = 3;
            break;
      case 'b':
            if (keyboard_state & PhysicalKeyboard::Alt) {
                  save = false;
                  goto save_state;
            }
            op = decrement;
            which = 4;
            break;
      case 'n':
            op = decrement;
            which = 5;
            break;
      case 'm':
            op = decrement;
            which = 6;
            break;
      case ',':
            op = decrement;
            which = 7;
            break;
      case '.':
            op = decrement;
            which = 8;
            break;
      case '/':
            op = decrement;
            which = 9;
            break;

      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
      case '0':
            if (key > '0') {
                  which = key - '1';
            } else {
                  which = 9;
            }

            if (keyboard_state & PhysicalKeyboard::Alt) {
                  ensure_selection_mode(Record);
            }
            if (keyboard_state & PhysicalKeyboard::Shift) {
                  process_selection (which, Add, op);
            } else if (keyboard_state & PhysicalKeyboard::Control) {
                  process_selection (which, Remove, op);
            } else {
                  process_selection (which, Replace, op);
            }
            break;

      case K_F1:
            group_selected (1, Replace);
            break;

      case K_F2:
            group_selected (2, Replace);
            break;

      case K_F3:
            group_selected (3, Replace);
            break;

      case K_F4:
            group_selected (4, Replace);
            break;

      case K_F5:
            group_selected (5, Replace);
            break;

      case K_F6:
            group_selected (6, Replace);
            break;

      case K_F7:
            group_selected (7, Replace);
            break;

      case K_F8:
            group_selected (8, Replace);
            break;

      case K_F9:
            group_selected (9, Replace);
            break;

      case K_F10:
            group_selected (10, Replace);
            break;

      case K_F11:
            group_selected (11, Replace);
            break;

      case K_F12:
            group_selected (12, Replace);
            break;

      case K_F13:
            break;
      case K_F14:
            break;
      case K_F15:
            break;
      case K_F16:
            break;
      case K_F17:
            break;
      case K_F18:
            break;
      case K_F19:
            break;
      case K_FIND:
            break;

      case K_INSERT:
            if (keyboard_state & PhysicalKeyboard::Shift) {
                  start_insert_add ();
            } else if (keyboard_state & PhysicalKeyboard::Alt) {
                  start_insert_activate ();
            } else if (keyboard_state & PhysicalKeyboard::Control) {
                  remove_inserts ();
            } else {
                  start_insert_edit ();
            }
            break;

      case K_REMOVE:
            if (keyboard_state & PhysicalKeyboard::Control) {
                  yn = false;
            } else {
                  yn = true;
            }
            switch (selection_mode()) {
            case Parameter:
                  set_insert_state (!yn); /* logic is reversed here */
//                pop_selection_mode ();
                  break;
            case Route:
                  set_mute (yn);
                  save = true;
                  break;
            default:
                  break;
            }
            break;

      case K_PGUP:
            shift_selection_left ();
            break;

      case K_PGDN:
            shift_selection_right ();
            break;

      case K_MACRO:
            break;
      case K_HELP:
            break;
      case K_DO:
            break;
      case K_F20:
      case K_PAUSE:
            if (paused) {
                  engine.start ();
                  paused = false;
            } else {
                  engine.stop ();
                  paused = true;
            }
            break;

      case K_UP:
            if (selection_mode() == Group) {
                  op = increment;
                  group = true;
            }
            break;
      case K_DOWN:
            if (selection_mode() == Group) {
                  op = decrement;
                  group = true;
            }
            break;
      case K_LEFT:
            if (keyboard_state & PhysicalKeyboard::Alt) {
            if ((keyboard_state &PhysicalKeyboard::Control) && (keyboard_state &PhysicalKeyboard::Shift)) {
                  scrub_speed -= 0.001f;
            } else if (keyboard_state & PhysicalKeyboard::Control) {
                  scrub_speed -= 0.01f;
            } else if (keyboard_state & PhysicalKeyboard::Shift) {
                  scrub_speed -= 0.5f;
            } else {
                  scrub_speed -= 0.25f;
            }
/*
            if (scrub_speed == 1.00)  {
                  _scrubbing = false;
            }
*/
/*
            if (scrub_speed <= 0) {
            scrub_speed = 0.00;
            }
*/
            if (scrub_speed < -25.00)
                  scrub_speed = -25.00;
                  info << compose(_("Scrubbing: %1"), scrub_speed) << endmsg;
                  scrub();
            } else {
            scrub_speed = 1.0f;
/*
            _scrubbing = false;
*/
//          session->request_transport_speed (max((double) -25, session->transport_speed() - 0.25));
            transport_rewind();
            }
            break;
      case K_RIGHT:
            if (keyboard_state & PhysicalKeyboard::Alt) {
            if ((keyboard_state &PhysicalKeyboard::Control) && (keyboard_state &PhysicalKeyboard::Shift)) {
                  scrub_speed += 0.001f;
            } else if (keyboard_state & PhysicalKeyboard::Control) {
                  scrub_speed += 0.01f;
            } else if (keyboard_state & PhysicalKeyboard::Shift) {
                  scrub_speed += 0.50f;
            } else {
                  scrub_speed += 0.25f;
            }
                  info << compose(_("Scrubbing: %1"), scrub_speed) << endmsg;
/*
            if (scrub_speed == 1.00)  {
                  session->request_transport_speed (1.0);
                  _scrubbing = false;
            }
*/
            if (scrub_speed > 25.00)
                  scrub_speed = 25; // sanity
                  scrub();
            } else {
            scrub_speed = 1.0f;
//          session->request_transport_speed (min ((double) 25, session->transport_speed() + 0.25));
            transport_forward();
            }
            break;
      }

      if (op == none) {
            goto save_state;
      }


      if (selection_mode() == KSI::RecordParameter) {
            process_selection(which, Replace, op);
            goto save_state;
            }

      if (selection_mode() == Route) {
            route_selected (which, Replace, &selection);
      }

      if (selection_mode() == Group || selection_mode() == Route) {
            if (keyboard_state & PhysicalKeyboard::Shift) {
                  if (keyboard_state & PhysicalKeyboard::Control) {
                        amount = 0.003;
                  } else {
                        amount = 0.10;
                  }
            } else if (keyboard_state & PhysicalKeyboard::Control) {
                  amount = 0.006;
            } else {
                  amount = 0.014;
            }
            switch (op) {
            case reset:
                  if (group) group_unity_gain ();
                  else channel_unity_gain ();
                  break;
            case increment:
                  if (group) group_adjust_gain (amount);
                  else channel_adjust_gain (amount);
                  break;
            case decrement:
                  amount *= -1.0;
                  if (group) group_adjust_gain (amount);
                  else channel_adjust_gain (amount);
                  break;
            default:
                  break;
            }

            save = true;

      } else if (selection_mode() == Parameter) {

            which += (parameter_page * selection_size);

            if (keyboard_state & PhysicalKeyboard::Shift) {
                  if (keyboard_state & PhysicalKeyboard::Control) {
                        amount = 0.05;
                  } else {
                        amount = 1.0;
                  }
            } else if (keyboard_state & PhysicalKeyboard::Control) {
                  amount = 0.5;
            } else {
                  amount = 0.2;
            }

            switch (op) {
            case reset:
                  adjust_parameter (which, 0.0);
                  break;
            case increment:
                  adjust_parameter (which, amount);
                  break;
            case decrement:
                  adjust_parameter (which, -amount);
                  break;
            default:
                  break;
            }

            save = true;
      }

  save_state:
      /*
            JHALL: temporarily deactivated because of xruns, use alt_s to 
            JHALL: force a save. SAVE DOES NOT OCCUR NATURALLY!
      if (save) {
            session->save_state ("default");
      }
*/

      return 0;
}

void
KSI::adjust_parameter (guint32 which, double amt)
{
      ARDOUR::Route *mx = get_first_selected_route ();
      LADSPA_Data value, upper, lower;
      LADSPA_PortRangeHintDescriptor hint;
      unsigned long port;
      bool port_ok;

      if (mx == 0) {
            return;
      }

      if (editing_insert == 0) {
            fatal << _("programming error: no editing insert") << endmsg;
            /*NOTREACHED*/
            return;
      }
      
      LadspaPlugin* plugin = dynamic_cast<LadspaPlugin*> (&editing_insert->plugin());

      port = plugin->nth_parameter (which, port_ok);

      if (!port_ok) {
            info << _("no such parameter") << endmsg;
            return;
      }

      value = plugin->get_parameter (port);

      hint = plugin->port_range_hints()[port].HintDescriptor;

      /* XXX how to handle unhinted ports ? */
      
      if (LADSPA_IS_HINT_TOGGLED(hint)) {

            if (amt > 0.0) {
                  value = 1.0;
            } else {
                  value = 0.0;
            }

      } else {

            if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint)) {
                  upper = plugin->port_range_hints()[port].UpperBound;
            } else {
                  upper = 1.0f;
            }
            
            if (LADSPA_IS_HINT_BOUNDED_BELOW(hint)) {
                  lower = plugin->port_range_hints()[port].LowerBound;
            } else {
                  lower = 0.0f;
            }

            if (LADSPA_IS_HINT_SAMPLE_RATE(hint)) {
                  lower *= engine.frame_rate();
                  upper *= engine.frame_rate();
            }

            if (amt == 0.0) {

                  /* "reset": use midpoint, since LADSPA has no defaults */
                  value = lower + ((upper - lower) / 2.0);

            } else {

                  if (LADSPA_IS_HINT_INTEGER(hint)) {
                        if (amt > 0.0) {
                              amt = 1.0;
                        } else {
                              amt = -1.0;
                        }
                  }
                  
                  if (LADSPA_IS_HINT_SAMPLE_RATE(hint)) {
                        amt *= engine.frame_rate()/ 1000;
                  }

                  if (value == 0) {

                        /* don't get stuck with 0 * N = 0 */

                        value = amt;

                  } else {

                        if (LADSPA_IS_HINT_LOGARITHMIC(hint)) {
                              value *= (1.0 + amt);
                        } else {
                              value += amt;
                        }
                  }

                  value = min (value, upper);
                  value = max (value, lower);
            }
      }

      plugin->set_parameter (port, value);
      show_parameters (parameter_page, editing_insert);
}

void
KSI::group_adjust_gain (gain_t amt)

{
      if (current_group) {
            LockMonitor lm(gain_lock, __LINE__, __FILE__);
            g_amount = amt;
            current_group->foreach_route(this, &KSI::adjust_gain);
      }
}

void
KSI::channel_adjust_gain (gain_t amt)

{
      LockMonitor lm(gain_lock, __LINE__, __FILE__);
      g_amount = amt;
      selection.foreach_route(this, &KSI::adjust_gain);
}

ARDOUR::Route *
KSI::new_route (bool want_diskstream) 
{
      ARDOUR::Route *route;
      ARDOUR::AudioTrack *track = 0;
      unsigned long nroutes = session->nroutes();
      pan_t pan_amt;

      if (want_diskstream) {
            if ((route = session->new_audio_track (1, 1)) == 0) {
                  error << _("cannot create new track.") << endmsg;
                  return 0;
            }

            track = dynamic_cast<AudioTrack*>(route);

      } else {
            if ((route = session->new_audio_route (1, 1)) == 0) {
                  error << _("cannot create new route.") << endmsg;
                  return 0;
            }
      }

      route->disconnect_outputs(this);
      route->connect_output (route->output(0), master_lr_channels[0], this);
      route->add_output_port (master_lr_channels[1], this);
      if ((nroutes + 1) % 2) {
            pan_amt = 0.0f;
      } else {
            pan_amt = 1.0f;
      }
      
      StreamPanner *panner = route->panner()[0];
      panner->set_position(pan_amt);

      if (need_control_room_outs) {
            route->connect_output (route->output (0), control_route->output (0)->name(), this);
            route->connect_output (route->output (1), control_route->output (1)->name(), this);
            route->control_outs()->panner()[0]->set_position(pan_amt);
      }
      
      paint_channel_gain (nroutes, route);
      paint_channel_mute (nroutes, route);
      paint_channel_solo (nroutes, route);
      
      if (want_diskstream) {
            paint_channel_record_enable (nroutes, track);
            track->record_enable_changed.connect (bind (slot (this, &KSI::route_record_enable_changed), track, nroutes));
      }
      route->solo_changed.connect (bind (slot (this, &KSI::route_solo_changed), route, nroutes));
      route->mute_changed.connect (bind (slot (this, &KSI::route_mute_changed), route, nroutes));
      route->gain_changed.connect (bind (slot (this, &KSI::route_gain_changed), route, nroutes));
      
      return route;
}

int
KSI::get_route_channel (ARDOUR::Route *mx)
{
      int chn;
      sscanf ((mx->name().substr (mx->name().find_last_of (' '))).c_str(), "%d", &chn);
      return chn - 1;
}
      
void
KSI::adjust_gain (ARDOUR::Route& route)
{
      gfloat current_amt = 0;
      gfloat amt_adjustment = 0;

      /* XXX fix me to use dB */
      
      /* XXX this doesn't seem right to me. but i don't have a better answer ... */
      current_amt = pow((6*log(route.gain())/log(2.0)+192)/198, 8);
      if (g_amount + current_amt <= 0) {
            amt_adjustment = 0;
      } else {
            amt_adjustment = current_amt + g_amount;
      }
      route.set_gain (pow (2,(sqrt(sqrt(sqrt(amt_adjustment)))*198-192)/6), this);
}

int
KSI::io_mode_selected(RouteGroup *trk) 
{
      ARDOUR::Route *route;
      
      if (trk->empty()) { // new route time
            if ((route = new_route()) == 0) {
                  error << _("ERROR new route not added.") << endmsg;
                  return -1;
            }
            _track.clear();
            _track.add(route);
      } else {
            trk->foreach_route(this, &KSI::_add_track);
      }

        update_io_display();

      return 0;
}

void
KSI::update_io_display ()
{
}

void
KSI::_add_track (ARDOUR::Route& route) 
{
      _track.add (&route);
}

void
KSI::start_input_selection ()
{
//    push_selection_mode (Output);
      io_page = 0;
      show_possible_outputs (io_page);
}

void
KSI::start_output_selection ()
{
//    push_selection_mode (Input);
      io_page = 0;
      show_possible_inputs (io_page);
}

int
KSI::show_possible_ports (int page, unsigned long flags)
{
      const char **ports = engine.get_ports ("", "", flags);
      unsigned long x, i;

      if (ports == 0) {
            return -1;
      }

      if (ports[0] == 0) {
            return -1;
      }
      
      x = page * selection_size;
      
      /* check that the page range is valid */

      for (i = 0; i < x && ports[i]; ++i);
      
      if (i != x) {
            free (ports);
            return -1;
      }
            
      for (x = 0; (x < selection_size) && ports[x]; x++) {
            wprintw (io_window, "%d %s\n", 
                   1 + (x + (page * selection_size)),
                   ports[x]);
      }

      redraw_screen ();
      return 0;
}

int
KSI::show_possible_outputs (int page)
{
      return show_possible_ports (page, JackPortIsInput);
}

int
KSI::show_possible_inputs (int page)
{
      return show_possible_ports (page, JackPortIsInput);
}

void 
KSI::io_selected (guint32 which, SelectionType type) 
{
      switch(type) {
      case Add:
            io_selection.push_back (engine.get_nth_physical_output (which));
            break;

      case Replace:
            io_selection.clear ();
            io_selection.push_back (engine.get_nth_physical_output (which));
            break;

      case Remove:
            vector<string>::iterator i;
            string name = engine.get_nth_physical_output (which);

            if ((i = find (io_selection.begin(), io_selection.end(), name)) != io_selection.end()) {
                  io_selection.erase (i);
            }

            break;
      }
      return;
}

void
KSI::inputs_selected() 
{
      LockMonitor lm(chns_lock, __LINE__, __FILE__);

      if (_track.empty()) {
            error << _("ERROR no tracks to add inputs selected.") << endmsg;
            return;
      }

      if (io_selection.empty()) {
            error << _("ERROR no channels to set inputs for tracks.") << endmsg;
            return;
      }

      _track.foreach_route(this, &KSI::_inputs_selected);
}

void
KSI::_inputs_selected(ARDOUR::Route& route)
      
{
      vector<string>::size_type n;
      vector<string>::iterator i;

      route.disconnect_inputs (this);
      
      for (i = io_selection.begin(), n = 0; i != io_selection.end(); ++i, ++n) {
            
            if (route.n_inputs() < n+1) {
                  route.add_input_port (io_selection[n], this);
            } else {
                  route.connect_input (route.input (n), io_selection[n], this);
            }
      }
}

void
KSI::outputs_selected() 
{
      LockMonitor lm(chns_lock, __LINE__, __FILE__);

      if (_track.empty()) {
            error << _("ERROR no tracks to add outputs selected.") << endmsg;
            return;
      }

      if (io_selection.empty()) {
            error << _("ERROR no channels to set output for tracks.") << endmsg;
            return;
      }
      
      _track.foreach_route(this, &KSI::_outputs_selected);
}

void
KSI::_outputs_selected(ARDOUR::Route& route)
{
      vector<string>::size_type n;
      vector<string>::iterator i;
pan_t x, y, z;

      route.panner()[0]->get_position (x,y,z);

      /* XXX pans may not be the correct size after the reset */

      route.disconnect_outputs (this);

      for (i = io_selection.begin(), n = 0; i != io_selection.end(); ++i, ++n) {
            
            if (route.n_outputs() < n+1) {
                  route.add_output_port (io_selection[n], this);
            } else {
                  route.connect_output (route.output (n), io_selection[n], this);
            }
      }

      route.panner()[0]->set_position (x,y,z);
}

void
KSI::group_selected (guint32 which, SelectionType type)

{
      char buf[16];
      RouteGroup *group = 0;
      
      sprintf (buf, "Group %u", which);
      
      if ((group = session->mix_group_by_name (buf)) != 0){
            current_group = group;
            ensure_selection_mode (Group);
            update_group_display (group);
      } else {
            error << compose(_("ERROR group %1 not found for %2"), buf, __PRETTY_FUNCTION__) << endmsg;
            }
}

void
KSI::pan_left (pan_t amount)
      
{
      if (selection_mode() == KSI::Route) {
            if (selection.empty()) {
                  info << _("no selection or group") << endmsg;
                  return;
            } else {
                  LockMonitor lm(pan_lock, __LINE__, __FILE__);
                  p_amount = amount;
                  selection.foreach_route(this, &KSI::_pan_left);
            }
      } else if (selection_mode() == KSI::Group) {
            if (current_group->empty()) {
                  info << _("no selection or group") << endmsg;
                  return;
            } else {
                  LockMonitor lm (pan_lock, __LINE__, __FILE__);
                  p_amount = amount;
                  current_group->foreach_route(this, &KSI::_pan_left);
            }
      } else {
            error << _("PROGRAMMING ERROR asked to pan left something that is not a group or channel") << endmsg;
      }
}

void
KSI::_pan_left(ARDOUR::Route& rt)
{
      pan_t current_x, current_y, current_z, x;
      
      rt.panner()[0]->get_position(current_x, current_y, current_z);
      x = MAX(current_x - p_amount, 0.0f);
      rt.panner()[0]->set_position(x,current_y,current_z);

      if (need_control_room_outs) {
            rt.control_outs()->panner()[0]->set_position(x,current_y,current_z);
      }
}

void
KSI::scrub()
{
      if (! session) {
            error << _("ERROR no session for scrub!") << endmsg;
            return;
      }
      if (! _scrubbing) {
            session->request_locate (session->audible_frame());
            _scrubbing = true;
      }
      session->request_transport_speed(scrub_speed);
/*
      if (selection.empty()) {
            error << _("ERROR no routes selected for scrub!") << endmsg;
            return;
      }
      
      selection.foreach_route(this, &KSI::_scrub);
*/
      return;
}

void
KSI::_scrub (ARDOUR::Route& route) 
{
      if (session) {
            session->request_transport_speed (scrub_speed);
      }
}

void
KSI::pan_right (pan_t amount)
{
      
      if (selection_mode() == KSI::Route) {
            if (selection.empty()) {
                  info << _("no selection or group") << endmsg;
                  return;
            } else {
                  LockMonitor lm(pan_lock, __LINE__, __FILE__);
                  p_amount = amount;
                  selection.foreach_route(this, &KSI::_pan_right);
            }
      } else 
            if (selection_mode() == KSI::Group) {
                  if (current_group->empty()) {
                        info << _("no selection or group") << endmsg;
                        return;
                  } else {
                        LockMonitor lm (pan_lock, __LINE__, __FILE__);
                        p_amount = amount;
                        current_group->foreach_route(this, &KSI::_pan_right);
                  }
            } else {
                  error << _("PROGRAMMING ERROR asked to pan right something that is not a group or channel") << endmsg;
            }
      return;
}

void
KSI::_pan_right (ARDOUR::Route& rt)
      
{
      pan_t current_x, current_y, current_z, x;

      rt.panner()[0]->get_position(current_x,current_y,current_z);

      x = MAX(p_amount+current_x,1.0f);
      rt.panner()[0]->set_position(x,current_y,current_z);
      if (need_control_room_outs) {
      rt.control_outs()->panner()[0]->set_position(x,current_y,current_z);
      }
}

void
KSI::pan_hard_right ()
      
{
      pan_right(1.0);
}

void
KSI::pan_hard_left ()
      
{
      pan_left(0.0);
}

void
KSI::set_mute (bool yn)
{
      if (selection_mode() == KSI::Route) {
            if (selection.empty()) {
                  info << _("no selection or group") << endmsg;
                  return;
            } else {
                  LockMonitor lm(choice_lock, __LINE__, __FILE__);
                  _yn = yn;
                  selection.foreach_route(this, &KSI::_set_mute);
            }
      } else if (selection_mode() == KSI::Group) {
            if (current_group->empty()) {
                  info << _("no selection or group") << endmsg;
                  return;
            } else {
                  LockMonitor lm (choice_lock, __LINE__, __FILE__);
                  _yn = yn;
                  current_group->foreach_route(this, &KSI::_set_mute);
            }
      } else {
            error << _("PROGRAMMING ERROR asked to mute something that is not a group or channel") << endmsg;
      }
      return;
}

void
KSI::_set_mute (ARDOUR::Route& route)
{
      route.set_mute (_yn, this);
}

void
KSI::unset_solo (ARDOUR::Route& route)
{
      route.set_solo (false, this);
}

void
KSI::set_solo (bool yn)
{
      /* semantics: if unsetting solo, apply to every route. if
         setting solo, apply to current selection.
      */
      
      if (!yn) {
            session->foreach_route (this, &KSI::unset_solo);
            return;
      } 
      
      if ((current_group) && (selection_mode() == KSI::Group)) {
            if (! current_group->empty()) {
                  current_group->foreach_route(this, &KSI::_set_solo);
            } else {
                  info << _("no selection or group") << endmsg;
                  return;
            }
      } else {
            if (! selection.empty()) {
                  selection.foreach_route(this, &KSI::_set_solo);
            } else {
                  info << _("no selection or group") << endmsg;
                  return;
            }
      }
      
}

void
KSI::_set_solo (ARDOUR::Route& rt) 
{
      rt.set_solo (true, this);
}

void
KSI::group_unity_gain ()

{
      if (current_group) {
            current_group->foreach_route(this, &KSI::unity_gain);
      }
}

void
KSI::channel_unity_gain ()
{
      selection.foreach_route(this, &KSI::unity_gain);
}

void
KSI::unity_gain (ARDOUR::Route& route)
{
      route.set_gain (1.0, 0);
}

int
KSI::show_possible_plugins (guint32 page)
      
{
      list<PluginInfo *>& plugins = PluginManager::the_manager()->ladspa_plugin_info();
      list<PluginInfo *>::iterator i;
      
      guint32 x = page * selection_size;
      
      /* count forward to the start of the requested "page" */

      for (i = plugins.begin(); ((x > 0) && (i != plugins.end())); i++, x--);

      if (i == plugins.end()) {
            info << _("no more plugins") << endmsg;
            return -1;
      }

      wclear (plugins_window);
      
      for (x = 0; ((x < selection_size) && (i != plugins.end())); i++, x++) {
            wprintw (plugins_window, "%d %s\n", 
                   1 + (x + (page * selection_size)),
                   (*i)->name.c_str());
      }

      redraw_screen ();
      return 0;
}

void
KSI::shift_selection_right ()
{
      switch (selection_mode()) {
      case Group:
            break;
            
      case IO:
/*
            if (show_possible_io (++io_page)) {
                  io_page--;
            }
*/
            break;

      case RecordParameter:
// do nothing
      break;
      case Record:
      case Route:
            if ((route_start + selection_size) < session->nroutes()) {
                  route_start += selection_size;
            }
            update_channel_range_display ();
            break;

      case Locations:
            _location_page ++;
            show_locations();
            break;
            
      case Location:
            // we will never have THAT many ways to change a location
            break;
            
      case Plugin:
            if (show_possible_plugins (++plugin_page)) {
                  plugin_page--;
            }
            break;

      case Insert:
            if (show_inserts (++insert_page, true)) {
                  insert_page--;
            }
            break;

      case Parameter:
            if (editing_insert) {
                  if (show_parameters (++parameter_page, editing_insert)) {
                        parameter_page--;
                  }
            }
            break;
      }
}

void
KSI::shift_selection_left ()
{
      switch (selection_mode()) {
      case Group:
      case Location:
            break;

      case IO:
            if (io_start > selection_size) {
                  io_start -= selection_size;
            } else {
                  io_start = 0;
            }
            break;

      case RecordParameter:
// do nothing
      break;

      case Route:
      case Record:
            if (route_start > selection_size) {
                  route_start -= selection_size;
            } else {
                  route_start = 0;
            }
            update_channel_range_display ();
            break;
            
      case Locations:
            if (_location_page) _location_page --;
            show_locations();
      break;

      case Insert:
            if (insert_page) insert_page--;
            show_inserts (insert_page, true);
      break;

      case Plugin:
            if (plugin_page) plugin_page--;
            show_possible_plugins (plugin_page);
            break;

      case Parameter:
            if (editing_insert) {
                  if (parameter_page) parameter_page--;
                  show_parameters (parameter_page, editing_insert);
            }
            break;
      }
}

void
KSI::pop_selection_mode ()
{
      if (selection_mode_stack.size() > 1) {
            selection_mode_stack.pop();
      } 

      update_selection_mode_display ();
}

int
KSI::show_parameters (guint32 parameter_page, ARDOUR::PluginInsert *insert)
{
      LadspaPlugin* plugin = dynamic_cast<LadspaPlugin*> (&insert->plugin ());
      guint32 n;

      mvwprintw (insert_box, 0, 4, "insert: %s", plugin->name());
      wclear (insert_window);

      for (n = parameter_page * selection_size; n < plugin->parameter_count(); n++) {
            LADSPA_PortDescriptor pd;

            pd = plugin->port_descriptor(n);

            if (LADSPA_IS_PORT_CONTROL(pd)) {
                  wprintw (insert_window, "%s = %.3f\n",
                         plugin->port_names()[n],
                         plugin->get_parameter (n));
            }
      }
      
      redraw_screen ();
      return 0;
}

ARDOUR::Route *
KSI::get_first_selected_route ()
{
      RouteGroup *grp;
      if ((selection_mode() == KSI::Group) && (current_group)) {
            grp = current_group;
      } else {
            grp = &selection;
            }

      if (grp->empty()) {
            info << _("nothing selected") << endmsg;
            return 0;
      }

      if (grp->size() > 1) {
            info << _("selection contains more than one channel") << endmsg;
            return 0;
      }

      return grp->first();
}

int
KSI::initialize_ui ()
{
      initscr();
      cbreak();
      noecho();
      nonl();
      werase (stdscr);

      message_box = newwin (4, COLS, 0, 0);
      wborder (message_box, 0, 0, 0, 0, 0, 0, 0, 0);
      mvwaddstr (message_box, 0, 4, " messages ");
//    leaveok (message_box, true);
      wnoutrefresh (message_box);
      
      message_window = derwin (message_box, 2, COLS-2, 1, 1);
      scrollok (message_window, true);
      syncok (message_window, true);
//    leaveok (message_window, true);

      channels_box = newwin (12, COLS, 4, 0);
      wborder (channels_box, 0, 0, 0, 0, 0, 0, 0, 0);
      mvwaddstr (channels_box, 0, 4, " faders ");
//    leaveok (channels_box, true);
      wnoutrefresh (channels_box);
      
      channels_window = derwin (channels_box, 10, COLS-2, 1, 1);
      syncok (channels_window, true);
//    leaveok (channels_window, true);

      record_box = newwin (12, COLS, 4, 0);
      wborder (record_box, 0, 0, 0, 0, 0, 0, 0, 0);
      mvwaddstr (record_box, 0, 4, " route ");
//    leaveok (record_box, true);
      wnoutrefresh (record_box);
      
      record_window = derwin (record_box, 10, COLS-2, 1, 1);
      syncok (record_window, true);
//    leaveok (record_window, true);
      channel_gain_unity_position = (COLS * 0.66) - 6;

      io_box = newwin (12, COLS, 4, 0);
      wborder (io_box, 0, 0, 0, 0, 0, 0, 0, 0);
      mvwaddstr (io_box, 0, 4, " I/O ");
//    leaveok (io_box, true);
      wnoutrefresh (io_box);
      
      io_window = derwin (io_box, 10, COLS-2, 1, 1);
      syncok (io_window, true);
//    leaveok (io_window, true);

      inserts_box = newwin (12, COLS, 4, 0);
      wborder (inserts_box, 0, 0, 0, 0, 0, 0, 0, 0);
      mvwaddstr (inserts_box, 0, 4, " inserts: ");
//    leaveok (inserts_box, true);
      wnoutrefresh (inserts_box);

      inserts_window = derwin (inserts_box, 10, COLS-2, 1, 1);
//    leaveok (inserts_window, true);
      syncok (inserts_window, true);

      insert_box = newwin (12, COLS, 4, 0);
      wborder (insert_box, 0, 0, 0, 0, 0, 0, 0, 0);
      mvwaddstr (insert_box, 0, 4, " insert: ");
//    leaveok (insert_box, true);
      wnoutrefresh (insert_box);

      insert_window = derwin (insert_box, 10, COLS-2, 1, 1);
//    leaveok (insert_window, true);
      syncok (insert_window, true);

      plugins_box = newwin (12, COLS, 4, 0);
      wborder (plugins_box, 0, 0, 0, 0, 0, 0, 0, 0);
      mvwaddstr (plugins_box, 0, 4, " plugins ");
//    leaveok (plugins_box, true);
      wnoutrefresh (plugins_box);

      plugins_window = derwin (plugins_box, 10, COLS-2, 1, 1);
//    leaveok (plugins_window, true);
      syncok (plugins_window, true);

      locations_box = newwin (12, COLS, 4, 0);
      wborder (locations_box, 0, 0, 0, 0, 0, 0, 0, 0);
      mvwaddstr (locations_box, 0, 4, " locations ");
//    leaveok (locations_box, true);
      wnoutrefresh (locations_box);

      locations_window = derwin (locations_box, 10, COLS-2, 1, 1);
//    leaveok (locations_window, true);
      syncok (locations_window, true);

      message_panel = new_panel (message_box);
      route_panel = new_panel (channels_box);
      io_panel = new_panel (io_box);
      inserts_panel = new_panel (inserts_box);
      insert_panel = new_panel (insert_box);
      plugins_panel = new_panel (plugins_box);
      locations_panel = new_panel (locations_box);
      record_panel = new_panel(record_box);

      lower_window = newwin (LINES-16, COLS, 16, 0);
      lower_panel = new_panel (lower_window);
//    leaveok(lower_window, true);

      show_panel (lower_panel);
      show_panel (message_panel);

      status_box = derwin (lower_window, 3, COLS, 0, 0);
      wborder (status_box, 0, 0, 0, 0, 0, 0, 0, 0);
//    leaveok (status_box, true);
      wnoutrefresh (status_box);

      status_window = derwin (status_box, 1, COLS-2, 1, 1);
//    leaveok (status_window, true);
      syncok (status_window, true);

      my_top_panel = 0;
      ensure_panel_on_top (route_panel);

      return 0;
}

void
KSI::paint_channel_gain (unsigned long chn, ARDOUR::Route *mx)
{

      int xpos;

      chn %= KSI::selection_size;
      
      /* unity gain roughly 2/3 of the way across the screen */
      
      xpos = 7 + (int) floor (mx->gain() * channel_gain_unity_position);
      
      wmove (channels_window, chn, 7);
      wclrtoeol (channels_window);
      if (xpos > COLS - 4) {
            mvwaddch (channels_window, chn, COLS-4, '>');
      } else {
            mvwaddch (channels_window, chn, xpos, ACS_BLOCK);
      }
      redraw_screen ();
}

void
KSI::receive (Transmitter::Channel chn, const char *str)
{
      if (display_is_remote) {
            /* duplicate the error message on stderr */
            cerr << str << endl;
      }

      waddch (message_window, '\n');
      waddstr (message_window, str);
      redraw_screen ();
}

void
KSI::update_selection_mode_display ()
{
      wmove (status_window, 0, 0);
      wclrtoeol (status_window);

      switch (selection_mode()) {
      case KSI::Plugin:
            mvwaddstr (status_window, 0, 0, "Mode: plugin");
            ensure_panel_on_top (plugins_panel);
            break;
      case KSI::Route:
            update_selection_display(&selection);
            mvwaddstr (status_window, 0, 0, "Mode: channel");
            ensure_panel_on_top (route_panel);
            break;
      case KSI::RecordParameter:
            mvwaddstr (status_window, 0, 0, "Mode: recordParameter");
            ensure_panel_on_top (record_panel);
            break;
      case KSI::Record:
            update_selection_display(&selection);
            mvwaddstr (status_window, 0, 0, "Mode: record");
            ensure_panel_on_top (route_panel);
            break;
      case KSI::Group:
            update_group_content_display (current_group);
            mvwaddstr (status_window, 0, 0, "Mode: group");
            ensure_panel_on_top (route_panel);
            break;
      case KSI::Parameter:
            mvwaddstr (status_window, 0, 0, "Mode: parameter");
            ensure_panel_on_top (insert_panel);
            break;
      case KSI::Insert:
            update_insert_display ();
            mvwaddstr (status_window, 0, 0, "Mode: insert");
            ensure_panel_on_top (inserts_panel);
            break;
      case KSI::IO:
            update_selection_display(&selection);
            mvwaddstr(status_window, 0, 0, "Mode: io");
            ensure_panel_on_top(io_panel);
            break;
      case KSI::Locations:
            show_locations();
            mvwaddstr(status_window, 0, 0, "Mode: locations");
            ensure_panel_on_top(locations_panel);
            break;
      case KSI::Location:
            update_current_location_display();
            mvwaddstr(status_window, 0, 0, "Mode: location");
            ensure_panel_on_top(locations_panel);
            break;
      }
      
      redraw_screen ();
}

void
KSI::_location_selected (Locations::LocationList& locations)
{
      Locations::LocationList::iterator i;
      ARDOUR::Location *location;

        /* move through to the correct location */
      for (i = locations.begin(); ((i != locations.end()) && (_location_cnt > 0)); i++, _location_cnt--);

      if (i == locations.end()) {
            error << _("ERROR location not found") << endmsg;
            return;
      }

      location = *i;
      session->locations()->set_current(location, false);
      session->request_locate(location->start());
      ensure_selection_mode(Location);
}

void
KSI::update_locations_display (Locations::LocationList& locations)
{

      Locations::LocationList::iterator i;
      ARDOUR::Location *location;
      guint32 n; 
      guint32 x = (selection_size * _location_page);

      werase(locations_window);

        /* move through to the correct location */
      for (i = locations.begin(); ((i != locations.end()) && (x > 0)); i++, x--);

      if (i == locations.end()) {
            error << _("no more locations to display") << endmsg;
            return;
      }

      for (n = 0; ((i != locations.end()) && (n < selection_size)); n++, i++) {

            location = *i;

            mvwprintw(locations_window, n, 0, "%3d %s", (_location_page * selection_size) + n + 1, location->name().c_str());
      }

      wclrtobot(locations_window);
      redraw_screen();
      return;
}

void
KSI::update_channel_range_display ()
{

      guint32 i, x;

      /* relabel channel columns */

      for (x = 0, i = route_start; x < selection_size; i++, x++) {
            if (session)
            if (i == session->nroutes()) {
                  wclrtobot(channels_window);
                  break;
            }
            mvwprintw (channels_window, x, 0, "%3d", i+1);
      }
      redraw_screen ();
}

void
KSI::paint_channel_mute (unsigned long chn, ARDOUR::Route *mx)
{

      chn %= KSI::selection_size;

      if (mx->muted()) {
            mvwaddch (channels_window, chn, 5, 'M');
      } else {
            mvwaddch (channels_window, chn, 5, ' ');
      }
      redraw_screen ();
}

void
KSI::paint_channel_solo (unsigned long chn, ARDOUR::Route *mx)
{

      chn %= KSI::selection_size;

      if (mx->soloed()) {
            mvwaddch (channels_window, chn, 6, 'S');
      } else {
            mvwaddch (channels_window, chn, 6, ' ');
      }
      redraw_screen ();
}

void
KSI::paint_channel_record_enable (unsigned long chn, ARDOUR::AudioTrack* track)
{

      chn %= KSI::selection_size;

      if (track->record_enabled()) {
            mvwaddch (channels_window, chn, 7, 'R');
      } else {
            mvwaddch (channels_window, chn, 7, ' ');
      }
      redraw_screen ();
}

void
KSI::update_selection_display(RouteGroup *grp)
{

      wmove (status_window, 0, 15);
      wclrtoeol (status_window);
      mvwaddstr (status_window, 0, 18, " Selection: ");
      if (! grp->empty()) {
            LockMonitor lm (selection_lock, __LINE__, __FILE__);
      selection_cnt = 0;
            grp->foreach_route(this, &KSI::_update_selection_display);
            selection_cnt = 0;
      }
      
      update_transport_state_display ();

      redraw_screen ();
}

void
KSI::_update_selection_display (ARDOUR::Route& rt)
{
      if (selection_cnt > 0) {
            waddstr (status_window, "/");
      }
      waddstr (status_window, rt.name().c_str());
      selection_cnt ++;
}

void
KSI::update_insert_display ()
{
      show_inserts (insert_page, true);
}

void
KSI::update_group_content_display (RouteGroup *grp)
{
      wmove (status_window, 0, 25);
      wclrtoeol (status_window);
      wmove (status_window, 0, 25);

      if (! grp->empty()) {
            LockMonitor lm (group_lock, __LINE__, __FILE__);
            group_cnt = 0;
            grp->foreach_route(this, &KSI::_update_group_content_display);
            group_cnt = 0;
      } else {
            waddstr (status_window, "empty");
      }

      redraw_screen ();
}

void
KSI::_update_group_content_display (ARDOUR::Route& rt)
{
      if (group_cnt > 0) {
            waddstr (status_window, "/");
      }
      waddstr (status_window, rt.name().c_str());
      group_cnt ++;
}

void
KSI::update_group_display (RouteGroup *grp)
{
      wmove (status_window, 0, 15);
      wclrtoeol (status_window);
      waddstr (status_window, grp->name().c_str());
      waddstr (status_window, ": ");
      update_group_content_display (grp);
}

void
KSI::update_transport_state_display ()
{
      if (session == 0) {
            return;
      }

      mvwaddstr (status_window,0, 40, "Rec: ");
      mvwaddstr (status_window, 0, 45, session->get_record_enabled() ? "ON " : "off");
      
      if (session->transport_stopped()) { 
            mvwaddstr (status_window, 0, 50, "Stopped");
      } else if (session->transport_rolling()) {
            mvwaddstr (status_window, 0, 50, "Rolling");
      } else if (session->transport_speed() > 1.0) {
            mvwaddstr (status_window, 0, 50, "Forwarding");
      } else {
            mvwaddstr (status_window, 0, 50, "Rewinding");
      }
      
      redraw_screen ();
}

void
KSI::add_group(RouteGroup *rg) 
{
      rg->changed.connect (bind(slot (this, &KSI::update_group_display), rg));
      groups.push_back(rg);
}

void
KSI::remove_group (RouteGroup *n) 
{
      list <RouteGroup *>::iterator i;
      for (i = groups.begin(); i != groups.end(); i++) {
            if (*i == n) {
                  groups.erase(i);
            }
      }
}

void
KSI::ensure_panel_on_top (PANEL *p)
{
      if (my_top_panel) {
            hide_panel (p);
      }

      show_panel (p);
      top_panel (p);
      my_top_panel = p;

      redraw_screen ();
}

void
KSI::redraw_screen (bool wait, bool hide_cursor)
{
      int x, y;
      PBD::TentativeLockMonitor tm(screen_lock, __LINE__, __FILE__);
      x = y = 0;
      if (!tm.locked()) {
            if (wait) {
                  PBD::LockMonitor lm(screen_lock, __LINE__, __FILE__);
                  if (hide_cursor)
                        getsyx (y, x);
                  update_panels ();
                  if (hide_cursor)
                        setsyx (y, x);
                  doupdate ();
                  } else {
                  return;
            }
      } else {
            if (hide_cursor)
                  getsyx (y, x);
            update_panels ();
            if (hide_cursor)
                  setsyx (y, x);
            doupdate ();
      }

}

void
KSI::totally_redraw_screen (void)

{
      PBD::LockMonitor lm (screen_lock, __LINE__, __FILE__);
      clearok (stdscr, 1);
      update_panels ();
      wrefresh (stdscr);
}

void
KSI::push_selection_mode (SelectionMode m)

{
      selection_mode_stack.push (m);
      update_selection_mode_display ();
}

int
KSI::tcp_connect (const string& host, int port)
{
      int fd;
      struct sockaddr_in addr;
      struct hostent *hp;

      if ((hp = gethostbyname (host.c_str())) == 0) {
            error << compose(_("cannot get host by name for %1%2"), host, strerror (errno)) << endmsg;
            return -1;
      }

      if ((fd = socket (AF_INET, SOCK_STREAM, 6)) < 0) {
            error << _("cannot create server socket") << endmsg;
            return -1;
      }

      addr.sin_family = AF_INET;
      addr.sin_port = htons(port);
      memcpy((char *)&addr.sin_addr, hp->h_addr, hp->h_length);

      if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
            error << compose(_("cannot connect to %1:%2 (%3)"), host, port, strerror (errno)) << endmsg;
            close (fd);
            return -1;
      }

      if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0) {
            error << compose(_("cannot set nonblocking mode on socket (%1)"), strerror (errno)) << endmsg;
            close (fd);
            return -1;
      }

      return fd;
}

void
KSI::start_butler_thread (void)
{
      pthread_t thread;
      
      {
            PBD::LockMonitor lm(butler_lock, __LINE__, __FILE__);
            if (pthread_create (&thread, 0, KSI::butler_thread, this)) {
                  error << _("ERROR cannot create ksi's butler thread") << endmsg;
                  butler_lock.unlock();
                  return;
            }
            pthread_cond_wait(&cond, butler_lock.mutex());
      }
      pthread_detach (thread);
      return;
}

Generated by  Doxygen 1.6.0   Back to index