Factor out SessionController from BasicUI

Towards sharing this code with ARDOUR_UI.
This commit is contained in:
David Robillard 2021-06-17 11:02:08 -04:00
parent 8998efa8c8
commit 1559829e24
24 changed files with 1050 additions and 849 deletions

View file

@ -160,15 +160,15 @@ CC121::CC121 (Session& s)
get_button (EButton).set_action (boost::bind (&CC121::touch, this), true);
get_button (OpenVST).set_action (boost::bind (&CC121::off, this), true);
get_button (Play).set_action (boost::bind (&BasicUI::transport_play, this, true), true);
get_button (ToStart).set_action (boost::bind (&BasicUI::prev_marker, this), true);
get_button (ToEnd).set_action (boost::bind (&BasicUI::next_marker, this), true);
get_button (RecEnable).set_action (boost::bind (&BasicUI::rec_enable_toggle, this), true);
get_button (Stop).set_action (boost::bind (&BasicUI::transport_stop, this), true);
get_button (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true);
get_button (Play).set_action (boost::bind (&SessionController::transport_play, _controller, true), true);
get_button (ToStart).set_action (boost::bind (&SessionController::prev_marker, _controller), true);
get_button (ToEnd).set_action (boost::bind (&SessionController::next_marker, _controller), true);
get_button (RecEnable).set_action (boost::bind (&SessionController::rec_enable_toggle, _controller), true);
get_button (Stop).set_action (boost::bind (&SessionController::transport_stop, _controller), true);
get_button (Ffwd).set_action (boost::bind (&SessionController::ffwd, _controller), true);
get_button (Rewind).set_action (boost::bind (&BasicUI::rewind, this), true);
get_button (Loop).set_action (boost::bind (&BasicUI::loop_toggle, this), true);
get_button (Rewind).set_action (boost::bind (&SessionController::rewind, _controller), true);
get_button (Loop).set_action (boost::bind (&SessionController::loop_toggle, _controller), true);
get_button (Jog).set_action (boost::bind (&CC121::jog, this), true);
get_button (Mute).set_action (boost::bind (&CC121::mute, this), true);
@ -669,7 +669,7 @@ CC121::map_transport_state ()
{
get_button (Loop).set_led_state (_output_port, _session->get_play_loop());
float ts = get_transport_speed();
float ts = _controller.get_transport_speed();
if (ts == 0) {
stop_blinking (Play);

View file

@ -574,9 +574,9 @@ ContourDesignControlProtocol::jump_forward (JumpDistance dist)
{
LocateTransportDisposition kr = _keep_rolling ? RollIfAppropriate : MustStop;
switch (dist.unit) {
case SECONDS: jump_by_seconds (dist.value, kr); break;
case BEATS: jump_by_beats (dist.value, kr); break;
case BARS: jump_by_bars (dist.value, kr); break;
case SECONDS: _controller.jump_by_seconds (dist.value, kr); break;
case BEATS: _controller.jump_by_beats (dist.value, kr); break;
case BARS: _controller.jump_by_bars (dist.value, kr); break;
default: break;
}
}
@ -607,17 +607,17 @@ ContourDesignControlProtocol::shuttle_event (int position)
if (position != 0) {
if (_shuttle_was_zero) {
_was_rolling_before_shuttle = transport_rolling ();
_was_rolling_before_shuttle = _controller.transport_rolling ();
}
const vector<double>& spds = _shuttle_speeds;
const double speed = position > 0 ? spds[position-1] : -spds[-position-1];
set_transport_speed (speed);
_controller.set_transport_speed (speed);
_shuttle_was_zero = false;
} else {
if (_keep_rolling && _was_rolling_before_shuttle) {
set_transport_speed (1.0);
_controller.set_transport_speed (1.0);
} else {
transport_stop ();
_controller.transport_stop ();
}
_shuttle_was_zero = true;
}

View file

@ -42,6 +42,7 @@ PBD::Signal2<void,std::string,std::string> BasicUI::AccessAction;
BasicUI::BasicUI (Session& s)
: _session (&s)
, _controller (&s)
{
}
@ -69,226 +70,6 @@ BasicUI::access_action ( std::string action_path )
AccessAction( group, item );
}
void
BasicUI::loop_toggle ()
{
if (!_session) {
return;
}
Location * looploc = _session->locations()->auto_loop_location();
if (!looploc) {
return;
}
if (_session->get_play_loop()) {
/* looping enabled, our job is to disable it */
_session->request_play_loop (false);
} else {
/* looping not enabled, our job is to enable it.
loop-is-NOT-mode: this action always starts the transport rolling.
loop-IS-mode: this action simply sets the loop play mechanism, but
does not start transport.
*/
if (Config->get_loop_is_mode()) {
_session->request_play_loop (true, false);
} else {
_session->request_play_loop (true, true);
}
}
//show the loop markers
looploc->set_hidden (false, this);
}
void
BasicUI::loop_location (samplepos_t start, samplepos_t end)
{
Location* tll;
if ((tll = _session->locations()->auto_loop_location()) == 0) {
Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
_session->locations()->add (loc, true);
_session->set_auto_loop_location (loc);
} else {
tll->set_hidden (false, this);
tll->set (start, end);
}
}
void
BasicUI::goto_start (bool and_roll)
{
_session->goto_start (and_roll);
}
void
BasicUI::goto_zero ()
{
_session->request_locate (0);
}
void
BasicUI::goto_end ()
{
_session->goto_end ();
}
void
BasicUI::add_marker (const std::string& markername)
{
samplepos_t where = _session->audible_sample();
Location *location = new Location (*_session, where, where, markername, Location::IsMark);
_session->begin_reversible_command (_("add marker"));
XMLNode &before = _session->locations()->get_state();
_session->locations()->add (location, true);
XMLNode &after = _session->locations()->get_state();
_session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
_session->commit_reversible_command ();
}
void
BasicUI::remove_marker_at_playhead ()
{
if (_session) {
//set up for undo
XMLNode &before = _session->locations()->get_state();
bool removed = false;
//find location(s) at this time
Locations::LocationList locs;
_session->locations()->find_all_between (_session->audible_sample(), _session->audible_sample()+1, locs, Location::Flags(0));
for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
if ((*i)->is_mark()) {
_session->locations()->remove (*i);
removed = true;
}
}
//store undo
if (removed) {
_session->begin_reversible_command (_("remove marker"));
XMLNode &after = _session->locations()->get_state();
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
_session->commit_reversible_command ();
}
}
}
void
BasicUI::button_varispeed (bool fwd)
{
// incrementally increase speed by semitones
// (keypress auto-repeat is 100ms)
const float maxspeed = Config->get_shuttle_max_speed();
float semitone_ratio = exp2f (1.0f/12.0f);
const float octave_down = pow (1.0/semitone_ratio, 12.0);
float transport_speed = get_transport_speed ();
float speed;
if (Config->get_rewind_ffwd_like_tape_decks()) {
if (fwd) {
if (transport_speed <= 0) {
_session->request_transport_speed (1.0, false);
_session->request_roll (TRS_UI);
return;
}
} else {
if (transport_speed >= 0) {
_session->request_transport_speed (-1.0, false);
_session->request_roll (TRS_UI);
return;
}
}
} else {
if (fabs (transport_speed) <= 0.1) {
/* close to zero, maybe flip direction */
if (fwd) {
if (transport_speed <= 0) {
_session->request_transport_speed (1.0, false);
_session->request_roll (TRS_UI);
}
} else {
if (transport_speed >= 0) {
_session->request_transport_speed (-1.0, false);
_session->request_roll (TRS_UI);
}
}
/* either we've just started, or we're moving as slowly as we
* ever should
*/
return;
}
if (fwd) {
if (transport_speed < 0.f) {
if (fabs (transport_speed) < octave_down) {
/* we need to move the speed back towards zero */
semitone_ratio = powf (1.f / semitone_ratio, 4.f);
} else {
semitone_ratio = 1.f / semitone_ratio;
}
} else {
if (fabs (transport_speed) < octave_down) {
/* moving very slowly, use 4 semitone steps */
semitone_ratio = powf (semitone_ratio, 4.f);
}
}
} else {
if (transport_speed > 0.f) {
/* we need to move the speed back towards zero */
if (transport_speed < octave_down) {
semitone_ratio = powf (1.f / semitone_ratio, 4.f);
} else {
semitone_ratio = 1.f / semitone_ratio;
}
} else {
if (fabs (transport_speed) < octave_down) {
/* moving very slowly, use 4 semitone steps */
semitone_ratio = powf (semitone_ratio, 4.f);
}
}
}
}
speed = semitone_ratio * transport_speed;
speed = std::max (-maxspeed, std::min (maxspeed, speed));
_session->request_transport_speed (speed, false);
_session->request_roll (TRS_UI);
}
void
BasicUI::rewind ()
{
button_varispeed (false);
}
void
BasicUI::ffwd ()
{
button_varispeed (true);
}
void
BasicUI::transport_stop ()
{
_session->request_stop ();
}
bool
BasicUI::stop_button_onoff () const
{
@ -298,19 +79,19 @@ BasicUI::stop_button_onoff () const
bool
BasicUI::play_button_onoff () const
{
return get_transport_speed() == 1.0;
return _controller.get_transport_speed() == 1.0;
}
bool
BasicUI::ffwd_button_onoff () const
{
return get_transport_speed() > 1.0;
return _controller.get_transport_speed() > 1.0;
}
bool
BasicUI::rewind_button_onoff () const
{
return get_transport_speed() < 0.0;
return _controller.get_transport_speed() < 0.0;
}
bool
@ -319,129 +100,6 @@ BasicUI::loop_button_onoff () const
return _session->get_play_loop();
}
void
BasicUI::transport_play (bool from_last_start)
{
/* ::toggle_roll() is smarter and preferred */
if (!_session) {
return;
}
if (_session->is_auditioning()) {
return;
}
bool rolling = transport_rolling();
if (_session->get_play_loop()) {
/* If loop playback is not a mode, then we should cancel
it when this action is requested. If it is a mode
we just leave it in place.
*/
if (!Config->get_loop_is_mode()) {
/* XXX it is not possible to just leave seamless loop and keep
playing at present (nov 4th 2009)
*/
if (rolling) {
/* stop loop playback but keep rolling */
_session->request_play_loop (false, false);
}
}
} else if (_session->get_play_range () ) {
/* stop playing a range if we currently are */
_session->request_play_range (0, true);
}
if (rolling) {
_session->request_transport_speed (1.0, false, TRS_UI);
} else {
_session->request_roll ();
}
}
void
BasicUI::rec_enable_toggle ()
{
switch (_session->record_status()) {
case (RecordState)Disabled:
if (_session->ntracks() == 0) {
// string txt = _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu.");
// MessageDialog msg (*editor, txt);
// msg.run ();
return;
}
_session->maybe_enable_record ();
break;
case (RecordState)Recording:
case (RecordState)Enabled:
_session->disable_record (false, true);
}
}
void
BasicUI::all_tracks_rec_in ()
{
_session->set_all_tracks_record_enabled (true);
}
void
BasicUI::all_tracks_rec_out ()
{
_session->set_all_tracks_record_enabled (false);
}
void
BasicUI::save_state ()
{
_session->save_state ("");
}
void
BasicUI::prev_marker ()
{
samplepos_t pos = _session->locations()->first_mark_before (_session->transport_sample());
if (pos >= 0) {
_session->request_locate (pos);
} else {
_session->goto_start ();
}
}
void
BasicUI::next_marker ()
{
samplepos_t pos = _session->locations()->first_mark_after (_session->transport_sample());
if (pos >= 0) {
_session->request_locate (pos);
} else {
_session->goto_end();
}
}
void
BasicUI::set_transport_speed (double speed)
{
_session->request_transport_speed (speed);
}
double
BasicUI::get_transport_speed () const
{
return _session->actual_speed ();
}
double
BasicUI::transport_rolling () const
{
return !_session->transport_stopped_or_stopping ();
}
void
BasicUI::undo ()
{
@ -454,227 +112,6 @@ BasicUI::redo ()
access_action ("Editor/redo");
}
void
BasicUI::toggle_all_rec_enables ()
{
if (_session->get_record_enabled()) {
// _session->record_disenable_all ();
} else {
// _session->record_enable_all ();
}
}
void
BasicUI::toggle_punch_in ()
{
_session->config.set_punch_in (!_session->config.get_punch_in());
}
void
BasicUI::toggle_punch_out ()
{
_session->config.set_punch_out (!_session->config.get_punch_out());
}
bool
BasicUI::get_record_enabled ()
{
return _session->get_record_enabled();
}
void
BasicUI::set_record_enable (bool yn)
{
if (yn) {
_session->maybe_enable_record ();
} else {
_session->disable_record (false, true);
}
}
samplepos_t
BasicUI::transport_sample ()
{
return _session->transport_sample();
}
void
BasicUI::locate (samplepos_t where, LocateTransportDisposition ltd)
{
_session->request_locate (where, ltd);
}
void
BasicUI::locate (samplepos_t where, bool roll)
{
_session->request_locate (where, roll ? MustRoll : RollIfAppropriate);
}
void
BasicUI::jump_by_seconds (double secs, LocateTransportDisposition ltd)
{
samplepos_t current = _session->transport_sample();
double s = (double) current / (double) _session->nominal_sample_rate();
s+= secs;
if (s < 0) {
s = 0;
}
s = s * _session->nominal_sample_rate();
_session->request_locate (floor(s), ltd);
}
void
BasicUI::jump_by_bars (double bars, LocateTransportDisposition ltd)
{
TempoMap& tmap (_session->tempo_map());
Timecode::BBT_Time bbt (tmap.bbt_at_sample (_session->transport_sample()));
bars += bbt.bars;
if (bars < 0) {
bars = 0;
}
AnyTime any;
any.type = AnyTime::BBT;
any.bbt.bars = bars;
_session->request_locate (_session->convert_to_samples (any), ltd);
}
void
BasicUI::jump_by_beats (double beats, LocateTransportDisposition ltd)
{
TempoMap& tmap (_session->tempo_map ());
double qn_goal = tmap.quarter_note_at_sample (_session->transport_sample ()) + beats;
if (qn_goal < 0.0) {
qn_goal = 0.0;
}
_session->request_locate (tmap.sample_at_quarter_note (qn_goal), ltd);
}
void
BasicUI::toggle_monitor_mute ()
{
if (_session->monitor_out()) {
boost::shared_ptr<MonitorProcessor> mon = _session->monitor_out()->monitor_control();
if (mon->cut_all ()) {
mon->set_cut_all (false);
} else {
mon->set_cut_all (true);
}
}
}
void
BasicUI::toggle_monitor_dim ()
{
if (_session->monitor_out()) {
boost::shared_ptr<MonitorProcessor> mon = _session->monitor_out()->monitor_control();
if (mon->dim_all ()) {
mon->set_dim_all (false);
} else {
mon->set_dim_all (true);
}
}
}
void
BasicUI::toggle_monitor_mono ()
{
if (_session->monitor_out()) {
boost::shared_ptr<MonitorProcessor> mon = _session->monitor_out()->monitor_control();
if (mon->mono()) {
mon->set_mono (false);
} else {
mon->set_mono (true);
}
}
}
void
BasicUI::midi_panic ()
{
_session->midi_panic ();
}
void
BasicUI::toggle_click ()
{
bool state = !Config->get_clicking();
Config->set_clicking (state);
}
void
BasicUI::toggle_roll (bool roll_out_of_bounded_mode)
{
/* TO BE KEPT IN SYNC WITH ARDOUR_UI::toggle_roll() */
if (!_session) {
return;
}
if (_session->is_auditioning()) {
_session->cancel_audition ();
return;
}
if (_session->config.get_external_sync()) {
switch (TransportMasterManager::instance().current()->type()) {
case Engine:
break;
default:
/* transport controlled by the master */
return;
}
}
bool rolling = transport_rolling();
if (rolling) {
if (roll_out_of_bounded_mode) {
/* drop out of loop/range playback but leave transport rolling */
if (_session->get_play_loop()) {
if (_session->actively_recording()) {
/* actually stop transport because
otherwise the captured data will make
no sense.
*/
_session->request_play_loop (false, true);
} else {
_session->request_play_loop (false, false);
}
} else if (_session->get_play_range ()) {
_session->request_cancel_play_range ();
}
} else {
_session->request_stop (true, true);
}
} else { /* not rolling */
if (_session->get_play_loop() && Config->get_loop_is_mode()) {
_session->request_locate (_session->locations()->auto_loop_location()->start(), MustRoll);
} else {
_session->request_roll (TRS_UI);
}
}
}
void
BasicUI::stop_forget ()
{
_session->request_stop (true, true);
}
void BasicUI::mark_in () { access_action("Common/start-range-from-playhead"); }
void BasicUI::mark_out () { access_action("Common/finish-range-from-playhead"); }
@ -708,62 +145,3 @@ void BasicUI::scroll_up_1_track() { access_action("Editor/step-tracks-up"); }
void BasicUI::scroll_dn_1_track() { access_action("Editor/step-tracks-down"); }
void BasicUI::scroll_up_1_page() { access_action("Editor/scroll-tracks-up"); }
void BasicUI::scroll_dn_1_page() { access_action("Editor/scroll-tracks-down"); }
bool
BasicUI::locating ()
{
return _session->locate_pending();
}
bool
BasicUI::locked ()
{
return _session->transport_locked ();
}
void
BasicUI::timecode_time (samplepos_t where, Timecode::Time& timecode)
{
_session->timecode_time (where, *((Timecode::Time *) &timecode));
}
void
BasicUI::cancel_all_solo ()
{
if (_session) {
_session->cancel_all_solo ();
}
}
struct SortLocationsByPosition {
bool operator() (Location* a, Location* b) {
return a->start() < b->start();
}
};
void
BasicUI::goto_nth_marker (int n)
{
if (!_session) {
return;
}
const Locations::LocationList& l (_session->locations()->list());
Locations::LocationList ordered;
ordered = l;
SortLocationsByPosition cmp;
ordered.sort (cmp);
for (Locations::LocationList::iterator i = ordered.begin(); n >= 0 && i != ordered.end(); ++i) {
if ((*i)->is_mark() && !(*i)->is_hidden() && !(*i)->is_session_range()) {
if (n == 0) {
_session->request_locate ((*i)->start());
break;
}
--n;
}
}
}

