mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-08 22:55:44 +01:00
start breaking apart the various controls into their own headers and source code, and making each control know how to generate MIDI; throttle delivery of meter data and get meter ID right
git-svn-id: svn://localhost/ardour2/branches/3.0@11846 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
63e15e1737
commit
f02edae438
24 changed files with 893 additions and 551 deletions
|
|
@ -4,10 +4,13 @@
|
|||
#include "controls.h"
|
||||
#include "mackie_midi_builder.h"
|
||||
#include "surface_port.h"
|
||||
#include "jog.h"
|
||||
#include "pot.h"
|
||||
|
||||
using namespace Mackie;
|
||||
|
||||
void BcfSurface::display_bank_start (SurfacePort & port, MackieMidiBuilder & builder, uint32_t current_bank)
|
||||
void
|
||||
BcfSurface::display_bank_start (SurfacePort & port, MackieMidiBuilder & builder, uint32_t current_bank)
|
||||
{
|
||||
if (current_bank == 0) {
|
||||
// send Ar. to 2-char display on the master
|
||||
|
|
|
|||
49
libs/surfaces/mackie/button.h
Normal file
49
libs/surfaces/mackie/button.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 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_mackie_control_protocol_button_h__
|
||||
#define __ardour_mackie_control_protocol_button_h__
|
||||
|
||||
#include "controls.h"
|
||||
#include "led.h"
|
||||
|
||||
namespace Mackie {
|
||||
|
||||
class Surface;
|
||||
|
||||
class Button : public Control
|
||||
{
|
||||
public:
|
||||
Button (int id, int ordinal, std::string name, Group & group)
|
||||
: Control (id, ordinal, name, group)
|
||||
, _led (id, ordinal, name + "_led", group) {}
|
||||
|
||||
virtual const Led & led() const { return _led; }
|
||||
|
||||
virtual type_t type() const { return type_button; };
|
||||
|
||||
static Control* factory (Surface&, int id, int ordinal, const char*, Group&);
|
||||
|
||||
private:
|
||||
Led _led;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
42
libs/surfaces/mackie/control_group.h
Normal file
42
libs/surfaces/mackie/control_group.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef __ardour_mackie_control_protocol_control_group_h__
|
||||
#define __ardour_mackie_control_protocol_control_group_h__
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Mackie {
|
||||
|
||||
class Control;
|
||||
|
||||
/**
|
||||
This is a loose group of controls, eg cursor buttons,
|
||||
transport buttons, functions buttons etc.
|
||||
*/
|
||||
class Group
|
||||
{
|
||||
public:
|
||||
Group (const std::string & name)
|
||||
: _name (name) {}
|
||||
|
||||
virtual ~Group() {}
|
||||
|
||||
virtual bool is_strip() const { return false; }
|
||||
virtual bool is_master() const { return false; }
|
||||
|
||||
virtual void add (Control & control);
|
||||
|
||||
const std::string & name() const { return _name; }
|
||||
void set_name (const std::string & rhs) { _name = rhs; }
|
||||
|
||||
typedef std::vector<Control*> Controls;
|
||||
const Controls & controls() const { return _controls; }
|
||||
|
||||
protected:
|
||||
Controls _controls;
|
||||
|
||||
private:
|
||||
std::string _name;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -24,6 +24,16 @@
|
|||
#include "types.h"
|
||||
#include "mackie_midi_builder.h"
|
||||
#include "surface.h"
|
||||
#include "control_group.h"
|
||||
|
||||
#include "button.h"
|
||||
#include "led.h"
|
||||
#include "ledring.h"
|
||||
#include "pot.h"
|
||||
#include "fader.h"
|
||||
#include "jog.h"
|
||||
#include "meter.h"
|
||||
|
||||
|
||||
using namespace Mackie;
|
||||
using namespace std;
|
||||
|
|
@ -33,77 +43,6 @@ void Group::add (Control& control)
|
|||
_controls.push_back (&control);
|
||||
}
|
||||
|
||||
Strip::Strip (const std::string& name, int index)
|
||||
: Group (name)
|
||||
, _solo (0)
|
||||
, _recenable (0)
|
||||
, _mute (0)
|
||||
, _select (0)
|
||||
, _vselect (0)
|
||||
, _fader_touch (0)
|
||||
, _vpot (0)
|
||||
, _gain (0)
|
||||
, _index (index)
|
||||
{
|
||||
/* master strip only */
|
||||
}
|
||||
|
||||
Strip::Strip (Surface& surface, const std::string& name, int index, int unit_index, StripControlDefinition* ctls)
|
||||
: Group (name)
|
||||
, _solo (0)
|
||||
, _recenable (0)
|
||||
, _mute (0)
|
||||
, _select (0)
|
||||
, _vselect (0)
|
||||
, _fader_touch (0)
|
||||
, _vpot (0)
|
||||
, _gain (0)
|
||||
, _index (index)
|
||||
{
|
||||
/* build the controls for this track, which will automatically add them
|
||||
to the Group
|
||||
*/
|
||||
|
||||
for (uint32_t i = 0; ctls[i].name[0]; ++i) {
|
||||
ctls[i].factory (surface, ctls[i].base_id + unit_index, unit_index+1, ctls[i].name, *this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
TODO could optimise this to use enum, but it's only
|
||||
called during the protocol class instantiation.
|
||||
*/
|
||||
void Strip::add (Control & control)
|
||||
{
|
||||
Group::add (control);
|
||||
|
||||
if (control.name() == "gain") {
|
||||
_gain = reinterpret_cast<Fader*>(&control);
|
||||
} else if (control.name() == "vpot") {
|
||||
_vpot = reinterpret_cast<Pot*>(&control);
|
||||
} else if (control.name() == "recenable") {
|
||||
_recenable = reinterpret_cast<Button*>(&control);
|
||||
} else if (control.name() == "solo") {
|
||||
_solo = reinterpret_cast<Button*>(&control);
|
||||
} else if (control.name() == "mute") {
|
||||
_mute = reinterpret_cast<Button*>(&control);
|
||||
} else if (control.name() == "select") {
|
||||
_select = reinterpret_cast<Button*>(&control);
|
||||
} else if (control.name() == "vselect") {
|
||||
_vselect = reinterpret_cast<Button*>(&control);
|
||||
} else if (control.name() == "fader_touch") {
|
||||
_fader_touch = reinterpret_cast<Button*>(&control);
|
||||
} else if (control.name() == "meter") {
|
||||
_meter = reinterpret_cast<Meter*>(&control);
|
||||
} else if (control.type() == Control::type_led || control.type() == Control::type_led_ring) {
|
||||
// relax
|
||||
} else {
|
||||
ostringstream os;
|
||||
os << "Strip::add: unknown control type " << control;
|
||||
throw MackieControlException (os.str());
|
||||
}
|
||||
}
|
||||
|
||||
Control::Control (int id, int ordinal, std::string name, Group & group)
|
||||
: _id (id)
|
||||
, _ordinal (ordinal)
|
||||
|
|
@ -113,86 +52,6 @@ Control::Control (int id, int ordinal, std::string name, Group & group)
|
|||
{
|
||||
}
|
||||
|
||||
Fader&
|
||||
Strip::gain()
|
||||
{
|
||||
if (_gain == 0) {
|
||||
throw MackieControlException ("gain is null");
|
||||
}
|
||||
return *_gain;
|
||||
}
|
||||
|
||||
Pot&
|
||||
Strip::vpot()
|
||||
{
|
||||
if (_vpot == 0) {
|
||||
throw MackieControlException ("vpot is null");
|
||||
}
|
||||
return *_vpot;
|
||||
}
|
||||
|
||||
Button&
|
||||
Strip::recenable()
|
||||
{
|
||||
if (_recenable == 0) {
|
||||
throw MackieControlException ("recenable is null");
|
||||
}
|
||||
return *_recenable;
|
||||
}
|
||||
|
||||
Button&
|
||||
Strip::solo()
|
||||
{
|
||||
if (_solo == 0) {
|
||||
throw MackieControlException ("solo is null");
|
||||
}
|
||||
return *_solo;
|
||||
}
|
||||
Button&
|
||||
Strip::mute()
|
||||
{
|
||||
if (_mute == 0) {
|
||||
throw MackieControlException ("mute is null");
|
||||
}
|
||||
return *_mute;
|
||||
}
|
||||
|
||||
Button&
|
||||
Strip::select()
|
||||
{
|
||||
if (_select == 0) {
|
||||
throw MackieControlException ("select is null");
|
||||
}
|
||||
return *_select;
|
||||
}
|
||||
|
||||
Button&
|
||||
Strip::vselect()
|
||||
{
|
||||
if (_vselect == 0) {
|
||||
throw MackieControlException ("vselect is null");
|
||||
}
|
||||
return *_vselect;
|
||||
}
|
||||
|
||||
Button&
|
||||
Strip::fader_touch()
|
||||
{
|
||||
if (_fader_touch == 0) {
|
||||
throw MackieControlException ("fader_touch is null");
|
||||
}
|
||||
return *_fader_touch;
|
||||
}
|
||||
|
||||
Meter&
|
||||
Strip::meter()
|
||||
{
|
||||
if (_meter == 0) {
|
||||
throw MackieControlException ("meter is null");
|
||||
}
|
||||
return *_meter;
|
||||
}
|
||||
|
||||
/** @return true if the control is in use, or false otherwise.
|
||||
Buttons are `in use' when they are held down.
|
||||
Faders with touch support are `in use' when they are being touched.
|
||||
|
|
@ -231,30 +90,6 @@ ostream & Mackie::operator << (ostream & os, const Mackie::Control & control)
|
|||
return os;
|
||||
}
|
||||
|
||||
std::ostream & Mackie::operator << (std::ostream & os, const Strip & strip)
|
||||
{
|
||||
os << typeid (strip).name();
|
||||
os << " { ";
|
||||
os << "has_solo: " << boolalpha << strip.has_solo();
|
||||
os << ", ";
|
||||
os << "has_recenable: " << boolalpha << strip.has_recenable();
|
||||
os << ", ";
|
||||
os << "has_mute: " << boolalpha << strip.has_mute();
|
||||
os << ", ";
|
||||
os << "has_select: " << boolalpha << strip.has_select();
|
||||
os << ", ";
|
||||
os << "has_vselect: " << boolalpha << strip.has_vselect();
|
||||
os << ", ";
|
||||
os << "has_fader_touch: " << boolalpha << strip.has_fader_touch();
|
||||
os << ", ";
|
||||
os << "has_vpot: " << boolalpha << strip.has_vpot();
|
||||
os << ", ";
|
||||
os << "has_gain: " << boolalpha << strip.has_gain();
|
||||
os << " }";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
Control*
|
||||
Button::factory (Surface& surface, int id, int ordinal, const char* name, Group& group)
|
||||
{
|
||||
|
|
@ -305,12 +140,3 @@ Jog::factory (Surface& surface, int id, int ordinal, const char* name, Group& gr
|
|||
return j;
|
||||
}
|
||||
|
||||
Control*
|
||||
Meter::factory (Surface& surface, int id, int ordinal, const char* name, Group& group)
|
||||
{
|
||||
Meter* m = new Meter (id, ordinal, name, group);
|
||||
surface.meters[id] = m;
|
||||
surface.controls.push_back (m);
|
||||
group.add (*m);
|
||||
return m;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,119 +32,11 @@
|
|||
namespace Mackie
|
||||
{
|
||||
|
||||
class Control;
|
||||
class Strip;
|
||||
class Group;
|
||||
class Led;
|
||||
class Surface;
|
||||
|
||||
/**
|
||||
This is a loose group of controls, eg cursor buttons,
|
||||
transport buttons, functions buttons etc.
|
||||
*/
|
||||
class Group
|
||||
{
|
||||
public:
|
||||
Group (const std::string & name)
|
||||
: _name (name) {}
|
||||
|
||||
virtual ~Group() {}
|
||||
|
||||
virtual bool is_strip() const { return false; }
|
||||
virtual bool is_master() const { return false; }
|
||||
|
||||
virtual void add (Control & control);
|
||||
|
||||
const std::string & name() const { return _name; }
|
||||
void set_name (const std::string & rhs) { _name = rhs; }
|
||||
|
||||
typedef std::vector<Control*> Controls;
|
||||
const Controls & controls() const { return _controls; }
|
||||
|
||||
protected:
|
||||
Controls _controls;
|
||||
|
||||
private:
|
||||
std::string _name;
|
||||
};
|
||||
|
||||
class Button;
|
||||
class Pot;
|
||||
class Fader;
|
||||
class Meter;
|
||||
|
||||
struct StripControlDefinition {
|
||||
const char* name;
|
||||
uint32_t base_id;
|
||||
Control* (*factory)(Surface&, int index, int ordinal, const char* name, Group&);
|
||||
};
|
||||
|
||||
struct GlobalControlDefinition {
|
||||
const char* name;
|
||||
uint32_t id;
|
||||
Control* (*factory)(Surface&, int index, int ordinal, const char* name, Group&);
|
||||
const char* group_name;
|
||||
};
|
||||
|
||||
/**
|
||||
This is the set of controls that make up a strip.
|
||||
*/
|
||||
class Strip : public Group
|
||||
{
|
||||
public:
|
||||
Strip (const std::string& name, int index); /* master strip only */
|
||||
Strip (Surface&, const std::string & name, int index, int unit_index, StripControlDefinition* ctls);
|
||||
|
||||
virtual bool is_strip() const { return true; }
|
||||
virtual void add (Control & control);
|
||||
int index() const { return _index; } // zero based
|
||||
|
||||
Button & solo();
|
||||
Button & recenable();
|
||||
Button & mute();
|
||||
Button & select();
|
||||
Button & vselect();
|
||||
Button & fader_touch();
|
||||
Pot & vpot();
|
||||
Fader & gain();
|
||||
Meter& meter ();
|
||||
|
||||
bool has_solo() const { return _solo != 0; }
|
||||
bool has_recenable() const { return _recenable != 0; }
|
||||
bool has_mute() const { return _mute != 0; }
|
||||
bool has_select() const { return _select != 0; }
|
||||
bool has_vselect() const { return _vselect != 0; }
|
||||
bool has_fader_touch() const { return _fader_touch != 0; }
|
||||
bool has_vpot() const { return _vpot != 0; }
|
||||
bool has_gain() const { return _gain != 0; }
|
||||
bool has_meter() const { return _meter != 0; }
|
||||
private:
|
||||
Button* _solo;
|
||||
Button* _recenable;
|
||||
Button* _mute;
|
||||
Button* _select;
|
||||
Button* _vselect;
|
||||
Button* _fader_touch;
|
||||
Pot* _vpot;
|
||||
Fader* _gain;
|
||||
Meter* _meter;
|
||||
int _index;
|
||||
};
|
||||
|
||||
std::ostream & operator << (std::ostream &, const Strip &);
|
||||
|
||||
class MasterStrip : public Strip
|
||||
{
|
||||
public:
|
||||
MasterStrip (const std::string & name, int index)
|
||||
: Strip (name, index) {}
|
||||
|
||||
virtual bool is_master() const { return true; }
|
||||
};
|
||||
|
||||
class Led;
|
||||
|
||||
/**
|
||||
The base class for controls on the surface. They deliberately
|
||||
don't know the midi protocol for updating them.
|
||||
*/
|
||||
class Control
|
||||
{
|
||||
public:
|
||||
|
|
@ -189,8 +81,6 @@ public:
|
|||
|
||||
const std::string & name() const { return _name; }
|
||||
const Group & group() const { return _group; }
|
||||
const Strip & strip() const { return dynamic_cast<const Strip&> (_group); }
|
||||
Strip & strip() { return dynamic_cast<Strip&> (_group); }
|
||||
virtual bool accepts_feedback() const { return true; }
|
||||
|
||||
virtual type_t type() const = 0;
|
||||
|
|
@ -219,103 +109,6 @@ private:
|
|||
|
||||
std::ostream & operator << (std::ostream & os, const Control & control);
|
||||
|
||||
class Fader : public Control
|
||||
{
|
||||
public:
|
||||
Fader (int id, int ordinal, std::string name, Group & group)
|
||||
: Control (id, ordinal, name, group)
|
||||
{
|
||||
}
|
||||
|
||||
virtual type_t type() const { return type_fader; }
|
||||
|
||||
static Control* factory (Surface&, int id, int ordinal, const char*, Group&);
|
||||
};
|
||||
|
||||
class Led : public Control
|
||||
{
|
||||
public:
|
||||
Led (int id, int ordinal, std::string name, Group & group)
|
||||
: Control (id, ordinal, name, group)
|
||||
{
|
||||
}
|
||||
|
||||
virtual const Led & led() const { return *this; }
|
||||
|
||||
virtual type_t type() const { return type_led; }
|
||||
|
||||
static Control* factory (Surface&, int id, int ordinal, const char*, Group&);
|
||||
};
|
||||
|
||||
class Button : public Control
|
||||
{
|
||||
public:
|
||||
Button (int id, int ordinal, std::string name, Group & group)
|
||||
: Control (id, ordinal, name, group)
|
||||
, _led (id, ordinal, name + "_led", group) {}
|
||||
|
||||
virtual const Led & led() const { return _led; }
|
||||
|
||||
virtual type_t type() const { return type_button; };
|
||||
|
||||
static Control* factory (Surface&, int id, int ordinal, const char*, Group&);
|
||||
|
||||
private:
|
||||
Led _led;
|
||||
};
|
||||
|
||||
class LedRing : public Led
|
||||
{
|
||||
public:
|
||||
LedRing (int id, int ordinal, std::string name, Group & group)
|
||||
: Led (id, ordinal, name, group)
|
||||
{
|
||||
}
|
||||
|
||||
virtual type_t type() const { return type_led_ring; }
|
||||
};
|
||||
|
||||
class Pot : public Control
|
||||
{
|
||||
public:
|
||||
Pot (int id, int ordinal, std::string name, Group & group)
|
||||
: Control (id, ordinal, name, group)
|
||||
, _led_ring (id, ordinal, name + "_ring", group) {}
|
||||
|
||||
virtual type_t type() const { return type_pot; }
|
||||
|
||||
virtual const LedRing & led_ring() const {return _led_ring; }
|
||||
|
||||
static Control* factory (Surface&, int id, int ordinal, const char*, Group&);
|
||||
|
||||
private:
|
||||
LedRing _led_ring;
|
||||
};
|
||||
|
||||
class Jog : public Pot
|
||||
{
|
||||
public:
|
||||
Jog (int id, int ordinal, std::string name, Group & group)
|
||||
: Pot (id, ordinal, name, group)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool is_jog() const { return true; }
|
||||
|
||||
static Control* factory (Surface&, int id, int ordinal, const char*, Group&);
|
||||
};
|
||||
|
||||
class Meter : public Control
|
||||
{
|
||||
public:
|
||||
Meter (int id, int ordinal, std::string name, Group & group)
|
||||
: Control (id, ordinal, name, group) {}
|
||||
|
||||
virtual type_t type() const { return type_meter; }
|
||||
|
||||
static Control* factory (Surface&, int id, int ordinal, const char*, Group&);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* __mackie_controls_h__ */
|
||||
|
|
|
|||
23
libs/surfaces/mackie/fader.h
Normal file
23
libs/surfaces/mackie/fader.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef __ardour_mackie_control_protocol_fader_h__
|
||||
#define __ardour_mackie_control_protocol_fader_h__
|
||||
|
||||
#include "controls.h"
|
||||
|
||||
namespace Mackie {
|
||||
|
||||
class Fader : public Control
|
||||
{
|
||||
public:
|
||||
Fader (int id, int ordinal, std::string name, Group & group)
|
||||
: Control (id, ordinal, name, group)
|
||||
{
|
||||
}
|
||||
|
||||
virtual type_t type() const { return type_fader; }
|
||||
|
||||
static Control* factory (Surface&, int id, int ordinal, const char*, Group&);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
43
libs/surfaces/mackie/jog.h
Normal file
43
libs/surfaces/mackie/jog.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 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_mackie_control_protocol_jog_h__
|
||||
#define __ardour_mackie_control_protocol_jog_h__
|
||||
|
||||
#include "controls.h"
|
||||
#include "pot.h"
|
||||
|
||||
namespace Mackie {
|
||||
|
||||
class Jog : public Pot
|
||||
{
|
||||
public:
|
||||
Jog (int id, int ordinal, std::string name, Group & group)
|
||||
: Pot (id, ordinal, name, group)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool is_jog() const { return true; }
|
||||
|
||||
static Control* factory (Surface&, int id, int ordinal, const char*, Group&);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* __ardour_mackie_control_protocol_jog_h__ */
|
||||
44
libs/surfaces/mackie/led.h
Normal file
44
libs/surfaces/mackie/led.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 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_mackie_control_protocol_led_h__
|
||||
#define __ardour_mackie_control_protocol_led_h__
|
||||
|
||||
#include "controls.h"
|
||||
|
||||
namespace Mackie {
|
||||
|
||||
class Led : public Control
|
||||
{
|
||||
public:
|
||||
Led (int id, int ordinal, std::string name, Group & group)
|
||||
: Control (id, ordinal, name, group)
|
||||
{
|
||||
}
|
||||
|
||||
virtual const Led & led() const { return *this; }
|
||||
|
||||
virtual type_t type() const { return type_led; }
|
||||
|
||||
static Control* factory (Surface&, int id, int ordinal, const char*, Group&);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* __ardour_mackie_control_protocol_led_h__ */
|
||||
41
libs/surfaces/mackie/ledring.h
Normal file
41
libs/surfaces/mackie/ledring.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 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_mackie_control_protocol_ledring_h__
|
||||
#define __ardour_mackie_control_protocol_ledring_h__
|
||||
|
||||
#include "controls.h"
|
||||
#include "led.h"
|
||||
|
||||
namespace Mackie {
|
||||
|
||||
class LedRing : public Led
|
||||
{
|
||||
public:
|
||||
LedRing (int id, int ordinal, std::string name, Group & group)
|
||||
: Led (id, ordinal, name, group)
|
||||
{
|
||||
}
|
||||
|
||||
virtual type_t type() const { return type_led_ring; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -3,6 +3,13 @@
|
|||
*/
|
||||
#include "mackie_button_handler.h"
|
||||
#include "controls.h"
|
||||
#include "button.h"
|
||||
#include "led.h"
|
||||
#include "ledring.h"
|
||||
#include "pot.h"
|
||||
#include "fader.h"
|
||||
#include "jog.h"
|
||||
#include "meter.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,13 @@
|
|||
#include "bcf_surface.h"
|
||||
#include "mackie_surface.h"
|
||||
|
||||
#include "strip.h"
|
||||
#include "control_group.h"
|
||||
#include "meter.h"
|
||||
#include "button.h"
|
||||
#include "fader.h"
|
||||
#include "pot.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
using namespace std;
|
||||
using namespace Mackie;
|
||||
|
|
@ -106,6 +113,8 @@ MackieControlProtocol::~MackieControlProtocol()
|
|||
{
|
||||
DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::~MackieControlProtocol\n");
|
||||
|
||||
_active = false;
|
||||
|
||||
try {
|
||||
close();
|
||||
}
|
||||
|
|
@ -400,11 +409,11 @@ MackieControlProtocol::set_active (bool yn)
|
|||
// must come after _active = true otherwise it won't run
|
||||
update_surface();
|
||||
|
||||
Glib::RefPtr<Glib::TimeoutSource> meter_timeout = Glib::TimeoutSource::create (100); // milliseconds
|
||||
Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (100); // milliseconds
|
||||
|
||||
meter_connection = meter_timeout->connect (sigc::mem_fun (*this, &MackieControlProtocol::meter_update));
|
||||
periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, &MackieControlProtocol::periodic));
|
||||
|
||||
meter_timeout->attach (main_loop()->get_context());
|
||||
periodic_timeout->attach (main_loop()->get_context());
|
||||
|
||||
} else {
|
||||
BaseUI::quit ();
|
||||
|
|
@ -423,51 +432,29 @@ MackieControlProtocol::set_active (bool yn)
|
|||
}
|
||||
|
||||
bool
|
||||
MackieControlProtocol::meter_update ()
|
||||
MackieControlProtocol::periodic ()
|
||||
{
|
||||
/* update automation while we're here */
|
||||
|
||||
poll_session_data ();
|
||||
if (!_active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
Glib::Mutex::Lock lm (route_signals_lock);
|
||||
|
||||
for (std::vector<RouteSignal*>::iterator r = route_signals.begin(); r != route_signals.end(); ++r) {
|
||||
float dB;
|
||||
|
||||
dB = const_cast<PeakMeter&> ((*r)->route()->peak_meter()).peak_power (0);
|
||||
Mackie::Meter& m = (*r)->strip().meter();
|
||||
|
||||
float def = 0.0f; /* Meter deflection %age */
|
||||
|
||||
if (dB < -70.0f) {
|
||||
def = 0.0f;
|
||||
} else if (dB < -60.0f) {
|
||||
def = (dB + 70.0f) * 0.25f;
|
||||
} else if (dB < -50.0f) {
|
||||
def = (dB + 60.0f) * 0.5f + 2.5f;
|
||||
} else if (dB < -40.0f) {
|
||||
def = (dB + 50.0f) * 0.75f + 7.5f;
|
||||
} else if (dB < -30.0f) {
|
||||
def = (dB + 40.0f) * 1.5f + 15.0f;
|
||||
} else if (dB < -20.0f) {
|
||||
def = (dB + 30.0f) * 2.0f + 30.0f;
|
||||
} else if (dB < 6.0f) {
|
||||
def = (dB + 20.0f) * 2.5f + 50.0f;
|
||||
} else {
|
||||
def = 115.0f;
|
||||
}
|
||||
|
||||
/* 115 is the deflection %age that would be
|
||||
when dB=6.0. this is an arbitrary
|
||||
endpoint for our scaling.
|
||||
*/
|
||||
|
||||
(*r)->port().write (builder.build_meter (m, def/115.0));
|
||||
for (RouteSignals::iterator rs = route_signals.begin(); rs != route_signals.end(); ++rs) {
|
||||
update_automation (**rs);
|
||||
float dB = const_cast<PeakMeter&> ((*rs)->route()->peak_meter()).peak_power (0);
|
||||
(*rs)->port().write ((*rs)->strip().meter().update_message (dB));
|
||||
}
|
||||
|
||||
// and the master strip
|
||||
if (master_route_signal != 0) {
|
||||
update_automation (*master_route_signal);
|
||||
}
|
||||
}
|
||||
|
||||
return _active; // call it again as long as we're active
|
||||
update_timecode_display();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -496,13 +483,17 @@ MackieControlProtocol::handle_strip_button (SurfacePort & port, Control & contro
|
|||
|
||||
if (control.name() == "fader_touch") {
|
||||
state = bs == press;
|
||||
control.strip().gain().set_in_use (state);
|
||||
Strip* strip = const_cast<Strip*>(dynamic_cast<const Strip*>(&control.group()));
|
||||
|
||||
if (strip) {
|
||||
strip->gain().set_in_use (state);
|
||||
|
||||
if (ARDOUR::Config->get_mackie_emulation() == "bcf" && state) {
|
||||
/* BCF faders don't support touch, so add a timeout to reset
|
||||
their `in_use' state.
|
||||
*/
|
||||
add_in_use_timeout (port, control.strip().gain(), &control.strip().fader_touch());
|
||||
if (ARDOUR::Config->get_mackie_emulation() == "bcf" && state) {
|
||||
/* BCF faders don't support touch, so add a timeout to reset
|
||||
their `in_use' state.
|
||||
*/
|
||||
add_in_use_timeout (port, strip->gain(), &strip->fader_touch());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -733,7 +724,7 @@ MackieControlProtocol::close()
|
|||
port_connections.drop_connections ();
|
||||
session_connections.drop_connections ();
|
||||
route_connections.drop_connections ();
|
||||
meter_connection.disconnect ();
|
||||
periodic_connection.disconnect ();
|
||||
|
||||
if (_surface != 0) {
|
||||
// These will fail if the port has gone away.
|
||||
|
|
@ -1169,27 +1160,6 @@ MackieControlProtocol::update_timecode_display()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
MackieControlProtocol::poll_session_data()
|
||||
{
|
||||
if (_active) {
|
||||
// do all currently mapped routes
|
||||
{
|
||||
Glib::Mutex::Lock lm (route_signals_lock);
|
||||
for (RouteSignals::iterator it = route_signals.begin(); it != route_signals.end(); ++it) {
|
||||
update_automation (**it);
|
||||
}
|
||||
}
|
||||
|
||||
// and the master strip
|
||||
if (master_route_signal != 0) {
|
||||
update_automation (*master_route_signal);
|
||||
}
|
||||
|
||||
update_timecode_display();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
// Transport Buttons
|
||||
/////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -278,13 +278,6 @@ class MackieControlProtocol
|
|||
|
||||
void add_port (MIDI::Port &, MIDI::Port &, int number, Mackie::MackiePort::port_type_t);
|
||||
|
||||
/**
|
||||
Read session data and send to surface. Includes
|
||||
automation from the currently active routes and
|
||||
timecode displays.
|
||||
*/
|
||||
void poll_session_data();
|
||||
|
||||
// called from poll_automation to figure out which automations need to be sent
|
||||
void update_automation(Mackie::RouteSignal &);
|
||||
|
||||
|
|
@ -317,8 +310,9 @@ class MackieControlProtocol
|
|||
|
||||
void port_connected_or_disconnected (std::string, std::string, bool);
|
||||
bool control_in_use_timeout (Mackie::SurfacePort*, Mackie::Control *, Mackie::Control *);
|
||||
bool meter_update();
|
||||
sigc::connection meter_connection;
|
||||
|
||||
bool periodic();
|
||||
sigc::connection periodic_connection;
|
||||
|
||||
boost::shared_ptr<Mackie::RouteSignal> master_route_signal;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,16 @@
|
|||
|
||||
#include "ardour/debug.h"
|
||||
#include "controls.h"
|
||||
#include "control_group.h"
|
||||
|
||||
#include "strip.h"
|
||||
#include "button.h"
|
||||
#include "led.h"
|
||||
#include "ledring.h"
|
||||
#include "pot.h"
|
||||
#include "fader.h"
|
||||
#include "jog.h"
|
||||
#include "meter.h"
|
||||
#include "midi_byte_array.h"
|
||||
#include "mackie_port.h"
|
||||
|
||||
|
|
@ -36,52 +46,52 @@ using namespace std;
|
|||
|
||||
#define NUCLEUS_DEBUG 1
|
||||
|
||||
MIDI::byte MackieMidiBuilder::calculate_pot_value( midi_pot_mode mode, const ControlState & state )
|
||||
MIDI::byte MackieMidiBuilder::calculate_pot_value (midi_pot_mode mode, const ControlState & state)
|
||||
{
|
||||
// TODO do an exact calc for 0.50? To allow manually re-centering the port.
|
||||
|
||||
// center on or off
|
||||
MIDI::byte retval = ( state.pos > 0.45 && state.pos < 0.55 ? 1 : 0 ) << 6;
|
||||
MIDI::byte retval = (state.pos > 0.45 && state.pos < 0.55 ? 1 : 0) << 6;
|
||||
|
||||
// mode
|
||||
retval |= ( mode << 4 );
|
||||
retval |= (mode << 4);
|
||||
|
||||
// value, but only if off hasn't explicitly been set
|
||||
if ( state.led_state != off )
|
||||
retval += ( int(state.pos * 10.0) + 1 ) & 0x0f; // 0b00001111
|
||||
if (state.led_state != off)
|
||||
retval += (int(state.pos * 10.0) + 1) & 0x0f; // 0b00001111
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
MidiByteArray MackieMidiBuilder::build_led_ring( const Pot & pot, const ControlState & state, midi_pot_mode mode )
|
||||
MidiByteArray MackieMidiBuilder::build_led_ring (const Pot & pot, const ControlState & state, midi_pot_mode mode )
|
||||
{
|
||||
return build_led_ring( pot.led_ring(), state, mode );
|
||||
return build_led_ring (pot.led_ring(), state, mode);
|
||||
}
|
||||
|
||||
MidiByteArray MackieMidiBuilder::build_led_ring( const LedRing & led_ring, const ControlState & state, midi_pot_mode mode )
|
||||
MidiByteArray MackieMidiBuilder::build_led_ring (const LedRing & led_ring, const ControlState & state, midi_pot_mode mode)
|
||||
{
|
||||
// The other way of doing this:
|
||||
// 0x30 + pot/ring number (0-7)
|
||||
//, 0x30 + led_ring.ordinal() - 1
|
||||
return MidiByteArray ( 3
|
||||
return MidiByteArray (3
|
||||
// the control type
|
||||
, midi_pot_id
|
||||
// the id
|
||||
, 0x20 + led_ring.raw_id()
|
||||
// the value
|
||||
, calculate_pot_value( mode, state )
|
||||
, calculate_pot_value (mode, state)
|
||||
);
|
||||
}
|
||||
|
||||
MidiByteArray MackieMidiBuilder::build_led( const Button & button, LedState ls )
|
||||
MidiByteArray MackieMidiBuilder::build_led (const Button & button, LedState ls)
|
||||
{
|
||||
return build_led( button.led(), ls );
|
||||
return build_led (button.led(), ls);
|
||||
}
|
||||
|
||||
MidiByteArray MackieMidiBuilder::build_led( const Led & led, LedState ls )
|
||||
MidiByteArray MackieMidiBuilder::build_led (const Led & led, LedState ls)
|
||||
{
|
||||
MIDI::byte state = 0;
|
||||
switch ( ls.state() )
|
||||
switch (ls.state())
|
||||
{
|
||||
case LedState::on: state = 0x7f; break;
|
||||
case LedState::off: state = 0x00; break;
|
||||
|
|
@ -89,107 +99,98 @@ MidiByteArray MackieMidiBuilder::build_led( const Led & led, LedState ls )
|
|||
case LedState::flashing: state = 0x01; break;
|
||||
}
|
||||
|
||||
return MidiByteArray ( 3
|
||||
return MidiByteArray (3
|
||||
, midi_button_id
|
||||
, led.raw_id()
|
||||
, state
|
||||
);
|
||||
}
|
||||
|
||||
MidiByteArray MackieMidiBuilder::build_fader( const Fader & fader, float pos )
|
||||
MidiByteArray MackieMidiBuilder::build_fader (const Fader & fader, float pos)
|
||||
{
|
||||
int posi = int( 0x3fff * pos );
|
||||
int posi = int (0x3fff * pos);
|
||||
|
||||
return MidiByteArray ( 3
|
||||
return MidiByteArray (3
|
||||
, midi_fader_id | fader.raw_id()
|
||||
// lower-order bits
|
||||
, posi & 0x7f
|
||||
// higher-order bits
|
||||
, ( posi >> 7 )
|
||||
, (posi >> 7)
|
||||
);
|
||||
}
|
||||
|
||||
MidiByteArray MackieMidiBuilder::build_meter (const Meter & meter, float val)
|
||||
{
|
||||
MIDI::byte segment = lrintf (val*16.0);
|
||||
|
||||
return MidiByteArray (2,
|
||||
0xD0,
|
||||
(meter.raw_id()<<3) | segment);
|
||||
}
|
||||
|
||||
MidiByteArray MackieMidiBuilder::zero_strip( SurfacePort & port, const Strip & strip )
|
||||
MidiByteArray MackieMidiBuilder::zero_strip (SurfacePort & port, const Strip & strip)
|
||||
{
|
||||
Group::Controls::const_iterator it = strip.controls().begin();
|
||||
MidiByteArray retval;
|
||||
for (; it != strip.controls().end(); ++it )
|
||||
{
|
||||
|
||||
for (; it != strip.controls().end(); ++it) {
|
||||
Control & control = **it;
|
||||
if ( control.accepts_feedback() )
|
||||
retval << zero_control( control );
|
||||
if (control.accepts_feedback())
|
||||
retval << zero_control (control);
|
||||
}
|
||||
|
||||
// These must have sysex headers
|
||||
|
||||
/* XXX: not sure about this check to only display stuff for strips of index < 8 */
|
||||
if (strip.index() < 8) {
|
||||
retval << strip_display_blank( port, strip, 0 );
|
||||
retval << strip_display_blank( port, strip, 1 );
|
||||
retval << strip_display_blank (port, strip, 0);
|
||||
retval << strip_display_blank (port, strip, 1);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
MidiByteArray MackieMidiBuilder::zero_control( const Control & control )
|
||||
MidiByteArray MackieMidiBuilder::zero_control (const Control & control)
|
||||
{
|
||||
switch( control.type() ) {
|
||||
switch (control.type()) {
|
||||
case Control::type_button:
|
||||
return build_led( (Button&)control, off );
|
||||
return build_led ((Button&)control, off);
|
||||
|
||||
case Control::type_led:
|
||||
return build_led( (Led&)control, off );
|
||||
return build_led ((Led&)control, off);
|
||||
|
||||
case Control::type_fader:
|
||||
return build_fader( (Fader&)control, 0.0 );
|
||||
return build_fader ((Fader&)control, 0.0);
|
||||
|
||||
case Control::type_pot:
|
||||
return build_led_ring( dynamic_cast<const Pot&>( control ), off );
|
||||
return build_led_ring (dynamic_cast<const Pot&> (control), off);
|
||||
|
||||
case Control::type_led_ring:
|
||||
return build_led_ring( dynamic_cast<const LedRing&>( control ), off );
|
||||
return build_led_ring (dynamic_cast<const LedRing&> (control), off);
|
||||
|
||||
case Control::type_meter:
|
||||
return build_meter (dynamic_cast<const Meter&>(control), 0.0);
|
||||
return const_cast<Meter&>(dynamic_cast<const Meter&>(control)).update_message (0.0);
|
||||
|
||||
default:
|
||||
ostringstream os;
|
||||
os << "Unknown control type " << control << " in Strip::zero_control";
|
||||
throw MackieControlException( os.str() );
|
||||
throw MackieControlException (os.str());
|
||||
}
|
||||
}
|
||||
|
||||
char translate_seven_segment( char achar )
|
||||
char translate_seven_segment (char achar)
|
||||
{
|
||||
achar = toupper( achar );
|
||||
if ( achar >= 0x40 && achar <= 0x60 )
|
||||
achar = toupper (achar);
|
||||
if (achar >= 0x40 && achar <= 0x60)
|
||||
return achar - 0x40;
|
||||
else if ( achar >= 0x21 && achar <= 0x3f )
|
||||
else if (achar >= 0x21 && achar <= 0x3f)
|
||||
return achar;
|
||||
else
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
MidiByteArray MackieMidiBuilder::two_char_display( const std::string & msg, const std::string & dots )
|
||||
MidiByteArray MackieMidiBuilder::two_char_display (const std::string & msg, const std::string & dots)
|
||||
{
|
||||
if ( msg.length() != 2 ) throw MackieControlException( "MackieMidiBuilder::two_char_display: msg must be exactly 2 characters" );
|
||||
if ( dots.length() != 2 ) throw MackieControlException( "MackieMidiBuilder::two_char_display: dots must be exactly 2 characters" );
|
||||
if (msg.length() != 2) throw MackieControlException ("MackieMidiBuilder::two_char_display: msg must be exactly 2 characters");
|
||||
if (dots.length() != 2) throw MackieControlException ("MackieMidiBuilder::two_char_display: dots must be exactly 2 characters");
|
||||
|
||||
MidiByteArray bytes( 5, 0xb0, 0x4a, 0x00, 0x4b, 0x00 );
|
||||
MidiByteArray bytes (5, 0xb0, 0x4a, 0x00, 0x4b, 0x00);
|
||||
|
||||
// chars are understood by the surface in right-to-left order
|
||||
// could also exchange the 0x4a and 0x4b, above
|
||||
bytes[4] = translate_seven_segment( msg[0] ) + ( dots[0] == '.' ? 0x40 : 0x00 );
|
||||
bytes[2] = translate_seven_segment( msg[1] ) + ( dots[1] == '.' ? 0x40 : 0x00 );
|
||||
bytes[4] = translate_seven_segment (msg[0]) + (dots[0] == '.' ? 0x40 : 0x00);
|
||||
bytes[2] = translate_seven_segment (msg[1]) + (dots[1] == '.' ? 0x40 : 0x00);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
|
@ -198,16 +199,16 @@ MidiByteArray MackieMidiBuilder::two_char_display (unsigned int value, const std
|
|||
{
|
||||
ostringstream os;
|
||||
os << setfill('0') << setw(2) << value % 100;
|
||||
return two_char_display( os.str() );
|
||||
return two_char_display (os.str());
|
||||
}
|
||||
|
||||
MidiByteArray MackieMidiBuilder::strip_display_blank( SurfacePort & port, const Strip & strip, unsigned int line_number )
|
||||
MidiByteArray MackieMidiBuilder::strip_display_blank (SurfacePort & port, const Strip & strip, unsigned int line_number)
|
||||
{
|
||||
// 6 spaces, not 7 because strip_display adds a space where appropriate
|
||||
return strip_display( port, strip, line_number, " " );
|
||||
return strip_display (port, strip, line_number, " ");
|
||||
}
|
||||
|
||||
MidiByteArray MackieMidiBuilder::strip_display (SurfacePort & port, const Strip & strip, unsigned int line_number, const std::string & line )
|
||||
MidiByteArray MackieMidiBuilder::strip_display (SurfacePort & port, const Strip & strip, unsigned int line_number, const std::string & line)
|
||||
{
|
||||
assert (line_number <= 1);
|
||||
|
||||
|
|
@ -221,7 +222,7 @@ MidiByteArray MackieMidiBuilder::strip_display (SurfacePort & port, const Strip
|
|||
|
||||
// code for display
|
||||
retval << 0x12;
|
||||
// offset (0 to 0x37 first line, 0x38 to 0x6f for second line )
|
||||
// offset (0 to 0x37 first line, 0x38 to 0x6f for second line)
|
||||
retval << (index * 7 + (line_number * 0x38));
|
||||
|
||||
// ascii data to display
|
||||
|
|
@ -253,20 +254,26 @@ MidiByteArray MackieMidiBuilder::all_strips_display (SurfacePort & /*port*/, std
|
|||
return retval;
|
||||
}
|
||||
|
||||
MidiByteArray MackieMidiBuilder::timecode_display( SurfacePort & port, const std::string & timecode, const std::string & last_timecode )
|
||||
MidiByteArray MackieMidiBuilder::timecode_display (SurfacePort & port, const std::string & timecode, const std::string & last_timecode)
|
||||
{
|
||||
// if there's no change, send nothing, not even sysex header
|
||||
if ( timecode == last_timecode ) return MidiByteArray();
|
||||
if (timecode == last_timecode) return MidiByteArray();
|
||||
|
||||
// length sanity checking
|
||||
string local_timecode = timecode;
|
||||
|
||||
// truncate to 10 characters
|
||||
if ( local_timecode.length() > 10 ) local_timecode = local_timecode.substr( 0, 10 );
|
||||
if (local_timecode.length() > 10) {
|
||||
local_timecode = local_timecode.substr (0, 10);
|
||||
}
|
||||
|
||||
// pad to 10 characters
|
||||
while ( local_timecode.length() < 10 ) local_timecode += " ";
|
||||
while (local_timecode.length() < 10) {
|
||||
local_timecode += " ";
|
||||
}
|
||||
|
||||
// find the suffix of local_timecode that differs from last_timecode
|
||||
std::pair<string::const_iterator,string::iterator> pp = mismatch( last_timecode.begin(), last_timecode.end(), local_timecode.begin() );
|
||||
std::pair<string::const_iterator,string::iterator> pp = mismatch (last_timecode.begin(), last_timecode.end(), local_timecode.begin());
|
||||
|
||||
MidiByteArray retval;
|
||||
|
||||
|
|
@ -278,10 +285,9 @@ MidiByteArray MackieMidiBuilder::timecode_display( SurfacePort & port, const std
|
|||
|
||||
// translate characters. These are sent in reverse order of display
|
||||
// hence the reverse iterators
|
||||
string::reverse_iterator rend = reverse_iterator<string::iterator>( pp.second );
|
||||
for ( string::reverse_iterator it = local_timecode.rbegin(); it != rend; ++it )
|
||||
{
|
||||
retval << translate_seven_segment( *it );
|
||||
string::reverse_iterator rend = reverse_iterator<string::iterator> (pp.second);
|
||||
for (string::reverse_iterator it = local_timecode.rbegin(); it != rend; ++it) {
|
||||
retval << translate_seven_segment (*it);
|
||||
}
|
||||
|
||||
// sysex trailer
|
||||
|
|
|
|||
|
|
@ -26,6 +26,13 @@ namespace Mackie
|
|||
{
|
||||
|
||||
class SurfacePort;
|
||||
class Button;
|
||||
class Meter;
|
||||
class Fader;
|
||||
class Jog;
|
||||
class Pot;
|
||||
class Led;
|
||||
class LedRing;
|
||||
|
||||
/**
|
||||
This knows how to build midi messages given a control and
|
||||
|
|
@ -63,8 +70,6 @@ public:
|
|||
|
||||
MidiByteArray build_fader( const Fader & fader, float pos );
|
||||
|
||||
MidiByteArray build_meter (const Meter& meter, float val);
|
||||
|
||||
/// return bytes that will reset all controls to their zero positions
|
||||
/// And blank the display for the strip. Pass SurfacePort so we know which sysex header to use.
|
||||
MidiByteArray zero_strip( SurfacePort &, const Strip & strip );
|
||||
|
|
|
|||
|
|
@ -15,6 +15,12 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <glibmm/main.h>
|
||||
#include <boost/shared_array.hpp>
|
||||
|
||||
#include "mackie_port.h"
|
||||
|
||||
#include "mackie_control_exception.h"
|
||||
|
|
@ -23,9 +29,11 @@
|
|||
#include "controls.h"
|
||||
#include "surface.h"
|
||||
|
||||
#include <glibmm/main.h>
|
||||
|
||||
#include <boost/shared_array.hpp>
|
||||
#include "fader.h"
|
||||
#include "button.h"
|
||||
#include "strip.h"
|
||||
#include "pot.h"
|
||||
#include "control_group.h"
|
||||
|
||||
#include "midi++/types.h"
|
||||
#include "midi++/port.h"
|
||||
|
|
@ -35,8 +43,6 @@
|
|||
|
||||
#include "i18n.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
using namespace Mackie;
|
||||
using namespace ARDOUR;
|
||||
|
|
|
|||
92
libs/surfaces/mackie/meter.cc
Normal file
92
libs/surfaces/mackie/meter.cc
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 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 <cmath>
|
||||
|
||||
#include "meter.h"
|
||||
#include "surface.h"
|
||||
#include "surface_port.h"
|
||||
#include "control_group.h"
|
||||
|
||||
using namespace Mackie;
|
||||
|
||||
Control*
|
||||
Meter::factory (Surface& surface, int id, int ordinal, const char* name, Group& group)
|
||||
{
|
||||
Meter* m = new Meter (id, ordinal, name, group);
|
||||
surface.meters[id] = m;
|
||||
surface.controls.push_back (m);
|
||||
group.add (*m);
|
||||
return m;
|
||||
}
|
||||
|
||||
MidiByteArray
|
||||
Meter::update_message (float dB)
|
||||
{
|
||||
float def = 0.0f; /* Meter deflection %age */
|
||||
|
||||
if (dB < -70.0f) {
|
||||
def = 0.0f;
|
||||
} else if (dB < -60.0f) {
|
||||
def = (dB + 70.0f) * 0.25f;
|
||||
} else if (dB < -50.0f) {
|
||||
def = (dB + 60.0f) * 0.5f + 2.5f;
|
||||
} else if (dB < -40.0f) {
|
||||
def = (dB + 50.0f) * 0.75f + 7.5f;
|
||||
} else if (dB < -30.0f) {
|
||||
def = (dB + 40.0f) * 1.5f + 15.0f;
|
||||
} else if (dB < -20.0f) {
|
||||
def = (dB + 30.0f) * 2.0f + 30.0f;
|
||||
} else if (dB < 6.0f) {
|
||||
def = (dB + 20.0f) * 2.5f + 50.0f;
|
||||
} else {
|
||||
def = 115.0f;
|
||||
}
|
||||
|
||||
/* 115 is the deflection %age that would be
|
||||
when dB=6.0. this is an arbitrary
|
||||
endpoint for our scaling.
|
||||
*/
|
||||
|
||||
MidiByteArray msg;
|
||||
|
||||
if (def > 100.0f) {
|
||||
if (!overload_on) {
|
||||
overload_on = true;
|
||||
msg << MidiByteArray (2, 0xd0, (raw_id() << 4) | 0xe);
|
||||
}
|
||||
} else {
|
||||
if (overload_on) {
|
||||
overload_on = false;
|
||||
msg << MidiByteArray (2, 0xd0, (raw_id() << 4) | 0xf);
|
||||
}
|
||||
}
|
||||
|
||||
/* we can use up to 13 segments */
|
||||
|
||||
int segment = lrintf ((def/115.0) * 13.0);
|
||||
|
||||
if (last_segment_value_sent != segment) {
|
||||
last_segment_value_sent = segment;
|
||||
std::cerr << "Meter ID " << raw_id() << " as byte " << (((int) raw_id() << 4) | segment) << std::endl;
|
||||
msg << MidiByteArray (2, 0xD0, (raw_id()<<4) | segment);
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
52
libs/surfaces/mackie/meter.h
Normal file
52
libs/surfaces/mackie/meter.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 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_mackie_control_protocol_meter_h__
|
||||
#define __ardour_mackie_control_protocol_meter_h__
|
||||
|
||||
#include "controls.h"
|
||||
#include "midi_byte_array.h"
|
||||
|
||||
namespace Mackie {
|
||||
|
||||
class SurfacePort;
|
||||
|
||||
class Meter : public Control
|
||||
{
|
||||
public:
|
||||
Meter (int id, int ordinal, std::string name, Group & group)
|
||||
: Control (id, ordinal, name, group)
|
||||
, last_segment_value_sent (-1)
|
||||
, overload_on (false) {}
|
||||
|
||||
virtual type_t type() const { return type_meter; }
|
||||
|
||||
MidiByteArray update_message (float dB);
|
||||
|
||||
static Control* factory (Surface&, int id, int ordinal, const char*, Group&);
|
||||
|
||||
int last_segment_value_sent;
|
||||
|
||||
private:
|
||||
bool overload_on;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* __ardour_mackie_control_protocol_meter_h__ */
|
||||
28
libs/surfaces/mackie/pot.h
Normal file
28
libs/surfaces/mackie/pot.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef __ardour_mackie_control_protocol_pot_h__
|
||||
#define __ardour_mackie_control_protocol_pot_h__
|
||||
|
||||
#include "controls.h"
|
||||
#include "ledring.h"
|
||||
|
||||
namespace Mackie {
|
||||
|
||||
class Pot : public Control
|
||||
{
|
||||
public:
|
||||
Pot (int id, int ordinal, std::string name, Group & group)
|
||||
: Control (id, ordinal, name, group)
|
||||
, _led_ring (id, ordinal, name + "_ring", group) {}
|
||||
|
||||
virtual type_t type() const { return type_pot; }
|
||||
|
||||
virtual const LedRing & led_ring() const {return _led_ring; }
|
||||
|
||||
static Control* factory (Surface&, int id, int ordinal, const char*, Group&);
|
||||
|
||||
private:
|
||||
LedRing _led_ring;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* __ardour_mackie_control_protocol_pot_h__ */
|
||||
|
|
@ -15,7 +15,8 @@
|
|||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include "route_signal.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "ardour/route.h"
|
||||
#include "ardour/track.h"
|
||||
|
|
@ -24,8 +25,8 @@
|
|||
#include "ardour/session_object.h" // for Properties::name
|
||||
|
||||
#include "mackie_control_protocol.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include "route_signal.h"
|
||||
#include "strip.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
using namespace Mackie;
|
||||
|
|
|
|||
208
libs/surfaces/mackie/strip.cc
Normal file
208
libs/surfaces/mackie/strip.cc
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 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 <sstream>
|
||||
#include <stdint.h>
|
||||
#include "strip.h"
|
||||
|
||||
#include "button.h"
|
||||
#include "led.h"
|
||||
#include "ledring.h"
|
||||
#include "pot.h"
|
||||
#include "fader.h"
|
||||
#include "jog.h"
|
||||
#include "meter.h"
|
||||
|
||||
using namespace Mackie;
|
||||
using namespace std;
|
||||
|
||||
Strip::Strip (const std::string& name, int index)
|
||||
: Group (name)
|
||||
, _solo (0)
|
||||
, _recenable (0)
|
||||
, _mute (0)
|
||||
, _select (0)
|
||||
, _vselect (0)
|
||||
, _fader_touch (0)
|
||||
, _vpot (0)
|
||||
, _gain (0)
|
||||
, _index (index)
|
||||
{
|
||||
/* master strip only */
|
||||
}
|
||||
|
||||
Strip::Strip (Surface& surface, const std::string& name, int index, int unit_index, StripControlDefinition* ctls)
|
||||
: Group (name)
|
||||
, _solo (0)
|
||||
, _recenable (0)
|
||||
, _mute (0)
|
||||
, _select (0)
|
||||
, _vselect (0)
|
||||
, _fader_touch (0)
|
||||
, _vpot (0)
|
||||
, _gain (0)
|
||||
, _index (index)
|
||||
{
|
||||
/* build the controls for this track, which will automatically add them
|
||||
to the Group
|
||||
*/
|
||||
|
||||
for (uint32_t i = 0; ctls[i].name[0]; ++i) {
|
||||
ctls[i].factory (surface, ctls[i].base_id + unit_index, unit_index+1, ctls[i].name, *this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
TODO could optimise this to use enum, but it's only
|
||||
called during the protocol class instantiation.
|
||||
*/
|
||||
void Strip::add (Control & control)
|
||||
{
|
||||
Group::add (control);
|
||||
|
||||
if (control.name() == "gain") {
|
||||
_gain = reinterpret_cast<Fader*>(&control);
|
||||
} else if (control.name() == "vpot") {
|
||||
_vpot = reinterpret_cast<Pot*>(&control);
|
||||
} else if (control.name() == "recenable") {
|
||||
_recenable = reinterpret_cast<Button*>(&control);
|
||||
} else if (control.name() == "solo") {
|
||||
_solo = reinterpret_cast<Button*>(&control);
|
||||
} else if (control.name() == "mute") {
|
||||
_mute = reinterpret_cast<Button*>(&control);
|
||||
} else if (control.name() == "select") {
|
||||
_select = reinterpret_cast<Button*>(&control);
|
||||
} else if (control.name() == "vselect") {
|
||||
_vselect = reinterpret_cast<Button*>(&control);
|
||||
} else if (control.name() == "fader_touch") {
|
||||
_fader_touch = reinterpret_cast<Button*>(&control);
|
||||
} else if (control.name() == "meter") {
|
||||
_meter = reinterpret_cast<Meter*>(&control);
|
||||
} else if (control.type() == Control::type_led || control.type() == Control::type_led_ring) {
|
||||
// relax
|
||||
} else {
|
||||
ostringstream os;
|
||||
os << "Strip::add: unknown control type " << control;
|
||||
throw MackieControlException (os.str());
|
||||
}
|
||||
}
|
||||
|
||||
Fader&
|
||||
Strip::gain()
|
||||
{
|
||||
if (_gain == 0) {
|
||||
throw MackieControlException ("gain is null");
|
||||
}
|
||||
return *_gain;
|
||||
}
|
||||
|
||||
Pot&
|
||||
Strip::vpot()
|
||||
{
|
||||
if (_vpot == 0) {
|
||||
throw MackieControlException ("vpot is null");
|
||||
}
|
||||
return *_vpot;
|
||||
}
|
||||
|
||||
Button&
|
||||
Strip::recenable()
|
||||
{
|
||||
if (_recenable == 0) {
|
||||
throw MackieControlException ("recenable is null");
|
||||
}
|
||||
return *_recenable;
|
||||
}
|
||||
|
||||
Button&
|
||||
Strip::solo()
|
||||
{
|
||||
if (_solo == 0) {
|
||||
throw MackieControlException ("solo is null");
|
||||
}
|
||||
return *_solo;
|
||||
}
|
||||
Button&
|
||||
Strip::mute()
|
||||
{
|
||||
if (_mute == 0) {
|
||||
throw MackieControlException ("mute is null");
|
||||
}
|
||||
return *_mute;
|
||||
}
|
||||
|
||||
Button&
|
||||
Strip::select()
|
||||
{
|
||||
if (_select == 0) {
|
||||
throw MackieControlException ("select is null");
|
||||
}
|
||||
return *_select;
|
||||
}
|
||||
|
||||
Button&
|
||||
Strip::vselect()
|
||||
{
|
||||
if (_vselect == 0) {
|
||||
throw MackieControlException ("vselect is null");
|
||||
}
|
||||
return *_vselect;
|
||||
}
|
||||
|
||||
Button&
|
||||
Strip::fader_touch()
|
||||
{
|
||||
if (_fader_touch == 0) {
|
||||
throw MackieControlException ("fader_touch is null");
|
||||
}
|
||||
return *_fader_touch;
|
||||
}
|
||||
|
||||
Meter&
|
||||
Strip::meter()
|
||||
{
|
||||
if (_meter == 0) {
|
||||
throw MackieControlException ("meter is null");
|
||||
}
|
||||
return *_meter;
|
||||
}
|
||||
|
||||
std::ostream & Mackie::operator << (std::ostream & os, const Strip & strip)
|
||||
{
|
||||
os << typeid (strip).name();
|
||||
os << " { ";
|
||||
os << "has_solo: " << boolalpha << strip.has_solo();
|
||||
os << ", ";
|
||||
os << "has_recenable: " << boolalpha << strip.has_recenable();
|
||||
os << ", ";
|
||||
os << "has_mute: " << boolalpha << strip.has_mute();
|
||||
os << ", ";
|
||||
os << "has_select: " << boolalpha << strip.has_select();
|
||||
os << ", ";
|
||||
os << "has_vselect: " << boolalpha << strip.has_vselect();
|
||||
os << ", ";
|
||||
os << "has_fader_touch: " << boolalpha << strip.has_fader_touch();
|
||||
os << ", ";
|
||||
os << "has_vpot: " << boolalpha << strip.has_vpot();
|
||||
os << ", ";
|
||||
os << "has_gain: " << boolalpha << strip.has_gain();
|
||||
os << " }";
|
||||
|
||||
return os;
|
||||
}
|
||||
89
libs/surfaces/mackie/strip.h
Normal file
89
libs/surfaces/mackie/strip.h
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#ifndef __ardour_mackie_control_protocol_strip_h__
|
||||
#define __ardour_mackie_control_protocol_strip_h__
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "control_group.h"
|
||||
|
||||
namespace Mackie {
|
||||
|
||||
class Control;
|
||||
class Surface;
|
||||
class Button;
|
||||
class Pot;
|
||||
class Fader;
|
||||
class Meter;
|
||||
|
||||
struct StripControlDefinition {
|
||||
const char* name;
|
||||
uint32_t base_id;
|
||||
Control* (*factory)(Surface&, int index, int ordinal, const char* name, Group&);
|
||||
};
|
||||
|
||||
struct GlobalControlDefinition {
|
||||
const char* name;
|
||||
uint32_t id;
|
||||
Control* (*factory)(Surface&, int index, int ordinal, const char* name, Group&);
|
||||
const char* group_name;
|
||||
};
|
||||
|
||||
/**
|
||||
This is the set of controls that make up a strip.
|
||||
*/
|
||||
class Strip : public Group
|
||||
{
|
||||
public:
|
||||
Strip (const std::string& name, int index); /* master strip only */
|
||||
Strip (Surface&, const std::string & name, int index, int unit_index, StripControlDefinition* ctls);
|
||||
|
||||
virtual bool is_strip() const { return true; }
|
||||
virtual void add (Control & control);
|
||||
int index() const { return _index; } // zero based
|
||||
|
||||
Button & solo();
|
||||
Button & recenable();
|
||||
Button & mute();
|
||||
Button & select();
|
||||
Button & vselect();
|
||||
Button & fader_touch();
|
||||
Pot & vpot();
|
||||
Fader & gain();
|
||||
Meter& meter ();
|
||||
|
||||
bool has_solo() const { return _solo != 0; }
|
||||
bool has_recenable() const { return _recenable != 0; }
|
||||
bool has_mute() const { return _mute != 0; }
|
||||
bool has_select() const { return _select != 0; }
|
||||
bool has_vselect() const { return _vselect != 0; }
|
||||
bool has_fader_touch() const { return _fader_touch != 0; }
|
||||
bool has_vpot() const { return _vpot != 0; }
|
||||
bool has_gain() const { return _gain != 0; }
|
||||
bool has_meter() const { return _meter != 0; }
|
||||
private:
|
||||
Button* _solo;
|
||||
Button* _recenable;
|
||||
Button* _mute;
|
||||
Button* _select;
|
||||
Button* _vselect;
|
||||
Button* _fader_touch;
|
||||
Pot* _vpot;
|
||||
Fader* _gain;
|
||||
Meter* _meter;
|
||||
int _index;
|
||||
};
|
||||
|
||||
std::ostream & operator << (std::ostream &, const Strip &);
|
||||
|
||||
class MasterStrip : public Strip
|
||||
{
|
||||
public:
|
||||
MasterStrip (const std::string & name, int index)
|
||||
: Strip (name, index) {}
|
||||
|
||||
virtual bool is_master() const { return true; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* __ardour_mackie_control_protocol_strip_h__ */
|
||||
|
|
@ -6,8 +6,19 @@
|
|||
#include "ardour/debug.h"
|
||||
|
||||
#include "mackie_button_handler.h"
|
||||
#include "control_group.h"
|
||||
#include "surface_port.h"
|
||||
#include "surface.h"
|
||||
#include "strip.h"
|
||||
|
||||
#include "strip.h"
|
||||
#include "button.h"
|
||||
#include "led.h"
|
||||
#include "ledring.h"
|
||||
#include "pot.h"
|
||||
#include "fader.h"
|
||||
#include "jog.h"
|
||||
#include "meter.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace PBD;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,13 @@ namespace Mackie
|
|||
class MackieButtonHandler;
|
||||
class SurfacePort;
|
||||
class MackieMidiBuilder;
|
||||
class Button;
|
||||
class Meter;
|
||||
class Fader;
|
||||
class Jog;
|
||||
class Pot;
|
||||
class Led;
|
||||
class LedRing;
|
||||
|
||||
/**
|
||||
This represents an entire control surface, made up of Groups,
|
||||
|
|
|
|||
|
|
@ -33,8 +33,10 @@ def build(bld):
|
|||
mackie_midi_builder.cc
|
||||
mackie_port.cc
|
||||
mackie_surface.cc
|
||||
meter.cc
|
||||
midi_byte_array.cc
|
||||
route_signal.cc
|
||||
strip.cc
|
||||
surface.cc
|
||||
surface_port.cc
|
||||
types.cc
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue