diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2007-06-28 19:35:48 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2007-06-28 19:35:48 +0000 |
commit | f95aa76f4a16a3f2bfd427b1e454023c3b886e5f (patch) | |
tree | f595f3b5b0fcae6a52e6268d1c714d4d5674d6b5 | |
parent | 39f5c0ad562349404bf3f6c4ddae94fef17f1295 (diff) |
add basic support for the griffin powermate (a control surface) (from ben loftis)
git-svn-id: svn://localhost/ardour2/trunk@2078 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r-- | SConstruct | 7 | ||||
-rw-r--r-- | gtk2_ardour/ladspa_pluginui.cc | 10 | ||||
-rw-r--r-- | gtk2_ardour/latency_gui.h | 5 | ||||
-rw-r--r-- | gtk2_ardour/plugin_ui.cc | 11 | ||||
-rw-r--r-- | gtk2_ardour/plugin_ui.h | 11 | ||||
-rw-r--r-- | gtk2_ardour/processor_box.cc | 4 | ||||
-rw-r--r-- | gtk2_ardour/route_params_ui.cc | 2 | ||||
-rw-r--r-- | libs/surfaces/powermate/README | 21 | ||||
-rw-r--r-- | libs/surfaces/powermate/SConscript | 57 | ||||
-rw-r--r-- | libs/surfaces/powermate/interface.cc | 57 | ||||
-rw-r--r-- | libs/surfaces/powermate/interface.os | bin | 0 -> 45208 bytes | |||
-rwxr-xr-x | libs/surfaces/powermate/libardour_powermate.so | bin | 0 -> 130667 bytes | |||
-rw-r--r-- | libs/surfaces/powermate/powermate.cc | 235 | ||||
-rw-r--r-- | libs/surfaces/powermate/powermate.h | 34 | ||||
-rw-r--r-- | libs/surfaces/powermate/powermate.os | bin | 0 -> 108016 bytes |
15 files changed, 438 insertions, 16 deletions
diff --git a/SConstruct b/SConstruct index 4dc0c8274b..069136d427 100644 --- a/SConstruct +++ b/SConstruct @@ -989,7 +989,12 @@ else: # its included in the tarball # -surface_subdirs = [ 'libs/surfaces/control_protocol', 'libs/surfaces/generic_midi', 'libs/surfaces/tranzport', 'libs/surfaces/mackie' ] +surface_subdirs = [ 'libs/surfaces/control_protocol', + 'libs/surfaces/generic_midi', + 'libs/surfaces/tranzport', + 'libs/surfaces/mackie', + 'libs/surfaces/powermate' + ] if env['SURFACES']: if have_libusb: diff --git a/gtk2_ardour/ladspa_pluginui.cc b/gtk2_ardour/ladspa_pluginui.cc index 3d516d3056..721e50753a 100644 --- a/gtk2_ardour/ladspa_pluginui.cc +++ b/gtk2_ardour/ladspa_pluginui.cc @@ -56,8 +56,8 @@ using namespace Gtkmm2ext; using namespace Gtk; using namespace sigc; -LadspaPluginUI::LadspaPluginUI (boost::shared_ptr<PluginInsert> pi, bool scrollable) - : PlugUIBase (pi), +LadspaPluginUI::LadspaPluginUI (boost::shared_ptr<PluginInsert> pi, nframes64_t sample_rate, nframes64_t period_size, bool scrollable) + : PlugUIBase (pi, sample_rate, period_size), button_table (initial_button_rows, initial_button_cols), output_table (initial_output_rows, initial_output_cols), hAdjustment(0.0, 0.0, 0.0), @@ -77,7 +77,11 @@ LadspaPluginUI::LadspaPluginUI (boost::shared_ptr<PluginInsert> pi, bool scrolla Label* combo_label = manage (new Label (_("<span size=\"large\">Presets</span>"))); combo_label->set_use_markup (true); - smaller_hbox->pack_start (*combo_label, false, false, 10); + Label* latency_label = manage (new Label (_("<span size=\"large\">Latency</span>"))); + latency_label->set_use_markup (true); + + smaller_hbox->pack_start (*latency_label, false, false, 10); + smaller_hbox->pack_start (latency_gui, false, false, 10); smaller_hbox->pack_start (combo, false, false); smaller_hbox->pack_start (save_button, false, false); diff --git a/gtk2_ardour/latency_gui.h b/gtk2_ardour/latency_gui.h index 49f22fa266..0be7fdbf4c 100644 --- a/gtk2_ardour/latency_gui.h +++ b/gtk2_ardour/latency_gui.h @@ -1,3 +1,6 @@ +#ifndef __gtk2_ardour_latency_gui_h__ +#define __gtk2_ardour_latency_gui_h__ + #include <vector> #include <string> @@ -59,3 +62,5 @@ class LatencyDialog : public ArdourDialog private: LatencyGUI lwidget; }; + +#endif /* __gtk2_ardour_latency_gui_h__ */ diff --git a/gtk2_ardour/plugin_ui.cc b/gtk2_ardour/plugin_ui.cc index 80bd9ba6f3..935fc6000d 100644 --- a/gtk2_ardour/plugin_ui.cc +++ b/gtk2_ardour/plugin_ui.cc @@ -61,7 +61,7 @@ using namespace Gtkmm2ext; using namespace Gtk; using namespace sigc; -PluginUIWindow::PluginUIWindow (boost::shared_ptr<PluginInsert> insert, bool scrollable) +PluginUIWindow::PluginUIWindow (boost::shared_ptr<PluginInsert> insert, nframes64_t sr, nframes64_t period, bool scrollable) : ArdourDialog ("plugin ui") { if (insert->plugin()->has_editor()) { @@ -73,7 +73,7 @@ PluginUIWindow::PluginUIWindow (boost::shared_ptr<PluginInsert> insert, bool scr if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (insert->plugin())) != 0) { - VSTPluginUI* vpu = new VSTPluginUI (insert, vp); + VSTPluginUI* vpu = new VSTPluginUI (insert, vp, session.frame_rate(), session.engine().frames_per_cycle()); _pluginui = vpu; get_vbox()->add (*vpu); @@ -90,7 +90,7 @@ PluginUIWindow::PluginUIWindow (boost::shared_ptr<PluginInsert> insert, bool scr } else { - LadspaPluginUI* pu = new LadspaPluginUI (insert, scrollable); + LadspaPluginUI* pu = new LadspaPluginUI (insert, sr, period, scrollable); _pluginui = pu; get_vbox()->add (*pu); @@ -145,11 +145,12 @@ PluginUIWindow::plugin_going_away () delete_when_idle (this); } -PlugUIBase::PlugUIBase (boost::shared_ptr<PluginInsert> pi) +PlugUIBase::PlugUIBase (boost::shared_ptr<PluginInsert> pi, nframes64_t sr, nframes64_t period) : insert (pi), plugin (insert->plugin()), save_button(_("Add")), - bypass_button (_("Bypass")) + bypass_button (_("Bypass")), + latency_gui (*pi, sr, period) { //combo.set_use_arrows_always(true); set_popdown_strings (combo, plugin->get_presets()); diff --git a/gtk2_ardour/plugin_ui.h b/gtk2_ardour/plugin_ui.h index 83fdf05444..ef899af6e7 100644 --- a/gtk2_ardour/plugin_ui.h +++ b/gtk2_ardour/plugin_ui.h @@ -43,6 +43,8 @@ #include <ardour_dialog.h> #include <ardour/types.h> +#include "latency_gui.h" + namespace ARDOUR { class PluginInsert; class Plugin; @@ -66,7 +68,7 @@ namespace Gtkmm2ext { class PlugUIBase : public virtual sigc::trackable { public: - PlugUIBase (boost::shared_ptr<ARDOUR::PluginInsert>); + PlugUIBase (boost::shared_ptr<ARDOUR::PluginInsert>, nframes64_t sample_rate, nframes64_t period_size); virtual ~PlugUIBase() {} virtual gint get_preferred_height () = 0; @@ -79,6 +81,7 @@ class PlugUIBase : public virtual sigc::trackable Gtk::ComboBoxText combo; Gtk::Button save_button; Gtk::ToggleButton bypass_button; + LatencyGUI latency_gui; void setting_selected(); void save_plugin_setting (void); @@ -88,7 +91,7 @@ class PlugUIBase : public virtual sigc::trackable class LadspaPluginUI : public PlugUIBase, public Gtk::VBox { public: - LadspaPluginUI (boost::shared_ptr<ARDOUR::PluginInsert> plug, bool scrollable=false); + LadspaPluginUI (boost::shared_ptr<ARDOUR::PluginInsert> plug, nframes64_t sample_rate, nframes64_t period_size, bool scrollable = false); ~LadspaPluginUI (); gint get_preferred_height () { return prefheight; } @@ -198,7 +201,7 @@ class LadspaPluginUI : public PlugUIBase, public Gtk::VBox class PluginUIWindow : public ArdourDialog { public: - PluginUIWindow (boost::shared_ptr<ARDOUR::PluginInsert> insert, bool scrollable=false); + PluginUIWindow (boost::shared_ptr<ARDOUR::PluginInsert> insert, nframes64_t sample_rate, nframes64_t period_size, bool scrollable = false); ~PluginUIWindow (); PlugUIBase& pluginui() { return *_pluginui; } @@ -217,7 +220,7 @@ class PluginUIWindow : public ArdourDialog class VSTPluginUI : public PlugUIBase, public Gtk::VBox { public: - VSTPluginUI (boost::shared_ptr<ARDOUR::PluginInsert>, boost::shared_ptr<ARDOUR::VSTPlugin>); + VSTPluginUI (boost::shared_ptr<ARDOUR::PluginInsert>, boost::shared_ptr<ARDOUR::VSTPlugin>, nframes64_t sample_rate, nframes64_t period_size); ~VSTPluginUI (); gint get_preferred_height (); diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc index d9b0dbd845..51257e18c0 100644 --- a/gtk2_ardour/processor_box.cc +++ b/gtk2_ardour/processor_box.cc @@ -1088,7 +1088,7 @@ ProcessorBox::edit_processor (boost::shared_ptr<Processor> processor) if (plugin_processor->get_gui() == 0) { - plugin_ui = new PluginUIWindow (plugin_processor); + plugin_ui = new PluginUIWindow (plugin_processor, _session.frame_rate(), _session.engine().frames_per_cycle()); if (_owner_is_mixer) { ARDOUR_UI::instance()->the_mixer()->ensure_float (*plugin_ui); @@ -1190,7 +1190,7 @@ ProcessorBox::register_actions () /* new stuff */ ActionManager::register_action (popup_act_grp, X_("newplugin"), _("New Plugin ..."), sigc::ptr_fun (ProcessorBox::rb_choose_plugin)); - act = ActionManager::register_action (popup_act_grp, X_("newprocessor"), _("New Insert"), sigc::ptr_fun (ProcessorBox::rb_choose_processor)); + act = ActionManager::register_action (popup_act_grp, X_("newinsert"), _("New Insert"), sigc::ptr_fun (ProcessorBox::rb_choose_processor)); ActionManager::jack_sensitive_actions.push_back (act); act = ActionManager::register_action (popup_act_grp, X_("newsend"), _("New Send ..."), sigc::ptr_fun (ProcessorBox::rb_choose_send)); ActionManager::jack_sensitive_actions.push_back (act); diff --git a/gtk2_ardour/route_params_ui.cc b/gtk2_ardour/route_params_ui.cc index 7807cd4a84..fb63ae8bd6 100644 --- a/gtk2_ardour/route_params_ui.cc +++ b/gtk2_ardour/route_params_ui.cc @@ -581,7 +581,7 @@ RouteParams_UI::redirect_selected (boost::shared_ptr<ARDOUR::Processor> insert, } } else if ((plugin_insert = boost::dynamic_pointer_cast<PluginInsert> (insert)) != 0) { - LadspaPluginUI *plugin_ui = new LadspaPluginUI (plugin_insert, true); + LadspaPluginUI *plugin_ui = new LadspaPluginUI (plugin_insert, session->frame_rate(), session->engine().frames_per_cycle(), true); if (place == PreFader) { cleanup_pre_view(); diff --git a/libs/surfaces/powermate/README b/libs/surfaces/powermate/README new file mode 100644 index 0000000000..d786b1d898 --- /dev/null +++ b/libs/surfaces/powermate/README @@ -0,0 +1,21 @@ + +This module works with the Griffin Powermate and allows some basic transport control. + +It autodetects the Powermate on any input device of the form "/dev/input/event*". This means you must have the powermate module in your kernel. It works out-of-the-box with 64Studio and presumably lots of other modern distributions. + +Turning the wheel left and right will act as a "Shuttle" wheel, adjusting playback speed up and down +Pushing the knob will switch between play and stop +Pushing the knob while turning will jump to the next or previous markers + + +In order for the powermate to work, you have to have permission to open the input device for reading. +In debian, I changed /etc/udev/rules.d/0_permissions.rules to have the line: +KERNEL=="event[0-9]*", MODE="0666" +but there are other ways to achieve this + + +Feedback, tweaks, bug fixes and feature ideas are encouraged + +-Ben Loftis, ben@benloftis.com + +
\ No newline at end of file diff --git a/libs/surfaces/powermate/SConscript b/libs/surfaces/powermate/SConscript new file mode 100644 index 0000000000..e6f7e251df --- /dev/null +++ b/libs/surfaces/powermate/SConscript @@ -0,0 +1,57 @@ +# -*- python -*- + +import os +import os.path +import glob + +Import('env final_prefix install_prefix final_config_prefix libraries i18n') + +powermate = env.Copy() + +# +# this defines the version number of powermate +# + +domain = 'ardour_powermate' + +powermate.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0) +powermate.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"") +powermate.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED") +powermate.Append(PACKAGE = domain) +powermate.Append(POTFILE = domain + '.pot') + +powermate_files=Split(""" +interface.cc +powermate.cc +""") + +powermate.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE") +powermate.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"") +powermate.Append(CXXFLAGS="-DCONFIG_DIR=\\\""+final_config_prefix+"\\\"") +powermate.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"") + +powermate.Merge ([ + libraries['ardour'], + libraries['ardour_cp'], + libraries['sigc2'], + libraries['pbd'], + libraries['midi++2'], + libraries['xml'], + libraries['usb'], + libraries['glib2'], + libraries['glibmm2'] + ]) + +libardour_powermate = powermate.SharedLibrary('ardour_powermate', powermate_files) + +Default(libardour_powermate) + +if env['NLS']: + i18n (powermate, powermate_files, env) + +env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2/surfaces'), libardour_powermate)) + +env.Alias('tarball', env.Distribute (env['DISTTREE'], + [ 'SConscript' ] + + powermate_files + + glob.glob('po/*.po') + glob.glob('*.h'))) diff --git a/libs/surfaces/powermate/interface.cc b/libs/surfaces/powermate/interface.cc new file mode 100644 index 0000000000..6012c064d8 --- /dev/null +++ b/libs/surfaces/powermate/interface.cc @@ -0,0 +1,57 @@ +/* + Ardour9pin interface file + Ben Loftis + Created: 05/18/06 11:07:56 + Copyright Harrison Audio, LLC, 2007 +*/ + +#include "powermate.h" + +using namespace ARDOUR; + +ControlProtocol* +new_powermate_protocol (ControlProtocolDescriptor* descriptor, Session* s) +{ + PowermateControlProtocol* pcp = new PowermateControlProtocol (*s); + + if (pcp->set_active (true)) { + delete pcp; + return 0; + } + + return pcp; + +} + +void +delete_powermate_protocol (ControlProtocolDescriptor* descriptor, ControlProtocol* cp) +{ + delete cp; +} + +bool +probe_powermate_protocol (ControlProtocolDescriptor* descriptor) +{ + return PowermateControlProtocol::probe (); +} + +static ControlProtocolDescriptor powermate_descriptor = { + name : "powermate", + id : "uri://ardour.org/ardour/powermate:0", + ptr : 0, + module : 0, + mandatory : 0, + supports_feedback : false, + probe : probe_powermate_protocol, + initialize : new_powermate_protocol, + destroy : delete_powermate_protocol +}; + + +extern "C" { +ControlProtocolDescriptor* +protocol_descriptor () { + return &powermate_descriptor; +} +} + diff --git a/libs/surfaces/powermate/interface.os b/libs/surfaces/powermate/interface.os Binary files differnew file mode 100644 index 0000000000..e0afeea53e --- /dev/null +++ b/libs/surfaces/powermate/interface.os diff --git a/libs/surfaces/powermate/libardour_powermate.so b/libs/surfaces/powermate/libardour_powermate.so Binary files differnew file mode 100755 index 0000000000..8f17d04fdd --- /dev/null +++ b/libs/surfaces/powermate/libardour_powermate.so diff --git a/libs/surfaces/powermate/powermate.cc b/libs/surfaces/powermate/powermate.cc new file mode 100644 index 0000000000..139313f3f8 --- /dev/null +++ b/libs/surfaces/powermate/powermate.cc @@ -0,0 +1,235 @@ +/* + powermate.cc + Ben Loftis + Created: 03/26/07 20:07:56 +*/ + + +#include <linux/input.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> + +#include <i18n.h> +#include <pbd/xml++.h> + +#include "powermate.h" + +using namespace ARDOUR; +using namespace std; +using namespace sigc; + +#define NUM_VALID_PREFIXES 2 + +static const char *valid_prefix[NUM_VALID_PREFIXES] = { + "Griffin PowerMate", + "Griffin SoundKnob" +}; + +#define NUM_EVENT_DEVICES 16 + +int open_powermate(const char *dev, int mode) +{ + int fd = open(dev, mode); + int i; + char name[255]; + + if(fd < 0){ + fprintf(stderr, "Unable to open \"%s\": %s\n", dev, strerror(errno)); + return -1; + } + + if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0){ + fprintf(stderr, "\"%s\": EVIOCGNAME failed: %s\n", dev, strerror(errno)); + close(fd); + return -1; + } + + // it's the correct device if the prefix matches what we expect it to be: + for(i=0; i<NUM_VALID_PREFIXES; i++) + if(!strncasecmp(name, valid_prefix[i], strlen(valid_prefix[i]))) + return fd; + + close(fd); + return -1; +} + +int find_powermate(int mode) +{ + char devname[256]; + int i, r; + + for(i=0; i<NUM_EVENT_DEVICES; i++){ + sprintf(devname, "/dev/input/event%d", i); + r = open_powermate(devname, mode); + if(r >= 0) + return r; + } + + return -1; +} + +PowermateControlProtocol::PowermateControlProtocol (Session& s) + : ControlProtocol (s, "powermate") +{ +} + +PowermateControlProtocol::~PowermateControlProtocol () +{ + set_active (false); +} + +bool +PowermateControlProtocol::probe () +{ + int port = find_powermate( O_RDONLY ); + + if (port < 0) { + printf ("powermate: Opening of powermate failed - %s\n", strerror(errno)); + close (port); + return false; + } + + close (port); + return true; +} + +int +PowermateControlProtocol::set_active (bool inActivate) +{ + if (inActivate != _active) { + + if (inActivate) { + + mPort = find_powermate(O_RDONLY); + + if ( mPort < 0 ) { + return -1; + } + + if (pthread_create (&mThread, 0, SerialThreadEntry, this) == 0) { + _active = true; + } else { + return -1; + } + + printf("Powermate Control Protocol activated\n"); + + } else { + pthread_cancel (mThread); + close (mPort); + _active = false; + printf("Powermate Control Protocol deactivated\n"); + } + } + + return 0; +} + +XMLNode& +PowermateControlProtocol::get_state () +{ + XMLNode* node = new XMLNode (X_("Protocol")); + node->add_property (X_("name"), _name); + return *node; +} + +int +PowermateControlProtocol::set_state (const XMLNode& node) +{ + return 0; +} + + +void* +PowermateControlProtocol::SerialThreadEntry (void* arg) +{ + return static_cast<PowermateControlProtocol*>(arg)->SerialThread (); +} + +#define BUFFER_SIZE 32 + +bool held = false; +bool skippingMarkers = false; + +void +PowermateControlProtocol::ProcessEvent(struct input_event *ev) +{ +#ifdef VERBOSE + fprintf(stderr, "type=0x%04x, code=0x%04x, value=%d\n", + ev->type, ev->code, (int)ev->value); +#endif + + switch(ev->type){ + case EV_MSC: + printf("The LED pulse settings were changed; code=0x%04x, value=0x%08x\n", ev->code, ev->value); + break; + case EV_REL: + if(ev->code != REL_DIAL) + fprintf(stderr, "Warning: unexpected rotation event; ev->code = 0x%04x\n", ev->code); + else{ + if (held) { + //click and hold to skip forward and back by markers + skippingMarkers = true;; + if (ev->value > 0) + next_marker(); + else + prev_marker(); + } else { + //scale the range so that we can go from +/-8x within 180 degrees, with less precision at the higher speeds + float speed = get_transport_speed(); + speed += (float)ev->value * 0.05; + if (speed > 1.5 || speed < -1.5 ) + speed += ev->value; + set_transport_speed( speed ); + } + } + break; + case EV_KEY: + if(ev->code != BTN_0) + fprintf(stderr, "Warning: unexpected key event; ev->code = 0x%04x\n", ev->code); + else + if (ev->value) + held = true; + else { + held = false; + if (skippingMarkers) { + skippingMarkers = false; + } else { + if (get_transport_speed() == 0.0) { + set_transport_speed(1.0); + } else { + set_transport_speed(0.0); + } + } + } + break; + } + + fflush(stdout); +} + +void* +PowermateControlProtocol::SerialThread () +{ + struct input_event ibuffer[BUFFER_SIZE]; + int r, events, i; + + while(1){ + r = read(mPort, ibuffer, sizeof(struct input_event) * BUFFER_SIZE); + if( r > 0 ){ + events = r / sizeof(struct input_event); + for(i=0; i<events; i++) + ProcessEvent(&ibuffer[i]); + }else{ + fprintf(stderr, "read() failed: %s\n", strerror(errno)); + return (void*) 0; + } + } + + return (void*) 0; +} + + diff --git a/libs/surfaces/powermate/powermate.h b/libs/surfaces/powermate/powermate.h new file mode 100644 index 0000000000..6b0a2fbbc3 --- /dev/null +++ b/libs/surfaces/powermate/powermate.h @@ -0,0 +1,34 @@ +#ifndef ardour_powermate_h +#define ardour_powermate_h + +#include <sys/time.h> +#include <pthread.h> + +#include "control_protocol/control_protocol.h" + +class PowermateControlProtocol : public ARDOUR::ControlProtocol +{ + public: + PowermateControlProtocol (ARDOUR::Session&); + virtual ~PowermateControlProtocol(); + + int set_active (bool yn); + static bool probe (); + + XMLNode& get_state (); + int set_state (const XMLNode&); + + private: + + static void* SerialThreadEntry (void* arg); + void* SerialThread (); + + void ProcessEvent(struct input_event *ev); + + int mPort; + pthread_t mThread; + +}; + + +#endif diff --git a/libs/surfaces/powermate/powermate.os b/libs/surfaces/powermate/powermate.os Binary files differnew file mode 100644 index 0000000000..45519ee1c9 --- /dev/null +++ b/libs/surfaces/powermate/powermate.os |