View file

@ -25,6 +25,7 @@
#include "ardour/presentation_info.h"
#include "ardour/types.h"
#include "control_protocol/session_controller.h"
#include "control_protocol/visibility.h"
#include "pbd/signals.h"
#include "temporal/time.h"
@ -41,75 +42,37 @@ class LIBCONTROLCP_API BasicUI {
BasicUI (Session&);
virtual ~BasicUI ();
void add_marker (const std::string& = std::string());
void remove_marker_at_playhead ();
void register_thread (std::string name);
/* transport control */
/* Access to GUI actions */
void access_action (std::string action_path);
void loop_toggle ();
void loop_location (samplepos_t start, samplepos_t end);
void access_action ( std::string action_path );
static PBD::Signal2<void,std::string,std::string> AccessAction;
void goto_zero ();
void goto_start (bool and_roll = false);
void goto_end ();
void button_varispeed (bool fwd);
void rewind ();
void ffwd ();
void transport_stop ();
void transport_play (bool jump_back = false);
void set_transport_speed (double speed);
double get_transport_speed () const;
double transport_rolling () const;
/* Undo/Redo */
void jump_by_seconds (double sec, LocateTransportDisposition ltd = RollIfAppropriate);
void jump_by_bars (double bars, LocateTransportDisposition ltd = RollIfAppropriate);
void jump_by_beats (double beats, LocateTransportDisposition ltd = RollIfAppropriate);
samplepos_t transport_sample ();
void locate (samplepos_t sample, LocateTransportDisposition ltd);
void locate (samplepos_t sample, bool);
bool locating ();
bool locked ();
void save_state ();
void prev_marker ();
void next_marker ();
void undo ();
void redo ();
void toggle_punch_in ();
void toggle_punch_out ();
/* Convenience methods that fire actions */
void mark_in();
void mark_out();
void toggle_click();
void midi_panic();
void toggle_monitor_mute();
void toggle_monitor_dim();
void toggle_monitor_mono();
void cancel_all_solo ();
void quick_snapshot_stay ();
void quick_snapshot_switch ();
void toggle_roll(bool roll_out_of_bounded_mode=true); //this provides the same operation as the "spacebar", it's a lot smarter than "play".
void stop_forget();
void set_punch_range();
void set_loop_range();
void set_session_range();
void set_record_enable (bool yn);
bool get_record_enabled ();
/* Editor Visibility
We need to explicitly bake in the "arguments" here, because GUI actions
don't have arguments.
*/
//editor visibility stuff (why do we have to make explicit numbers here? because "gui actions" don't accept args
void fit_1_track();
void fit_2_tracks();
void fit_4_tracks();
@ -133,15 +96,7 @@ class LIBCONTROLCP_API BasicUI {
void scroll_up_1_page();
void scroll_dn_1_page();
void rec_enable_toggle ();
void toggle_all_rec_enables ();
void all_tracks_rec_in ();
void all_tracks_rec_out ();
void goto_nth_marker (int n);
void timecode_time (samplepos_t where, Timecode::Time&);
/* Button state */
bool stop_button_onoff() const;
bool play_button_onoff() const;
@ -149,8 +104,11 @@ class LIBCONTROLCP_API BasicUI {
bool rewind_button_onoff() const;
bool loop_button_onoff() const;
SessionController& controller() { return _controller; }
protected:
Session* _session;
SessionController _controller;
};
} // namespace ARDOUR

View file

@ -0,0 +1,141 @@
/*
* Copyright (C) 2006-2021 David Robillard <d@drobilla.net>
* Copyright (C) 2007-2017 Paul Davis <paul@linuxaudiosystems.com>
* Copyright (C) 2010 Carl Hetherington <carl@carlh.net>
* Copyright (C) 2015 Robin Gareus <robin@gareus.org>
* Copyright (C) 2016 Ben Loftis <ben@harrisonconsoles.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_session_controller_h__
#define __ardour_session_controller_h__
#include "ardour/types.h"
#include "control_protocol/visibility.h"
#include "temporal/time.h"
#include <cstdint>
#include <string>
namespace ARDOUR {
class Session;
/** A controller for a session used by UIs and control surfaces.
*
* This implements operations that manipulate a session which are common to any
* kind of UI. Application logic that isn't specific to any particular UI
* should go here and be reused, so UIs do things consistently and correctly.
*
* This only interacts with Session (and the objects it contains) directly, not
* with any UI facilities like actions or event loops.
*/
class LIBCONTROLCP_API SessionController
{
public:
SessionController (Session* s)
: _session (s)
{}
/* Transport Control */
void loop_toggle ();
void loop_location (samplepos_t start, samplepos_t end);
void button_varispeed (bool fwd);
void rewind ();
void ffwd ();
void transport_stop ();
void transport_play (bool jump_back = false);
void set_transport_speed (double speed);
void toggle_roll (bool roll_out_of_bounded_mode = true);
void stop_forget ();
double get_transport_speed () const;
bool transport_rolling () const;
samplepos_t transport_sample () const;
/* Markers */
void add_marker (const std::string& = std::string ());
void remove_marker_at_playhead ();
/* Locating */
void goto_zero ();
void goto_start (bool and_roll = false);
void goto_end ();
void goto_nth_marker (int n);
void jump_by_seconds (double sec,
LocateTransportDisposition ltd = RollIfAppropriate);
void jump_by_bars (double bars,
LocateTransportDisposition ltd = RollIfAppropriate);
void jump_by_beats (double beats,
LocateTransportDisposition ltd = RollIfAppropriate);
void locate (samplepos_t sample, LocateTransportDisposition ltd);
void locate (samplepos_t sample, bool);
void prev_marker ();
void next_marker ();
bool locating () const;
bool locked () const;
/* State */
void save_state ();
/* Monitoring */
void toggle_click ();
void midi_panic ();
void toggle_monitor_mute ();
void toggle_monitor_dim ();
void toggle_monitor_mono ();
void cancel_all_solo ();
/* Recording */
void toggle_punch_in ();
void toggle_punch_out ();
void set_record_enable (bool yn);
void rec_enable_toggle ();
void toggle_all_rec_enables ();
void all_tracks_rec_in ();
void all_tracks_rec_out ();
bool get_record_enabled () const;
/* Time */
void timecode_time (samplepos_t where, Timecode::Time&);
private:
Session* _session;
};
} // namespace ARDOUR
#endif /* __ardour_session_controller_h__ */

