2021-07-17 15:21:45 -04:00
/*
* Copyright ( C ) 2021 Paul Davis < paul @ linuxaudiosystems . com >
*
* 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 . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
# ifndef __ardour_triggerbox_h__
# define __ardour_triggerbox_h__
2021-11-09 23:47:15 -05:00
# include <pthread.h>
2021-08-08 21:08:16 -04:00
# include <atomic>
2021-07-19 11:57:31 -04:00
# include <map>
2021-07-17 15:21:45 -04:00
# include <vector>
# include <string>
# include <exception>
# include <glibmm/threads.h>
2021-11-09 23:47:15 -05:00
# include "pbd/crossthread.h"
2021-08-15 09:24:23 -04:00
# include "pbd/pcg_rand.h"
2021-11-04 13:16:22 -04:00
# include "pbd/pool.h"
2021-09-26 23:59:15 -04:00
# include "pbd/properties.h"
2021-07-17 15:21:45 -04:00
# include "pbd/ringbuffer.h"
2021-09-26 23:59:15 -04:00
# include "pbd/stateful.h"
2021-07-17 15:21:45 -04:00
2022-10-21 00:07:52 -04:00
# include "midi++/types.h"
2021-07-17 15:21:45 -04:00
# include "temporal/beats.h"
2021-08-05 17:03:28 -04:00
# include "temporal/bbt_time.h"
# include "temporal/tempo.h"
2021-07-17 15:21:45 -04:00
2022-02-02 14:45:57 -05:00
# include "evoral/PatchChange.h"
2022-02-24 15:38:58 -05:00
# include "evoral/SMF.h"
2022-02-02 14:45:57 -05:00
2021-11-19 16:50:50 -05:00
# include "ardour/midi_model.h"
2021-10-28 00:54:40 -04:00
# include "ardour/midi_state_tracker.h"
2021-07-17 15:21:45 -04:00
# include "ardour/processor.h"
2021-12-12 13:20:58 -05:00
# include "ardour/segment_descriptor.h"
2022-01-19 17:50:32 -05:00
# include "ardour/types.h"
# include "ardour/types_convert.h"
2021-10-20 18:19:09 -04:00
2021-07-17 15:21:45 -04:00
# include "ardour/libardour_visibility.h"
class XMLNode ;
2021-11-11 17:10:33 -05:00
namespace RubberBand {
class RubberBandStretcher ;
}
2021-08-07 18:20:36 -04:00
2022-10-21 00:07:52 -04:00
namespace MIDI {
class Parser ;
}
2021-07-17 15:21:45 -04:00
namespace ARDOUR {
class Session ;
class AudioRegion ;
2021-10-20 18:19:09 -04:00
class MidiRegion ;
2021-07-17 15:21:45 -04:00
class TriggerBox ;
2021-10-08 15:37:29 -04:00
class SideChain ;
2022-11-19 12:12:14 -05:00
class MidiPort ;
2021-07-17 15:21:45 -04:00
2021-12-27 12:40:09 -05:00
typedef uint32_t color_t ;
2022-02-14 05:19:47 -05:00
LIBARDOUR_API std : : string cue_marker_name ( int32_t ) ;
2022-02-11 13:33:27 -05:00
2022-02-20 11:20:47 -05:00
class Trigger ;
2023-02-16 18:33:28 -05:00
typedef std : : shared_ptr < Trigger > TriggerPtr ;
2022-02-20 11:20:47 -05:00
2021-08-05 18:20:37 -04:00
class LIBARDOUR_API Trigger : public PBD : : Stateful {
2021-07-17 15:21:45 -04:00
public :
2021-08-08 21:08:16 -04:00
enum State {
2021-12-04 13:48:15 -05:00
/* This is the initial state for a Trigger, and means that it is not
2022-02-18 14:50:28 -05:00
* doing anything at all
2021-12-04 13:48:15 -05:00
*/
2021-12-02 13:27:18 -05:00
Stopped ,
2021-12-04 13:48:15 -05:00
/* A Trigger in this state has been chosen by its parent TriggerBox
* ( e . g . because of a bang ( ) call that put it in the queue ) , a Trigger in
* this state is waiting for the next occurence of its quantization to
2022-02-18 14:50:28 -05:00
* occur before transitioning to Running
2021-12-04 13:48:15 -05:00
*/
2021-12-02 13:27:18 -05:00
WaitingToStart ,
2021-12-04 13:48:15 -05:00
/* a Trigger in this state is going to deliver data during calls
2022-02-18 14:50:28 -05:00
* to its : : run ( ) method .
2021-12-04 13:48:15 -05:00
*/
2021-12-02 13:27:18 -05:00
Running ,
2021-12-04 13:48:15 -05:00
/* a Trigger in this state was running, has been re-triggered e.g. by a
2022-02-18 14:50:28 -05:00
* : : bang ( ) call with LaunchStyle set to Repeat , and is waiting for the
* next occurence of its quantization to occur before transitioning
* back to Running .
2021-12-04 13:48:15 -05:00
*/
2021-12-02 13:27:18 -05:00
WaitingForRetrigger ,
2021-12-04 13:48:15 -05:00
/* a Trigger in this state is delivering data during calls to ::run(), but
2022-02-18 14:50:28 -05:00
* is waiting for the next occurence of its quantization to occur when it will
* transition to Stopping and then Stopped .
2021-12-04 13:48:15 -05:00
*/
2021-12-02 13:27:18 -05:00
WaitingToStop ,
2022-02-20 11:20:47 -05:00
/* a Trigger in this state is delivering data during calls to ::run(), but
* is waiting for the next occurence of another Trigger ' s quantization to occur when it will
* transition to Stopping and then Stopped ( and be followed by
* the other Trigger .
*/
WaitingToSwitch ,
2021-12-04 13:48:15 -05:00
/* a Trigger in this state was Running but noticed that it should stop
* during the current call to : : run ( ) . By the end of that call , it will
* have transitioned to Stopped .
*/
2022-01-07 14:46:04 -05:00
Stopping ,
2021-08-08 21:08:16 -04:00
} ;
2022-01-26 12:11:27 -05:00
enum LaunchStyle {
OneShot , /* mouse down/NoteOn starts; mouse up/NoteOff ignored */
ReTrigger , /* mouse down/NoteOn starts or retriggers; mouse up/NoteOff */
Gate , /* runs till mouse up/note off then to next quantization */
Toggle , /* runs till next mouse down/NoteOn */
Repeat , /* plays only quantization extent until mouse up/note off */
} ;
enum StretchMode { /* currently mapped to the matching RubberBand::RubberBandStretcher::Option */
Crisp ,
Mixed ,
Smooth ,
} ;
2021-12-21 15:37:47 -05:00
Trigger ( uint32_t index , TriggerBox & ) ;
2021-07-17 15:21:45 -04:00
virtual ~ Trigger ( ) { }
2021-08-07 18:20:36 -04:00
static void make_property_quarks ( ) ;
2022-01-26 12:11:27 -05:00
protected :
/* properties controllable by the user */
2021-08-31 13:53:24 -04:00
2022-01-26 12:11:27 -05:00
PBD : : Property < LaunchStyle > _launch_style ;
PBD : : Property < FollowAction > _follow_action0 ;
PBD : : Property < FollowAction > _follow_action1 ;
PBD : : Property < int > _follow_action_probability ; /* 1 .. 100 */
PBD : : Property < uint32_t > _follow_count ;
PBD : : Property < Temporal : : BBT_Offset > _quantization ;
PBD : : Property < Temporal : : BBT_Offset > _follow_length ;
PBD : : Property < bool > _use_follow_length ;
PBD : : Property < bool > _legato ;
PBD : : Property < gain_t > _gain ;
PBD : : Property < float > _velocity_effect ;
PBD : : Property < bool > _stretchable ;
PBD : : Property < bool > _cue_isolated ;
2022-02-28 10:50:46 -05:00
PBD : : Property < bool > _allow_patch_changes ;
2022-01-26 12:11:27 -05:00
PBD : : Property < StretchMode > _stretch_mode ;
/* Properties that are not CAS-updated at retrigger */
PBD : : Property < std : : string > _name ;
PBD : : Property < color_t > _color ;
2021-12-17 13:39:38 -05:00
2022-01-26 12:11:27 -05:00
public :
2023-08-20 22:57:40 -04:00
/* this is positioned here so that we can easily keep it in sync
2022-01-26 12:11:27 -05:00
with the properties list above .
*/
struct UIState {
std : : atomic < unsigned int > generation ; /* used for CAS */
2022-02-11 08:27:18 -05:00
LaunchStyle launch_style = OneShot ;
FollowAction follow_action0 = FollowAction ( FollowAction : : Again ) ;
FollowAction follow_action1 = FollowAction ( FollowAction : : Stop ) ;
int follow_action_probability = 0 ;
uint32_t follow_count = 1 ;
Temporal : : BBT_Offset quantization = Temporal : : BBT_Offset ( 1 , 0 , 0 ) ;
Temporal : : BBT_Offset follow_length = Temporal : : BBT_Offset ( 1 , 0 , 0 ) ;
bool use_follow_length = false ;
bool legato = false ;
gain_t gain = 1.0 ;
float velocity_effect = 0 ;
bool stretchable = true ;
bool cue_isolated = false ;
2022-02-28 10:50:46 -05:00
bool allow_patch_changes = true ;
2022-02-11 08:27:18 -05:00
StretchMode stretch_mode = Trigger : : Crisp ;
2022-02-24 15:38:58 -05:00
Evoral : : SMF : : UsedChannels used_channels = Evoral : : SMF : : UsedChannels ( ) ;
Evoral : : PatchChange < MidiBuffer : : TimeType > patch_change [ 16 ] ;
2022-02-11 08:28:10 -05:00
std : : string name = " " ;
color_t color = 0xBEBEBEFF ;
double tempo = 0 ; //unset
2022-01-26 12:11:27 -05:00
UIState ( ) : generation ( 0 ) { }
UIState & operator = ( UIState const & other ) {
/* we do not copy generation */
generation = 0 ;
launch_style = other . launch_style ;
follow_action0 = other . follow_action0 ;
follow_action1 = other . follow_action1 ;
follow_action_probability = other . follow_action_probability ;
follow_count = other . follow_count ;
quantization = other . quantization ;
follow_length = other . follow_length ;
use_follow_length = other . use_follow_length ;
legato = other . legato ;
gain = other . gain ;
velocity_effect = other . velocity_effect ;
stretchable = other . stretchable ;
cue_isolated = other . cue_isolated ;
2022-02-28 10:50:46 -05:00
allow_patch_changes = other . allow_patch_changes ;
2022-01-26 12:11:27 -05:00
stretch_mode = other . stretch_mode ;
2022-02-24 15:38:58 -05:00
used_channels = other . used_channels ;
for ( int i = 0 ; i < 16 ; i + + ) {
if ( other . patch_change [ i ] . is_set ( ) ) {
patch_change [ i ] = other . patch_change [ i ] ;
}
}
2022-01-26 12:11:27 -05:00
2022-02-11 08:28:10 -05:00
name = other . name ;
color = other . color ;
tempo = other . tempo ;
2022-01-26 12:11:27 -05:00
return * this ;
}
} ;
# define TRIGGERBOX_PROPERTY_DECL(name,type) void set_ ## name (type); type name () const;
# define TRIGGERBOX_PROPERTY_DECL_CONST_REF(name,type) void set_ ## name (type const &); type name () const
TRIGGERBOX_PROPERTY_DECL ( launch_style , LaunchStyle ) ;
TRIGGERBOX_PROPERTY_DECL_CONST_REF ( follow_action0 , FollowAction ) ;
TRIGGERBOX_PROPERTY_DECL_CONST_REF ( follow_action1 , FollowAction ) ;
TRIGGERBOX_PROPERTY_DECL ( follow_action_probability , int ) ;
TRIGGERBOX_PROPERTY_DECL ( follow_count , uint32_t ) ;
TRIGGERBOX_PROPERTY_DECL_CONST_REF ( quantization , Temporal : : BBT_Offset ) ;
TRIGGERBOX_PROPERTY_DECL_CONST_REF ( follow_length , Temporal : : BBT_Offset ) ;
TRIGGERBOX_PROPERTY_DECL ( use_follow_length , bool ) ;
TRIGGERBOX_PROPERTY_DECL ( legato , bool ) ;
TRIGGERBOX_PROPERTY_DECL ( velocity_effect , float ) ;
TRIGGERBOX_PROPERTY_DECL ( stretchable , bool ) ;
TRIGGERBOX_PROPERTY_DECL ( cue_isolated , bool ) ;
2022-02-28 10:50:46 -05:00
TRIGGERBOX_PROPERTY_DECL ( allow_patch_changes , bool ) ;
TRIGGERBOX_PROPERTY_DECL ( gain , gain_t ) ;
2022-01-26 12:11:27 -05:00
TRIGGERBOX_PROPERTY_DECL ( stretch_mode , StretchMode ) ;
TRIGGERBOX_PROPERTY_DECL ( color , color_t ) ;
TRIGGERBOX_PROPERTY_DECL_CONST_REF ( name , std : : string ) ;
# undef TRIGGERBOX_PROPERTY_DECL
# undef TRIGGERBOX_PROPERTY_DECL_CONST_REF
2021-12-17 13:39:38 -05:00
2021-12-04 13:48:15 -05:00
/* Calling ::bang() will cause this Trigger to be placed in its owning
TriggerBox ' s queue .
*/
2023-09-08 16:40:42 -04:00
void bang ( float velocity = 1.0f ) ;
2021-12-04 13:48:15 -05:00
2022-10-01 08:47:30 -04:00
/* Calling ::unbang() is equivalent to a mouse-up or note-off
. . . it MIGHT cause a clip to stop , but more likely has no effect , depending on the slot ' s launch - style .
2021-12-04 13:48:15 -05:00
*/
2021-08-08 21:08:16 -04:00
void unbang ( ) ;
2021-12-04 13:48:15 -05:00
/* Calling ::request_stop() to stop a Trigger at the earliest possible
* opportunity , rather than at the next quantization point .
*/
2021-11-29 23:50:19 -05:00
void request_stop ( ) ;
2021-07-19 11:57:31 -04:00
2022-10-01 08:47:30 -04:00
/* Call ::stop_quantized() to stop a Trigger at the next quantization point.
*/
void stop_quantized ( ) ;
2022-09-30 19:23:41 -04:00
virtual void tempo_map_changed ( ) { }
2021-12-02 13:27:18 -05:00
virtual pframes_t run ( BufferSet & , samplepos_t start_sample , samplepos_t end_sample ,
Temporal : : Beats const & start , Temporal : : Beats const & end ,
2022-07-07 18:44:56 -04:00
pframes_t nframes , pframes_t offset , double bpm , pframes_t & quantize_offset ) = 0 ;
2021-08-31 13:53:24 -04:00
virtual void set_start ( timepos_t const & ) = 0 ;
virtual void set_end ( timepos_t const & ) = 0 ;
2021-10-05 18:01:52 -04:00
virtual void set_length ( timecnt_t const & ) = 0 ;
2021-11-04 16:00:16 -04:00
virtual void reload ( BufferSet & , void * ) = 0 ;
2021-12-15 20:15:58 -05:00
virtual void io_change ( ) { }
2022-01-26 12:11:27 -05:00
virtual void set_legato_offset ( timepos_t const & offset ) = 0 ;
2021-08-13 00:59:04 -04:00
2022-02-14 11:52:43 -05:00
timepos_t current_pos ( ) const ;
double position_as_fraction ( ) const ;
2022-02-07 17:44:08 -05:00
2023-02-12 14:02:22 -05:00
Temporal : : BBT_Argument compute_start ( Temporal : : TempoMap : : SharedPtr const & , samplepos_t start , samplepos_t end , Temporal : : BBT_Offset const & q , samplepos_t & start_samples , bool & will_start ) ;
2022-03-19 17:24:41 -04:00
virtual timepos_t compute_end ( Temporal : : TempoMap : : SharedPtr const & , Temporal : : BBT_Time const & , samplepos_t , Temporal : : Beats & ) = 0 ;
2022-07-25 18:13:08 -04:00
virtual void start_and_roll_to ( samplepos_t start , samplepos_t position , uint32_t cnt ) = 0 ;
2021-10-04 00:44:03 -04:00
2022-01-14 19:31:58 -05:00
/* because follow actions involve probability is it easier to code the will-not-follow case */
bool will_not_follow ( ) const ;
bool will_follow ( ) const { return ! will_not_follow ( ) ; }
2021-09-26 23:59:15 -04:00
2022-02-11 15:36:58 -05:00
/* assumes that this is currently playing but does not enforce it */
bool cue_launched ( ) const { return _cue_launched ; }
2021-12-22 15:09:48 -05:00
virtual bool probably_oneshot ( ) const = 0 ;
2021-12-24 16:10:24 -05:00
virtual timepos_t start_offset ( ) const = 0 ; /* offset from start of data */
2021-08-13 00:59:04 -04:00
virtual timepos_t current_length ( ) const = 0 ; /* offset from start() */
virtual timepos_t natural_length ( ) const = 0 ; /* offset from start() */
2022-01-06 18:50:55 -05:00
void process_state_requests ( BufferSet & bufs , pframes_t dest_offset ) ;
2021-08-08 21:08:16 -04:00
bool active ( ) const { return _state > = Running ; }
State state ( ) const { return _state ; }
2021-07-17 21:01:10 -04:00
2024-03-10 07:44:31 -04:00
virtual bool has_data ( ) const = 0 ;
2023-02-16 18:33:28 -05:00
void set_region ( std : : shared_ptr < Region > , bool use_thread = true ) ;
2021-12-22 00:35:59 -05:00
void clear_region ( ) ;
2023-02-16 18:33:28 -05:00
virtual int set_region_in_worker_thread ( std : : shared_ptr < Region > ) = 0 ;
std : : shared_ptr < Region > region ( ) const { return _region ; }
2021-07-19 11:57:31 -04:00
2021-12-21 15:37:47 -05:00
uint32_t index ( ) const { return _index ; }
2021-07-20 00:37:17 -04:00
2021-10-25 14:53:27 -04:00
/* Managed by TriggerBox, these record the time that the trigger is
* scheduled to start or stop at . Computed in
* Trigger : : maybe_compute_next_transition ( ) .
*/
samplepos_t transition_samples ;
Temporal : : Beats transition_beats ;
2022-09-30 19:23:41 -04:00
Temporal : : BBT_Time _transition_bbt ;
2021-07-20 00:37:17 -04:00
2022-04-06 23:56:32 -04:00
XMLNode & get_state ( ) const ;
2021-08-05 18:20:37 -04:00
int set_state ( const XMLNode & , int version ) ;
2022-01-30 15:37:52 -05:00
void maybe_compute_next_transition ( samplepos_t start_sample , Temporal : : Beats const & start , Temporal : : Beats const & end , pframes_t & nframes , pframes_t & dest_offset ) ;
2022-02-07 17:44:08 -05:00
bool compute_quantized_transition ( samplepos_t start_sample , Temporal : : Beats const & start , Temporal : : Beats const & end ,
2023-02-12 14:02:22 -05:00
Temporal : : BBT_Argument & t_bbt , Temporal : : Beats & t_beats , samplepos_t & t_samples ,
2022-02-07 17:44:08 -05:00
Temporal : : TempoMap : : SharedPtr const & tmap , Temporal : : BBT_Offset const & q ) ;
2022-02-01 21:55:37 -05:00
pframes_t compute_next_transition ( samplepos_t start_sample , Temporal : : Beats const & start , Temporal : : Beats const & end , pframes_t nframes ,
2023-02-12 14:02:22 -05:00
Temporal : : BBT_Argument & t_bbt , Temporal : : Beats & t_beats , samplepos_t & t_samples ,
2022-02-07 17:44:08 -05:00
Temporal : : TempoMap : : SharedPtr const & tmap ) ;
2021-08-10 22:35:39 -04:00
2022-02-15 18:24:01 -05:00
template < typename TriggerType >
void start_and_roll_to ( samplepos_t start_pos , samplepos_t end_position , TriggerType & trigger ,
pframes_t ( TriggerType : : * run_method ) ( BufferSet & bufs , samplepos_t start_sample , samplepos_t end_sample ,
Temporal : : Beats const & start_beats , Temporal : : Beats const & end_beats ,
2022-07-25 18:13:08 -04:00
pframes_t nframes , pframes_t dest_offset , double bpm , pframes_t & ) , uint32_t cnt ) ;
2021-08-10 22:35:39 -04:00
void set_next_trigger ( int n ) ;
int next_trigger ( ) const { return _next_trigger ; }
2021-08-08 21:08:16 -04:00
2022-01-14 16:36:38 -05:00
/* any non-zero value will work for the default argument, and means
" use your own launch quantization " . BBT_Offset ( 0 , 0 , 0 ) means what
it says : start immediately
*/
2022-02-02 17:04:47 -05:00
void startup ( BufferSet & , pframes_t dest_offset , Temporal : : BBT_Offset const & start_quantization = Temporal : : BBT_Offset ( 9 , 3 , 0 ) ) ;
2022-08-03 13:00:37 -04:00
void startup_from_ffwd ( BufferSet & , uint32_t loop_cnt ) ;
2022-03-17 14:18:42 -04:00
void shutdown_from_fwd ( ) ;
2022-01-06 18:50:55 -05:00
virtual void shutdown ( BufferSet & bufs , pframes_t dest_offset ) ;
2021-09-05 12:40:58 -04:00
virtual void jump_start ( ) ;
2022-01-06 18:50:55 -05:00
virtual void jump_stop ( BufferSet & bufs , pframes_t dest_offset ) ;
2021-12-15 13:03:47 -05:00
void begin_stop ( bool explicit_stop = false ) ;
2022-02-20 11:20:47 -05:00
void begin_switch ( TriggerPtr ) ;
2021-12-15 13:03:47 -05:00
bool explicitly_stopped ( ) const { return _explicitly_stopped ; }
2021-09-04 12:37:36 -04:00
2021-12-15 08:08:20 -05:00
uint32_t loop_count ( ) const { return _loop_cnt ; }
2021-10-08 15:37:29 -04:00
2021-09-10 15:04:49 -04:00
void set_ui ( void * ) ;
void * ui ( ) const { return _ui ; }
2021-12-30 21:27:26 -05:00
TriggerBox & box ( ) const { return _box ; }
2021-10-17 19:57:43 -04:00
2022-01-17 19:03:04 -05:00
double estimated_tempo ( ) const { return _estimated_tempo ; }
2022-02-24 15:38:58 -05:00
/* the following functions deal with audio- or midi-specific SegmentDescriptor properties, provided as virtuals so we don't have to do lots of dynamic_casting */
/* segment_tempo is currently a no-op for MIDI, but may be implemented later */
2022-02-11 08:31:03 -05:00
virtual double segment_tempo ( ) const = 0 ;
virtual void set_segment_tempo ( double t ) = 0 ;
2022-01-17 19:03:04 -05:00
2022-02-24 15:38:58 -05:00
/* used_channels is a no-op for audio */
virtual Evoral : : SMF : : UsedChannels used_channels ( ) const { return Evoral : : SMF : : UsedChannels ( ) ; }
virtual void set_used_channels ( Evoral : : SMF : : UsedChannels ) { }
/* patch changes are a no-op for audio */
virtual void set_patch_change ( Evoral : : PatchChange < MidiBuffer : : TimeType > const & ) { }
virtual Evoral : : PatchChange < MidiBuffer : : TimeType > const patch_change ( uint8_t ) const { return Evoral : : PatchChange < MidiBuffer : : TimeType > ( ) ; }
virtual void unset_patch_change ( uint8_t channel ) { }
virtual void unset_all_patch_changes ( ) { }
virtual bool patch_change_set ( uint8_t channel ) const { return false ; }
2022-02-12 12:12:08 -05:00
virtual void setup_stretcher ( ) = 0 ;
2022-01-17 19:03:04 -05:00
Temporal : : Meter meter ( ) const { return _meter ; }
2022-01-10 20:33:05 -05:00
void set_velocity_gain ( gain_t g ) { _pending_velocity_gain = g ; }
2021-12-21 19:36:39 -05:00
void set_pending ( Trigger * ) ;
Trigger * swap_pending ( Trigger * ) ;
2022-02-09 18:30:02 -05:00
void update_properties ( ) ;
2021-12-27 14:04:21 -05:00
static Trigger * const MagicClearPointerValue ;
2021-12-22 00:35:59 -05:00
2021-12-12 13:20:58 -05:00
virtual SegmentDescriptor get_segment_descriptor ( ) const = 0 ;
2021-12-24 16:12:13 -05:00
static void request_trigger_delete ( Trigger * t ) ;
2022-02-11 08:31:03 -05:00
/* these operations are provided to get/set all the "user visible" trigger properties at once */
/* examples: drag+dropping from slot to slot, or "Range->Bounce to Slot", where a single operation sets many */
void get_ui_state ( UIState & state ) const ;
void set_ui_state ( UIState & state ) ;
2023-08-22 19:29:09 -04:00
static PBD : : Signal2 < void , PBD : : PropertyChange , Trigger * > TriggerPropertyChange ;
2023-08-20 22:57:40 -04:00
2021-07-17 21:01:10 -04:00
protected :
2021-11-29 23:50:19 -05:00
struct UIRequests {
std : : atomic < bool > stop ;
UIRequests ( ) : stop ( false ) { }
} ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Region > _region ;
2022-02-14 11:52:43 -05:00
samplecnt_t process_index ;
samplepos_t final_processed_sample ; /* where we stop playing, in process time, compare with process_index */
2022-01-26 12:11:27 -05:00
UIState ui_state ;
2021-11-11 17:10:33 -05:00
TriggerBox & _box ;
2021-11-29 23:50:19 -05:00
UIRequests _requests ;
2021-11-11 17:10:33 -05:00
State _state ;
2022-02-18 14:49:15 -05:00
bool _playout ;
2021-11-11 17:10:33 -05:00
std : : atomic < int > _bang ;
std : : atomic < int > _unbang ;
2021-12-21 15:37:47 -05:00
uint32_t _index ;
2021-11-11 17:10:33 -05:00
int _next_trigger ;
uint32_t _loop_cnt ; /* how many times in a row has this played */
2021-12-18 16:11:54 -05:00
void * _ui ;
bool _explicitly_stopped ;
2022-01-10 20:33:05 -05:00
gain_t _pending_velocity_gain ;
gain_t _velocity_gain ;
2022-02-11 15:36:58 -05:00
bool _cue_launched ;
2022-01-10 20:33:05 -05:00
2022-03-20 16:19:00 -04:00
/* these are only used by midi triggers but the ui_state API needs them */
Evoral : : SMF : : UsedChannels _used_channels ;
Evoral : : PatchChange < MidiBuffer : : TimeType > _patch_change [ 16 ] ;
std : : vector < int > _channel_map ;
2022-01-25 20:06:42 -05:00
void copy_to_ui_state ( ) ;
2021-12-29 14:41:11 -05:00
2021-12-18 16:11:54 -05:00
/* computed from data */
2022-01-14 00:19:01 -05:00
double _estimated_tempo ; //TODO: this should come from the MIDI file
double _segment_tempo ; //TODO: this will likely get stored in the SegmentDescriptor for audio triggers
2022-01-26 11:17:30 -05:00
/* basic process is :
1 ) when a file is loaded , we infer its bpm either by minibpm ' s estimate , a flag in the filename , metadata ( TBD ) or other means
2 ) we assume the clip must have an integer number of beats in it ( simplest case is a one - bar loop with 4 beats in it )
3 ) . . . so we round to the nearest beat length , and set the tempo to * exactly * fit the sample - length into the assumed beat - length
4 ) the user may recognize a problem : " this was a 3/4 beat, which was rounded to 4 beats but it should have been 3 "
5 ) if the user changes the beat - length , then the tempo is recalculated for use during stretching
6 ) someday , we will also allow the sample start and length to be adjusted in a trimmer , and that will also adjust the tempo
7 ) in all cases the user should be in final control ; but our " internal " value for stretching are just sample - start and BPM , end of story
*/
double _beatcnt ;
2022-01-13 17:48:44 -05:00
Temporal : : Meter _meter ;
2022-01-14 00:19:01 -05:00
2021-11-17 23:14:56 -05:00
samplepos_t expected_end_sample ;
2022-01-13 14:09:23 -05:00
Temporal : : BBT_Offset _start_quantization ;
2022-02-20 11:20:47 -05:00
Temporal : : BBT_Offset _nxt_quantization ;
2021-12-21 19:36:39 -05:00
std : : atomic < Trigger * > _pending ;
2022-02-09 18:30:02 -05:00
std : : atomic < unsigned int > last_property_generation ;
2021-12-21 19:36:39 -05:00
2022-01-06 18:50:55 -05:00
void when_stopped_during_run ( BufferSet & bufs , pframes_t dest_offset ) ;
2023-02-16 18:33:28 -05:00
void set_region_internal ( std : : shared_ptr < Region > ) ;
2022-02-14 11:52:43 -05:00
virtual void retrigger ( ) ;
2022-02-02 17:04:47 -05:00
virtual void _startup ( BufferSet & , pframes_t dest_offset , Temporal : : BBT_Offset const & ) ;
2022-01-20 16:03:40 -05:00
bool internal_use_follow_length ( ) const ;
2022-02-11 12:16:04 -05:00
void send_property_change ( PBD : : PropertyChange pc ) ;
2021-07-17 15:21:45 -04:00
} ;
class LIBARDOUR_API AudioTrigger : public Trigger {
public :
2021-12-21 15:37:47 -05:00
AudioTrigger ( uint32_t index , TriggerBox & ) ;
2021-07-17 15:21:45 -04:00
~ AudioTrigger ( ) ;
2022-02-07 17:44:08 -05:00
template < bool actually_run > pframes_t audio_run ( BufferSet & bufs , samplepos_t start_sample , samplepos_t end_sample ,
Temporal : : Beats const & start , Temporal : : Beats const & end ,
2022-07-07 18:44:56 -04:00
pframes_t nframes , pframes_t dest_offset , double bpm , pframes_t & quantize_offset ) ;
2022-02-07 17:44:08 -05:00
2022-07-07 18:44:56 -04:00
pframes_t run ( BufferSet & bufs , samplepos_t start_sample , samplepos_t end_sample , Temporal : : Beats const & start , Temporal : : Beats const & end , pframes_t nframes , pframes_t dest_offset , double bpm , pframes_t & quantize_offset ) {
return audio_run < true > ( bufs , start_sample , end_sample , start , end , nframes , dest_offset , bpm , quantize_offset ) ;
2022-02-07 17:44:08 -05:00
}
2021-07-17 15:21:45 -04:00
2024-03-10 07:44:31 -04:00
bool has_data ( ) const { return data . length > 0 ; }
uint32_t n_channels ( ) const { return data . size ( ) ; }
2022-01-17 19:03:04 -05:00
StretchMode stretch_mode ( ) const { return _stretch_mode ; }
void set_stretch_mode ( StretchMode ) ;
double segment_tempo ( ) const { return _segment_tempo ; }
void set_segment_tempo ( double t ) ;
2022-01-26 11:17:30 -05:00
double segment_beatcnt ( ) { return _beatcnt ; }
void set_segment_beatcnt ( double count ) ;
2022-01-17 19:03:04 -05:00
2021-08-31 13:53:24 -04:00
void set_start ( timepos_t const & ) ;
void set_end ( timepos_t const & ) ;
void set_legato_offset ( timepos_t const & ) ;
2021-10-05 18:01:52 -04:00
void set_length ( timecnt_t const & ) ;
2021-12-24 16:10:24 -05:00
timepos_t start_offset ( ) const ; /* offset from start of data */
2021-08-13 00:59:04 -04:00
timepos_t current_length ( ) const ; /* offset from start of data */
timepos_t natural_length ( ) const ; /* offset from start of data */
2021-11-04 16:00:16 -04:00
void reload ( BufferSet & , void * ) ;
2021-12-15 20:15:58 -05:00
void io_change ( ) ;
2021-12-22 15:09:48 -05:00
bool probably_oneshot ( ) const ;
2021-08-06 15:03:28 -04:00
2023-02-16 18:33:28 -05:00
int set_region_in_worker_thread ( std : : shared_ptr < Region > ) ;
2021-09-05 12:40:58 -04:00
void jump_start ( ) ;
2022-01-06 18:50:55 -05:00
void jump_stop ( BufferSet & bufs , pframes_t dest_offset ) ;
2021-08-08 21:08:16 -04:00
2022-04-06 23:56:32 -04:00
XMLNode & get_state ( ) const ;
2021-08-31 18:46:19 -04:00
int set_state ( const XMLNode & , int version ) ;
2021-11-11 17:10:33 -05:00
RubberBand : : RubberBandStretcher * stretcher ( ) { return ( _stretcher ) ; }
2021-10-07 10:03:46 -04:00
2021-12-12 13:20:58 -05:00
SegmentDescriptor get_segment_descriptor ( ) const ;
2022-03-19 17:24:41 -04:00
timepos_t compute_end ( Temporal : : TempoMap : : SharedPtr const & , Temporal : : BBT_Time const & , samplepos_t , Temporal : : Beats & ) ;
2022-07-25 18:13:08 -04:00
void start_and_roll_to ( samplepos_t start , samplepos_t position , uint32_t cnt ) ;
2021-12-15 12:21:28 -05:00
bool stretching ( ) const ;
2021-12-12 13:20:58 -05:00
2021-08-08 21:08:16 -04:00
protected :
2021-08-05 17:56:14 -04:00
void retrigger ( ) ;
2021-07-19 11:57:31 -04:00
2021-07-17 15:21:45 -04:00
private :
2021-12-17 14:37:51 -05:00
struct Data : std : : vector < Sample * > {
samplecnt_t length ;
Data ( ) : length ( 0 ) { }
} ;
Data data ;
2021-12-18 19:34:06 -05:00
RubberBand : : RubberBandStretcher * _stretcher ;
2021-08-13 00:59:04 -04:00
samplepos_t _start_offset ;
2021-12-18 19:34:06 -05:00
/* computed during run */
samplecnt_t read_index ;
2022-01-26 23:20:04 -05:00
samplepos_t last_readable_sample ; /* where the data runs out, relative to the start of the data, compare with read_index */
2021-12-18 19:34:06 -05:00
samplepos_t _legato_offset ;
2021-11-29 23:50:19 -05:00
samplecnt_t retrieved ;
2021-12-15 12:21:28 -05:00
samplecnt_t got_stretcher_padding ;
samplecnt_t to_pad ;
samplecnt_t to_drop ;
2021-11-11 17:10:33 -05:00
2022-02-12 12:12:08 -05:00
virtual void setup_stretcher ( ) ;
2021-07-19 11:57:31 -04:00
void drop_data ( ) ;
2023-02-16 18:33:28 -05:00
int load_data ( std : : shared_ptr < AudioRegion > ) ;
2024-03-10 07:44:31 -04:00
int load_data ( BufferSet const & ) ;
2022-01-14 00:19:01 -05:00
void estimate_tempo ( ) ;
2022-02-08 22:33:25 -05:00
void reset_stretcher ( ) ;
2022-02-02 17:04:47 -05:00
void _startup ( BufferSet & , pframes_t dest_offset , Temporal : : BBT_Offset const & ) ;
2021-07-17 15:21:45 -04:00
} ;
2021-10-20 18:19:09 -04:00
class LIBARDOUR_API MIDITrigger : public Trigger {
public :
2021-12-21 15:37:47 -05:00
MIDITrigger ( uint32_t index , TriggerBox & ) ;
2021-10-20 18:19:09 -04:00
~ MIDITrigger ( ) ;
2022-02-07 17:44:08 -05:00
template < bool actually_run > pframes_t midi_run ( BufferSet & , samplepos_t start_sample , samplepos_t end_sample ,
2022-07-07 18:44:56 -04:00
Temporal : : Beats const & start_beats , Temporal : : Beats const & end_beats , pframes_t nframes , pframes_t offset , double bpm , pframes_t & quantize_offset ) ;
2022-02-07 17:44:08 -05:00
2022-07-07 18:44:56 -04:00
pframes_t run ( BufferSet & bufs , samplepos_t start_sample , samplepos_t end_sample , Temporal : : Beats const & start , Temporal : : Beats const & end , pframes_t nframes , pframes_t dest_offset , double bpm , pframes_t & quantize_offset ) {
return midi_run < true > ( bufs , start_sample , end_sample , start , end , nframes , dest_offset , bpm , quantize_offset ) ;
2022-02-07 17:44:08 -05:00
}
2021-10-20 18:19:09 -04:00
2024-03-10 07:44:31 -04:00
bool has_data ( ) const { return ( bool ) model ; }
2021-10-20 18:19:09 -04:00
void set_start ( timepos_t const & ) ;
void set_end ( timepos_t const & ) ;
void set_legato_offset ( timepos_t const & ) ;
void set_length ( timecnt_t const & ) ;
timepos_t start_offset ( ) const ;
timepos_t end ( ) const ; /* offset from start of data */
timepos_t current_length ( ) const ; /* offset from start of data */
timepos_t natural_length ( ) const ; /* offset from start of data */
2021-11-04 16:00:16 -04:00
void reload ( BufferSet & , void * ) ;
2021-12-22 15:09:48 -05:00
bool probably_oneshot ( ) const ;
2021-10-20 18:19:09 -04:00
2022-09-30 19:23:41 -04:00
void tempo_map_changed ( ) ;
2022-02-24 15:37:19 -05:00
void estimate_midi_patches ( ) ;
2023-02-16 18:33:28 -05:00
int set_region_in_worker_thread ( std : : shared_ptr < Region > ) ;
2021-10-20 18:19:09 -04:00
void jump_start ( ) ;
2022-01-06 18:50:55 -05:00
void shutdown ( BufferSet & bufs , pframes_t dest_offset ) ;
void jump_stop ( BufferSet & bufs , pframes_t dest_offset ) ;
2021-10-20 18:19:09 -04:00
2022-04-06 23:56:32 -04:00
XMLNode & get_state ( ) const ;
2021-10-20 18:19:09 -04:00
int set_state ( const XMLNode & , int version ) ;
2021-12-12 13:20:58 -05:00
SegmentDescriptor get_segment_descriptor ( ) const ;
2022-03-19 17:24:41 -04:00
timepos_t compute_end ( Temporal : : TempoMap : : SharedPtr const & , Temporal : : BBT_Time const & , samplepos_t , Temporal : : Beats & ) ;
2022-07-25 18:13:08 -04:00
void start_and_roll_to ( samplepos_t start , samplepos_t position , uint32_t cnt ) ;
2021-12-12 13:20:58 -05:00
2022-02-02 14:45:57 -05:00
void set_patch_change ( Evoral : : PatchChange < MidiBuffer : : TimeType > const & ) ;
2022-02-24 15:38:58 -05:00
Evoral : : PatchChange < MidiBuffer : : TimeType > const patch_change ( uint8_t ) const ;
2022-02-02 14:45:57 -05:00
void unset_patch_change ( uint8_t channel ) ;
void unset_all_patch_changes ( ) ;
bool patch_change_set ( uint8_t channel ) const ;
2022-02-24 15:38:58 -05:00
/* It's possible that a portion of a midi file would use a subset of the total channels used, so store that info in the segment descriptor */
2022-03-20 16:19:00 -04:00
Evoral : : SMF : : UsedChannels used_channels ( ) const { return ui_state . used_channels ; }
2022-02-24 15:38:58 -05:00
void set_used_channels ( Evoral : : SMF : : UsedChannels ) ;
2022-02-11 08:31:03 -05:00
/* theoretically, MIDI files can have a dedicated tempo outside the session tempo map (*un-stretched*) but this is currently unimplemented */
2022-02-12 12:12:08 -05:00
/* boilerplate tempo functions are provided here so we don't have to do constant dynamic_cast checks to use the tempo+stretch APIs */
2022-02-11 08:31:03 -05:00
virtual double segment_tempo ( ) const { return 120.0 ; }
virtual void set_segment_tempo ( double t ) { }
2022-02-12 12:12:08 -05:00
virtual void setup_stretcher ( ) { }
2022-02-11 08:31:03 -05:00
2022-02-03 14:37:49 -05:00
void set_channel_map ( int channel , int target ) ;
void unset_channel_map ( int channel ) ;
int channel_map ( int channel ) ;
std : : vector < int > const & channel_map ( ) const { return _channel_map ; }
2021-10-20 18:19:09 -04:00
protected :
void retrigger ( ) ;
private :
PBD : : ID data_source ;
2021-11-04 16:00:16 -04:00
PBD : : ScopedConnection content_connection ;
2021-10-24 11:27:14 -04:00
2022-01-11 13:32:35 -05:00
Temporal : : Beats final_beat ;
2021-11-19 16:50:50 -05:00
Temporal : : DoubleableBeats data_length ; /* using timestamps from data */
Temporal : : DoubleableBeats last_event_beats ;
2022-09-30 19:23:41 -04:00
samplepos_t last_event_samples ;
2021-10-24 11:27:14 -04:00
2021-10-20 18:19:09 -04:00
Temporal : : BBT_Offset _start_offset ;
Temporal : : BBT_Offset _legato_offset ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < MidiModel > model ;
2022-03-02 12:12:50 -05:00
MidiModel : : const_iterator iter ;
2022-09-30 19:23:41 -04:00
bool map_change ;
2021-11-19 16:50:50 -05:00
2023-02-16 18:33:28 -05:00
int load_data ( std : : shared_ptr < MidiRegion > ) ;
2024-03-10 07:44:31 -04:00
int load_data ( BufferSet const & ) ;
2021-10-20 18:19:09 -04:00
void compute_and_set_length ( ) ;
2022-02-02 17:04:47 -05:00
void _startup ( BufferSet & , pframes_t dest_offset , Temporal : : BBT_Offset const & ) ;
2021-10-20 18:19:09 -04:00
} ;
2021-11-09 23:47:15 -05:00
class LIBARDOUR_API TriggerBoxThread
{
public :
TriggerBoxThread ( ) ;
~ TriggerBoxThread ( ) ;
2021-11-10 00:36:51 -05:00
static void init_request_pool ( ) { Request : : init_pool ( ) ; }
2023-02-16 18:33:28 -05:00
void set_region ( TriggerBox & , uint32_t slot , std : : shared_ptr < Region > ) ;
2021-12-24 16:12:13 -05:00
void request_delete_trigger ( Trigger * t ) ;
2021-11-10 00:36:51 -05:00
2021-11-09 23:47:15 -05:00
void summon ( ) ;
void stop ( ) ;
void wait_until_finished ( ) ;
2021-11-10 00:36:51 -05:00
private :
2021-11-09 23:47:15 -05:00
static void * _thread_work ( void * arg ) ;
void * thread_work ( ) ;
2021-11-10 10:45:38 -05:00
enum RequestType {
Quit ,
2021-12-24 16:12:13 -05:00
SetRegion ,
DeleteTrigger
2021-11-10 10:45:38 -05:00
} ;
2021-11-09 23:47:15 -05:00
struct Request {
2021-11-10 00:36:51 -05:00
Request ( RequestType t ) : type ( t ) { }
2021-11-09 23:47:15 -05:00
2021-11-10 00:36:51 -05:00
RequestType type ;
/* for set region */
2021-12-21 15:37:47 -05:00
TriggerBox * box ;
uint32_t slot ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Region > region ;
2021-12-24 16:12:13 -05:00
/* for DeleteTrigger */
Trigger * trigger ;
2021-11-09 23:47:15 -05:00
2021-11-10 00:36:51 -05:00
void * operator new ( size_t ) ;
void operator delete ( void * ptr , size_t ) ;
2021-11-09 23:47:15 -05:00
2022-07-06 23:07:11 -04:00
static PBD : : MultiAllocSingleReleasePool * pool ;
2021-11-10 00:36:51 -05:00
static void init_pool ( ) ;
} ;
pthread_t thread ;
PBD : : RingBuffer < Request * > requests ;
2021-11-09 23:47:15 -05:00
CrossThreadChannel _xthread ;
2021-11-10 00:36:51 -05:00
void queue_request ( Request * ) ;
2021-12-24 16:12:13 -05:00
void delete_trigger ( Trigger * ) ;
2021-11-09 23:47:15 -05:00
} ;
2022-01-21 11:30:12 -05:00
struct CueRecord {
int32_t cue_number ;
2022-01-21 12:11:32 -05:00
samplepos_t when ;
CueRecord ( int32_t cn , samplepos_t t ) : cue_number ( cn ) , when ( t ) { }
CueRecord ( ) : cue_number ( 0 ) , when ( 0 ) { }
2022-08-03 13:42:51 -04:00
static const int32_t stop_all = INT32_MAX ;
2022-01-21 11:30:12 -05:00
} ;
typedef PBD : : RingBuffer < CueRecord > CueRecords ;
2021-11-09 23:47:15 -05:00
2021-07-17 15:21:45 -04:00
class LIBARDOUR_API TriggerBox : public Processor
{
public :
2022-10-04 21:55:05 -04:00
# ifdef MIXBUS
static const int32_t default_triggers_per_box = 8 ;
# else
static const int32_t default_triggers_per_box = 16 ;
# endif
2021-08-05 14:10:40 -04:00
TriggerBox ( Session & , DataType dt ) ;
2021-07-17 15:21:45 -04:00
~ TriggerBox ( ) ;
2022-01-21 11:30:12 -05:00
static CueRecords cue_records ;
2022-01-21 11:57:40 -05:00
static bool cue_recording ( ) { return _cue_recording ; }
static void set_cue_recording ( bool yn ) ;
static PBD : : Signal0 < void > CueRecordingChanged ;
2022-01-21 11:30:12 -05:00
2021-07-17 15:21:45 -04:00
void run ( BufferSet & bufs , samplepos_t start_sample , samplepos_t end_sample , double speed , pframes_t nframes , bool result_required ) ;
bool can_support_io_configuration ( const ChanCount & in , ChanCount & out ) ;
2021-07-17 21:01:10 -04:00
bool configure_io ( ChanCount in , ChanCount out ) ;
2021-07-17 15:21:45 -04:00
2022-02-01 00:40:05 -05:00
bool empty ( ) const { return _active_slots = = 0 ; }
PBD : : Signal0 < void > EmptyStatusChanged ;
2021-10-13 11:07:07 -04:00
int32_t order ( ) const { return _order ; }
void set_order ( int32_t n ) ;
2021-12-21 15:37:47 -05:00
typedef std : : vector < TriggerPtr > Triggers ;
2021-07-19 11:57:31 -04:00
2021-12-21 15:37:47 -05:00
TriggerPtr trigger ( Triggers : : size_type ) ;
2021-07-19 11:57:31 -04:00
2023-09-08 16:40:42 -04:00
void bang_trigger_at ( Triggers : : size_type row , float velocity = 1.0f ) ;
2022-09-30 09:37:05 -04:00
void unbang_trigger_at ( Triggers : : size_type row ) ;
2021-12-21 15:37:47 -05:00
void add_trigger ( TriggerPtr ) ;
2021-07-17 15:21:45 -04:00
2022-02-07 17:44:08 -05:00
void fast_forward ( CueEvents const & , samplepos_t transport_postiion ) ;
2022-05-12 10:15:15 -04:00
bool fast_forwarding ( ) const { return _fast_forwarding ; }
2022-02-07 17:44:08 -05:00
2021-12-21 19:36:39 -05:00
void set_pending ( uint32_t slot , Trigger * ) ;
2021-12-21 17:15:06 -05:00
2022-04-06 23:56:32 -04:00
XMLNode & get_state ( ) const ;
2021-07-17 18:13:49 -04:00
int set_state ( const XMLNode & , int version ) ;
2023-02-16 18:33:28 -05:00
void deep_sources ( std : : set < std : : shared_ptr < Source > > & ) ;
void used_regions ( std : : set < std : : shared_ptr < Region > > & ) ;
2022-06-16 14:03:43 -04:00
2021-12-21 15:37:47 -05:00
void set_from_path ( uint32_t slot , std : : string const & path ) ;
2023-02-16 18:33:28 -05:00
void set_from_selection ( uint32_t slot , std : : shared_ptr < Region > ) ;
2021-08-05 14:10:40 -04:00
DataType data_type ( ) const { return _data_type ; }
2021-12-22 19:27:07 -05:00
void stop_all_immediately ( ) ;
void stop_all_quantized ( ) ;
2021-08-06 23:26:50 -04:00
2021-12-21 15:37:47 -05:00
TriggerPtr currently_playing ( ) const { return _currently_playing ; }
2021-12-06 11:06:46 -05:00
2022-01-27 13:45:29 -05:00
TriggerPtr trigger_by_id ( PBD : : ID ) ;
2021-12-23 11:59:31 -05:00
void clear_all_triggers ( ) ;
2023-09-05 14:44:20 -04:00
void clear_cue ( int cue ) ;
2022-01-19 17:50:32 -05:00
void set_all_follow_action ( ARDOUR : : FollowAction const & , uint32_t n = 0 ) ;
2021-12-22 13:28:48 -05:00
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 ) ;
2021-12-06 11:06:46 -05:00
/* Returns a negative value is there is no active Trigger, or a value between 0
* and 1.0 if there is , corresponding to the value of position_as_fraction ( ) for
* the active Trigger .
*/
double position_as_fraction ( ) const ;
2021-09-04 12:37:36 -04:00
2021-12-21 15:37:47 -05:00
void queue_explict ( uint32_t ) ;
TriggerPtr get_next_trigger ( ) ;
TriggerPtr peek_next_trigger ( ) ;
2021-09-04 12:37:36 -04:00
2021-11-04 16:00:16 -04:00
void request_reload ( int32_t slot , void * ) ;
2023-02-16 18:33:28 -05:00
void set_region ( uint32_t slot , std : : shared_ptr < Region > region ) ;
2021-11-04 13:16:22 -04:00
2022-02-07 17:44:08 -05:00
void non_realtime_transport_stop ( samplepos_t now , bool flush ) ;
void non_realtime_locate ( samplepos_t now ) ;
2022-02-09 18:30:02 -05:00
void realtime_handle_transport_stopped ( ) ;
2022-02-07 17:44:08 -05:00
2023-02-16 18:33:28 -05:00
void enqueue_trigger_state_for_region ( std : : shared_ptr < Region > , std : : shared_ptr < Trigger : : UIState > ) ;
2022-01-27 14:13:03 -05:00
2022-09-30 19:23:41 -04:00
void tempo_map_changed ( ) ;
2022-01-06 02:23:27 -05:00
/* valid only within the ::run() call tree */
int32_t active_scene ( ) const { return _active_scene ; }
2021-12-21 19:36:39 -05:00
PBD : : Signal1 < void , uint32_t > TriggerSwapped ;
2021-10-08 22:35:25 -04:00
enum TriggerMidiMapMode {
AbletonPush ,
SequentialNote ,
2022-10-21 00:07:52 -04:00
ByMidiChannel ,
Custom ,
2021-10-08 22:35:25 -04:00
} ;
2022-02-01 20:03:51 -05:00
/* This is null for TriggerBoxen constructed with DataType::AUDIO */
MidiStateTracker * tracker ;
2022-11-18 16:04:32 -05:00
static bool lookup_custom_midi_binding ( std : : vector < uint8_t > const & , int & x , int & y ) ;
static void add_custom_midi_binding ( std : : vector < uint8_t > const & , int x , int y ) ;
2022-10-21 00:07:52 -04:00
static void remove_custom_midi_binding ( int x , int y ) ;
static void clear_custom_midi_bindings ( ) ;
2022-11-18 16:04:32 -05:00
static int save_custom_midi_bindings ( std : : string const & path ) ;
static int load_custom_midi_bindings ( XMLNode const & ) ;
static XMLNode * get_custom_midi_binding_state ( ) ;
2022-10-21 00:07:52 -04:00
void begin_midi_learn ( int index ) ;
void midi_unlearn ( int index ) ;
void stop_midi_learn ( ) ;
2021-10-05 23:09:16 -04:00
static Temporal : : BBT_Offset assumed_trigger_duration ( ) { return _assumed_trigger_duration ; }
static void set_assumed_trigger_duration ( Temporal : : BBT_Offset const & ) ;
2021-10-08 22:35:25 -04:00
static TriggerMidiMapMode midi_map_mode ( ) { return _midi_map_mode ; }
static void set_midi_map_mode ( TriggerMidiMapMode m ) ;
static int first_midi_note ( ) { return _first_midi_note ; }
static void set_first_midi_note ( int n ) ;
2021-11-10 10:45:38 -05:00
static void init ( ) ;
2022-11-19 12:12:14 -05:00
static void static_init ( Session & ) ;
2022-06-10 13:59:12 -04:00
static void begin_process_cycle ( ) ;
2021-11-04 13:16:22 -04:00
2021-11-10 10:45:38 -05:00
static TriggerBoxThread * worker ;
2021-11-10 17:55:58 -05:00
static void start_transport_stop ( Session & ) ;
2022-03-15 09:53:18 -04:00
static PBD : : PropertyChange all_trigger_props ( ) ;
2023-08-20 22:57:40 -04:00
void send_property_change ( PBD : : PropertyChange pc ) ;
static PBD : : Signal2 < void , PBD : : PropertyChange , int > TriggerBoxPropertyChange ;
2022-03-17 14:19:11 -04:00
void dump ( std : : ostream & ) const ;
2021-07-17 15:21:45 -04:00
private :
2021-11-29 23:50:19 -05:00
struct Requests {
std : : atomic < bool > stop_all ;
2022-01-30 15:37:52 -05:00
Requests ( ) : stop_all ( false ) { }
2021-11-29 23:50:19 -05:00
} ;
2021-10-05 23:09:16 -04:00
static Temporal : : BBT_Offset _assumed_trigger_duration ;
2021-08-05 14:10:40 -04:00
DataType _data_type ;
2021-10-13 11:07:07 -04:00
int32_t _order ;
2022-04-06 23:56:32 -04:00
mutable Glib : : Threads : : RWLock trigger_lock ; /* protects all_triggers */
2021-07-17 15:21:45 -04:00
Triggers all_triggers ;
2021-12-21 19:36:39 -05:00
typedef std : : vector < Trigger * > PendingTriggers ;
PendingTriggers pending ;
2021-12-21 15:37:47 -05:00
PBD : : RingBuffer < uint32_t > explicit_queue ; /* user queued triggers */
2022-01-06 02:23:27 -05:00
TriggerPtr _currently_playing ;
Requests _requests ;
bool _stop_all ;
int32_t _active_scene ;
2022-02-01 00:40:05 -05:00
int32_t _active_slots ;
2022-02-08 19:05:15 -05:00
bool _locate_armed ;
2022-02-19 10:53:30 -05:00
bool _cancel_locate_armed ;
2022-05-12 10:15:15 -04:00
bool _fast_forwarding ;
2021-07-17 15:21:45 -04:00
2021-08-15 09:24:23 -04:00
PBD : : PCGRand _pcg ;
2021-09-04 12:37:36 -04:00
/* These four are accessed (read/write) only from process() context */
2021-07-20 00:37:17 -04:00
2021-07-19 11:57:31 -04:00
void drop_triggers ( ) ;
2021-07-20 00:37:17 -04:00
void process_ui_trigger_requests ( ) ;
void process_midi_trigger_requests ( BufferSet & ) ;
2021-12-21 15:37:47 -05:00
int determine_next_trigger ( uint32_t n ) ;
2021-09-05 01:19:47 -04:00
void stop_all ( ) ;
2021-07-19 11:57:31 -04:00
2021-12-21 19:36:39 -05:00
void maybe_swap_pending ( uint32_t ) ;
2021-10-09 18:58:58 -04:00
void parameter_changed ( std : : string const & ) ;
2022-11-19 12:12:14 -05:00
static void static_parameter_changed ( std : : string const & ) ;
2021-10-09 18:58:58 -04:00
2021-10-08 22:35:25 -04:00
static int _first_midi_note ;
static TriggerMidiMapMode _midi_map_mode ;
2021-11-04 11:50:34 -04:00
struct Request {
enum Type {
Use ,
Reload ,
} ;
Type type ;
2021-12-24 16:12:13 -05:00
/* cannot use a union here because we need Request to have a
* " trivial " constructor .
*/
2021-12-21 15:37:47 -05:00
TriggerPtr trigger ;
void * ptr ;
int32_t slot ;
2021-11-04 13:16:22 -04:00
Request ( Type t ) : type ( t ) { }
2022-07-06 23:07:11 -04:00
static PBD : : MultiAllocSingleReleasePool * pool ;
2021-11-04 13:16:22 -04:00
static void init_pool ( ) ;
void * operator new ( size_t ) ;
void operator delete ( void * ptr , size_t ) ;
2021-11-04 11:50:34 -04:00
} ;
2021-11-04 13:16:22 -04:00
typedef PBD : : RingBuffer < Request * > RequestBuffer ;
2021-11-04 11:50:34 -04:00
RequestBuffer requests ;
2021-11-04 16:00:16 -04:00
void process_requests ( BufferSet & ) ;
void process_request ( BufferSet & , Request * ) ;
2021-11-04 13:16:22 -04:00
2021-11-04 16:00:16 -04:00
void reload ( BufferSet & bufs , int32_t slot , void * ptr ) ;
2021-11-09 23:47:15 -05:00
2022-02-19 10:53:30 -05:00
void cancel_locate_armed ( ) ;
2022-08-05 09:15:42 -04:00
void fast_forward_nothing_to_do ( ) ;
2022-09-30 19:23:41 -04:00
int handle_stopped_trigger ( BufferSet & bufs , pframes_t dest_offset ) ;
2022-02-19 10:53:30 -05:00
2021-11-10 17:55:58 -05:00
PBD : : ScopedConnection stop_all_connection ;
2022-11-18 16:04:32 -05:00
typedef std : : map < std : : vector < uint8_t > , std : : pair < int , int > > CustomMidiMap ;
2022-10-21 00:07:52 -04:00
static CustomMidiMap _custom_midi_map ;
2022-11-19 12:12:14 -05:00
static void midi_input_handler ( MIDI : : Parser & , MIDI : : byte * , size_t , samplecnt_t ) ;
2023-06-03 16:25:15 -04:00
static std : : shared_ptr < MIDI : : Parser > input_parser ;
2022-11-19 12:12:14 -05:00
static PBD : : ScopedConnection midi_input_connection ;
static void input_port_check ( ) ;
static PBD : : ScopedConnectionList static_connections ;
2023-02-16 18:33:28 -05:00
static std : : shared_ptr < MidiPort > current_input ;
2022-11-19 12:12:14 -05:00
2022-10-21 00:07:52 -04:00
static bool _learning ;
static std : : pair < int , int > learning_for ;
static PBD : : Signal0 < void > TriggerMIDILearned ;
2021-11-10 10:45:38 -05:00
static void init_pool ( ) ;
2021-11-10 17:55:58 -05:00
static std : : atomic < int > active_trigger_boxes ;
2022-01-21 11:57:40 -05:00
static std : : atomic < bool > _cue_recording ;
2022-06-10 13:59:12 -04:00
static bool roll_requested ;
static void maybe_request_roll ( Session & ) ;
2021-07-17 15:21:45 -04:00
} ;
2021-12-24 16:11:06 -05:00
class TriggerReference
{
public :
TriggerReference ( ) : box ( 0 ) , slot ( 0 ) { }
TriggerReference ( ARDOUR : : TriggerBox & b , uint32_t s ) : box ( & b ) , slot ( s ) { }
2023-02-16 18:33:28 -05:00
std : : shared_ptr < ARDOUR : : Trigger > trigger ( ) const { assert ( box ) ; return box - > trigger ( slot ) ; }
2021-12-24 16:11:06 -05:00
ARDOUR : : TriggerBox * box ;
uint32_t slot ;
} ;
2021-10-01 20:39:06 -04:00
namespace Properties {
LIBARDOUR_API extern PBD : : PropertyDescriptor < bool > running ;
LIBARDOUR_API extern PBD : : PropertyDescriptor < bool > legato ;
2022-01-16 11:54:17 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < bool > use_follow_length ;
2021-12-06 11:26:18 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < Temporal : : BBT_Offset > quantization ;
2022-01-07 12:43:30 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < Temporal : : BBT_Offset > follow_length ;
2021-10-01 20:39:06 -04:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < Trigger : : LaunchStyle > launch_style ;
2022-01-19 17:50:32 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < FollowAction > follow_action0 ;
LIBARDOUR_API extern PBD : : PropertyDescriptor < FollowAction > follow_action1 ;
2022-01-11 17:27:03 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < Trigger : : StretchMode > stretch_mode ;
2021-12-17 17:26:07 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < uint32_t > follow_count ;
2021-12-06 11:26:18 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < int > follow_action_probability ;
2021-12-06 10:47:29 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < float > velocity_effect ;
LIBARDOUR_API extern PBD : : PropertyDescriptor < gain_t > gain ;
2021-12-21 15:37:47 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < uint32_t > currently_playing ;
2022-08-28 20:56:56 -04:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < uint32_t > queued ;
2021-12-15 19:06:25 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < bool > stretchable ;
2022-01-26 12:11:27 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < bool > cue_isolated ;
2022-02-28 10:50:46 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < bool > allow_patch_changes ;
2022-02-02 14:45:57 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < bool > patch_change ; /* type not important */
2022-02-03 15:07:04 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < bool > channel_map ; /* type not important */
2022-02-24 15:38:58 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < bool > used_channels ; /* type not important */
2022-01-14 00:19:01 -05:00
LIBARDOUR_API extern PBD : : PropertyDescriptor < bool > tempo_meter ; /* only used to transmit changes, not storage */
2021-10-01 20:39:06 -04:00
}
2021-07-17 15:21:45 -04:00
} // namespace ARDOUR
2021-08-31 20:36:16 -04:00
namespace PBD {
2022-01-19 17:50:32 -05:00
DEFINE_ENUM_CONVERT ( ARDOUR : : FollowAction : : Type ) ;
2021-08-31 20:36:16 -04:00
DEFINE_ENUM_CONVERT ( ARDOUR : : Trigger : : LaunchStyle ) ;
2022-01-11 17:27:03 -05:00
DEFINE_ENUM_CONVERT ( ARDOUR : : Trigger : : StretchMode ) ;
2021-08-31 20:36:16 -04:00
} /* namespace PBD */
2021-07-17 15:21:45 -04:00
# endif /* __ardour_triggerbox_h__ */