adjustments to build nascent push2 surface support

This commit is contained in:
Paul Davis 2016-06-15 22:41:01 -04:00
parent 2203e03831
commit 413fe2cf9a
7 changed files with 372 additions and 2 deletions

View File

@ -13,7 +13,7 @@ export GTK2_RC_FILES=/nonexistent
# can find all the components.
#
export ARDOUR_SURFACES_PATH=$libs/surfaces/osc:$libs/surfaces/faderport:$libs/surfaces/generic_midi:$libs/surfaces/tranzport:$libs/surfaces/powermate:$libs/surfaces/mackie:$libs/surfaces/wiimote
export ARDOUR_SURFACES_PATH=$libs/surfaces/osc:$libs/surfaces/faderport:$libs/surfaces/generic_midi:$libs/surfaces/tranzport:$libs/surfaces/powermate:$libs/surfaces/mackie:$libs/surfaces/wiimote:$libs/surfaces/push2
export ARDOUR_PANNER_PATH=$libs/panners
export ARDOUR_DATA_PATH=$TOP:$TOP/build:$TOP/gtk2_ardour:$TOP/build/gtk2_ardour:.
export ARDOUR_MIDIMAPS_PATH=$TOP/midi_maps:.

View File

@ -0,0 +1,100 @@
/*
Copyright (C) 2006,2007 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.
*/
#include <stdexcept>
#include "pbd/error.h"
#include "ardour/rc_configuration.h"
#include "control_protocol/control_protocol.h"
#include "push2.h"
using namespace ARDOUR;
using namespace PBD;
using namespace std;
using namespace ArdourSurface;
static ControlProtocol*
new_push2 (ControlProtocolDescriptor*, Session* s)
{
Push2 * p2 = 0;
try {
p2 = new Push2 (*s);
/* do not set active here - wait for set_state() */
}
catch (exception & e) {
error << "Error instantiating Push2 support: " << e.what() << endmsg;
delete p2;
p2 = 0;
}
return p2;
}
static void
delete_push2 (ControlProtocolDescriptor*, ControlProtocol* cp)
{
try
{
delete cp;
}
catch ( exception & e )
{
cout << "Exception caught trying to finalize Push2 support: " << e.what() << endl;
}
}
/**
This is called on startup to check whether the lib should be loaded.
So anything that can be changed in the UI should not be used here to
prevent loading of the lib.
*/
static bool
probe_push2 (ControlProtocolDescriptor*)
{
return Push2::probe();
}
static void*
push2_request_buffer_factory (uint32_t num_requests)
{
return Push2::request_factory (num_requests);
}
// Field names commented out by JE - 06-01-2010
static ControlProtocolDescriptor mackie_descriptor = {
/*name : */ "Ableton Push2",
/*id : */ "uri://ardour.org/surfaces/push2:0",
/*ptr : */ 0,
/*module : */ 0,
/*mandatory : */ 0,
// actually, the surface does support feedback, but all this
// flag does is show a submenu on the UI, which is useless for the mackie
// because feedback is always on. In any case, who'd want to use the
// mcu without the motorised sliders doing their thing?
/*supports_feedback : */ false,
/*probe : */ probe_push2,
/*initialize : */ new_push2,
/*destroy : */ delete_push2,
/*request_buffer_factory */ push2_request_buffer_factory
};
extern "C" ARDOURSURFACE_API ControlProtocolDescriptor* protocol_descriptor () { return &mackie_descriptor; }

View File