View file

@ -0,0 +1,685 @@
/*
* Copyright (C) 2006-2021 David Robillard <d@drobilla.net>
* Copyright (C) 2006-2018 Paul Davis <paul@linuxaudiosystems.com>
* Copyright (C) 2009-2010 Carl Hetherington <carl@carlh.net>
* Copyright (C) 2015 Robin Gareus <robin@gareus.org>
* Copyright (C) 2016-2017 Ben Loftis <ben@harrisonconsoles.com>
* Copyright (C) 2017-2019 Johannes Mueller <github@johannes-mueller.org>
* Copyright (C) 2017 Len Ovens <len@ovenwerks.net>
* Copyright (C) 2017 Tim Mayberry <mojofunk@gmail.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.
*/
#include "control_protocol/session_controller.h"
#include "ardour/location.h"
#include "ardour/session.h"
#include "ardour/tempo.h"
#include "ardour/transport_master_manager.h"
#include "ardour/utils.h"
#include "pbd/i18n.h"
#include "pbd/memento_command.h"
using namespace ARDOUR;
/* Transport Control */
void
SessionController::loop_toggle ()
{
if (!_session) {
return;
}
Location* looploc = _session->locations ()->auto_loop_location ();
if (!looploc) {
return;
}
if (_session->get_play_loop ()) {
/* looping enabled, our job is to disable it */
_session->request_play_loop (false);
} else {
/* looping not enabled, our job is to enable it.
loop-is-NOT-mode: this action always starts the transport rolling.
loop-IS-mode: this action simply sets the loop play mechanism,
but does not start transport.
*/
if (Config->get_loop_is_mode ()) {
_session->request_play_loop (true, false);
} else {
_session->request_play_loop (true, true);
}
}
// show the loop markers
looploc->set_hidden (false, this);
}
void
SessionController::loop_location (samplepos_t start, samplepos_t end)
{
Location* const tll = _session->locations ()->auto_loop_location ();
if (!tll) {
Location* loc = new Location (
*_session, start, end, _ ("Loop"), Location::IsAutoLoop);
_session->locations ()->add (loc, true);
_session->set_auto_loop_location (loc);
} else {
tll->set_hidden (false, this);
tll->set (start, end);
}
}
void
SessionController::button_varispeed (bool fwd)
{
// incrementally increase speed by semitones
// (keypress auto-repeat is 100ms)
const float maxspeed = Config->get_shuttle_max_speed ();
float semitone_ratio = exp2f (1.0f / 12.0f);
const float octave_down = pow (1.0 / semitone_ratio, 12.0);
float transport_speed = get_transport_speed ();
float speed;
if (Config->get_rewind_ffwd_like_tape_decks ()) {
if (fwd) {
if (transport_speed <= 0) {
_session->request_transport_speed (1.0, false);
_session->request_roll (TRS_UI);
return;
}
} else {
if (transport_speed >= 0) {
_session->request_transport_speed (-1.0, false);
_session->request_roll (TRS_UI);
return;
}
}
} else {
if (fabs (transport_speed) <= 0.1) {
/* close to zero, maybe flip direction */
if (fwd) {
if (transport_speed <= 0) {
_session->request_transport_speed (1.0, false);
_session->request_roll (TRS_UI);
}
} else {
if (transport_speed >= 0) {
_session->request_transport_speed (-1.0, false);
_session->request_roll (TRS_UI);
}
}
/* either we've just started, or we're moving as slowly as we
* ever should
*/
return;
}
if (fwd) {
if (transport_speed < 0.f) {
if (fabs (transport_speed) < octave_down) {
/* we need to move the speed back towards zero */
semitone_ratio = powf (1.f / semitone_ratio, 4.f);
} else {
semitone_ratio = 1.f / semitone_ratio;
}
} else {
if (fabs (transport_speed) < octave_down) {
/* moving very slowly, use 4 semitone steps */
semitone_ratio = powf (semitone_ratio, 4.f);
}
}
} else {
if (transport_speed > 0.f) {
/* we need to move the speed back towards zero */
if (transport_speed < octave_down) {
semitone_ratio = powf (1.f / semitone_ratio, 4.f);
} else {
semitone_ratio = 1.f / semitone_ratio;
}
} else {
if (fabs (transport_speed) < octave_down) {
/* moving very slowly, use 4 semitone steps */
semitone_ratio = powf (semitone_ratio, 4.f);
}
}
}
}
speed = semitone_ratio * transport_speed;
speed = std::max (-maxspeed, std::min (maxspeed, speed));
_session->request_transport_speed (speed, false);
_session->request_roll (TRS_UI);
}
void
SessionController::rewind ()
{
button_varispeed (false);
}
void
SessionController::ffwd ()
{
button_varispeed (true);
}
void
SessionController::transport_stop ()
{
_session->request_stop ();
}
void
SessionController::transport_play (bool from_last_start)
{
/* ::toggle_roll() is smarter and preferred */
if (!_session) {
return;
}
if (_session->is_auditioning ()) {
return;
}
bool rolling = transport_rolling ();
if (_session->get_play_loop ()) {
/* If loop playback is not a mode, then we should cancel
it when this action is requested. If it is a mode
we just leave it in place.
*/
if (!Config->get_loop_is_mode ()) {
/* XXX it is not possible to just leave seamless loop and keep
playing at present (nov 4th 2009)
*/
if (rolling) {
/* stop loop playback but keep rolling */
_session->request_play_loop (false, false);
}
}
} else if (_session->get_play_range ()) {
/* stop playing a range if we currently are */
_session->request_play_range (0, true);
}
if (rolling) {
_session->request_transport_speed (1.0, false, TRS_UI);
} else {
_session->request_roll ();
}
}
void
SessionController::set_transport_speed (double speed)
{
_session->request_transport_speed (speed);
}
void
SessionController::toggle_roll (bool roll_out_of_bounded_mode)
{
/* TO BE KEPT IN SYNC WITH ARDOUR_UI::toggle_roll() */
if (!_session) {
return;
}
if (_session->is_auditioning ()) {
_session->cancel_audition ();
return;
}
if (_session->config.get_external_sync ()) {
switch (TransportMasterManager::instance ().current ()->type ()) {
case Engine:
break;
default:
/* transport controlled by the master */
return;
}
}
bool rolling = transport_rolling ();
if (rolling) {
if (roll_out_of_bounded_mode) {
/* drop out of loop/range playback but leave transport rolling */
if (_session->get_play_loop ()) {
if (_session->actively_recording ()) {
/* actually stop transport because
otherwise the captured data will make
no sense.
*/
_session->request_play_loop (false, true);
} else {
_session->request_play_loop (false, false);
}
} else if (_session->get_play_range ()) {
_session->request_cancel_play_range ();
}
} else {
_session->request_stop (true, true);
}
} else { /* not rolling */
if (_session->get_play_loop () && Config->get_loop_is_mode ()) {
_session->request_locate (
_session->locations ()->auto_loop_location ()->start (),
MustRoll);
} else {
_session->request_roll (TRS_UI);
}
}
}
void
SessionController::stop_forget ()
{
_session->request_stop (true, true);
}
double
SessionController::get_transport_speed () const
{
return _session->actual_speed ();
}
bool
SessionController::transport_rolling () const
{
return !_session->transport_stopped_or_stopping ();
}
samplepos_t
SessionController::transport_sample () const
{
return _session->transport_sample ();
}
/* Markers */
void
SessionController::add_marker (const std::string& markername)
{
const samplepos_t where = _session->audible_sample ();
Location* location =
new Location (*_session, where, where, markername, Location::IsMark);
_session->begin_reversible_command (_ ("add marker"));
XMLNode& before = _session->locations ()->get_state ();
_session->locations ()->add (location, true);
XMLNode& after = _session->locations ()->get_state ();
_session->add_command (new MementoCommand<Locations> (
*(_session->locations ()), &before, &after));
_session->commit_reversible_command ();
}
void
SessionController::remove_marker_at_playhead ()
{
if (_session) {
// set up for undo
XMLNode& before = _session->locations ()->get_state ();
bool removed = false;
// find location(s) at this time
Locations::LocationList locs;
_session->locations ()->find_all_between (_session->audible_sample (),
_session->audible_sample () +
1,
locs,
Location::Flags (0));
for (Locations::LocationList::iterator i = locs.begin ();
i != locs.end ();
++i) {
if ((*i)->is_mark ()) {
_session->locations ()->remove (*i);
removed = true;
}
}
// store undo
if (removed) {
_session->begin_reversible_command (_ ("remove marker"));
XMLNode& after = _session->locations ()->get_state ();
_session->add_command (new MementoCommand<Locations> (
*(_session->locations ()), &before, &after));
_session->commit_reversible_command ();
}
}
}
/* Locating */
void
SessionController::goto_zero ()
{
_session->request_locate (0);
}
void
SessionController::goto_start (bool and_roll)
{
_session->goto_start (and_roll);
}
void
SessionController::goto_end ()
{
_session->goto_end ();
}
struct SortLocationsByPosition {
bool operator() (Location* a, Location* b)
{
return a->start () < b->start ();
}
};
void
SessionController::goto_nth_marker (int n)
{
if (!_session) {
return;
}
const Locations::LocationList& l (_session->locations ()->list ());
Locations::LocationList ordered;
ordered = l;
SortLocationsByPosition cmp;
ordered.sort (cmp);
for (Locations::LocationList::iterator i = ordered.begin ();
n >= 0 && i != ordered.end ();
++i) {
if ((*i)->is_mark () && !(*i)->is_hidden () &&
!(*i)->is_session_range ()) {
if (n == 0) {
_session->request_locate ((*i)->start ());
break;
}
--n;
}
}
}
void
SessionController::jump_by_seconds (double secs, LocateTransportDisposition ltd)
{
samplepos_t current = _session->transport_sample ();
double s = (double)current / (double)_session->nominal_sample_rate ();
s += secs;
if (s < 0) {
s = 0;
}
s = s * _session->nominal_sample_rate ();
_session->request_locate (floor (s), ltd);
}
void
SessionController::jump_by_bars (double bars, LocateTransportDisposition ltd)
{
TempoMap& tmap (_session->tempo_map ());
Timecode::BBT_Time bbt (tmap.bbt_at_sample (_session->transport_sample ()));
bars += bbt.bars;
if (bars < 0) {
bars = 0;
}
AnyTime any;
any.type = AnyTime::BBT;
any.bbt.bars = bars;
_session->request_locate (_session->convert_to_samples (any), ltd);
}
void
SessionController::jump_by_beats (double beats, LocateTransportDisposition ltd)
{
TempoMap& tmap (_session->tempo_map ());
double qn_goal =
tmap.quarter_note_at_sample (_session->transport_sample ()) + beats;
if (qn_goal < 0.0) {
qn_goal = 0.0;
}
_session->request_locate (tmap.sample_at_quarter_note (qn_goal), ltd);
}
void
SessionController::locate (samplepos_t where, LocateTransportDisposition ltd)
{
_session->request_locate (where, ltd);
}
void
SessionController::locate (samplepos_t where, bool roll)
{
_session->request_locate (where, roll ? MustRoll : RollIfAppropriate);
}
void
SessionController::prev_marker ()
{
samplepos_t pos =
_session->locations ()->first_mark_before (_session->transport_sample ());
if (pos >= 0) {
_session->request_locate (pos);
} else {
_session->goto_start ();
}
}
void
SessionController::next_marker ()
{
samplepos_t pos =
_session->locations ()->first_mark_after (_session->transport_sample ());
if (pos >= 0) {
_session->request_locate (pos);
} else {
_session->goto_end ();
}
}
bool
SessionController::locating () const
{
return _session->locate_pending ();
}
bool
SessionController::locked () const
{
return _session->transport_locked ();
}
/* State */
void
SessionController::save_state ()
{
_session->save_state ("");
}
/* Monitoring */
void
SessionController::toggle_click ()
{
bool state = !Config->get_clicking ();
Config->set_clicking (state);
}
void
SessionController::midi_panic ()
{
_session->midi_panic ();
}
void
SessionController::toggle_monitor_mute ()
{
if (_session->monitor_out ()) {
boost::shared_ptr<MonitorProcessor> mon =
_session->monitor_out ()->monitor_control ();
if (mon->cut_all ()) {
mon->set_cut_all (false);
} else {
mon->set_cut_all (true);
}
}
}
void
SessionController::toggle_monitor_dim ()
{
if (_session->monitor_out ()) {
boost::shared_ptr<MonitorProcessor> mon =
_session->monitor_out ()->monitor_control ();
if (mon->dim_all ()) {
mon->set_dim_all (false);
} else {
mon->set_dim_all (true);
}
}
}
void
SessionController::toggle_monitor_mono ()
{
if (_session->monitor_out ()) {
boost::shared_ptr<MonitorProcessor> mon =
_session->monitor_out ()->monitor_control ();
if (mon->mono ()) {
mon->set_mono (false);
} else {
mon->set_mono (true);
}
}
}
void
SessionController::cancel_all_solo ()
{
if (_session) {
_session->cancel_all_solo ();
}
}
/* Recording */
void
SessionController::toggle_punch_in ()
{
_session->config.set_punch_in (!_session->config.get_punch_in ());
}
void
SessionController::toggle_punch_out ()
{
_session->config.set_punch_out (!_session->config.get_punch_out ());
}
void
SessionController::set_record_enable (bool yn)
{
if (yn) {
_session->maybe_enable_record ();
} else {
_session->disable_record (false, true);
}
}
void
SessionController::rec_enable_toggle ()
{
switch (_session->record_status ()) {
case (RecordState)Disabled:
if (_session->ntracks () > 0) {
_session->maybe_enable_record ();
}
break;
case (RecordState)Recording:
case (RecordState)Enabled:
_session->disable_record (false, true);
}
}
void
SessionController::toggle_all_rec_enables ()
{
if (_session->get_record_enabled ()) {
// _session->record_disenable_all ();
} else {
// _session->record_enable_all ();
}
}
void
SessionController::all_tracks_rec_in ()
{
_session->set_all_tracks_record_enabled (true);
}
void
SessionController::all_tracks_rec_out ()
{
_session->set_all_tracks_record_enabled (false);
}
bool
SessionController::get_record_enabled () const
{
return _session->get_record_enabled ();
}
/* Time */
void
SessionController::timecode_time (samplepos_t where, Timecode::Time& timecode)
{
_session->timecode_time (where, *((Timecode::Time*)&timecode));
}

