Replace half-baked param metadata with descriptor.

Among other things, this means that automation controls/lists have the actual
min/max/normal/toggled of parameters, and not those inferred from the Parameter
ID, which is not correct for things like plugin parameters.

Pushing things down to the Evoral::ParmeterDescriptor may be useful in the
future to have lists do smarter things based on parameter range, but currently
I have just pushed down the above-mentioned currently used attributes.
This commit is contained in:
David Robillard 2014-12-01 14:28:03 -05:00
parent cb8abbe8d2
commit 767c0238a3
31 changed files with 484 additions and 297 deletions

View File

@ -3941,7 +3941,7 @@ Editor::cut_copy_points (CutCopyOp op)
*/
framepos_t start = std::numeric_limits<framepos_t>::max();
for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
i->second.copy = i->first->create (i->first->parameter ());
i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
/* Calculate earliest start position of any point in selection. */
start = std::min(start, i->second.line->session_position(i->first->begin()));

View File

@ -1265,7 +1265,7 @@ Selection::set_state (XMLNode const & node, int)
RouteTimeAxisView* rtv = editor->get_route_view_by_route_id (id);
if (rtv) {
boost::shared_ptr<AutomationTimeAxisView> atv = rtv->automation_child (EventTypeMap::instance().new_parameter (prop_parameter->value ()));
boost::shared_ptr<AutomationTimeAxisView> atv = rtv->automation_child (EventTypeMap::instance().from_symbol (prop_parameter->value ()));
/* the automation could be for an entity that was never saved
in the session file. Don't freak out if we can't find

View File

@ -763,6 +763,10 @@
RelativePath="..\panner_shell.cc"
>
</File>
<File
RelativePath="..\parameter_descriptor.cc"
>
</File>
<File
RelativePath="..\pcm_utils.cc"
>

View File

@ -46,7 +46,6 @@ Amp::Amp (Session& s)
, _gain_automation_buffer(0)
{
Evoral::Parameter p (GainAutomation);
p.set_range (0, max_gain_coefficient, 1, false);
boost::shared_ptr<AutomationList> gl (new AutomationList (p));
_gain_control = boost::shared_ptr<GainControl> (new GainControl (X_("gaincontrol"), s, this, p, gl));
_gain_control->set_flags (Controllable::GainLike);

View File

@ -64,13 +64,15 @@ private:
class LIBARDOUR_API AutomationList : public PBD::StatefulDestructible, public Evoral::ControlList
{
public:
AutomationList (Evoral::Parameter id);
AutomationList (const Evoral::Parameter& id, const Evoral::ParameterDescriptor& desc);
AutomationList (const Evoral::Parameter& id);
AutomationList (const XMLNode&, Evoral::Parameter id);
AutomationList (const AutomationList&);
AutomationList (const AutomationList&, double start, double end);
~AutomationList();
virtual boost::shared_ptr<Evoral::ControlList> create(Evoral::Parameter id);
virtual boost::shared_ptr<ControlList> create(const Evoral::Parameter& id,
const Evoral::ParameterDescriptor& desc);
AutomationList& operator= (const AutomationList&);

View File

@ -21,9 +21,12 @@
#ifndef __ardour_event_type_map_h__
#define __ardour_event_type_map_h__
#include <map>
#include <string>
#include "evoral/TypeMap.hpp"
#include "evoral/ControlList.hpp"
#include "evoral/ParameterDescriptor.hpp"
#include "ardour/libardour_visibility.h"
@ -43,19 +46,23 @@ public:
uint32_t midi_event_type(uint8_t status) const;
Evoral::ControlList::InterpolationStyle interpolation_of(const Evoral::Parameter& param);
bool is_integer(const Evoral::Parameter& param) const;
Evoral::Parameter new_parameter(uint32_t type, uint8_t channel=0, uint32_t id=0) const;
Evoral::Parameter new_parameter(const std::string& str) const;
std::string to_symbol(const Evoral::Parameter& param) const;
Evoral::Parameter from_symbol(const std::string& str) const;
std::string to_symbol(const Evoral::Parameter& param) const;
bool is_midi_parameter(const Evoral::Parameter& param);
const Evoral::ParameterDescriptor& descriptor(const Evoral::Parameter& param) const;
void set_descriptor(const Evoral::Parameter& param,
const Evoral::ParameterDescriptor& desc);
URIMap& uri_map() { return _uri_map; }
private:
typedef std::map<Evoral::Parameter, Evoral::ParameterDescriptor> Descriptors;
EventTypeMap(URIMap& uri_map) : _uri_map(uri_map) {}
URIMap& _uri_map;
URIMap& _uri_map;
Descriptors _descriptors;
static EventTypeMap* event_type_map;
};

View File

@ -21,7 +21,9 @@
#define __ardour_parameter_descriptor_h__
#include "ardour/variant.h"
#include "evoral/Parameter.hpp"
#include "evoral/ParameterDescriptor.hpp"
namespace ARDOUR {
@ -31,7 +33,7 @@ typedef std::map<const std::string, const float> ScalePoints;
*
* Essentially a union of LADSPA, VST and LV2 info.
*/
struct ParameterDescriptor
struct ParameterDescriptor : public Evoral::ParameterDescriptor
{
enum Unit {
NONE, ///< No unit
@ -40,72 +42,12 @@ struct ParameterDescriptor
HZ, ///< Frequency in Hertz
};
ParameterDescriptor(const Evoral::Parameter& parameter)
: key((uint32_t)-1)
, datatype(Variant::NOTHING)
, unit(NONE)
, normal(parameter.normal())
, lower(parameter.min())
, upper(parameter.max())
, step(0)
, smallstep(0)
, largestep(0)
, integer_step(parameter.type() >= MidiCCAutomation &&
parameter.type() <= MidiChannelPressureAutomation)
, toggled(parameter.toggled())
, logarithmic(false)
, sr_dependent(false)
, min_unbound(0)
, max_unbound(0)
, enumeration(false)
{
if (parameter.type() == GainAutomation) {
unit = DB;
}
update_steps();
}
ParameterDescriptor(const Evoral::Parameter& parameter);
ParameterDescriptor()
: key((uint32_t)-1)
, datatype(Variant::NOTHING)
, unit(NONE)
, normal(0)
, lower(0)
, upper(0)
, step(0)
, smallstep(0)
, largestep(0)
, integer_step(false)
, toggled(false)
, logarithmic(false)
, sr_dependent(false)
, min_unbound(0)
, max_unbound(0)
, enumeration(false)
{}
ParameterDescriptor();
/* Set step, smallstep, and largestep, based on current description */
void update_steps() {
if (unit == ParameterDescriptor::MIDI_NOTE) {
step = smallstep = 1; // semitone
largestep = 12; // octave
} else if (integer_step) {
const float delta = upper - lower;
smallstep = delta / 10000.0f;
step = delta / 1000.0f;
largestep = delta / 40.0f;
smallstep = std::max(1.0, rint(smallstep));
step = std::max(1.0, rint(step));
largestep = std::max(1.0, rint(largestep));
}
/* else: leave all others as default '0'
* in that case the UI (eg. AutomationController::create)
* uses internal_to_interface() to map the value
* to an appropriate interface range
*/
}
/** Set step, smallstep, and largestep, based on current description. */
void update_steps();
std::string label;
std::string print_fmt; ///< format string for pretty printing
@ -113,14 +55,10 @@ struct ParameterDescriptor
uint32_t key; ///< for properties
Variant::Type datatype; ///< for properties
Unit unit;
float normal;
float lower; ///< for frequencies, this is in Hz (not a fraction of the sample rate)
float upper; ///< for frequencies, this is in Hz (not a fraction of the sample rate)
float step;
float smallstep;
float largestep;
bool integer_step;
bool toggled;
bool logarithmic;
bool sr_dependent;
bool min_unbound;

View File

@ -40,11 +40,13 @@
#include "ardour/session.h"
#include "ardour/dB.h"
#include "ardour/debug.h"
#include "ardour/event_type_map.h"
#include "ardour/playlist.h"
#include "ardour/audiofilesource.h"
#include "ardour/region_factory.h"
#include "ardour/runtime_functions.h"
#include "ardour/transient_detector.h"
#include "ardour/parameter_descriptor.h"
#include "ardour/progress.h"
#include "i18n.h"
@ -1011,9 +1013,10 @@ AudioRegion::set_fade_in (boost::shared_ptr<AutomationList> f)
void
AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
{
boost::shared_ptr<Evoral::ControlList> c1 (new Evoral::ControlList (FadeInAutomation));
boost::shared_ptr<Evoral::ControlList> c2 (new Evoral::ControlList (FadeInAutomation));
boost::shared_ptr<Evoral::ControlList> c3 (new Evoral::ControlList (FadeInAutomation));
const ARDOUR::ParameterDescriptor desc(FadeInAutomation);
boost::shared_ptr<Evoral::ControlList> c1 (new Evoral::ControlList (FadeInAutomation, desc));
boost::shared_ptr<Evoral::ControlList> c2 (new Evoral::ControlList (FadeInAutomation, desc));
boost::shared_ptr<Evoral::ControlList> c3 (new Evoral::ControlList (FadeInAutomation, desc));
_fade_in->freeze ();
_fade_in->clear ();
@ -1093,8 +1096,9 @@ AudioRegion::set_fade_out (boost::shared_ptr<AutomationList> f)
void
AudioRegion::set_fade_out (FadeShape shape, framecnt_t len)
{
boost::shared_ptr<Evoral::ControlList> c1 (new Evoral::ControlList (FadeOutAutomation));
boost::shared_ptr<Evoral::ControlList> c2 (new Evoral::ControlList (FadeOutAutomation));
const ARDOUR::ParameterDescriptor desc(FadeOutAutomation);
boost::shared_ptr<Evoral::ControlList> c1 (new Evoral::ControlList (FadeOutAutomation, desc));
boost::shared_ptr<Evoral::ControlList> c2 (new Evoral::ControlList (FadeOutAutomation, desc));
_fade_out->freeze ();
_fade_out->clear ();

View File

@ -212,7 +212,7 @@ Automatable::set_automation_xml_state (const XMLNode& node, Evoral::Parameter le
const XMLProperty* id_prop = (*niter)->property("automation-id");
Evoral::Parameter param = (id_prop
? EventTypeMap::instance().new_parameter(id_prop->value())
? EventTypeMap::instance().from_symbol(id_prop->value())
: legacy_param);
if (param.type() == NullAutomation) {
@ -399,14 +399,15 @@ Automatable::transport_stopped (framepos_t now)
boost::shared_ptr<Evoral::Control>
Automatable::control_factory(const Evoral::Parameter& param)
{
boost::shared_ptr<AutomationList> list(new AutomationList(param));
Evoral::Control* control = NULL;
ParameterDescriptor desc(param);
Evoral::Control* control = NULL;
bool make_list = true;
ParameterDescriptor desc(param);
boost::shared_ptr<AutomationList> list;
if (param.type() >= MidiCCAutomation && param.type() <= MidiChannelPressureAutomation) {
MidiTrack* mt = dynamic_cast<MidiTrack*>(this);
if (mt) {
control = new MidiTrack::MidiControl(mt, param);
list.reset(); // No list, this is region "automation"
make_list = false; // No list, this is region "automation"
} else {
warning << "MidiCCAutomation for non-MidiTrack" << endl;
}
@ -424,7 +425,9 @@ Automatable::control_factory(const Evoral::Parameter& param)
desc = pi->plugin(0)->get_property_descriptor(param.id());
if (desc.datatype != Variant::NOTHING) {
if (!Variant::type_is_numeric(desc.datatype)) {
list.reset(); // Can't automate non-numeric data yet
make_list = false; // Can't automate non-numeric data yet
} else {
list = boost::shared_ptr<AutomationList>(new AutomationList(param, desc));
}
control = new PluginInsert::PluginPropertyControl(pi, param, desc, list);
}
@ -447,11 +450,14 @@ Automatable::control_factory(const Evoral::Parameter& param)
}
}
if (!control) {
control = new AutomationControl(_a_session, param, desc);
if (make_list && !list) {
list = boost::shared_ptr<AutomationList>(new AutomationList(param, desc));
}
if (!control) {
control = new AutomationControl(_a_session, param, desc, list);
}
control->set_list(list);
return boost::shared_ptr<Evoral::Control>(control);
}

View File

@ -35,7 +35,7 @@ AutomationControl::AutomationControl(ARDOUR::Session& s
boost::shared_ptr<ARDOUR::AutomationList> list,
const string& name)
: Controllable (name.empty() ? EventTypeMap::instance().to_symbol(parameter) : name)
, Evoral::Control(parameter, list)
, Evoral::Control(parameter, desc, list)
, _session(session)
, _desc(desc)
{

View File

@ -25,6 +25,7 @@
#include <algorithm>
#include "ardour/automation_list.h"
#include "ardour/event_type_map.h"
#include "ardour/parameter_descriptor.h"
#include "evoral/Curve.hpp"
#include "pbd/stacktrace.h"
#include "pbd/enumwriter.h"
@ -47,8 +48,21 @@ static void dumpit (const AutomationList& al, string prefix = "")
cerr << "\n";
}
#endif
AutomationList::AutomationList (Evoral::Parameter id)
: ControlList(id)
AutomationList::AutomationList (const Evoral::Parameter& id, const Evoral::ParameterDescriptor& desc)
: ControlList(id, desc)
{
_state = Off;
_style = Absolute;
g_atomic_int_set (&_touching, 0);
create_curve_if_necessary();
assert(_parameter.type() != NullAutomation);
AutomationListCreated(this);
}
AutomationList::AutomationList (const Evoral::Parameter& id)
: ControlList(id, ARDOUR::ParameterDescriptor(id))
{
_state = Off;
_style = Absolute;
@ -91,7 +105,7 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
* in or below the AutomationList node. It is used if @param id is non-null.
*/
AutomationList::AutomationList (const XMLNode& node, Evoral::Parameter id)
: ControlList(id)
: ControlList(id, ARDOUR::ParameterDescriptor(id))
{
g_atomic_int_set (&_touching, 0);
_state = Off;
@ -114,9 +128,10 @@ AutomationList::~AutomationList()
}
boost::shared_ptr<Evoral::ControlList>
AutomationList::create(Evoral::Parameter id)
AutomationList::create(const Evoral::Parameter& id,
const Evoral::ParameterDescriptor& desc)
{
return boost::shared_ptr<Evoral::ControlList>(new AutomationList(id));
return boost::shared_ptr<Evoral::ControlList>(new AutomationList(id, desc));
}
void
@ -414,7 +429,7 @@ AutomationList::set_state (const XMLNode& node, int version)
}
if ((prop = node.property (X_("automation-id"))) != 0){
_parameter = EventTypeMap::instance().new_parameter(prop->value());
_parameter = EventTypeMap::instance().from_symbol(prop->value());
} else {
warning << "Legacy session: automation list has no automation-id property." << endmsg;
}

View File

@ -25,6 +25,7 @@
#include "ardour/parameter_types.h"
#include "ardour/uri_map.h"
#include "evoral/Parameter.hpp"
#include "evoral/ParameterDescriptor.hpp"
#include "evoral/midi_events.h"
#include "pbd/error.h"
#include "pbd/compose.h"
@ -40,25 +41,6 @@ EventTypeMap::instance()
{
if (!EventTypeMap::event_type_map) {
EventTypeMap::event_type_map = new EventTypeMap(URIMap::instance());
// Initialize parameter metadata
EventTypeMap::event_type_map->new_parameter(NullAutomation);
EventTypeMap::event_type_map->new_parameter(GainAutomation);
EventTypeMap::event_type_map->new_parameter(PanAzimuthAutomation);
EventTypeMap::event_type_map->new_parameter(PanElevationAutomation);
EventTypeMap::event_type_map->new_parameter(PanWidthAutomation);
EventTypeMap::event_type_map->new_parameter(PluginAutomation);
EventTypeMap::event_type_map->new_parameter(PluginPropertyAutomation);
EventTypeMap::event_type_map->new_parameter(SoloAutomation);
EventTypeMap::event_type_map->new_parameter(MuteAutomation);
EventTypeMap::event_type_map->new_parameter(MidiCCAutomation);
EventTypeMap::event_type_map->new_parameter(MidiPgmChangeAutomation);
EventTypeMap::event_type_map->new_parameter(MidiPitchBenderAutomation);
EventTypeMap::event_type_map->new_parameter(MidiChannelPressureAutomation);
EventTypeMap::event_type_map->new_parameter(FadeInAutomation);
EventTypeMap::event_type_map->new_parameter(FadeOutAutomation);
EventTypeMap::event_type_map->new_parameter(EnvelopeAutomation);
EventTypeMap::event_type_map->new_parameter(MidiCCAutomation);
}
return *EventTypeMap::event_type_map;
}
@ -69,12 +51,6 @@ EventTypeMap::type_is_midi(uint32_t type) const
return ARDOUR::parameter_is_midi((AutomationType)type);
}
bool
EventTypeMap::is_midi_parameter(const Evoral::Parameter& param)
{
return type_is_midi(param.type());
}
uint8_t
EventTypeMap::parameter_midi_type(const Evoral::Parameter& param) const
{
@ -87,13 +63,6 @@ EventTypeMap::midi_event_type(uint8_t status) const
return (uint32_t)ARDOUR::midi_parameter_type(status);
}
bool
EventTypeMap::is_integer(const Evoral::Parameter& param) const
{
return ( param.type() >= MidiCCAutomation
&& param.type() <= MidiChannelPressureAutomation);
}
Evoral::ControlList::InterpolationStyle
EventTypeMap::interpolation_of(const Evoral::Parameter& param)
{
@ -147,75 +116,8 @@ EventTypeMap::interpolation_of(const Evoral::Parameter& param)
return Evoral::ControlList::Linear; // Not reached, suppress warnings
}
Evoral::Parameter
EventTypeMap::new_parameter(uint32_t type, uint8_t channel, uint32_t id) const
{
Evoral::Parameter p(type, channel, id);
double min = 0.0f;
double max = 1.0f;
double normal = 0.0f;
bool toggled = false;
switch((AutomationType)type) {
case NullAutomation:
case GainAutomation:
max = 2.0f;
normal = 1.0f;
break;
case PanAzimuthAutomation:
normal = 0.5f; // there really is no normal but this works for stereo, sort of
break;
case PanWidthAutomation:
min = -1.0;
max = 1.0;
normal = 0.0f;
break;
case PanElevationAutomation:
case PanFrontBackAutomation:
case PanLFEAutomation:
break;
case RecEnableAutomation:
/* default 0.0 - 1.0 is fine */
toggled = true;
break;
case PluginAutomation:
case FadeInAutomation:
case FadeOutAutomation:
case EnvelopeAutomation:
max = 2.0f;
normal = 1.0f;
break;
case SoloAutomation:
case MuteAutomation:
max = 1.0f;
normal = 0.0f;
toggled = true;
break;
case MidiCCAutomation:
case MidiPgmChangeAutomation:
case MidiChannelPressureAutomation:
min = 0.0;
normal = 0.0;
max = 127.0;
break;
case MidiPitchBenderAutomation:
min = 0.0;
normal = 8192.0;
max = 16383.0;
case MidiSystemExclusiveAutomation:
return p;
case PluginPropertyAutomation:
return p;
}
p.set_range(type, min, max, normal, toggled);
return p;
}
Evoral::Parameter
EventTypeMap::new_parameter(const string& str) const
EventTypeMap::from_symbol(const string& str) const
{
AutomationType p_type = NullAutomation;
uint8_t p_channel = 0;
@ -285,7 +187,7 @@ EventTypeMap::new_parameter(const string& str) const
PBD::warning << "Unknown Parameter '" << str << "'" << endmsg;
}
return new_parameter(p_type, p_channel, p_id);
return Evoral::Parameter(p_type, p_channel, p_id);
}
/** Unique string representation, suitable as an XML property value.
@ -341,5 +243,21 @@ EventTypeMap::to_symbol(const Evoral::Parameter& param) const
}
}
const Evoral::ParameterDescriptor&
EventTypeMap::descriptor(const Evoral::Parameter& param) const
{
static const Evoral::ParameterDescriptor nil;
Descriptors::const_iterator d = _descriptors.find(param);
return (d != _descriptors.end()) ? d->second : nil;
}
void
EventTypeMap::set_descriptor(const Evoral::Parameter& param,
const Evoral::ParameterDescriptor& desc)
{
_descriptors.insert(std::make_pair(param, desc));
}
} // namespace ARDOUR

View File

@ -45,7 +45,7 @@ MidiAutomationListBinder::MidiAutomationListBinder (XMLNode* node, Session::Sour
assert (i != sources.end());
_source = boost::dynamic_pointer_cast<MidiSource> (i->second);
_parameter = EventTypeMap::instance().new_parameter (parameter->value());
_parameter = EventTypeMap::instance().from_symbol (parameter->value());
}
AutomationList*

View File

@ -123,7 +123,7 @@ MidiSource::set_state (const XMLNode& node, int /*version*/)
error << _("Missing parameter property on InterpolationStyle") << endmsg;
return -1;
}
Evoral::Parameter p = EventTypeMap::instance().new_parameter (prop->value());
Evoral::Parameter p = EventTypeMap::instance().from_symbol (prop->value());
if ((prop = (*i)->property (X_("style"))) == 0) {
error << _("Missing style property on InterpolationStyle") << endmsg;
@ -138,7 +138,7 @@ MidiSource::set_state (const XMLNode& node, int /*version*/)
error << _("Missing parameter property on AutomationState") << endmsg;
return -1;
}
Evoral::Parameter p = EventTypeMap::instance().new_parameter (prop->value());
Evoral::Parameter p = EventTypeMap::instance().from_symbol (prop->value());
if ((prop = (*i)->property (X_("state"))) == 0) {
error << _("Missing state property on AutomationState") << endmsg;

View File

@ -37,6 +37,7 @@
#include "ardour/buffer_set.h"
#include "ardour/debug.h"
#include "ardour/delivery.h"
#include "ardour/event_type_map.h"
#include "ardour/meter.h"
#include "ardour/midi_diskstream.h"
#include "ardour/midi_playlist.h"
@ -657,16 +658,17 @@ void
MidiTrack::MidiControl::set_value(double val)
{
const Evoral::Parameter &parameter = _list ? _list->parameter() : Control::parameter();
const Evoral::ParameterDescriptor &desc = EventTypeMap::instance().descriptor(parameter);
bool valid = false;
if (isinf_local(val)) {
cerr << "MIDIControl value is infinity" << endl;
} else if (isnan_local(val)) {
cerr << "MIDIControl value is NaN" << endl;
} else if (val < parameter.min()) {
cerr << "MIDIControl value is < " << parameter.min() << endl;
} else if (val > parameter.max()) {
cerr << "MIDIControl value is > " << parameter.max() << endl;
} else if (val < desc.lower) {
cerr << "MIDIControl value is < " << desc.lower << endl;
} else if (val > desc.upper) {
cerr << "MIDIControl value is > " << desc.upper << endl;
} else {
valid = true;
}
@ -675,7 +677,7 @@ MidiTrack::MidiControl::set_value(double val)
return;
}
assert(val <= parameter.max());
assert(val <= desc.upper);
if ( ! _list || ! automation_playback()) {
size_t size = 3;
uint8_t ev[3] = { parameter.channel(), uint8_t (val), 0 };

View File

@ -0,0 +1,135 @@
/*
Copyright (C) 2014 Paul Davis
Author: David Robillard
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 "ardour/amp.h"
#include "ardour/parameter_descriptor.h"
#include "ardour/types.h"
namespace ARDOUR {
ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter)
: Evoral::ParameterDescriptor()
, key((uint32_t)-1)
, datatype(Variant::NOTHING)
, unit(NONE)
, step(0)
, smallstep(0)
, largestep(0)
, integer_step(parameter.type() >= MidiCCAutomation &&
parameter.type() <= MidiChannelPressureAutomation)
, logarithmic(false)
, sr_dependent(false)
, min_unbound(0)
, max_unbound(0)
, enumeration(false)
{
if (parameter.type() == GainAutomation) {
unit = DB;
}
switch((AutomationType)parameter.type()) {
case GainAutomation:
upper = Amp::max_gain_coefficient;
normal = 1.0f;
break;
case PanAzimuthAutomation:
normal = 0.5f; // there really is no _normal but this works for stereo, sort of
break;
case PanWidthAutomation:
lower = -1.0;
upper = 1.0;
normal = 0.0f;
break;
case RecEnableAutomation:
/* default 0.0 - 1.0 is fine */
toggled = true;
break;
case PluginAutomation:
case FadeInAutomation:
case FadeOutAutomation:
case EnvelopeAutomation:
upper = 2.0f;
normal = 1.0f;
break;
case SoloAutomation:
case MuteAutomation:
upper = 1.0f;
normal = 0.0f;
toggled = true;
break;
case MidiCCAutomation:
case MidiPgmChangeAutomation:
case MidiChannelPressureAutomation:
lower = 0.0;
normal = 0.0;
upper = 127.0;
break;
case MidiPitchBenderAutomation:
lower = 0.0;
normal = 8192.0;
upper = 16383.0;
break;
default:
break;
}
update_steps();
}
ParameterDescriptor::ParameterDescriptor()
: Evoral::ParameterDescriptor()
, key((uint32_t)-1)
, datatype(Variant::NOTHING)
, unit(NONE)
, step(0)
, smallstep(0)
, largestep(0)
, integer_step(false)
, logarithmic(false)
, sr_dependent(false)
, min_unbound(0)
, max_unbound(0)
, enumeration(false)
{}
void
ParameterDescriptor::update_steps()
{
if (unit == ParameterDescriptor::MIDI_NOTE) {
step = smallstep = 1; // semitone
largestep = 12; // octave
} else if (integer_step) {
const float delta = upper - lower;
smallstep = delta / 10000.0f;
step = delta / 1000.0f;
largestep = delta / 40.0f;
smallstep = std::max(1.0, rint(smallstep));
step = std::max(1.0, rint(step));
largestep = std::max(1.0, rint(largestep));
}
/* else: leave all others as default '0'
* in that case the UI (eg. AutomationController::create)
* uses internal_to_interface() to map the value
* to an appropriate interface range
*/
}
} // namespace ARDOUR

View File

@ -248,13 +248,8 @@ PluginInsert::create_automatable_parameters ()
ParameterDescriptor desc;
_plugins.front()->get_parameter_descriptor(i->id(), desc);
/* the Parameter belonging to the actual plugin doesn't have its range set
but we want the Controllable related to this Parameter to have those limits.
*/
param.set_range (desc.lower, desc.upper, _plugins.front()->default_value(i->id()), desc.toggled);
can_automate (param);
boost::shared_ptr<AutomationList> list(new AutomationList(param));
boost::shared_ptr<AutomationList> list(new AutomationList(param, desc));
add_control (boost::shared_ptr<AutomationControl> (new PluginControl(this, param, desc, list)));
} else if (i->type() == PluginPropertyAutomation) {
Evoral::Parameter param(*i);
@ -262,7 +257,7 @@ PluginInsert::create_automatable_parameters ()
if (desc.datatype != Variant::NOTHING) {
boost::shared_ptr<AutomationList> list;
if (Variant::type_is_numeric(desc.datatype)) {
list = boost::shared_ptr<AutomationList>(new AutomationList(param));
list = boost::shared_ptr<AutomationList>(new AutomationList(param, desc));
}
add_control (boost::shared_ptr<AutomationControl> (new PluginPropertyControl(this, param, desc, list)));
}

View File

@ -0,0 +1,76 @@
/*
Copyright (C) 2014 Paul Davis
Author: David Robillard
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 "ardour/value_as_string.h"
namespace ARDOUR {
std::string
value_as_string(const Evoral::ParameterDescriptor& desc,
double v)
{
char buf[32];
if (desc.scale_points) {
// Check if value is on a scale point
for (Evoral::ScalePoints::const_iterator i = desc.scale_points->begin();
i != desc.scale_points->end();
++i) {
if (i->second == v) {
return i->first; // Found it, return scale point label
}
}
}
// Value is not a scale point, print it normally
if (desc.unit == Evoral::ParameterDescriptor::MIDI_NOTE) {
if (v >= 0 && v <= 127) {
const int num = rint(v);
static const char names[12][3] = {
"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
};
snprintf(buf, sizeof(buf), "%s %d", names[num % 12], (num / 12) - 2);
} else {
// Odd, invalid range, just print the number
snprintf(buf, sizeof(buf), "%.0f", v);
}
} else if (!desc.print_fmt.empty()) {
snprintf(buf, sizeof(buf), desc.print_fmt.c_str(), v);
} else if (desc.integer_step) {
snprintf(buf, sizeof(buf), "%d", (int)v);
} else {
snprintf(buf, sizeof(buf), "%.3f", v);
}
if (desc.print_fmt.empty() && desc.unit == Evoral::ParameterDescriptor::DB) {
// TODO: Move proper dB printing from AutomationLine here
return std::string(buf) + " dB";
}
return buf;
}
std::string
value_as_string(const Evoral::ParameterDescriptor& desc,
const Evoral::Variant& val)
{
// Only numeric support, for now
return value_as_string(desc, val.to_double());
}
} // namespace ARDOUR

View File

@ -141,6 +141,7 @@ libardour_sources = [
'panner.cc',
'panner_manager.cc',
'panner_shell.cc',
'parameter_descriptor.cc',
'pcm_utils.cc',
'playlist.cc',
'playlist_factory.cc',

View File

@ -511,6 +511,10 @@
RelativePath="..\evoral\Parameter.hpp"
>
</File>
<File
RelativePath="..\evoral\ParameterDescriptor.hpp"
>
</File>
<File
RelativePath="..\evoral\PatchChange.hpp"
>

View File

@ -26,11 +26,14 @@
#include "evoral/visibility.h"
#include "evoral/Parameter.hpp"
#include "evoral/ParameterDescriptor.hpp"
namespace Evoral {
class ControlList;
class ParameterDescriptor;
class Transport;
class TypeMap;
/** Base class representing some kind of (automatable) control; a fader's gain,
* for example, or a compressor plugin's threshold.
@ -38,11 +41,13 @@ class Transport;
* The class knows the Evoral::Parameter that it is controlling, and has
* a list of values for automation.
*/
class LIBEVORAL_API Control
{
public:
Control(const Parameter& parameter, boost::shared_ptr<ControlList>);
Control(const Parameter& parameter,
const ParameterDescriptor& desc,
boost::shared_ptr<ControlList> list);
virtual ~Control() {}
virtual void set_double (double val, double frame=0, bool to_list=false);

View File

@ -34,10 +34,12 @@
#include "evoral/types.hpp"
#include "evoral/Range.hpp"
#include "evoral/Parameter.hpp"
#include "evoral/ParameterDescriptor.hpp"
namespace Evoral {
class Curve;
class TypeMap;
/** A single event (time-stamped value) for a control
*/
@ -82,12 +84,12 @@ public:
typedef EventList::const_iterator const_iterator;
typedef EventList::const_reverse_iterator const_reverse_iterator;
ControlList (const Parameter& id);
ControlList (const Parameter& id, const ParameterDescriptor& desc);
ControlList (const ControlList&);
ControlList (const ControlList&, double start, double end);
virtual ~ControlList();
virtual boost::shared_ptr<ControlList> create(Parameter id);
virtual boost::shared_ptr<ControlList> create(const Parameter& id, const ParameterDescriptor& desc);
void dump (std::ostream&);
@ -102,6 +104,9 @@ public:
const Parameter& parameter() const { return _parameter; }
void set_parameter(const Parameter& p) { _parameter = p; }
const ParameterDescriptor& descriptor() const { return _desc; }
void set_descriptor(const ParameterDescriptor& d) { _desc = d; }
EventList::size_type size() const { return _events.size(); }
double length() const {
Glib::Threads::Mutex::Lock lm (_lock);
@ -218,7 +223,7 @@ public:
};
const EventList& events() const { return _events; }
double default_value() const { return _parameter.normal(); }
double default_value() const { return _default_value; }
// FIXME: const violations for Curve
Glib::Threads::Mutex& lock() const { return _lock; }
@ -288,10 +293,12 @@ protected:
mutable LookupCache _lookup_cache;
mutable SearchCache _search_cache;
mutable Glib::Threads::Mutex _lock;
Parameter _parameter;
ParameterDescriptor _desc;
InterpolationStyle _interpolation;
EventList _events;
mutable Glib::Threads::Mutex _lock;
int8_t _frozen;
bool _changed_when_thawed;
double _min_yval;

View File

@ -28,7 +28,6 @@
namespace Evoral {
/** ID of a [play|record|automate]able parameter.
*
* A parameter is defined by (type, id, channel). Type is an integer which
@ -41,12 +40,10 @@ namespace Evoral {
class LIBEVORAL_API Parameter
{
public:
Parameter(uint32_t type, uint8_t channel=0, uint32_t id=0)
inline Parameter(uint32_t type, uint8_t channel=0, uint32_t id=0)
: _type(type), _id(id), _channel(channel)
{}
virtual ~Parameter() {}
inline uint32_t type() const { return _type; }
inline uint8_t channel() const { return _channel; }
inline uint32_t id() const { return _id; }
@ -78,52 +75,12 @@ public:
inline operator bool() const { return (_type != 0); }
/** Not used in indentity/comparison */
struct Metadata {
Metadata(double low=0.0, double high=1.0, double mid=0.0, bool tog=false)
: min(low), max(high), normal(mid), toggled(tog)
{}
double min;
double max;
double normal;
bool toggled;
};
inline static void set_range(uint32_t type, double min, double max, double normal, bool toggled) {
_type_metadata[type] = Metadata(min, max, normal, toggled);
}
inline void set_range(double min, double max, double normal, bool toggled) {
_metadata = boost::shared_ptr<Metadata>(new Metadata(min, max, normal, toggled));
}
inline Metadata& metadata() const {
if (_metadata)
return *_metadata.get();
else
return _type_metadata[_type];
}
inline double min() const { return metadata().min; }
inline double max() const { return metadata().max; }
inline double normal() const { return metadata().normal; }
inline double toggled() const { return metadata().toggled; }
protected:
// Default copy constructor is ok
// ID (used in comparison)
private:
uint32_t _type;
uint32_t _id;
uint8_t _channel;
boost::shared_ptr<Metadata> _metadata;
typedef std::map<uint32_t, Metadata> TypeMetadata;
static TypeMetadata _type_metadata;
};
} // namespace Evoral
#endif // EVORAL_PARAMETER_HPP

View File

@ -0,0 +1,42 @@
/* This file is part of Evoral.
* Copyright (C) 2000-2014 Paul Davis
* Author: David Robillard
*
* Evoral 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.
*
* Evoral 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 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.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef EVORAL_PARAMETER_DESCRIPTOR_HPP
#define EVORAL_PARAMETER_DESCRIPTOR_HPP
namespace Evoral {
/** Description of the value range of a parameter or control. */
struct ParameterDescriptor
{
ParameterDescriptor()
: normal(0.0)
, lower(0.0)
, upper(0.0)
, toggled(false)
{}
float normal; ///< Default value
float lower; ///< Minimum value (in Hz, for frequencies)
float upper; ///< Maximum value (in Hz, for frequencies)
bool toggled; ///< True iff parameter is boolean
};
} // namespace Evoral
#endif // EVORAL_PARAMETER_DESCRIPTOR_HPP

View File

@ -30,13 +30,13 @@
#include "evoral/visibility.h"
#include "evoral/types.hpp"
#include "evoral/Note.hpp"
#include "evoral/Parameter.hpp"
#include "evoral/ControlSet.hpp"
#include "evoral/ControlList.hpp"
#include "evoral/PatchChange.hpp"
namespace Evoral {
class Parameter;
class TypeMap;
template<typename Time> class EventSink;
template<typename Time> class Note;
@ -109,6 +109,8 @@ public:
void append(const Event<Time>& ev, Evoral::event_id_t evid);
const TypeMap& type_map() const { return _type_map; }
inline size_t n_notes() const { return _notes.size(); }
inline bool empty() const { return _notes.empty() && _sysexes.empty() && _patch_changes.empty() && ControlSet::controls_empty(); }

View File

@ -28,6 +28,7 @@
namespace Evoral {
class Parameter;
class ParameterDescriptor;
/** The applications passes one of these which provide the implementation
* with required information about event types in an opaque, type neutral way
@ -50,11 +51,8 @@ public:
*/
virtual uint32_t midi_event_type(uint8_t status) const = 0;
/** Return true iff parameter should be locked to integer boundaries */
virtual bool is_integer(const Evoral::Parameter& param) const = 0;
/** Create a parameter with the given type ID */
virtual Parameter new_parameter(uint32_t type, uint8_t channel, uint32_t id) const = 0;
/** Return the description of a parameter. */
virtual const ParameterDescriptor& descriptor(const Parameter& param) const = 0;
virtual std::string to_symbol(const Parameter& param) const = 0;
};

View File

@ -22,14 +22,16 @@
#include "evoral/Control.hpp"
#include "evoral/ControlList.hpp"
#include "evoral/ParameterDescriptor.hpp"
#include "evoral/TypeMap.hpp"
namespace Evoral {
Parameter::TypeMetadata Parameter::_type_metadata;
Control::Control(const Parameter& parameter, boost::shared_ptr<ControlList> list)
Control::Control(const Parameter& parameter,
const ParameterDescriptor& desc,
boost::shared_ptr<ControlList> list)
: _parameter(parameter)
, _user_value(list ? list->default_value() : parameter.normal())
, _user_value(list ? list->default_value() : desc.normal)
{
set_list (list);
}

View File

@ -28,10 +28,14 @@
#endif
#include <cassert>
#include <utility>
#include <cmath>
#include <iostream>
#include <utility>
#include "evoral/ControlList.hpp"
#include "evoral/Curve.hpp"
#include "evoral/ParameterDescriptor.hpp"
#include "evoral/TypeMap.hpp"
#include "pbd/compose.h"
#include "pbd/debug.h"
@ -46,16 +50,17 @@ inline bool event_time_less_than (ControlEvent* a, ControlEvent* b)
return a->when < b->when;
}
ControlList::ControlList (const Parameter& id)
ControlList::ControlList (const Parameter& id, const ParameterDescriptor& desc)
: _parameter(id)
, _interpolation(id.toggled() ? Discrete : Linear)
, _desc(desc)
, _curve(0)
{
_interpolation = desc.toggled ? Discrete : Linear;
_frozen = 0;
_changed_when_thawed = false;
_min_yval = id.min();
_max_yval = id.max();
_default_value = id.normal();
_min_yval = desc.lower;
_max_yval = desc.upper;
_default_value = desc.normal;
_lookup_cache.left = -1;
_lookup_cache.range.first = _events.end();
_lookup_cache.range.second = _events.end();
@ -71,6 +76,7 @@ ControlList::ControlList (const Parameter& id)
ControlList::ControlList (const ControlList& other)
: _parameter(other._parameter)
, _desc(other._desc)
, _interpolation(other._interpolation)
, _curve(0)
{
@ -96,6 +102,7 @@ ControlList::ControlList (const ControlList& other)
ControlList::ControlList (const ControlList& other, double start, double end)
: _parameter(other._parameter)
, _desc(other._desc)
, _interpolation(other._interpolation)
, _curve(0)
{
@ -136,9 +143,9 @@ ControlList::~ControlList()
}
boost::shared_ptr<ControlList>
ControlList::create(Parameter id)
ControlList::create(const Parameter& id, const ParameterDescriptor& desc)
{
return boost::shared_ptr<ControlList>(new ControlList(id));
return boost::shared_ptr<ControlList>(new ControlList(id, desc));
}
bool
@ -1503,7 +1510,7 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, do
boost::shared_ptr<ControlList>
ControlList::cut_copy_clear (double start, double end, int op)
{
boost::shared_ptr<ControlList> nal = create (_parameter);
boost::shared_ptr<ControlList> nal = create (_parameter, _desc);
iterator s, e;
ControlEvent cp (start, 0.0);

View File

@ -0,0 +1,67 @@
/* This file is part of Evoral.
* Copyright (C) 2000-2014 Paul Davis
* Author: David Robillard
*
* Evoral 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.
*
* Evoral 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 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.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "evoral/ParameterDescriptor.hpp"
namespace Evoral {
ParameterDescriptor::ParameterDescriptor()
: key((uint32_t)-1)
, datatype(Variant::NOTHING)
, unit(NONE)
, normal(0)
, lower(0)
, upper(0)
, step(0)
, smallstep(0)
, largestep(0)
, integer_step(false)
, toggled(false)
, logarithmic(false)
, sr_dependent(false)
, min_unbound(0)
, max_unbound(0)
, enumeration(false)
{}
/* Set step, smallstep, and largestep, based on current description */
void
ParameterDescriptor::update_steps()
{
if (unit == ParameterDescriptor::MIDI_NOTE) {
step = smallstep = 1; // semitone
largestep = 12; // octave
} else if (integer_step) {
const float delta = upper - lower;
smallstep = delta / 10000.0f;
step = delta / 1000.0f;
largestep = delta / 40.0f;
smallstep = std::max(1.0, rint(smallstep));
step = std::max(1.0, rint(step));
largestep = std::max(1.0, rint(largestep));
}
/* else: leave all others as default '0'
* in that case the UI (eg. AutomationController::create)
* uses internal_to_interface() to map the value
* to an appropriate interface range
*/
}
} // namespace Evoral

View File

@ -35,6 +35,7 @@
#include "evoral/ControlList.hpp"
#include "evoral/ControlSet.hpp"
#include "evoral/EventSink.hpp"
#include "evoral/ParameterDescriptor.hpp"
#include "evoral/Sequence.hpp"
#include "evoral/TypeMap.hpp"
#include "evoral/midi_util.h"
@ -140,9 +141,10 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq, Time t
assert(x >= 0);
if (y < i->first.min() || y > i->first.max()) {
const ParameterDescriptor& desc = seq.type_map().descriptor(i->first);
if (y < desc.lower || y > desc.upper) {
cerr << "ERROR: Controller value " << y
<< " out of range [" << i->first.min() << "," << i->first.max()
<< " out of range [" << desc.lower << "," << desc.upper
<< "], event ignored" << endl;
continue;
}

View File

@ -39,14 +39,6 @@ public:
};
}
bool is_integer (const Parameter& /*param*/) const { return true; }
Parameter new_parameter(uint32_t type, uint8_t channel, uint32_t id) const {
Parameter p(type, channel, id);
p.set_range(type, 0.0f, 1.0f, 0.0f);
return p;
}
std::string to_symbol(const Parameter& /*param*/) const { return "control"; }
};