@ -0,0 +1,98 @@
/*
Copyright (C) 2016 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.
*/
#include "pbd/failed_constructor.h"
#include "push2.h"
using namespace ARDOUR;
using namespace std;
using namespace PBD;
using namespace Glib;
using namespace ArdourSurface;
#include "i18n.h"
#include "pbd/abstract_ui.cc" // instantiate template
Push2::Push2 (Session& s)
: ControlProtocol (s, string (X_("Ableton Push2")))
, AbstractUI<Push2Request> (name())
, handle (0)
{
if ((handle = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
throw failed_constructor ();
}
libusb_claim_interface (handle, 0x00);
}
Push2::~Push2 ()
{
if (handle) {
libusb_release_interface (handle, 0x00);
libusb_close (handle);
}
}
bool
Push2::probe ()
{
libusb_device_handle *h;
libusb_init (NULL);
if ((h = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
return false;
}
libusb_close (h);
return true;
}
void*
Push2::request_factory (uint32_t num_requests)
{
/* AbstractUI<T>::request_buffer_factory() is a template method only
instantiated in this source module. To provide something visible for
use in the interface/descriptor, we have this static method that is
template-free.
*/
return request_buffer_factory (num_requests);
}
void
Push2::do_request (Push2Request * req)
{
// DEBUG_TRACE (DEBUG::MackieControl, string_compose ("doing request type %1\n", req->type));
if (req->type == CallSlot) {
call_slot (MISSING_INVALIDATOR, req->the_slot);
} else if (req->type == Quit) {
stop ();
}
}
int
Push2::stop ()
{
BaseUI::quit ();
return 0;
}

View File

@ -0,0 +1,65 @@
/*
Copyright (C) 2016 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.
*/
#ifndef __ardour_push2_h__
#define __ardour_push2_h__
#include <vector>
#include <map>
#include <list>
#include <set>
#include <libusb.h>
#define ABSTRACT_UI_EXPORTS
#include "pbd/abstract_ui.h"
#include "midi++/types.h"
#include "ardour/types.h"
#include "control_protocol/control_protocol.h"
#define ABLETON 0x2982
#define PUSH2 0x1967
namespace ArdourSurface {
struct Push2Request : public BaseUI::BaseRequestObject {
public:
Push2Request () {}
~Push2Request () {}
};
class Push2 : public ARDOUR::ControlProtocol
, public AbstractUI<Push2Request>
{
public:
Push2 (ARDOUR::Session&);
~Push2 ();
static bool probe ();
static void* request_factory (uint32_t);
private:
libusb_device_handle *handle;
void do_request (Push2Request*);
int stop ();
};
} /* namespace */
#endif /* __ardour_push2_h__ */

View File

@ -0,0 +1,64 @@
#include <libusb.h>
#include <unistd.h>
#include <assert.h>
#include <pangomm/layout.h>
#include <cairomm/context.h>
#include <cairomm/surface.h>
int
deliver_image_surface (libusb_device_handle* handle, Cairo::RefPtr<Cairo::ImageSurface> surface)
{
static uint8_t headerPkt[] = { 0xef, 0xcd, 0xab, 0x89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static uint16_t dataPkt[160*1024];
const Cairo::Format format = surface->get_format();
if (format != Cairo::FORMAT_ARGB32) {
return -1;
}
unsigned char *data = surface->get_data ();
const int width = surface->get_width();
const int height = surface->get_height();
const int stride = surface->get_stride();
assert (width == 960);
assert (height == 160);
/* fill a data packet (320kB) */
uint16_t* pkt_ptr = (uint16_t*) dataPkt;
for (int row = 0; row < height; ++row) {
uint8_t* dp = data + row * stride;
for (int col = 0; col < width; ++col) {
/* fetch r, g, b (range 0..255). Ignore alpha */
const int r = (*((uint32_t*)dp) >> 16) & 0xff;
const int g = (*((uint32_t*)dp) >> 8) & 0xff;
const int b = *((uint32_t*)dp) & 0xff;
/* convert to 5 bits, 6 bits, 5 bits, respectively */
/* generate 16 bit BGB565 value */
*pkt_ptr++ = (r >> 3) | ((g & 0xfc) << 3) | ((b & 0xf8) << 8);
dp += 4;
}
/* skip 128 bytes to next line. This is filler, used to avoid line borders occuring in the middle of 512
byte USB buffers
*/
pkt_ptr += 64; /* 128 bytes = 64 int16_t */
}
int transferred = 0;
libusb_bulk_transfer (handle, 0x01, headerPkt, sizeof(headerPkt), &transferred, 1000);
libusb_bulk_transfer (handle, 0x01, (uint8_t*) dataPkt, sizeof(dataPkt), &transferred, 1000);
}

View File

@ -0,0 +1,38 @@
#!/usr/bin/env python
from waflib.extras import autowaf as autowaf
import os
# Mandatory variables
top = '.'
out = 'build'
def options(opt):
autowaf.set_options(opt)
def configure(conf):
conf.load ('compiler_cxx')
autowaf.configure(conf)
autowaf.check_pkg(conf, 'cairomm-1.0', uselib_store='CAIROMM', atleast_version='1.8.4')
autowaf.check_pkg(conf, 'pangomm-1.5', uselib_store='CAIROMM', atleast_version='1.4')
def configure(conf):
autowaf.configure(conf)
def build(bld):
obj = bld(features = 'cxx cxxshlib')
obj.source = '''
push2.cc
interface.cc
'''
obj.export_includes = ['.']
obj.defines = [ 'PACKAGE="ardour_push2"' ]
obj.defines += [ 'ARDOURSURFACE_DLL_EXPORTS' ]
obj.includes = [ '.', './push2']
obj.name = 'libardour_push2'
obj.target = 'ardour_push2'
obj.uselib = 'CAIROMM PANGOMM USB'
obj.use = 'libardour libardour_cp libpbd'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
def shutdown():
autowaf.shutdown()

View File

@ -39,10 +39,13 @@ def configure(conf):
autowaf.set_recursive()
autowaf.configure(conf)
#autowaf.check_pkg(conf, 'libusb-1.0', uselib_store='USB', mandatory=False)
autowaf.check_pkg(conf, 'libusb-1.0', uselib_store='USB', mandatory=False)
#if Options.options.tranzport and conf.is_defined('HAVE_USB'):
# conf.define('BUILD_TRANZPORT', 1)
if conf.is_defined('HAVE_USB'):
children += [ 'push2' ]
if autowaf.check_pkg (conf, 'liblo', mandatory=False, uselib_store="LO", atleast_version="0.24"):
children += [ 'osc' ]
@ -77,6 +80,8 @@ def build(bld):
bld.recurse('wiimote')
if bld.is_defined('BUILD_TRANZPORT'):
bld.recurse('tranzport')
if bld.is_defined('HAVE_USB'):
bld.recurse('push2')
def shutdown():
autowaf.shutdown()