View file

@ -10,6 +10,7 @@ controlcp_sources = [
'basic_ui.cc',
'control_protocol.cc',
'midi_byte_array.cc',
'session_controller.cc',
]
def options(opt):

View file

@ -159,30 +159,30 @@ FaderPort::FaderPort (Session& s)
get_button (FP_Touch).set_action (boost::bind (&FaderPort::off, this), false, LongPress);
get_button (FP_Off).set_action (boost::bind (&FaderPort::off, this), true);
get_button (Play).set_action (boost::bind (&BasicUI::transport_play, this, true), true);
get_button (RecEnable).set_action (boost::bind (&BasicUI::rec_enable_toggle, this), true);
get_button (Play).set_action (boost::bind (&SessionController::transport_play, _controller, true), true);
get_button (RecEnable).set_action (boost::bind (&SessionController::rec_enable_toggle, _controller), true);
/* Stop is a modifier, so we have to use its own button state to get
the default action (since StopDown will be set when looking for the
action to invoke.
*/
get_button (Stop).set_action (boost::bind (&BasicUI::transport_stop, this), true, StopDown);
get_button (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true);
get_button (Stop).set_action (boost::bind (&SessionController::transport_stop, _controller), true, StopDown);
get_button (Ffwd).set_action (boost::bind (&SessionController::ffwd, _controller), true);
/* See comments about Stop above .. */
get_button (Rewind).set_action (boost::bind (&BasicUI::rewind, this), true, RewindDown);
get_button (Rewind).set_action (boost::bind (&BasicUI::goto_zero, this), true, ButtonState (RewindDown|StopDown));
get_button (Rewind).set_action (boost::bind (&BasicUI::goto_start, this, false), true, ButtonState (RewindDown|ShiftDown));
get_button (Rewind).set_action (boost::bind (&SessionController::rewind, _controller), true, RewindDown);
get_button (Rewind).set_action (boost::bind (&SessionController::goto_zero, _controller), true, ButtonState (RewindDown|StopDown));
get_button (Rewind).set_action (boost::bind (&SessionController::goto_start, _controller, false), true, ButtonState (RewindDown|ShiftDown));
get_button (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true);
get_button (Ffwd).set_action (boost::bind (&BasicUI::goto_end, this), true, ShiftDown);
get_button (Ffwd).set_action (boost::bind (&SessionController::ffwd, _controller), true);
get_button (Ffwd).set_action (boost::bind (&SessionController::goto_end, _controller), true, ShiftDown);
get_button (Punch).set_action (boost::bind (&FaderPort::punch, this), true);
get_button (Loop).set_action (boost::bind (&BasicUI::loop_toggle, this), true);
get_button (Loop).set_action (boost::bind (&BasicUI::add_marker, this, string()), true, ShiftDown);
get_button (Loop).set_action (boost::bind (&SessionController::loop_toggle, _controller), true);
get_button (Loop).set_action (boost::bind (&SessionController::add_marker, _controller, string()), true, ShiftDown);
get_button (Punch).set_action (boost::bind (&BasicUI::prev_marker, this), true, ShiftDown);
get_button (User).set_action (boost::bind (&BasicUI::next_marker, this), true, ShiftDown);
get_button (Punch).set_action (boost::bind (&SessionController::prev_marker, _controller), true, ShiftDown);
get_button (User).set_action (boost::bind (&SessionController::next_marker, _controller), true, ShiftDown);
get_button (Mute).set_action (boost::bind (&FaderPort::mute, this), true);
get_button (Solo).set_action (boost::bind (&FaderPort::solo, this), true);
@ -686,7 +686,7 @@ FaderPort::map_transport_state ()
{
get_button (Loop).set_led_state (_output_port, _session->get_play_loop());
float ts = get_transport_speed();
float ts = _controller.get_transport_speed();
if (ts == 0) {
stop_blinking (Play);

View file

@ -135,22 +135,22 @@ FaderPort8::setup_actions ()
void
FaderPort8::button_play ()
{
if (transport_rolling ()) {
if (get_transport_speed() != 1.0) {
if (_controller.transport_rolling ()) {
if (_controller.get_transport_speed() != 1.0) {
_session->request_roll (TRS_UI);
} else {
transport_stop ();
_controller.transport_stop ();
}
} else {
transport_play ();
_controller.transport_play ();
}
}
void
FaderPort8::button_stop ()
{
if (transport_rolling ()) {
transport_stop ();
if (_controller.transport_rolling ()) {
_controller.transport_stop ();
} else {
AccessAction ("Transport", "GotoStart");
}
@ -159,13 +159,13 @@ FaderPort8::button_stop ()
void
FaderPort8::button_record ()
{
set_record_enable (!get_record_enabled ());
_controller.set_record_enable (!_controller.get_record_enabled ());
}
void
FaderPort8::button_loop ()
{
loop_toggle ();
_controller.loop_toggle ();
}
void
@ -313,7 +313,7 @@ FaderPort8::button_varispeed (bool ffw)
return;
}
BasicUI::button_varispeed (ffw);
_controller.button_varispeed (ffw);
}
#ifdef FP8_MUTESOLO_UNDO
@ -336,7 +336,7 @@ FaderPort8::button_solo_clear ()
_solo_state.push_back (boost::weak_ptr<AutomationControl>(sc));
}
}
cancel_all_solo (); // AccessAction ("Main", "cancel-solo");
_controller.cancel_all_solo (); // AccessAction ("Main", "cancel-solo");
} else {
/* restore solo */
boost::shared_ptr<ControlList> cl (new ControlList);
@ -384,7 +384,7 @@ FaderPort8::button_mute_clear ()
void
FaderPort8::button_arm_all ()
{
BasicUI::all_tracks_rec_in ();
_controller.all_tracks_rec_in ();
}
/* access generic action */
@ -513,9 +513,9 @@ FaderPort8::button_prev_next (bool next)
break;
case NavMarker:
if (next) {
next_marker ();
_controller.next_marker ();
} else {
prev_marker ();
_controller.prev_marker ();
}
break;
}
@ -576,7 +576,7 @@ FaderPort8::button_encoder ()
}
_session->locations()->next_available_name (markername,"mark");
add_marker (markername);
_controller.add_marker (markername);
}
break;
}

