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(); framepos_t start = std::numeric_limits<framepos_t>::max();
for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) { 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. */ /* Calculate earliest start position of any point in selection. */
start = std::min(start, i->second.line->session_position(i->first->begin())); 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); RouteTimeAxisView* rtv = editor->get_route_view_by_route_id (id);
if (rtv) { 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 /* the automation could be for an entity that was never saved
in the session file. Don't freak out if we can't find in the session file. Don't freak out if we can't find

View file

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

View file

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

View file

@ -64,13 +64,15 @@ private:
class LIBARDOUR_API AutomationList : public PBD::StatefulDestructible, public Evoral::ControlList class LIBARDOUR_API AutomationList : public PBD::StatefulDestructible, public Evoral::ControlList
{ {
public: 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 XMLNode&, Evoral::Parameter id);
AutomationList (const AutomationList&); AutomationList (const AutomationList&);
AutomationList (const AutomationList&, double start, double end); AutomationList (const AutomationList&, double start, double end);
~AutomationList(); ~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&); AutomationList& operator= (const AutomationList&);

View file

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

View file

@ -21,7 +21,9 @@
#define __ardour_parameter_descriptor_h__ #define __ardour_parameter_descriptor_h__
#include "ardour/variant.h" #include "ardour/variant.h"
#include "evoral/Parameter.hpp" #include "evoral/Parameter.hpp"
#include "evoral/ParameterDescriptor.hpp"
namespace ARDOUR { namespace ARDOUR {
@ -31,7 +33,7 @@ typedef std::map<const std::string, const float> ScalePoints;
* *
* Essentially a union of LADSPA, VST and LV2 info. * Essentially a union of LADSPA, VST and LV2 info.
*/ */
struct ParameterDescriptor struct ParameterDescriptor : public Evoral::ParameterDescriptor
{ {
enum Unit { enum Unit {
NONE, ///< No unit NONE, ///< No unit
@ -40,72 +42,12 @@ struct ParameterDescriptor
HZ, ///< Frequency in Hertz HZ, ///< Frequency in Hertz
}; };
ParameterDescriptor(const Evoral::Parameter& parameter) 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() 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 */ /** Set step, smallstep, and largestep, based on current description. */
void update_steps() { 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
*/
}
std::string label; std::string label;
std::string print_fmt; ///< format string for pretty printing std::string print_fmt; ///< format string for pretty printing
@ -113,14 +55,10 @@ struct ParameterDescriptor
uint32_t key; ///< for properties uint32_t key; ///< for properties
Variant::Type datatype; ///< for properties Variant::Type datatype; ///< for properties
Unit unit; 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 step;
float smallstep; float smallstep;
float largestep; float largestep;
bool integer_step; bool integer_step;
bool toggled;
bool logarithmic; bool logarithmic;
bool sr_dependent; bool sr_dependent;
bool min_unbound; bool min_unbound;

View file

@ -40,11 +40,13 @@
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/dB.h" #include "ardour/dB.h"
#include "ardour/debug.h" #include "ardour/debug.h"
#include "ardour/event_type_map.h"
#include "ardour/playlist.h" #include "ardour/playlist.h"
#include "ardour/audiofilesource.h" #include "ardour/audiofilesource.h"
#include "ardour/region_factory.h" #include "ardour/region_factory.h"
#include "ardour/runtime_functions.h" #include "ardour/runtime_functions.h"
#include "ardour/transient_detector.h" #include "ardour/transient_detector.h"
#include "ardour/parameter_descriptor.h"
#include "ardour/progress.h" #include "ardour/progress.h"
#include "i18n.h" #include "i18n.h"
@ -1011,9 +1013,10 @@ AudioRegion::set_fade_in (boost::shared_ptr<AutomationList> f)
void void
AudioRegion::set_fade_in (FadeShape shape, framecnt_t len) AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
{ {
boost::shared_ptr<Evoral::ControlList> c1 (new Evoral::ControlList (FadeInAutomation)); const ARDOUR::ParameterDescriptor desc(FadeInAutomation);
boost::shared_ptr<Evoral::ControlList> c2 (new Evoral::ControlList (FadeInAutomation)); boost::shared_ptr<Evoral::ControlList> c1 (new Evoral::ControlList (FadeInAutomation, desc));
boost::shared_ptr<Evoral::ControlList> c3 (new Evoral::ControlList (FadeInAutomation)); 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->freeze ();
_fade_in->clear (); _fade_in->clear ();
@ -1093,8 +1096,9 @@ AudioRegion::set_fade_out (boost::shared_ptr<AutomationList> f)
void void
AudioRegion::set_fade_out (FadeShape shape, framecnt_t len) AudioRegion::set_fade_out (FadeShape shape, framecnt_t len)
{ {
boost::shared_ptr<Evoral::ControlList> c1 (new Evoral::ControlList (FadeOutAutomation)); const ARDOUR::ParameterDescriptor desc(FadeOutAutomation);
boost::shared_ptr<Evoral::ControlList> c2 (new Evoral::ControlList (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->freeze ();
_fade_out->clear (); _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"); const XMLProperty* id_prop = (*niter)->property("automation-id");
Evoral::Parameter param = (id_prop Evoral::Parameter param = (id_prop
? EventTypeMap::instance().new_parameter(id_prop->value()) ? EventTypeMap::instance().from_symbol(id_prop->value())
: legacy_param); : legacy_param);
if (param.type() == NullAutomation) { if (param.type() == NullAutomation) {
@ -399,14 +399,15 @@ Automatable::transport_stopped (framepos_t now)
boost::shared_ptr<Evoral::Control> boost::shared_ptr<Evoral::Control>
Automatable::control_factory(const Evoral::Parameter& param) Automatable::control_factory(const Evoral::Parameter& param)
{ {
boost::shared_ptr<AutomationList> list(new AutomationList(param)); Evoral::Control* control = NULL;
Evoral::Control* control = NULL; bool make_list = true;
ParameterDescriptor desc(param); ParameterDescriptor desc(param);
boost::shared_ptr<AutomationList> list;
if (param.type() >= MidiCCAutomation && param.type() <= MidiChannelPressureAutomation) { if (param.type() >= MidiCCAutomation && param.type() <= MidiChannelPressureAutomation) {
MidiTrack* mt = dynamic_cast<MidiTrack*>(this); MidiTrack* mt = dynamic_cast<MidiTrack*>(this);
if (mt) { if (mt) {
control = new MidiTrack::MidiControl(mt, param); control = new MidiTrack::MidiControl(mt, param);
list.reset(); // No list, this is region "automation" make_list = false; // No list, this is region "automation"
} else { } else {
warning << "MidiCCAutomation for non-MidiTrack" << endl; 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()); desc = pi->plugin(0)->get_property_descriptor(param.id());
if (desc.datatype != Variant::NOTHING) { if (desc.datatype != Variant::NOTHING) {
if (!Variant::type_is_numeric(desc.datatype)) { 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); control = new PluginInsert::PluginPropertyControl(pi, param, desc, list);
} }
@ -447,11 +450,14 @@ Automatable::control_factory(const Evoral::Parameter& param)
} }
} }
if (!control) { if (make_list && !list) {
control = new AutomationControl(_a_session, param, desc); 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); return boost::shared_ptr<Evoral::Control>(control);
} }

View file

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

View file

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

View file

@ -25,6 +25,7 @@
#include "ardour/parameter_types.h" #include "ardour/parameter_types.h"
#include "ardour/uri_map.h" #include "ardour/uri_map.h"
#include "evoral/Parameter.hpp" #include "evoral/Parameter.hpp"
#include "evoral/ParameterDescriptor.hpp"
#include "evoral/midi_events.h" #include "evoral/midi_events.h"
#include "pbd/error.h" #include "pbd/error.h"
#include "pbd/compose.h" #include "pbd/compose.h"
@ -40,25 +41,6 @@ EventTypeMap::instance()
{ {
if (!EventTypeMap::event_type_map) { if (!EventTypeMap::event_type_map) {
EventTypeMap::event_type_map = new EventTypeMap(URIMap::instance()); 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; return *EventTypeMap::event_type_map;
} }
@ -69,12 +51,6 @@ EventTypeMap::type_is_midi(uint32_t type) const
return ARDOUR::parameter_is_midi((AutomationType)type); return ARDOUR::parameter_is_midi((AutomationType)type);
} }
bool
EventTypeMap::is_midi_parameter(const Evoral::Parameter& param)
{
return type_is_midi(param.type());
}
uint8_t uint8_t
EventTypeMap::parameter_midi_type(const Evoral::Parameter& param) const 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); 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 Evoral::ControlList::InterpolationStyle
EventTypeMap::interpolation_of(const Evoral::Parameter& param) 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 return Evoral::ControlList::Linear; // Not reached, suppress warnings
} }
Evoral::Parameter Evoral::Parameter
EventTypeMap::new_parameter(uint32_t type, uint8_t channel, uint32_t id) const EventTypeMap::from_symbol(const string& str) 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
{ {
AutomationType p_type = NullAutomation; AutomationType p_type = NullAutomation;
uint8_t p_channel = 0; uint8_t p_channel = 0;
@ -285,7 +187,7 @@ EventTypeMap::new_parameter(const string& str) const
PBD::warning << "Unknown Parameter '" << str << "'" << endmsg; 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. /** 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 } // namespace ARDOUR

View file

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

View file

@ -123,7 +123,7 @@ MidiSource::set_state (const XMLNode& node, int /*version*/)
error << _("Missing parameter property on InterpolationStyle") << endmsg; error << _("Missing parameter property on InterpolationStyle") << endmsg;
return -1; 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) { if ((prop = (*i)->property (X_("style"))) == 0) {
error << _("Missing style property on InterpolationStyle") << endmsg; 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; error << _("Missing parameter property on AutomationState") << endmsg;
return -1; 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) { if ((prop = (*i)->property (X_("state"))) == 0) {
error << _("Missing state property on AutomationState") << endmsg; error << _("Missing state property on AutomationState") << endmsg;

View file

@ -37,6 +37,7 @@
#include "ardour/buffer_set.h" #include "ardour/buffer_set.h"
#include "ardour/debug.h" #include "ardour/debug.h"
#include "ardour/delivery.h" #include "ardour/delivery.h"
#include "ardour/event_type_map.h"
#include "ardour/meter.h" #include "ardour/meter.h"
#include "ardour/midi_diskstream.h" #include "ardour/midi_diskstream.h"
#include "ardour/midi_playlist.h" #include "ardour/midi_playlist.h"
@ -657,16 +658,17 @@ void
MidiTrack::MidiControl::set_value(double val) MidiTrack::MidiControl::set_value(double val)
{ {
const Evoral::Parameter &parameter = _list ? _list->parameter() : Control::parameter(); const Evoral::Parameter &parameter = _list ? _list->parameter() : Control::parameter();
const Evoral::ParameterDescriptor &desc = EventTypeMap::instance().descriptor(parameter);
bool valid = false; bool valid = false;
if (isinf_local(val)) { if (isinf_local(val)) {
cerr << "MIDIControl value is infinity" << endl; cerr << "MIDIControl value is infinity" << endl;
} else if (isnan_local(val)) { } else if (isnan_local(val)) {
cerr << "MIDIControl value is NaN" << endl; cerr << "MIDIControl value is NaN" << endl;
} else if (val < parameter.min()) { } else if (val < desc.lower) {
cerr << "MIDIControl value is < " << parameter.min() << endl; cerr << "MIDIControl value is < " << desc.lower << endl;
} else if (val > parameter.max()) { } else if (val > desc.upper) {
cerr << "MIDIControl value is > " << parameter.max() << endl; cerr << "MIDIControl value is > " << desc.upper << endl;
} else { } else {
valid = true; valid = true;
} }
@ -675,7 +677,7 @@ MidiTrack::MidiControl::set_value(double val)
return; return;
} }
assert(val <= parameter.max()); assert(val <= desc.upper);
if ( ! _list || ! automation_playback()) { if ( ! _list || ! automation_playback()) {
size_t size = 3; size_t size = 3;
uint8_t ev[3] = { parameter.channel(), uint8_t (val), 0 }; 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; ParameterDescriptor desc;
_plugins.front()->get_parameter_descriptor(i->id(), 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); 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))); add_control (boost::shared_ptr<AutomationControl> (new PluginControl(this, param, desc, list)));
} else if (i->type() == PluginPropertyAutomation) { } else if (i->type() == PluginPropertyAutomation) {
Evoral::Parameter param(*i); Evoral::Parameter param(*i);
@ -262,7 +257,7 @@ PluginInsert::create_automatable_parameters ()
if (desc.datatype != Variant::NOTHING) { if (desc.datatype != Variant::NOTHING) {
boost::shared_ptr<AutomationList> list; boost::shared_ptr<AutomationList> list;
if (Variant::type_is_numeric(desc.datatype)) { 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))); 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.cc',
'panner_manager.cc', 'panner_manager.cc',
'panner_shell.cc', 'panner_shell.cc',
'parameter_descriptor.cc',
'pcm_utils.cc', 'pcm_utils.cc',
'playlist.cc', 'playlist.cc',
'playlist_factory.cc', 'playlist_factory.cc',

View file

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

View file

@ -26,11 +26,14 @@
#include "evoral/visibility.h" #include "evoral/visibility.h"
#include "evoral/Parameter.hpp" #include "evoral/Parameter.hpp"
#include "evoral/ParameterDescriptor.hpp"
namespace Evoral { namespace Evoral {
class ControlList; class ControlList;
class ParameterDescriptor;
class Transport; class Transport;
class TypeMap;
/** Base class representing some kind of (automatable) control; a fader's gain, /** Base class representing some kind of (automatable) control; a fader's gain,
* for example, or a compressor plugin's threshold. * 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 * The class knows the Evoral::Parameter that it is controlling, and has
* a list of values for automation. * a list of values for automation.
*/ */
class LIBEVORAL_API Control class LIBEVORAL_API Control
{ {
public: public:
Control(const Parameter& parameter, boost::shared_ptr<ControlList>); Control(const Parameter& parameter,
const ParameterDescriptor& desc,
boost::shared_ptr<ControlList> list);
virtual ~Control() {} virtual ~Control() {}
virtual void set_double (double val, double frame=0, bool to_list=false); 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/types.hpp"
#include "evoral/Range.hpp" #include "evoral/Range.hpp"
#include "evoral/Parameter.hpp" #include "evoral/Parameter.hpp"
#include "evoral/ParameterDescriptor.hpp"
namespace Evoral { namespace Evoral {
class Curve; class Curve;
class TypeMap;
/** A single event (time-stamped value) for a control /** A single event (time-stamped value) for a control
*/ */
@ -82,12 +84,12 @@ public:
typedef EventList::const_iterator const_iterator; typedef EventList::const_iterator const_iterator;
typedef EventList::const_reverse_iterator const_reverse_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&);
ControlList (const ControlList&, double start, double end); ControlList (const ControlList&, double start, double end);
virtual ~ControlList(); 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&); void dump (std::ostream&);
@ -102,6 +104,9 @@ public:
const Parameter& parameter() const { return _parameter; } const Parameter& parameter() const { return _parameter; }
void set_parameter(const Parameter& p) { _parameter = p; } 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(); } EventList::size_type size() const { return _events.size(); }
double length() const { double length() const {
Glib::Threads::Mutex::Lock lm (_lock); Glib::Threads::Mutex::Lock lm (_lock);
@ -218,7 +223,7 @@ public:
}; };
const EventList& events() const { return _events; } 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 // FIXME: const violations for Curve
Glib::Threads::Mutex& lock() const { return _lock; } Glib::Threads::Mutex& lock() const { return _lock; }
@ -288,10 +293,12 @@ protected:
mutable LookupCache _lookup_cache; mutable LookupCache _lookup_cache;
mutable SearchCache _search_cache; mutable SearchCache _search_cache;
mutable Glib::Threads::Mutex _lock;
Parameter _parameter; Parameter _parameter;
ParameterDescriptor _desc;
InterpolationStyle _interpolation; InterpolationStyle _interpolation;
EventList _events; EventList _events;
mutable Glib::Threads::Mutex _lock;
int8_t _frozen; int8_t _frozen;
bool _changed_when_thawed; bool _changed_when_thawed;
double _min_yval; double _min_yval;

View file

@ -28,7 +28,6 @@
namespace Evoral { namespace Evoral {
/** ID of a [play|record|automate]able parameter. /** ID of a [play|record|automate]able parameter.
* *
* A parameter is defined by (type, id, channel). Type is an integer which * A parameter is defined by (type, id, channel). Type is an integer which
@ -41,12 +40,10 @@ namespace Evoral {
class LIBEVORAL_API Parameter class LIBEVORAL_API Parameter
{ {
public: 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) : _type(type), _id(id), _channel(channel)
{} {}
virtual ~Parameter() {}
inline uint32_t type() const { return _type; } inline uint32_t type() const { return _type; }
inline uint8_t channel() const { return _channel; } inline uint8_t channel() const { return _channel; }
inline uint32_t id() const { return _id; } inline uint32_t id() const { return _id; }
@ -78,52 +75,12 @@ public:
inline operator bool() const { return (_type != 0); } inline operator bool() const { return (_type != 0); }
/** Not used in indentity/comparison */ private:
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)
uint32_t _type; uint32_t _type;
uint32_t _id; uint32_t _id;
uint8_t _channel; uint8_t _channel;
boost::shared_ptr<Metadata> _metadata;
typedef std::map<uint32_t, Metadata> TypeMetadata;
static TypeMetadata _type_metadata;
}; };
} // namespace Evoral } // namespace Evoral
#endif // EVORAL_PARAMETER_HPP #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/visibility.h"
#include "evoral/types.hpp" #include "evoral/types.hpp"
#include "evoral/Note.hpp" #include "evoral/Note.hpp"
#include "evoral/Parameter.hpp"
#include "evoral/ControlSet.hpp" #include "evoral/ControlSet.hpp"
#include "evoral/ControlList.hpp" #include "evoral/ControlList.hpp"
#include "evoral/PatchChange.hpp" #include "evoral/PatchChange.hpp"
namespace Evoral { namespace Evoral {
class Parameter;
class TypeMap; class TypeMap;
template<typename Time> class EventSink; template<typename Time> class EventSink;
template<typename Time> class Note; template<typename Time> class Note;
@ -109,6 +109,8 @@ public:
void append(const Event<Time>& ev, Evoral::event_id_t evid); 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 size_t n_notes() const { return _notes.size(); }
inline bool empty() const { return _notes.empty() && _sysexes.empty() && _patch_changes.empty() && ControlSet::controls_empty(); } inline bool empty() const { return _notes.empty() && _sysexes.empty() && _patch_changes.empty() && ControlSet::controls_empty(); }

View file

@ -28,6 +28,7 @@
namespace Evoral { namespace Evoral {
class Parameter; class Parameter;
class ParameterDescriptor;
/** The applications passes one of these which provide the implementation /** The applications passes one of these which provide the implementation
* with required information about event types in an opaque, type neutral way * 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; virtual uint32_t midi_event_type(uint8_t status) const = 0;
/** Return true iff parameter should be locked to integer boundaries */ /** Return the description of a parameter. */
virtual bool is_integer(const Evoral::Parameter& param) const = 0; virtual const ParameterDescriptor& descriptor(const 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;
virtual std::string to_symbol(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/Control.hpp"
#include "evoral/ControlList.hpp" #include "evoral/ControlList.hpp"
#include "evoral/ParameterDescriptor.hpp"
#include "evoral/TypeMap.hpp"
namespace Evoral { namespace Evoral {
Parameter::TypeMetadata Parameter::_type_metadata; Control::Control(const Parameter& parameter,
const ParameterDescriptor& desc,
Control::Control(const Parameter& parameter, boost::shared_ptr<ControlList> list) boost::shared_ptr<ControlList> list)
: _parameter(parameter) : _parameter(parameter)
, _user_value(list ? list->default_value() : parameter.normal()) , _user_value(list ? list->default_value() : desc.normal)
{ {
set_list (list); set_list (list);
} }

View file

@ -28,10 +28,14 @@
#endif #endif
#include <cassert> #include <cassert>
#include <utility> #include <cmath>
#include <iostream> #include <iostream>
#include <utility>
#include "evoral/ControlList.hpp" #include "evoral/ControlList.hpp"
#include "evoral/Curve.hpp" #include "evoral/Curve.hpp"
#include "evoral/ParameterDescriptor.hpp"
#include "evoral/TypeMap.hpp"
#include "pbd/compose.h" #include "pbd/compose.h"
#include "pbd/debug.h" #include "pbd/debug.h"
@ -46,16 +50,17 @@ inline bool event_time_less_than (ControlEvent* a, ControlEvent* b)
return a->when < b->when; return a->when < b->when;
} }
ControlList::ControlList (const Parameter& id) ControlList::ControlList (const Parameter& id, const ParameterDescriptor& desc)
: _parameter(id) : _parameter(id)
, _interpolation(id.toggled() ? Discrete : Linear) , _desc(desc)
, _curve(0) , _curve(0)
{ {
_interpolation = desc.toggled ? Discrete : Linear;
_frozen = 0; _frozen = 0;
_changed_when_thawed = false; _changed_when_thawed = false;
_min_yval = id.min(); _min_yval = desc.lower;
_max_yval = id.max(); _max_yval = desc.upper;
_default_value = id.normal(); _default_value = desc.normal;
_lookup_cache.left = -1; _lookup_cache.left = -1;
_lookup_cache.range.first = _events.end(); _lookup_cache.range.first = _events.end();
_lookup_cache.range.second = _events.end(); _lookup_cache.range.second = _events.end();
@ -71,6 +76,7 @@ ControlList::ControlList (const Parameter& id)
ControlList::ControlList (const ControlList& other) ControlList::ControlList (const ControlList& other)
: _parameter(other._parameter) : _parameter(other._parameter)
, _desc(other._desc)
, _interpolation(other._interpolation) , _interpolation(other._interpolation)
, _curve(0) , _curve(0)
{ {
@ -96,6 +102,7 @@ ControlList::ControlList (const ControlList& other)
ControlList::ControlList (const ControlList& other, double start, double end) ControlList::ControlList (const ControlList& other, double start, double end)
: _parameter(other._parameter) : _parameter(other._parameter)
, _desc(other._desc)
, _interpolation(other._interpolation) , _interpolation(other._interpolation)
, _curve(0) , _curve(0)
{ {
@ -136,9 +143,9 @@ ControlList::~ControlList()
} }
boost::shared_ptr<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 bool
@ -1503,7 +1510,7 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, do
boost::shared_ptr<ControlList> boost::shared_ptr<ControlList>
ControlList::cut_copy_clear (double start, double end, int op) 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; iterator s, e;
ControlEvent cp (start, 0.0); 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/ControlList.hpp"
#include "evoral/ControlSet.hpp" #include "evoral/ControlSet.hpp"
#include "evoral/EventSink.hpp" #include "evoral/EventSink.hpp"
#include "evoral/ParameterDescriptor.hpp"
#include "evoral/Sequence.hpp" #include "evoral/Sequence.hpp"
#include "evoral/TypeMap.hpp" #include "evoral/TypeMap.hpp"
#include "evoral/midi_util.h" #include "evoral/midi_util.h"
@ -140,9 +141,10 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq, Time t
assert(x >= 0); 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 cerr << "ERROR: Controller value " << y
<< " out of range [" << i->first.min() << "," << i->first.max() << " out of range [" << desc.lower << "," << desc.upper
<< "], event ignored" << endl; << "], event ignored" << endl;
continue; 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"; } std::string to_symbol(const Parameter& /*param*/) const { return "control"; }
}; };