diff --git a/libs/ardour/ardour/triggerbox.h b/libs/ardour/ardour/triggerbox.h index b6cedf6ac8..05eb518100 100644 --- a/libs/ardour/ardour/triggerbox.h +++ b/libs/ardour/ardour/triggerbox.h @@ -44,6 +44,8 @@ #include "ardour/midi_state_tracker.h" #include "ardour/processor.h" #include "ardour/segment_descriptor.h" +#include "ardour/types.h" +#include "ardour/types_convert.h" #include "ardour/libardour_visibility.h" @@ -171,21 +173,6 @@ class LIBARDOUR_API Trigger : public PBD::Stateful { LaunchStyle launch_style() const; void set_launch_style (LaunchStyle); - enum FollowAction { - None, - Stop, - Again, - QueuedTrigger, /* DP-style */ - NextTrigger, /* Live-style, and below */ - PrevTrigger, - ForwardTrigger, /* any "next" skipping empties */ - ReverseTrigger, /* any "prev" skipping empties */ - FirstTrigger, - LastTrigger, - AnyTrigger, - OtherTrigger, - }; - FollowAction follow_action (uint32_t n) const { assert (n < 2); return n ? _follow_action1 : _follow_action0; } void set_follow_action (FollowAction, uint32_t n); @@ -571,7 +558,7 @@ class LIBARDOUR_API TriggerBox : public Processor TriggerPtr currently_playing() const { return _currently_playing; } void clear_all_triggers (); - void set_all_follow_action (ARDOUR::Trigger::FollowAction, uint32_t n=0); + void set_all_follow_action (ARDOUR::FollowAction const &, uint32_t n=0); void set_all_launch_style (ARDOUR::Trigger::LaunchStyle); void set_all_quantization (Temporal::BBT_Offset const&); void set_all_probability (int zero_to_a_hundred); @@ -617,8 +604,6 @@ class LIBARDOUR_API TriggerBox : public Processor static void init (); - static const int32_t default_triggers_per_box; - static TriggerBoxThread* worker; static void start_transport_stop (Session&); @@ -733,8 +718,8 @@ namespace Properties { LIBARDOUR_API extern PBD::PropertyDescriptor quantization; LIBARDOUR_API extern PBD::PropertyDescriptor follow_length; LIBARDOUR_API extern PBD::PropertyDescriptor launch_style; - LIBARDOUR_API extern PBD::PropertyDescriptor follow_action0; - LIBARDOUR_API extern PBD::PropertyDescriptor follow_action1; + LIBARDOUR_API extern PBD::PropertyDescriptor follow_action0; + LIBARDOUR_API extern PBD::PropertyDescriptor follow_action1; LIBARDOUR_API extern PBD::PropertyDescriptor stretch_mode; LIBARDOUR_API extern PBD::PropertyDescriptor follow_count; LIBARDOUR_API extern PBD::PropertyDescriptor follow_action_probability; @@ -751,7 +736,7 @@ namespace Properties { } // namespace ARDOUR namespace PBD { -DEFINE_ENUM_CONVERT(ARDOUR::Trigger::FollowAction); +DEFINE_ENUM_CONVERT(ARDOUR::FollowAction::Type); DEFINE_ENUM_CONVERT(ARDOUR::Trigger::LaunchStyle); DEFINE_ENUM_CONVERT(ARDOUR::Trigger::StretchMode); } /* namespace PBD */ diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 7644a30f0f..6159fdd43d 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -31,6 +31,7 @@ #ifndef __ardour_types_h__ #define __ardour_types_h__ +#include #include #include #include @@ -818,6 +819,53 @@ enum CueBehavior { typedef std::vector CaptureInfos; +const int32_t default_triggers_per_box = 8; + + +struct FollowAction { + enum Type { + None, + Stop, + Again, + QueuedTrigger, /* DP-style */ + NextTrigger, /* Live-style, and below */ + PrevTrigger, + ForwardTrigger, /* any "next" skipping empties */ + ReverseTrigger, /* any "prev" skipping empties */ + FirstTrigger, + LastTrigger, + AnyTrigger, + OtherTrigger, + }; + + /* We could theoretically limit this to default_triggers_per_box but + * doing it this way makes it likely that this will not change. Could + * be worth a constexpr-style compile time assert to check + * default_triggers_per_box < 64. + */ + + typedef std::bitset<64> Targets; + + Type type; + Targets targets; + + FollowAction () : type (None) {} + FollowAction (Type t, Targets const & tgts = Targets()) : type (t), targets (tgts) {} + FollowAction (Type t, std::string const & bitstring) : type (t), targets (bitstring) {} + FollowAction (std::string const &); + + bool operator!= (FollowAction const & other) const { + return other.type != type || other.targets != targets; + } + + bool operator== (FollowAction const & other) const { + return other.type == type && other.targets == targets; + } + + std::string to_string() const; +}; + + } // namespace ARDOUR /* for now, break the rules and use "using" to make this "global" */ diff --git a/libs/ardour/ardour/types_convert.h b/libs/ardour/ardour/types_convert.h index 4bf2778edb..3d445eef81 100644 --- a/libs/ardour/ardour/types_convert.h +++ b/libs/ardour/ardour/types_convert.h @@ -30,6 +30,14 @@ #include "ardour/data_type.h" #include "ardour/mode.h" +/* NOTE: when adding types to this file, you must add four functions: + + std::string to_string (T); + T string_to (std::string const &); + bool to_string (T, std::string &); + bool string_to (std::string const &, T&); +*/ + namespace PBD { DEFINE_ENUM_CONVERT(Timecode::TimecodeFormat) @@ -162,6 +170,33 @@ inline bool string_to (const std::string& str, ARDOUR::DataType& dt) return true; } +template <> +inline bool to_string (ARDOUR::FollowAction fa, std::string& str) +{ + str = fa.to_string(); + return true; +} + +template <> +inline bool string_to (const std::string& str, ARDOUR::FollowAction& fa) +{ + fa = ARDOUR::FollowAction (str); + return true; +} + +template<> +inline std::string to_string (ARDOUR::FollowAction fa) +{ + return fa.to_string (); +} + +template<> +inline ARDOUR::FollowAction string_to (std::string const & str) +{ + return ARDOUR::FollowAction (str); +} + + } // namespace PBD #endif // ARDOUR_TYPES_CONVERT_H diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index baa01cfe90..a64154872d 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -157,7 +157,7 @@ setup_enum_writer () LocateTransportDisposition _LocateTransportDisposition; Trigger::State _TriggerState; Trigger::LaunchStyle _TriggerLaunchStyle; - Trigger::FollowAction _TriggerFollowAction; + FollowAction::Type _FollowAction; Trigger::StretchMode _TriggerStretchMode; CueBehavior _CueBehavior; @@ -859,19 +859,19 @@ setup_enum_writer () REGISTER_CLASS_ENUM (Trigger, Stopping); REGISTER (_TriggerState); - REGISTER_CLASS_ENUM (Trigger, None); - REGISTER_CLASS_ENUM (Trigger, Stop); - REGISTER_CLASS_ENUM (Trigger, Again); - REGISTER_CLASS_ENUM (Trigger, QueuedTrigger); - REGISTER_CLASS_ENUM (Trigger, NextTrigger); - REGISTER_CLASS_ENUM (Trigger, PrevTrigger); - REGISTER_CLASS_ENUM (Trigger, ForwardTrigger); - REGISTER_CLASS_ENUM (Trigger, ReverseTrigger); - REGISTER_CLASS_ENUM (Trigger, FirstTrigger); - REGISTER_CLASS_ENUM (Trigger, LastTrigger); - REGISTER_CLASS_ENUM (Trigger, AnyTrigger); - REGISTER_CLASS_ENUM (Trigger, OtherTrigger); - REGISTER (_TriggerFollowAction); + REGISTER_CLASS_ENUM (FollowAction, None); + REGISTER_CLASS_ENUM (FollowAction, Stop); + REGISTER_CLASS_ENUM (FollowAction, Again); + REGISTER_CLASS_ENUM (FollowAction, QueuedTrigger); + REGISTER_CLASS_ENUM (FollowAction, NextTrigger); + REGISTER_CLASS_ENUM (FollowAction, PrevTrigger); + REGISTER_CLASS_ENUM (FollowAction, ForwardTrigger); + REGISTER_CLASS_ENUM (FollowAction, ReverseTrigger); + REGISTER_CLASS_ENUM (FollowAction, FirstTrigger); + REGISTER_CLASS_ENUM (FollowAction, LastTrigger); + REGISTER_CLASS_ENUM (FollowAction, AnyTrigger); + REGISTER_CLASS_ENUM (FollowAction, OtherTrigger); + REGISTER (_FollowAction); REGISTER_CLASS_ENUM (Trigger, OneShot); REGISTER_CLASS_ENUM (Trigger, ReTrigger); diff --git a/libs/ardour/triggerbox.cc b/libs/ardour/triggerbox.cc index 185c9de16b..69d5be13fa 100644 --- a/libs/ardour/triggerbox.cc +++ b/libs/ardour/triggerbox.cc @@ -54,8 +54,8 @@ namespace ARDOUR { PBD::PropertyDescriptor quantization; PBD::PropertyDescriptor follow_length; PBD::PropertyDescriptor launch_style; - PBD::PropertyDescriptor follow_action0; - PBD::PropertyDescriptor follow_action1; + PBD::PropertyDescriptor follow_action0; + PBD::PropertyDescriptor follow_action1; PBD::PropertyDescriptor currently_playing; PBD::PropertyDescriptor follow_count; PBD::PropertyDescriptor follow_action_probability; @@ -68,6 +68,38 @@ namespace ARDOUR { } } +FollowAction::FollowAction (std::string const & str) +{ + std::string::size_type colon = str.find_first_of (':'); + + if (colon == std::string::npos) { + throw failed_constructor (); + } + + type = FollowAction::Type (string_2_enum (str.substr (0, colon), type)); + + /* We use the ulong representation of the bitset because the string + version is absurd. + */ + unsigned long ul; + std::stringstream ss (str.substr (colon+1)); + ss >> ul; + if (!ss) { + throw failed_constructor(); + } + targets = Targets (ul); +} + +std::string +FollowAction::to_string () const +{ + /* We use the ulong representation of the bitset because the string + version is absurd. + */ + return string_compose ("%1:%2", enum_2_string (type), targets.to_ulong()); +} + + Trigger * const Trigger::MagicClearPointerValue = (Trigger*) 0xfeedface; Trigger::Trigger (uint32_t n, TriggerBox& b) @@ -82,8 +114,8 @@ Trigger::Trigger (uint32_t n, TriggerBox& b) , _pending_velocity_gain (1.0) , _velocity_gain (1.0) , _launch_style (Properties::launch_style, OneShot) - , _follow_action0 (Properties::follow_action0, Again) - , _follow_action1 (Properties::follow_action1, Stop) + , _follow_action0 (Properties::follow_action0, FollowAction (FollowAction::Again)) + , _follow_action1 (Properties::follow_action1, FollowAction (FollowAction::Stop)) , _follow_action_probability (Properties::follow_action_probability, 0) , _follow_count (Properties::follow_count, 1) , _quantization (Properties::quantization, Temporal::BBT_Offset (1, 0, 0)) @@ -148,8 +180,8 @@ Trigger::swap_pending (Trigger* t) bool Trigger::will_not_follow () const { - return (_follow_action0 == None && _follow_action_probability == 0) || - (_follow_action0 == None && _follow_action1 == None); + return (_follow_action0.val().type == FollowAction::None && _follow_action_probability == 0) || + (_follow_action0.val().type == FollowAction::None && _follow_action1.val().type == FollowAction::None); } void @@ -1132,18 +1164,18 @@ AudioTrigger::set_region_in_worker_thread (boost::shared_ptr r) if (_segment_tempo == 0.) { _stretchable = false; _quantization = Temporal::BBT_Offset (-1, 0, 0); - _follow_action0 = None; + _follow_action0 = FollowAction (FollowAction::None); } else { if (probably_oneshot()) { /* short trigger, treat as a one shot */ _stretchable = false; - _follow_action0 = None; + _follow_action0 = FollowAction (FollowAction::None); _quantization = Temporal::BBT_Offset (-1, 0, 0); } else { _stretchable = true; _quantization = Temporal::BBT_Offset (1, 0, 0); - _follow_action0 = Again; + _follow_action0 = FollowAction (FollowAction::Again); } } @@ -2138,7 +2170,6 @@ Trigger::make_property_quarks () DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for stretch_mode = %1\n", Properties::stretch_mode.property_id)); } -const int32_t TriggerBox::default_triggers_per_box = 8; Temporal::BBT_Offset TriggerBox::_assumed_trigger_duration (4, 0, 0); //TriggerBox::TriggerMidiMapMode TriggerBox::_midi_map_mode (TriggerBox::AbletonPush); TriggerBox::TriggerMidiMapMode TriggerBox::_midi_map_mode (TriggerBox::SequentialNote); @@ -2378,7 +2409,7 @@ TriggerBox::set_all_launch_style (ARDOUR::Trigger::LaunchStyle ls) } void -TriggerBox::set_all_follow_action (ARDOUR::Trigger::FollowAction fa, uint32_t fa_n) +TriggerBox::set_all_follow_action (ARDOUR::FollowAction const & fa, uint32_t fa_n) { for (uint64_t n = 0; n < all_triggers.size(); ++n) { all_triggers[n]->set_follow_action (fa, fa_n); @@ -2982,7 +3013,7 @@ TriggerBox::determine_next_trigger (uint32_t current) */ int r = _pcg.rand (100); // 0 .. 99 - Trigger::FollowAction fa; + FollowAction fa; if (r >= all_triggers[current]->follow_action_probability()) { fa = all_triggers[current]->follow_action (0); @@ -2994,14 +3025,14 @@ TriggerBox::determine_next_trigger (uint32_t current) * nothing or just repeat the current trigger */ - DEBUG_TRACE (DEBUG::Triggers, string_compose ("choose next trigger using follow action %1 given prob %2 and rnd %3\n", enum_2_string (fa), all_triggers[current]->follow_action_probability(), r)); + DEBUG_TRACE (DEBUG::Triggers, string_compose ("choose next trigger using follow action %1 given prob %2 and rnd %3\n", fa.to_string(), all_triggers[current]->follow_action_probability(), r)); - switch (fa) { + switch (fa.type) { - case Trigger::Stop: + case FollowAction::Stop: return -1; - case Trigger::QueuedTrigger: + case FollowAction::QueuedTrigger: /* XXX implement me */ return -1; default: @@ -3015,15 +3046,15 @@ TriggerBox::determine_next_trigger (uint32_t current) /* second switch: handle the "real" follow actions */ - switch (fa) { - case Trigger::None: + switch (fa.type) { + case FollowAction::None: return -1; - case Trigger::Again: + case FollowAction::Again: return current; - case Trigger::NextTrigger: + case FollowAction::NextTrigger: n = current + 1; if (n < all_triggers.size()) { if (all_triggers[n]->region()) { @@ -3032,7 +3063,7 @@ TriggerBox::determine_next_trigger (uint32_t current) } break; - case Trigger::PrevTrigger: + case FollowAction::PrevTrigger: if (current > 0) { n = current - 1; if (all_triggers[n]->region()) { @@ -3041,7 +3072,7 @@ TriggerBox::determine_next_trigger (uint32_t current) } break; - case Trigger::ForwardTrigger: + case FollowAction::ForwardTrigger: n = current; while (true) { ++n; @@ -3062,7 +3093,7 @@ TriggerBox::determine_next_trigger (uint32_t current) } break; - case Trigger::ReverseTrigger: + case FollowAction::ReverseTrigger: n = current; while (true) { if (n == 0) { @@ -3081,14 +3112,14 @@ TriggerBox::determine_next_trigger (uint32_t current) } break; - case Trigger::FirstTrigger: + case FollowAction::FirstTrigger: for (n = 0; n < all_triggers.size(); ++n) { if (all_triggers[n]->region() && !all_triggers[n]->active ()) { return n; } } break; - case Trigger::LastTrigger: + case FollowAction::LastTrigger: for (int i = all_triggers.size() - 1; i >= 0; --i) { if (all_triggers[i]->region() && !all_triggers[i]->active ()) { return i; @@ -3096,7 +3127,7 @@ TriggerBox::determine_next_trigger (uint32_t current) } break; - case Trigger::AnyTrigger: + case FollowAction::AnyTrigger: while (true) { n = _pcg.rand (all_triggers.size()); if (!all_triggers[n]->region()) { @@ -3110,7 +3141,7 @@ TriggerBox::determine_next_trigger (uint32_t current) return n; - case Trigger::OtherTrigger: + case FollowAction::OtherTrigger: while (true) { n = _pcg.rand (all_triggers.size()); if ((uint32_t) n == current) { @@ -3128,8 +3159,8 @@ TriggerBox::determine_next_trigger (uint32_t current) /* NOTREACHED */ - case Trigger::Stop: - case Trigger::QueuedTrigger: + case FollowAction::Stop: + case FollowAction::QueuedTrigger: break; }