View file

@ -125,11 +125,11 @@ FaderPort8::notify_parameter_changed (std::string param)
void
FaderPort8::notify_transport_state_changed ()
{
_ctrls.button (FP8Controls::BtnPlay).set_active (get_transport_speed()==1.0);
_ctrls.button (FP8Controls::BtnStop).set_active (get_transport_speed()==0.0);
_ctrls.button (FP8Controls::BtnPlay).set_active (_controller.get_transport_speed()==1.0);
_ctrls.button (FP8Controls::BtnStop).set_active (_controller.get_transport_speed()==0.0);
/* set rewind/fastforward lights */
const float ts = get_transport_speed();
const float ts = _controller.get_transport_speed();
FP8ButtonInterface& b_rew = _ctrls.button (FP8Controls::BtnRewind);
FP8ButtonInterface& b_ffw = _ctrls.button (FP8Controls::BtnFastForward);

View file

@ -119,17 +119,17 @@ MIDIFunction::execute ()
break;
case TransportStop:
_ui->transport_stop ();
_ui->controller().transport_stop ();
DEBUG_TRACE (DEBUG::GenericMidi, "Function: transport_stop\n");
break;
case TransportRoll:
_ui->transport_play ();
_ui->controller().transport_play ();
DEBUG_TRACE (DEBUG::GenericMidi, "Function: transport_play\n");
break;
case TransportStart:
_ui->goto_start ();
_ui->controller().goto_start ();
DEBUG_TRACE (DEBUG::GenericMidi, "Function: goto_start\n");
break;
@ -139,27 +139,27 @@ MIDIFunction::execute ()
break;
case TransportEnd:
_ui->goto_end ();
_ui->controller().goto_end ();
DEBUG_TRACE (DEBUG::GenericMidi, "Function: goto_end\n");
break;
case TransportLoopToggle:
_ui->loop_toggle ();
_ui->controller().loop_toggle ();
DEBUG_TRACE (DEBUG::GenericMidi, "Function: loop_toggle\n");
break;
case TransportRecordToggle:
_ui->rec_enable_toggle ();
_ui->controller().rec_enable_toggle ();
DEBUG_TRACE (DEBUG::GenericMidi, "Function: toggle_record_enable\n");
break;
case TransportRecordEnable:
_ui->set_record_enable (true);
_ui->controller().set_record_enable (true);
DEBUG_TRACE (DEBUG::GenericMidi, "Function: set_record_enable = true\n");
break;
case TransportRecordDisable:
_ui->set_record_enable (false);
_ui->controller().set_record_enable (false);
DEBUG_TRACE (DEBUG::GenericMidi, "Function: set_record_enable = false\n");
break;
@ -168,7 +168,7 @@ MIDIFunction::execute ()
uint32_t rid;
sscanf (_argument.c_str(), "%d", &rid);
// XX fix me ... need to get stripable, not RID
//_ui->toggle_selection (rid, ARDOUR::PresentationInfo::Flag (ARDOUR::PresentationInfo::Route|ARDOUR::PresentationInfo::VCA));
//_ui->controller().toggle_selection (rid, ARDOUR::PresentationInfo::Flag (ARDOUR::PresentationInfo::Route|ARDOUR::PresentationInfo::VCA));
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Function: SetRouteSelection = %1\n", rid));
}
break;

View file

@ -1030,7 +1030,7 @@ LaunchControlXL::button_solo()
void
LaunchControlXL::button_solo_long_press()
{
cancel_all_solo();
_controller.cancel_all_solo();
}
void

View file

@ -73,9 +73,9 @@ void JogWheel::jog_event (float delta)
break;
default:
if (delta > 0) {
_mcp.button_varispeed (true);
_mcp.controller ().button_varispeed (true);
} else if (delta < 0) {
_mcp.button_varispeed (false);
_mcp.controller ().button_varispeed (false);
}
break;
}

View file

@ -370,7 +370,7 @@ LedState
MackieControlProtocol::undo_press (Button&)
{
if (main_modifier_state() == MODIFIER_SHIFT) {
redo();
redo ();
} else {
undo ();
}
@ -387,7 +387,7 @@ LedState
MackieControlProtocol::drop_press (Button &)
{
if (main_modifier_state() == MODIFIER_SHIFT) {
toggle_punch_in();
_controller.toggle_punch_in();
return none;
} else {
access_action ("Common/start-range-from-playhead");
@ -407,7 +407,7 @@ MackieControlProtocol::save_press (Button &)
if (main_modifier_state() == MODIFIER_SHIFT) {
quick_snapshot_switch();
} else {
save_state ();
_controller.save_state ();
}
return none;
@ -490,7 +490,7 @@ MackieControlProtocol::marker_release (Button &)
}
_session->locations()->next_available_name (markername,"mark");
add_marker (markername);
_controller.add_marker (markername);
return off;
}
@ -502,7 +502,7 @@ MackieControlProtocol::marker_release (Button &)
LedState
MackieControlProtocol::stop_press (Button &)
{
transport_stop ();
_controller.transport_stop ();
if (main_modifier_state() == MODIFIER_SHIFT) {
_session->midi_panic();
@ -524,7 +524,7 @@ MackieControlProtocol::play_press (Button &)
again, jump back to where we started last time
*/
transport_play (get_transport_speed() == 1.0);
_controller.transport_play (_controller.get_transport_speed() == 1.0);
return none;
}
@ -537,7 +537,7 @@ MackieControlProtocol::play_release (Button &)
LedState
MackieControlProtocol::record_press (Button &)
{
rec_enable_toggle ();
_controller.rec_enable_toggle ();
return none;
}
@ -551,13 +551,13 @@ LedState
MackieControlProtocol::rewind_press (Button &)
{
if (modifier_state() & MODIFIER_MARKER) {
prev_marker ();
_controller.prev_marker ();
} else if (modifier_state() & MODIFIER_NUDGE) {
access_action ("Common/nudge-playhead-backward");
} else if (main_modifier_state() & MODIFIER_SHIFT) {
goto_start ();
_controller.goto_start ();
} else {
rewind ();
_controller.rewind ();
}
return none;
}
@ -572,13 +572,13 @@ LedState
MackieControlProtocol::ffwd_press (Button &)
{
if (modifier_state() & MODIFIER_MARKER) {
next_marker ();
_controller.next_marker ();
} else if (modifier_state() & MODIFIER_NUDGE) {
access_action ("Common/nudge-playhead-forward");
} else if (main_modifier_state() & MODIFIER_SHIFT) {
goto_end();
_controller.goto_end();
} else {
ffwd ();
_controller.ffwd ();
}
return none;
}
@ -597,7 +597,7 @@ MackieControlProtocol::loop_press (Button &)
return off;
} else {
bool was_on = _session->get_play_loop();
loop_toggle ();
_controller.loop_toggle ();
return was_on ? off : on;
}
}
@ -837,7 +837,7 @@ MackieControlProtocol::cancel_release (Button &)
LedState
MackieControlProtocol::user_a_press (Button &)
{
transport_play (get_transport_speed() == 1.0);
_controller.transport_play (_controller.get_transport_speed() == 1.0);
return off;
}
LedState
@ -848,7 +848,7 @@ MackieControlProtocol::user_a_release (Button &)
LedState
MackieControlProtocol::user_b_press (Button &)
{
transport_stop();
_controller.transport_stop();
return off;
}
LedState
@ -920,7 +920,7 @@ MackieControlProtocol::clearsolo_press (Mackie::Button&)
return none;
}
cancel_all_solo ();
_controller.cancel_all_solo ();
return none;
}
@ -1109,7 +1109,7 @@ Mackie::LedState
MackieControlProtocol::replace_press (Mackie::Button&)
{
if (main_modifier_state() == MODIFIER_SHIFT) {
toggle_punch_out();
_controller.toggle_punch_out();
return none;
} else {
access_action ("Common/finish-range-from-playhead");

View file

@ -1231,7 +1231,7 @@ Strip::notify_metering_state_changed()
return;
}
bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
bool transport_is_rolling = (_surface->mcp().controller().get_transport_speed () != 0.0f);
bool metering_active = _surface->mcp().metering_active ();
if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {

View file

@ -127,7 +127,7 @@ Maschine2::notify_record_state_changed ()
void
Maschine2::notify_transport_state_changed ()
{
if (transport_rolling ()) {
if (_controller.transport_rolling ()) {
_ctrl->button (M2Contols::Play)->set_color (COLOR_WHITE);
} else {
_ctrl->button (M2Contols::Play)->set_color (0);
@ -198,23 +198,23 @@ Maschine2::notify_history_changed ()
void
Maschine2::button_play ()
{
if (transport_rolling ()) {
transport_stop ();
if (_controller.transport_rolling ()) {
_controller.transport_stop ();
} else {
transport_play ();
_controller.transport_play ();
}
}
void
Maschine2::button_record ()
{
set_record_enable (!get_record_enabled ());
_controller.set_record_enable (!_controller.get_record_enabled ());
}
void
Maschine2::button_loop ()
{
loop_toggle ();
_controller.loop_toggle ();
}
void
@ -226,7 +226,7 @@ Maschine2::button_metronom ()
void
Maschine2::button_rewind ()
{
goto_start (transport_rolling ());
_controller.goto_start (_controller.transport_rolling ());
}
void

View file

@ -1279,7 +1279,7 @@ OSC::osc_toggle_roll (bool ret2strt)
return 0;
}
bool rolling = transport_rolling();
bool rolling = _controller.transport_rolling();
if (rolling) {
_session->request_stop (ret2strt, true);
@ -2915,7 +2915,7 @@ void
OSC::transport_speed (lo_message msg)
{
check_surface (msg);
double ts = get_transport_speed();
double ts = _controller.get_transport_speed();
lo_message reply = lo_message_new ();
lo_message_add_double (reply, ts);
@ -2994,7 +2994,7 @@ OSC::jog (float delta, lo_message msg)
{
case 0:
if (delta) {
jump_by_seconds (delta / 5);
_controller.jump_by_seconds (delta / 5);
}
break;
case 1:
@ -3009,17 +3009,17 @@ OSC::jog (float delta, lo_message msg)
break;
case 3:
if (delta) {
double speed = get_transport_speed ();
set_transport_speed (speed + (delta / 8.1));
double speed = _controller.get_transport_speed ();
_controller.set_transport_speed (speed + (delta / 8.1));
} else {
set_transport_speed (0);
_controller.set_transport_speed (0);
}
break;
case 4:
if (delta > 0) {
next_marker ();
_controller.next_marker ();
} else if (delta < 0) {
prev_marker ();
_controller.prev_marker ();
}
break;
case 5:
@ -3055,8 +3055,8 @@ int
OSC::jog_mode (float mode, lo_message msg)
{
OSCSurface *s = get_surface(get_address (msg));
if (get_transport_speed () != 1.0) {
set_transport_speed (0);
if (_controller.get_transport_speed () != 1.0) {
_controller.set_transport_speed (0);
}
s->jogmode = (uint32_t) mode;
s->global_obs->jog_mode (mode);

View file

@ -344,7 +344,7 @@ class OSC : public ARDOUR::ControlProtocol, public AbstractUI<OSCUIRequest>
void record_enabled (lo_message msg);
void add_marker_name(const std::string &markername) {
add_marker(markername);
_controller.add_marker(markername);
}
// cue
@ -416,38 +416,50 @@ class OSC : public ARDOUR::ControlProtocol, public AbstractUI<OSCUIRequest>
return 0; \
}
PATH_CALLBACK(add_marker);
PATH_CALLBACK(loop_toggle);
PATH_CALLBACK(goto_start);
PATH_CALLBACK(goto_end);
PATH_CALLBACK(rewind);
PATH_CALLBACK(ffwd);
PATH_CALLBACK(transport_stop);
PATH_CALLBACK(transport_play);
PATH_CALLBACK(save_state);
PATH_CALLBACK(prev_marker);
PATH_CALLBACK(next_marker);
#define PATH_CONTROLLER_CALLBACK(name) \
static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data) { \
return static_cast<OSC*>(user_data)->cb_ ## name (path, types, argv, argc, msg); \
} \
int cb_ ## name (const char *path, const char *types, lo_arg ** argv, int argc, lo_message msg) { \
OSC_DEBUG; \
check_surface (msg); \
if (argc > 0 && !strcmp (types, "f") && argv[0]->f != 1.0) { return 0; } \
_controller.name (); \
return 0; \
}
PATH_CONTROLLER_CALLBACK(add_marker);
PATH_CONTROLLER_CALLBACK(loop_toggle);
PATH_CONTROLLER_CALLBACK(goto_start);
PATH_CONTROLLER_CALLBACK(goto_end);
PATH_CONTROLLER_CALLBACK(rewind);
PATH_CONTROLLER_CALLBACK(ffwd);
PATH_CONTROLLER_CALLBACK(transport_stop);
PATH_CONTROLLER_CALLBACK(transport_play);
PATH_CONTROLLER_CALLBACK(save_state);
PATH_CONTROLLER_CALLBACK(prev_marker);
PATH_CONTROLLER_CALLBACK(next_marker);
PATH_CALLBACK(undo);
PATH_CALLBACK(redo);
PATH_CALLBACK(toggle_punch_in);
PATH_CALLBACK(toggle_punch_out);
PATH_CALLBACK(rec_enable_toggle);
PATH_CALLBACK(toggle_all_rec_enables);
PATH_CALLBACK(all_tracks_rec_in);
PATH_CALLBACK(all_tracks_rec_out);
PATH_CONTROLLER_CALLBACK(toggle_punch_in);
PATH_CONTROLLER_CALLBACK(toggle_punch_out);
PATH_CONTROLLER_CALLBACK(rec_enable_toggle);
PATH_CONTROLLER_CALLBACK(toggle_all_rec_enables);
PATH_CONTROLLER_CALLBACK(all_tracks_rec_in);
PATH_CONTROLLER_CALLBACK(all_tracks_rec_out);
PATH_CALLBACK(cancel_all_solos);
PATH_CALLBACK(remove_marker_at_playhead);
PATH_CONTROLLER_CALLBACK(remove_marker_at_playhead);
PATH_CALLBACK(mark_in);
PATH_CALLBACK(mark_out);
PATH_CALLBACK(toggle_click);
PATH_CALLBACK(midi_panic);
PATH_CALLBACK(stop_forget);
PATH_CONTROLLER_CALLBACK(toggle_click);
PATH_CONTROLLER_CALLBACK(midi_panic);
PATH_CONTROLLER_CALLBACK(stop_forget);
PATH_CALLBACK(set_punch_range);
PATH_CALLBACK(set_loop_range);
PATH_CALLBACK(set_session_range);
PATH_CALLBACK(toggle_monitor_mute);
PATH_CALLBACK(toggle_monitor_dim);
PATH_CALLBACK(toggle_monitor_mono);
PATH_CONTROLLER_CALLBACK(toggle_monitor_mute);
PATH_CONTROLLER_CALLBACK(toggle_monitor_dim);
PATH_CONTROLLER_CALLBACK(toggle_monitor_mono);
PATH_CALLBACK(quick_snapshot_stay);
PATH_CALLBACK(quick_snapshot_switch);
PATH_CALLBACK(fit_1_track);
@ -484,12 +496,25 @@ class OSC : public ARDOUR::ControlProtocol, public AbstractUI<OSCUIRequest>
return 0; \
}
PATH_CALLBACK1(set_transport_speed,f,);
#define PATH_CONTROLLER_CALLBACK1(name,type,optional) \
static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data) { \
return static_cast<OSC*>(user_data)->cb_ ## name (path, types, argv, argc, msg); \
} \
int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, lo_message msg) { \
OSC_DEBUG; \
check_surface (msg); \
if (argc > 0) { \
_controller.name (optional argv[0]->type); \
} \
return 0; \
}
PATH_CONTROLLER_CALLBACK1(set_transport_speed,f,);
PATH_CALLBACK1(add_marker_name,s,&);
PATH_CALLBACK1(access_action,s,&);
PATH_CALLBACK1(jump_by_bars,f,);
PATH_CALLBACK1(jump_by_seconds,f,);
PATH_CONTROLLER_CALLBACK1(jump_by_bars,f,);
PATH_CONTROLLER_CALLBACK1(jump_by_seconds,f,);
PATH_CALLBACK1(click_level,f,);
#define PATH_CALLBACK1_MSG(name,arg1type) \
@ -559,6 +584,19 @@ class OSC : public ARDOUR::ControlProtocol, public AbstractUI<OSCUIRequest>
return 0; \
}
#define PATH_CONTROLLER_CALLBACK2(name,arg1type,arg2type) \
static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data) { \
return static_cast<OSC*>(user_data)->cb_ ## name (path, types, argv, argc, msg); \
} \
int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, lo_message msg) { \
OSC_DEBUG; \
check_surface (msg); \
if (argc > 1) { \
_controller.name (argv[0]->arg1type, argv[1]->arg2type); \
} \
return 0; \
}
#define PATH_CALLBACK2_MSG(name,arg1type,arg2type) \
static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data) { \
return static_cast<OSC*>(user_data)->cb_ ## name (path, types, argv, argc, msg); \
@ -615,8 +653,8 @@ class OSC : public ARDOUR::ControlProtocol, public AbstractUI<OSCUIRequest>
PATH_CALLBACK2_MSG(sel_eq_q,i,f);
PATH_CALLBACK2_MSG(sel_eq_shape,i,f);
PATH_CALLBACK2(locate,i,i);
PATH_CALLBACK2(loop_location,i,i);
PATH_CONTROLLER_CALLBACK2(locate,i,i);
PATH_CONTROLLER_CALLBACK2(loop_location,i,i);
PATH_CALLBACK3(route_set_send_gain_dB,i,i,f);
PATH_CALLBACK3(route_set_send_fader,i,i,f);
PATH_CALLBACK3(route_set_send_enable,i,i,f);

View file

@ -360,7 +360,7 @@ Push2::button_play ()
}
if (_modifier_state & ModShift) {
goto_start (_session->transport_rolling());
_controller.goto_start (_session->transport_rolling());
return;
}
@ -376,16 +376,16 @@ Push2::button_play ()
}
if (_session->transport_rolling ()) {
transport_stop ();
_controller.transport_stop ();
} else {
transport_play ();
_controller.transport_play ();
}
}
void
Push2::button_recenable ()
{
rec_enable_toggle ();
_controller.rec_enable_toggle ();
}
void
@ -427,19 +427,19 @@ Push2::button_left ()
void
Push2::button_repeat ()
{
loop_toggle ();
_controller.loop_toggle ();
}
void
Push2::button_metronome ()
{
toggle_click ();
_controller.toggle_click ();
}
void
Push2::button_solo_long_press ()
{
cancel_all_solo ();
_controller.cancel_all_solo ();
}
void
@ -527,56 +527,56 @@ void
Push2::button_fwd32t ()
{
const int n = (_modifier_state & ModShift) ? 8 : 0;
goto_nth_marker (0+n);
_controller.goto_nth_marker (0+n);
}
void
Push2::button_fwd32 ()
{
const int n = (_modifier_state & ModShift) ? 8 : 0;
goto_nth_marker (1+n);
_controller.goto_nth_marker (1+n);
}
void
Push2::button_fwd16t ()
{
const int n = (_modifier_state & ModShift) ? 8 : 0;
goto_nth_marker (2+n);
_controller.goto_nth_marker (2+n);
}
void
Push2::button_fwd16 ()
{
const int n = (_modifier_state & ModShift) ? 8 : 0;
goto_nth_marker (3+n);
_controller.goto_nth_marker (3+n);
}
void
Push2::button_fwd8t ()
{
const int n = (_modifier_state & ModShift) ? 8 : 0;
goto_nth_marker (4+n);
_controller.goto_nth_marker (4+n);
}
void
Push2::button_fwd8 ()
{
const int n = (_modifier_state & ModShift) ? 8 : 0;
goto_nth_marker (5+n);
_controller.goto_nth_marker (5+n);
}
void
Push2::button_fwd4t ()
{
const int n = (_modifier_state & ModShift) ? 8 : 0;
goto_nth_marker (6+n);
_controller.goto_nth_marker (6+n);
}
void
Push2::button_fwd4 ()
{
const int n = (_modifier_state & ModShift) ? 8 : 0;
goto_nth_marker (7+n);
_controller.goto_nth_marker (7+n);
}
void

View file

@ -764,7 +764,7 @@ Push2::handle_midi_note_on_message (MIDI::Parser& parser, MIDI::EventTwoBytes* e
/* touch strip */
case 12:
if (ev->velocity < 64) {
transport_stop ();
_controller.transport_stop ();
}
break;
}

View file

@ -380,7 +380,7 @@ US2400Protocol::save_press (Button &)
if (main_modifier_state() == MODIFIER_SHIFT) {
quick_snapshot_switch();
} else {
save_state ();
_controller.save_state ();
}
return none;
@ -463,7 +463,7 @@ US2400Protocol::marker_release (Button &)
}
_session->locations()->next_available_name (markername,"mark");
add_marker (markername);
_controller.add_marker (markername);
return off;
}
@ -475,7 +475,7 @@ US2400Protocol::marker_release (Button &)
LedState
US2400Protocol::stop_press (Button &)
{
transport_stop ();
_controller.transport_stop ();
if (main_modifier_state() == MODIFIER_SHIFT) {
_session->midi_panic();
@ -497,7 +497,7 @@ US2400Protocol::play_press (Button &)
again, jump back to where we started last time
*/
transport_play (get_transport_speed() == 1.0);
_controller.transport_play (_controller.get_transport_speed() == 1.0);
return none;
}
@ -510,7 +510,7 @@ US2400Protocol::play_release (Button &)
LedState
US2400Protocol::record_press (Button &)
{
rec_enable_toggle ();
_controller.rec_enable_toggle ();
return none;
}
@ -524,13 +524,13 @@ LedState
US2400Protocol::rewind_press (Button &)
{
if (modifier_state() & MODIFIER_MARKER) {
prev_marker ();
_controller.prev_marker ();
} else if ( (_modifier_state & MODIFIER_DROP) == MODIFIER_DROP) {
access_action ("Common/start-range-from-playhead");
} else if (main_modifier_state() & MODIFIER_SHIFT) {
goto_start ();
_controller.goto_start ();
} else {
rewind ();
_controller.rewind ();
}
return none;
}
@ -545,13 +545,13 @@ LedState
US2400Protocol::ffwd_press (Button &)
{
if (modifier_state() & MODIFIER_MARKER) {
next_marker ();
_controller.next_marker ();
} else if ( (_modifier_state & MODIFIER_DROP) == MODIFIER_DROP) {
access_action ("Common/finish-range-from-playhead");
} else if (main_modifier_state() & MODIFIER_SHIFT) {
goto_end();
_controller.goto_end();
} else {
ffwd ();
_controller.ffwd ();
}
return none;
}
@ -570,7 +570,7 @@ US2400Protocol::loop_press (Button &)
return off;
} else {
bool was_on = _session->get_play_loop();
loop_toggle ();
_controller.loop_toggle ();
return was_on ? off : on;
}
}
@ -821,7 +821,7 @@ US2400Protocol::cancel_release (Button &)
LedState
US2400Protocol::user_a_press (Button &)
{
transport_play (get_transport_speed() == 1.0);
_controller.transport_play (_controller.get_transport_speed() == 1.0);
return off;
}
LedState
@ -832,7 +832,7 @@ US2400Protocol::user_a_release (Button &)
LedState
US2400Protocol::user_b_press (Button &)
{
transport_stop();
_controller.transport_stop();
return off;
}
LedState
@ -897,7 +897,7 @@ US2400Protocol::clearsolo_press (US2400::Button&)
{
// clears all solos and listens (pfl/afl)
if (main_modifier_state() & MODIFIER_OPTION) {
cancel_all_solo ();
_controller.cancel_all_solo ();
}
return none;
@ -1082,7 +1082,7 @@ US2400::LedState
US2400Protocol::replace_press (US2400::Button&)
{
if (main_modifier_state() == MODIFIER_SHIFT) {
toggle_punch_out();
_controller.toggle_punch_out();
return none;
} else {
access_action ("Common/finish-range-from-playhead");

View file

@ -993,7 +993,7 @@ Strip::notify_metering_state_changed()
return;
}
bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
bool transport_is_rolling = (_surface->mcp().controller ().get_transport_speed () != 0.0f);
bool metering_active = _surface->mcp().metering_active ();
if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {

View file

@ -50,7 +50,7 @@ ArdourTransport::time () const
bool
ArdourTransport::roll () const
{
return basic_ui ().transport_rolling ();
return basic_ui ().controller ().transport_rolling ();
}
void
@ -58,7 +58,7 @@ ArdourTransport::set_roll (bool value)
{
if ((value && !roll ()) || (!value && roll ())) {
// this call is equivalent to hitting the spacebar
basic_ui ().toggle_roll (false);
basic_ui ().controller ().toggle_roll (false);
}
}
@ -72,6 +72,6 @@ void
ArdourTransport::set_record (bool value)
{
if ((value && !record ()) || (!value && record ())) {
basic_ui ().rec_enable_toggle ();
basic_ui ().controller ().rec_enable_toggle ();
}
}

View file

@ -299,7 +299,7 @@ WiimoteControlProtocol::update_led_state ()
}
// enable LED1 if Ardour is playing
if (transport_rolling ()) {
if (_controller.transport_rolling ()) {
DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state playing, activate LED1\n");
state |= CWIID_LED1_ON;
}
@ -365,12 +365,12 @@ WiimoteControlProtocol::wiimote_callback (int mesg_count, union cwiid_mesg mesg[
// B + up = move playhead to next marker
if (b & CWIID_BTN_UP) {
next_marker ();
_controller.next_marker ();
}
// B + down = move playhead to prev marker
if (b & CWIID_BTN_DOWN) {
prev_marker ();
_controller.prev_marker ();
}
// B + Home = add marker at playhead
@ -400,7 +400,7 @@ WiimoteControlProtocol::wiimote_callback (int mesg_count, union cwiid_mesg mesg[
// 2 = enable recording in general
if (b & CWIID_BTN_2) {
rec_enable_toggle ();
_controller.rec_enable_toggle ();
}
// left = move playhead back a bit