many changes relating to session construction and audioengine interaction
every session member is now initialized using C++ constructor syntax session construction reordered to clarify the split(s) between work where the engine is not relevant and work where is it is. this split is still not 100% obvious, but is enormously clearer than previously. if engine/backend are not running as session is created, and the SR of the sample rate is known, attempt to force backend to that value.
This commit is contained in:
parent
a6815efb86
commit
209e4bdcae
@ -268,7 +268,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
|
|||||||
|
|
||||||
/* handle Audio/MIDI setup when session requires it */
|
/* handle Audio/MIDI setup when session requires it */
|
||||||
|
|
||||||
ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this));
|
ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
|
||||||
|
|
||||||
/* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
|
/* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
|
||||||
|
|
||||||
@ -4159,10 +4159,12 @@ ARDOUR_UI::launch_audio_midi_setup ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ARDOUR_UI::do_audio_midi_setup ()
|
ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
|
||||||
{
|
{
|
||||||
launch_audio_midi_setup ();
|
launch_audio_midi_setup ();
|
||||||
|
|
||||||
|
_audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
|
||||||
|
|
||||||
int r = _audio_midi_setup->run ();
|
int r = _audio_midi_setup->run ();
|
||||||
|
|
||||||
switch (r) {
|
switch (r) {
|
||||||
|
@ -750,7 +750,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
|
|||||||
|
|
||||||
EngineControl* _audio_midi_setup;
|
EngineControl* _audio_midi_setup;
|
||||||
void launch_audio_midi_setup ();
|
void launch_audio_midi_setup ();
|
||||||
int do_audio_midi_setup ();
|
int do_audio_midi_setup (uint32_t);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __ardour_gui_h__ */
|
#endif /* __ardour_gui_h__ */
|
||||||
|
@ -65,6 +65,7 @@ EngineControl::EngineControl ()
|
|||||||
, control_app_button (_("Launch Control App"))
|
, control_app_button (_("Launch Control App"))
|
||||||
, basic_packer (9, 3)
|
, basic_packer (9, 3)
|
||||||
, ignore_changes (0)
|
, ignore_changes (0)
|
||||||
|
, _desired_sample_rate (0)
|
||||||
{
|
{
|
||||||
build_notebook ();
|
build_notebook ();
|
||||||
|
|
||||||
@ -340,6 +341,8 @@ EngineControl::device_changed ()
|
|||||||
ignore_changes++;
|
ignore_changes++;
|
||||||
|
|
||||||
/* sample rates */
|
/* sample rates */
|
||||||
|
|
||||||
|
string desired;
|
||||||
|
|
||||||
vector<float> sr = backend->available_sample_rates (device_name);
|
vector<float> sr = backend->available_sample_rates (device_name);
|
||||||
for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
|
for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) {
|
||||||
@ -350,11 +353,17 @@ EngineControl::device_changed ()
|
|||||||
snprintf (buf, sizeof (buf), "%.0f kHz", (*x)/1000.0);
|
snprintf (buf, sizeof (buf), "%.0f kHz", (*x)/1000.0);
|
||||||
}
|
}
|
||||||
s.push_back (buf);
|
s.push_back (buf);
|
||||||
|
if (*x == _desired_sample_rate) {
|
||||||
|
desired = buf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set_popdown_strings (sample_rate_combo, s);
|
set_popdown_strings (sample_rate_combo, s);
|
||||||
sample_rate_combo.set_active_text (s.front());
|
if (desired.empty()) {
|
||||||
|
sample_rate_combo.set_active_text (s.front());
|
||||||
|
} else {
|
||||||
|
sample_rate_combo.set_active_text (desired);
|
||||||
|
}
|
||||||
|
|
||||||
vector<uint32_t> bs = backend->available_buffer_sizes(device_name);
|
vector<uint32_t> bs = backend->available_buffer_sizes(device_name);
|
||||||
s.clear ();
|
s.clear ();
|
||||||
@ -514,7 +523,9 @@ EngineControl::maybe_display_saved_state ()
|
|||||||
|
|
||||||
if (state) {
|
if (state) {
|
||||||
ignore_changes++;
|
ignore_changes++;
|
||||||
sample_rate_combo.set_active_text (state->sample_rate);
|
if (!_desired_sample_rate) {
|
||||||
|
sample_rate_combo.set_active_text (state->sample_rate);
|
||||||
|
}
|
||||||
buffer_size_combo.set_active_text (state->buffer_size);
|
buffer_size_combo.set_active_text (state->buffer_size);
|
||||||
input_latency.set_value (state->input_latency);
|
input_latency.set_value (state->input_latency);
|
||||||
output_latency.set_value (state->output_latency);
|
output_latency.set_value (state->output_latency);
|
||||||
@ -843,3 +854,10 @@ EngineControl::manage_control_app_sensitivity ()
|
|||||||
control_app_button.set_sensitive (true);
|
control_app_button.set_sensitive (true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EngineControl::set_desired_sample_rate (uint32_t sr)
|
||||||
|
{
|
||||||
|
_desired_sample_rate = sr;
|
||||||
|
device_changed ();
|
||||||
|
}
|
||||||
|
@ -37,14 +37,16 @@
|
|||||||
|
|
||||||
class EngineControl : public ArdourDialog {
|
class EngineControl : public ArdourDialog {
|
||||||
public:
|
public:
|
||||||
EngineControl ();
|
EngineControl ();
|
||||||
~EngineControl ();
|
~EngineControl ();
|
||||||
|
|
||||||
static bool need_setup ();
|
static bool need_setup ();
|
||||||
|
|
||||||
XMLNode& get_state ();
|
XMLNode& get_state ();
|
||||||
void set_state (const XMLNode&);
|
void set_state (const XMLNode&);
|
||||||
|
|
||||||
|
void set_desired_sample_rate (uint32_t);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Gtk::Notebook notebook;
|
Gtk::Notebook notebook;
|
||||||
|
|
||||||
@ -153,6 +155,7 @@ class EngineControl : public ArdourDialog {
|
|||||||
void control_app_button_clicked ();
|
void control_app_button_clicked ();
|
||||||
void manage_control_app_sensitivity ();
|
void manage_control_app_sensitivity ();
|
||||||
int push_state_to_backend (bool start);
|
int push_state_to_backend (bool start);
|
||||||
|
uint32_t _desired_sample_rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __gtk2_ardour_engine_dialog_h__ */
|
#endif /* __gtk2_ardour_engine_dialog_h__ */
|
||||||
|
@ -558,7 +558,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||||||
/** handlers should return 0 for "everything OK", and any other value for
|
/** handlers should return 0 for "everything OK", and any other value for
|
||||||
* "cannot setup audioengine".
|
* "cannot setup audioengine".
|
||||||
*/
|
*/
|
||||||
static PBD::Signal0<int> AudioEngineSetupRequired;
|
static PBD::Signal1<int,uint32_t> AudioEngineSetupRequired;
|
||||||
|
|
||||||
/** handlers should return -1 for "stop cleanup",
|
/** handlers should return -1 for "stop cleanup",
|
||||||
0 for "yes, delete this playlist",
|
0 for "yes, delete this playlist",
|
||||||
@ -1071,7 +1071,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||||||
boost::scoped_ptr<SessionDirectory> _session_dir;
|
boost::scoped_ptr<SessionDirectory> _session_dir;
|
||||||
|
|
||||||
void hookup_io ();
|
void hookup_io ();
|
||||||
void when_engine_running ();
|
int when_engine_running ();
|
||||||
void graph_reordered ();
|
void graph_reordered ();
|
||||||
|
|
||||||
/** current snapshot name, without the .ardour suffix */
|
/** current snapshot name, without the .ardour suffix */
|
||||||
@ -1137,8 +1137,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||||||
void auto_loop_changed (Location *);
|
void auto_loop_changed (Location *);
|
||||||
void auto_loop_declick_range (Location *, framepos_t &, framepos_t &);
|
void auto_loop_declick_range (Location *, framepos_t &, framepos_t &);
|
||||||
|
|
||||||
void first_stage_init (std::string path, std::string snapshot_name);
|
void pre_engine_init (std::string path);
|
||||||
int second_stage_init ();
|
int post_engine_init ();
|
||||||
void remove_empty_sounds ();
|
void remove_empty_sounds ();
|
||||||
|
|
||||||
void setup_midi_control ();
|
void setup_midi_control ();
|
||||||
@ -1620,6 +1620,10 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||||||
/* persistent, non-track related MIDI ports */
|
/* persistent, non-track related MIDI ports */
|
||||||
MidiPortManager* _midi_ports;
|
MidiPortManager* _midi_ports;
|
||||||
MIDI::MachineControl* _mmc;
|
MIDI::MachineControl* _mmc;
|
||||||
|
|
||||||
|
void setup_ltc ();
|
||||||
|
void setup_click ();
|
||||||
|
void setup_bundles ();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ARDOUR
|
} // namespace ARDOUR
|
||||||
|
@ -153,8 +153,10 @@ Port::connect (std::string const & other)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sends_output ()) {
|
if (sends_output ()) {
|
||||||
|
DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", our_name, other_name));
|
||||||
r = port_engine.connect (our_name, other_name);
|
r = port_engine.connect (our_name, other_name);
|
||||||
} else {
|
} else {
|
||||||
|
DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", other_name, our_name));
|
||||||
r = port_engine.connect (other_name, our_name);
|
r = port_engine.connect (other_name, our_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,6 +422,8 @@ Port::reconnect ()
|
|||||||
{
|
{
|
||||||
/* caller must hold process lock; intended to be used only after reestablish() */
|
/* caller must hold process lock; intended to be used only after reestablish() */
|
||||||
|
|
||||||
|
DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2 destinations\n",name(), _connections.size()));
|
||||||
|
|
||||||
for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
|
for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
|
||||||
if (connect (*i)) {
|
if (connect (*i)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -107,7 +107,7 @@ using namespace PBD;
|
|||||||
|
|
||||||
bool Session::_disable_all_loaded_plugins = false;
|
bool Session::_disable_all_loaded_plugins = false;
|
||||||
|
|
||||||
PBD::Signal0<int> Session::AudioEngineSetupRequired;
|
PBD::Signal1<int,uint32_t> Session::AudioEngineSetupRequired;
|
||||||
PBD::Signal1<void,std::string> Session::Dialog;
|
PBD::Signal1<void,std::string> Session::Dialog;
|
||||||
PBD::Signal0<int> Session::AskAboutPendingState;
|
PBD::Signal0<int> Session::AskAboutPendingState;
|
||||||
PBD::Signal2<int, framecnt_t, framecnt_t> Session::AskAboutSampleRateMismatch;
|
PBD::Signal2<int, framecnt_t, framecnt_t> Session::AskAboutSampleRateMismatch;
|
||||||
@ -132,106 +132,137 @@ Session::Session (AudioEngine &eng,
|
|||||||
const string& snapshot_name,
|
const string& snapshot_name,
|
||||||
BusProfile* bus_profile,
|
BusProfile* bus_profile,
|
||||||
string mix_template)
|
string mix_template)
|
||||||
: _engine (eng)
|
: playlists (new SessionPlaylists)
|
||||||
, _target_transport_speed (0.0)
|
, _engine (eng)
|
||||||
, _requested_return_frame (-1)
|
, process_function (&Session::process_with_events)
|
||||||
, _under_nsm_control (false)
|
, waiting_for_sync_offset (false)
|
||||||
, _session_dir (new SessionDirectory (fullpath))
|
, _base_frame_rate (0)
|
||||||
, state_tree (0)
|
, _current_frame_rate (0)
|
||||||
, _state_of_the_state (StateOfTheState(CannotSave|InitialConnecting|Loading))
|
, _nominal_frame_rate (0)
|
||||||
, _butler (new Butler (*this))
|
, transport_sub_state (0)
|
||||||
, _post_transport_work (0)
|
, _record_status (Disabled)
|
||||||
, _send_timecode_update (false)
|
, _transport_frame (0)
|
||||||
, ltc_enc_buf(0)
|
, _session_range_location (0)
|
||||||
, _all_route_group (new RouteGroup (*this, "all"))
|
, _slave (0)
|
||||||
, routes (new RouteList)
|
, _silent (false)
|
||||||
, _total_free_4k_blocks (0)
|
|
||||||
, _total_free_4k_blocks_uncertain (false)
|
|
||||||
, _bundles (new BundleList)
|
|
||||||
, _bundle_xml_node (0)
|
|
||||||
, _current_trans (0)
|
|
||||||
, click_data (0)
|
|
||||||
, click_emphasis_data (0)
|
|
||||||
, main_outs (0)
|
|
||||||
, _have_rec_enabled_track (false)
|
|
||||||
, _suspend_timecode_transmission (0)
|
|
||||||
, _non_soloed_outs_muted (false)
|
|
||||||
, _listen_cnt (0)
|
|
||||||
, _solo_isolated_cnt (0)
|
|
||||||
, _transport_speed (0)
|
, _transport_speed (0)
|
||||||
, _default_transport_speed (1.0)
|
, _default_transport_speed (1.0)
|
||||||
, _last_transport_speed (0)
|
, _last_transport_speed (0)
|
||||||
|
, _target_transport_speed (0.0)
|
||||||
, auto_play_legal (false)
|
, auto_play_legal (false)
|
||||||
, transport_sub_state (0)
|
, _last_slave_transport_frame (0)
|
||||||
, _transport_frame (0)
|
, maximum_output_latency (0)
|
||||||
, _session_range_location (0)
|
, _requested_return_frame (-1)
|
||||||
, loop_changing (false)
|
|
||||||
, play_loop (false)
|
|
||||||
, have_looped (false)
|
|
||||||
, _last_roll_location (0)
|
|
||||||
, _last_roll_or_reversal_location (0)
|
|
||||||
, _last_record_location (0)
|
|
||||||
, pending_locate_frame (0)
|
|
||||||
, pending_locate_roll (false)
|
|
||||||
, pending_locate_flush (false)
|
|
||||||
, state_was_pending (false)
|
|
||||||
, outbound_mtc_timecode_frame (0)
|
|
||||||
, next_quarter_frame_to_send (-1)
|
|
||||||
, current_block_size (0)
|
, current_block_size (0)
|
||||||
, solo_update_disabled (false)
|
|
||||||
, _have_captured (false)
|
|
||||||
, _worst_output_latency (0)
|
, _worst_output_latency (0)
|
||||||
, _worst_input_latency (0)
|
, _worst_input_latency (0)
|
||||||
, _worst_track_latency (0)
|
, _worst_track_latency (0)
|
||||||
|
, _have_captured (false)
|
||||||
|
, _meter_hold (0)
|
||||||
|
, _meter_falloff (0)
|
||||||
|
, _non_soloed_outs_muted (false)
|
||||||
|
, _listen_cnt (0)
|
||||||
|
, _solo_isolated_cnt (0)
|
||||||
|
, _writable (false)
|
||||||
, _was_seamless (Config->get_seamless_loop ())
|
, _was_seamless (Config->get_seamless_loop ())
|
||||||
, _slave (0)
|
, _under_nsm_control (false)
|
||||||
|
, delta_accumulator_cnt (0)
|
||||||
|
, average_slave_delta (1800) // !!! why 1800 ???
|
||||||
|
, average_dir (0)
|
||||||
|
, have_first_delta_accumulator (false)
|
||||||
|
, _slave_state (Stopped)
|
||||||
|
, post_export_sync (false)
|
||||||
|
, post_export_position (0)
|
||||||
|
, _exporting (false)
|
||||||
|
, _export_started (false)
|
||||||
|
, _export_rolling (false)
|
||||||
|
, _pre_export_mmc_enabled (false)
|
||||||
|
, _name (snapshot_name)
|
||||||
|
, _is_new (true)
|
||||||
, _send_qf_mtc (false)
|
, _send_qf_mtc (false)
|
||||||
, _pframes_since_last_mtc (0)
|
, _pframes_since_last_mtc (0)
|
||||||
, _play_range (false)
|
, session_midi_feedback (0)
|
||||||
, _exporting (false)
|
, play_loop (false)
|
||||||
|
, loop_changing (false)
|
||||||
|
, last_loopend (0)
|
||||||
|
, _session_dir (new SessionDirectory (fullpath))
|
||||||
|
, _current_snapshot_name (snapshot_name)
|
||||||
|
, state_tree (0)
|
||||||
|
, state_was_pending (false)
|
||||||
|
, _state_of_the_state (StateOfTheState(CannotSave|InitialConnecting|Loading))
|
||||||
|
, _last_roll_location (0)
|
||||||
|
, _last_roll_or_reversal_location (0)
|
||||||
|
, _last_record_location (0)
|
||||||
|
, pending_locate_roll (false)
|
||||||
|
, pending_locate_frame (0)
|
||||||
|
, pending_locate_flush (false)
|
||||||
, pending_abort (false)
|
, pending_abort (false)
|
||||||
|
, pending_auto_loop (false)
|
||||||
|
, _butler (new Butler (*this))
|
||||||
|
, _post_transport_work (0)
|
||||||
|
, cumulative_rf_motion (0)
|
||||||
|
, rf_scale (1.0)
|
||||||
|
, _locations (new Locations (*this))
|
||||||
|
, step_speed (0)
|
||||||
|
, outbound_mtc_timecode_frame (0)
|
||||||
|
, next_quarter_frame_to_send (-1)
|
||||||
|
, _frames_per_timecode_frame (0)
|
||||||
|
, _frames_per_hour (0)
|
||||||
|
, _timecode_frames_per_hour (0)
|
||||||
|
, last_timecode_valid (false)
|
||||||
|
, last_timecode_when (0)
|
||||||
|
, _send_timecode_update (false)
|
||||||
|
, ltc_encoder (0)
|
||||||
|
, ltc_enc_buf(0)
|
||||||
|
, ltc_buf_off (0)
|
||||||
|
, ltc_buf_len (0)
|
||||||
|
, ltc_speed (0)
|
||||||
|
, ltc_enc_byte (0)
|
||||||
|
, ltc_enc_pos (0)
|
||||||
|
, ltc_enc_cnt (0)
|
||||||
|
, ltc_enc_off (0)
|
||||||
|
, restarting (false)
|
||||||
|
, ltc_prev_cycle (0)
|
||||||
|
, ltc_timecode_offset (0)
|
||||||
|
, ltc_timecode_negative_offset (false)
|
||||||
|
, midi_control_ui (0)
|
||||||
|
, _tempo_map (0)
|
||||||
|
, _all_route_group (new RouteGroup (*this, "all"))
|
||||||
|
, routes (new RouteList)
|
||||||
, _adding_routes_in_progress (false)
|
, _adding_routes_in_progress (false)
|
||||||
, destructive_index (0)
|
, destructive_index (0)
|
||||||
, first_file_data_format_reset (true)
|
, solo_update_disabled (false)
|
||||||
, first_file_header_format_reset (true)
|
, default_fade_steepness (0)
|
||||||
, post_export_sync (false)
|
, default_fade_msecs (0)
|
||||||
, midi_control_ui (0)
|
, _total_free_4k_blocks (0)
|
||||||
, _step_editors (0)
|
, _total_free_4k_blocks_uncertain (false)
|
||||||
, no_questions_about_missing_files (false)
|
, no_questions_about_missing_files (false)
|
||||||
, _speakers (new Speakers)
|
, _playback_load (0)
|
||||||
, _clicks_cleared (0)
|
, _capture_load (0)
|
||||||
, ignore_route_processor_changes (false)
|
, _bundles (new BundleList)
|
||||||
, _pre_export_mmc_enabled (false)
|
, _bundle_xml_node (0)
|
||||||
, _locations (new Locations (*this))
|
, _current_trans (0)
|
||||||
, ltc_encoder (0)
|
, _clicking (false)
|
||||||
, playlists (new SessionPlaylists)
|
, click_data (0)
|
||||||
, _name (snapshot_name)
|
, click_emphasis_data (0)
|
||||||
, _current_snapshot_name (snapshot_name)
|
|
||||||
, step_speed (0.0)
|
|
||||||
, click_length (0)
|
, click_length (0)
|
||||||
, click_emphasis_length (0)
|
, click_emphasis_length (0)
|
||||||
, _clicking (false)
|
, _clicks_cleared (0)
|
||||||
, process_function (&Session::process_with_events)
|
, _play_range (false)
|
||||||
, last_timecode_when (0)
|
, main_outs (0)
|
||||||
, last_timecode_valid (false)
|
, first_file_data_format_reset (true)
|
||||||
, average_slave_delta (1800) // !!! why 1800 ???
|
, first_file_header_format_reset (true)
|
||||||
, have_first_delta_accumulator (false)
|
, have_looped (false)
|
||||||
, delta_accumulator_cnt (0)
|
, _have_rec_enabled_track (false)
|
||||||
, _slave_state (Stopped)
|
, _step_editors (0)
|
||||||
|
, _suspend_timecode_transmission (0)
|
||||||
|
, _speakers (new Speakers)
|
||||||
|
, ignore_route_processor_changes (false)
|
||||||
{
|
{
|
||||||
if (_engine.current_backend() == 0 || _engine.setup_required()) {
|
uint32_t sr = 0;
|
||||||
boost::optional<int> r = AudioEngineSetupRequired ();
|
|
||||||
if (r.get_value_or (-1) != 0) {
|
|
||||||
throw failed_constructor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_engine.connected()) {
|
|
||||||
throw failed_constructor();
|
|
||||||
}
|
|
||||||
|
|
||||||
first_stage_init (fullpath, snapshot_name);
|
|
||||||
|
|
||||||
|
pre_engine_init (fullpath);
|
||||||
|
|
||||||
if (_is_new) {
|
if (_is_new) {
|
||||||
if (create (mix_template, bus_profile)) {
|
if (create (mix_template, bus_profile)) {
|
||||||
destroy ();
|
destroy ();
|
||||||
@ -241,14 +272,44 @@ Session::Session (AudioEngine &eng,
|
|||||||
if (load_state (_current_snapshot_name)) {
|
if (load_state (_current_snapshot_name)) {
|
||||||
throw failed_constructor ();
|
throw failed_constructor ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* try to get sample rate from XML state so that we
|
||||||
|
* can influence the SR if we set up the audio
|
||||||
|
* engine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (state_tree) {
|
||||||
|
const XMLProperty* prop;
|
||||||
|
if ((prop = state_tree->root()->property (X_("sample-rate"))) != 0) {
|
||||||
|
sr = atoi (prop->value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_engine.current_backend() == 0 || _engine.setup_required()) {
|
||||||
|
boost::optional<int> r = AudioEngineSetupRequired (sr);
|
||||||
|
if (r.get_value_or (-1) != 0) {
|
||||||
|
destroy ();
|
||||||
|
throw failed_constructor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (second_stage_init ()) {
|
/* at this point the engine should be connected (i.e. interacting
|
||||||
|
with a backend device (or psuedo-device) and available to us
|
||||||
|
for determinining sample rates and other settings.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!_engine.connected()) {
|
||||||
|
destroy ();
|
||||||
|
throw failed_constructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (post_engine_init ()) {
|
||||||
destroy ();
|
destroy ();
|
||||||
throw failed_constructor ();
|
throw failed_constructor ();
|
||||||
}
|
}
|
||||||
|
|
||||||
store_recent_sessions(_name, _path);
|
store_recent_sessions (_name, _path);
|
||||||
|
|
||||||
bool was_dirty = dirty();
|
bool was_dirty = dirty();
|
||||||
|
|
||||||
@ -397,135 +458,103 @@ Session::destroy ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Session::when_engine_running ()
|
Session::setup_ltc ()
|
||||||
{
|
{
|
||||||
string first_physical_output;
|
XMLNode* child = 0;
|
||||||
|
|
||||||
BootMessage (_("Set block size and sample rate"));
|
_ltc_input.reset (new IO (*this, _("LTC In"), IO::Input));
|
||||||
|
_ltc_output.reset (new IO (*this, _("LTC Out"), IO::Output));
|
||||||
set_block_size (_engine.samples_per_cycle());
|
|
||||||
set_frame_rate (_engine.sample_rate());
|
if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-In")) != 0) {
|
||||||
|
_ltc_input->set_state (*(child->children().front()), Stateful::loading_state_version);
|
||||||
BootMessage (_("Using configuration"));
|
} else {
|
||||||
|
{
|
||||||
boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
|
Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
|
||||||
boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
|
_ltc_input->ensure_io (ChanCount (DataType::AUDIO, 1), true, this);
|
||||||
|
}
|
||||||
Config->map_parameters (ff);
|
reconnect_ltc_input ();
|
||||||
config.map_parameters (ft);
|
|
||||||
|
|
||||||
/* every time we reconnect, recompute worst case output latencies */
|
|
||||||
|
|
||||||
_engine.Running.connect_same_thread (*this, boost::bind (&Session::initialize_latencies, this));
|
|
||||||
|
|
||||||
if (synced_to_jack()) {
|
|
||||||
_engine.transport_stop ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.get_jack_time_master()) {
|
if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-Out")) != 0) {
|
||||||
_engine.transport_locate (_transport_frame);
|
_ltc_output->set_state (*(child->children().front()), Stateful::loading_state_version);
|
||||||
|
} else {
|
||||||
|
{
|
||||||
|
Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
|
||||||
|
_ltc_output->ensure_io (ChanCount (DataType::AUDIO, 1), true, this);
|
||||||
|
}
|
||||||
|
reconnect_ltc_output ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* fix up names of LTC ports because we don't want the normal
|
||||||
|
* IO style of NAME/TYPE-{in,out}N
|
||||||
|
*/
|
||||||
|
|
||||||
|
_ltc_input->nth (0)->set_name (_("LTC-in"));
|
||||||
|
_ltc_output->nth (0)->set_name (_("LTC-out"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Session::setup_click ()
|
||||||
|
{
|
||||||
|
XMLNode* child = 0;
|
||||||
|
|
||||||
_clicking = false;
|
_clicking = false;
|
||||||
|
_click_io.reset (new ClickIO (*this, "click"));
|
||||||
try {
|
_click_gain.reset (new Amp (*this));
|
||||||
XMLNode* child = 0;
|
_click_gain->activate ();
|
||||||
|
|
||||||
|
if (state_tree && (child = find_named_node (*state_tree->root(), "Click")) != 0) {
|
||||||
|
|
||||||
_ltc_input.reset (new IO (*this, _("LTC In"), IO::Input));
|
/* existing state for Click */
|
||||||
_ltc_output.reset (new IO (*this, _("LTC Out"), IO::Output));
|
int c = 0;
|
||||||
|
|
||||||
if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-In")) != 0) {
|
if (Stateful::loading_state_version < 3000) {
|
||||||
_ltc_input->set_state (*(child->children().front()), Stateful::loading_state_version);
|
c = _click_io->set_state_2X (*child->children().front(), Stateful::loading_state_version, false);
|
||||||
} else {
|
} else {
|
||||||
{
|
const XMLNodeList& children (child->children());
|
||||||
Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
|
XMLNodeList::const_iterator i = children.begin();
|
||||||
_ltc_input->ensure_io (ChanCount (DataType::AUDIO, 1), true, this);
|
if ((c = _click_io->set_state (**i, Stateful::loading_state_version)) == 0) {
|
||||||
}
|
++i;
|
||||||
reconnect_ltc_input ();
|
if (i != children.end()) {
|
||||||
}
|
c = _click_gain->set_state (**i, Stateful::loading_state_version);
|
||||||
|
|
||||||
if (state_tree && (child = find_named_node (*state_tree->root(), "LTC-Out")) != 0) {
|
|
||||||
_ltc_output->set_state (*(child->children().front()), Stateful::loading_state_version);
|
|
||||||
} else {
|
|
||||||
{
|
|
||||||
Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
|
|
||||||
_ltc_output->ensure_io (ChanCount (DataType::AUDIO, 1), true, this);
|
|
||||||
}
|
|
||||||
reconnect_ltc_output ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fix up names of LTC ports because we don't want the normal
|
|
||||||
* IO style of NAME/TYPE-{in,out}N
|
|
||||||
*/
|
|
||||||
|
|
||||||
_ltc_input->nth (0)->set_name (_("LTC-in"));
|
|
||||||
_ltc_output->nth (0)->set_name (_("LTC-out"));
|
|
||||||
|
|
||||||
_click_io.reset (new ClickIO (*this, "click"));
|
|
||||||
_click_gain.reset (new Amp (*this));
|
|
||||||
_click_gain->activate ();
|
|
||||||
|
|
||||||
if (state_tree && (child = find_named_node (*state_tree->root(), "Click")) != 0) {
|
|
||||||
|
|
||||||
/* existing state for Click */
|
|
||||||
int c = 0;
|
|
||||||
|
|
||||||
if (Stateful::loading_state_version < 3000) {
|
|
||||||
c = _click_io->set_state_2X (*child->children().front(), Stateful::loading_state_version, false);
|
|
||||||
} else {
|
|
||||||
const XMLNodeList& children (child->children());
|
|
||||||
XMLNodeList::const_iterator i = children.begin();
|
|
||||||
if ((c = _click_io->set_state (**i, Stateful::loading_state_version)) == 0) {
|
|
||||||
++i;
|
|
||||||
if (i != children.end()) {
|
|
||||||
c = _click_gain->set_state (**i, Stateful::loading_state_version);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (c == 0) {
|
if (c == 0) {
|
||||||
_clicking = Config->get_clicking ();
|
_clicking = Config->get_clicking ();
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
error << _("could not setup Click I/O") << endmsg;
|
|
||||||
_clicking = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* default state for Click: dual-mono to first 2 physical outputs */
|
error << _("could not setup Click I/O") << endmsg;
|
||||||
|
_clicking = false;
|
||||||
|
}
|
||||||
|
|
||||||
vector<string> outs;
|
|
||||||
_engine.get_physical_outputs (DataType::AUDIO, outs);
|
|
||||||
|
|
||||||
for (uint32_t physport = 0; physport < 2; ++physport) {
|
} else {
|
||||||
if (outs.size() > physport) {
|
|
||||||
if (_click_io->add_port (outs[physport], this)) {
|
/* default state for Click: dual-mono to first 2 physical outputs */
|
||||||
// relax, even though its an error
|
|
||||||
}
|
vector<string> outs;
|
||||||
|
_engine.get_physical_outputs (DataType::AUDIO, outs);
|
||||||
|
|
||||||
|
for (uint32_t physport = 0; physport < 2; ++physport) {
|
||||||
|
if (outs.size() > physport) {
|
||||||
|
if (_click_io->add_port (outs[physport], this)) {
|
||||||
|
// relax, even though its an error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_click_io->n_ports () > ChanCount::ZERO) {
|
if (_click_io->n_ports () > ChanCount::ZERO) {
|
||||||
_clicking = Config->get_clicking ();
|
_clicking = Config->get_clicking ();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
catch (failed_constructor& err) {
|
void
|
||||||
error << _("cannot setup Click I/O") << endmsg;
|
Session::setup_bundles ()
|
||||||
}
|
{
|
||||||
|
|
||||||
BootMessage (_("Compute I/O Latencies"));
|
|
||||||
|
|
||||||
if (_clicking) {
|
|
||||||
// XXX HOW TO ALERT UI TO THIS ? DO WE NEED TO?
|
|
||||||
}
|
|
||||||
|
|
||||||
BootMessage (_("Set up standard connections"));
|
|
||||||
|
|
||||||
vector<string> inputs[DataType::num_types];
|
vector<string> inputs[DataType::num_types];
|
||||||
vector<string> outputs[DataType::num_types];
|
vector<string> outputs[DataType::num_types];
|
||||||
for (uint32_t i = 0; i < DataType::num_types; ++i) {
|
for (uint32_t i = 0; i < DataType::num_types; ++i) {
|
||||||
@ -624,6 +653,37 @@ Session::when_engine_running ()
|
|||||||
add_bundle (c);
|
add_bundle (c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Session::when_engine_running ()
|
||||||
|
{
|
||||||
|
/* every time we reconnect, recompute worst case output latencies */
|
||||||
|
|
||||||
|
_engine.Running.connect_same_thread (*this, boost::bind (&Session::initialize_latencies, this));
|
||||||
|
|
||||||
|
if (synced_to_jack()) {
|
||||||
|
_engine.transport_stop ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.get_jack_time_master()) {
|
||||||
|
_engine.transport_locate (_transport_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
BootMessage (_("Set up LTC"));
|
||||||
|
setup_ltc ();
|
||||||
|
BootMessage (_("Set up Click"));
|
||||||
|
setup_click ();
|
||||||
|
BootMessage (_("Set up standard connections"));
|
||||||
|
setup_bundles ();
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (failed_constructor& err) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
BootMessage (_("Setup signal flow and plugins"));
|
BootMessage (_("Setup signal flow and plugins"));
|
||||||
|
|
||||||
/* Reset all panners */
|
/* Reset all panners */
|
||||||
@ -672,6 +732,8 @@ Session::when_engine_running ()
|
|||||||
BootMessage (_("Connect to engine"));
|
BootMessage (_("Connect to engine"));
|
||||||
_engine.set_session (this);
|
_engine.set_session (this);
|
||||||
_engine.reset_timebase ();
|
_engine.reset_timebase ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -125,10 +125,35 @@ using namespace std;
|
|||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
|
|
||||||
/** @param snapshot_name Snapshot name, without the .ardour prefix */
|
|
||||||
void
|
void
|
||||||
Session::first_stage_init (string fullpath, string /*snapshot_name*/)
|
Session::pre_engine_init (string fullpath)
|
||||||
{
|
{
|
||||||
|
if (fullpath.empty()) {
|
||||||
|
destroy ();
|
||||||
|
throw failed_constructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* discover canonical fullpath */
|
||||||
|
|
||||||
|
char buf[PATH_MAX+1];
|
||||||
|
if (!realpath (fullpath.c_str(), buf) && (errno != ENOENT)) {
|
||||||
|
error << string_compose(_("Could not use path %1 (%2)"), buf, strerror(errno)) << endmsg;
|
||||||
|
destroy ();
|
||||||
|
throw failed_constructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
_path = string(buf);
|
||||||
|
|
||||||
|
/* we require _path to end with a dir separator */
|
||||||
|
|
||||||
|
if (_path[_path.length()-1] != G_DIR_SEPARATOR) {
|
||||||
|
_path += G_DIR_SEPARATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* is it new ? */
|
||||||
|
|
||||||
|
_is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
|
||||||
|
|
||||||
/* finish initialization that can't be done in a normal C++ constructor
|
/* finish initialization that can't be done in a normal C++ constructor
|
||||||
definition.
|
definition.
|
||||||
*/
|
*/
|
||||||
@ -168,32 +193,6 @@ Session::first_stage_init (string fullpath, string /*snapshot_name*/)
|
|||||||
boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
|
boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
|
||||||
add_controllable (_solo_cut_control);
|
add_controllable (_solo_cut_control);
|
||||||
|
|
||||||
/* discover canonical fullpath */
|
|
||||||
|
|
||||||
if (fullpath.length() == 0) {
|
|
||||||
destroy ();
|
|
||||||
throw failed_constructor();
|
|
||||||
}
|
|
||||||
|
|
||||||
char buf[PATH_MAX+1];
|
|
||||||
if (!realpath (fullpath.c_str(), buf) && (errno != ENOENT)) {
|
|
||||||
error << string_compose(_("Could not use path %1 (%2)"), buf, strerror(errno)) << endmsg;
|
|
||||||
destroy ();
|
|
||||||
throw failed_constructor();
|
|
||||||
}
|
|
||||||
|
|
||||||
_path = string(buf);
|
|
||||||
|
|
||||||
/* we require _path to end with a dir separator */
|
|
||||||
|
|
||||||
if (_path[_path.length()-1] != G_DIR_SEPARATOR) {
|
|
||||||
_path += G_DIR_SEPARATOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* is it new ? */
|
|
||||||
|
|
||||||
_is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
|
|
||||||
|
|
||||||
/* These are all static "per-class" signals */
|
/* These are all static "per-class" signals */
|
||||||
|
|
||||||
SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
|
SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
|
||||||
@ -207,95 +206,90 @@ Session::first_stage_init (string fullpath, string /*snapshot_name*/)
|
|||||||
Delivery::disable_panners ();
|
Delivery::disable_panners ();
|
||||||
IO::disable_connecting ();
|
IO::disable_connecting ();
|
||||||
|
|
||||||
/* ENGINE */
|
AudioFileSource::set_peak_dir (_session_dir->peak_path());
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Session::post_engine_init ()
|
||||||
|
{
|
||||||
|
BootMessage (_("Set block size and sample rate"));
|
||||||
|
|
||||||
|
set_block_size (_engine.samples_per_cycle());
|
||||||
|
set_frame_rate (_engine.sample_rate());
|
||||||
|
|
||||||
n_physical_outputs = _engine.n_physical_outputs ();
|
n_physical_outputs = _engine.n_physical_outputs ();
|
||||||
n_physical_inputs = _engine.n_physical_inputs ();
|
n_physical_inputs = _engine.n_physical_inputs ();
|
||||||
|
|
||||||
_current_frame_rate = _engine.sample_rate ();
|
BootMessage (_("Using configuration"));
|
||||||
_nominal_frame_rate = _current_frame_rate;
|
|
||||||
_base_frame_rate = _current_frame_rate;
|
|
||||||
|
|
||||||
_midi_ports = new MidiPortManager;
|
_midi_ports = new MidiPortManager;
|
||||||
_mmc = new MIDI::MachineControl;
|
setup_midi_machine_control ();
|
||||||
|
|
||||||
_mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
|
|
||||||
|
|
||||||
_tempo_map = new TempoMap (_current_frame_rate);
|
|
||||||
_tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
|
|
||||||
|
|
||||||
AudioDiskstream::allocate_working_buffers();
|
|
||||||
|
|
||||||
SndFileSource::setup_standard_crossfades (*this, frame_rate());
|
|
||||||
_engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
|
|
||||||
|
|
||||||
refresh_disk_space ();
|
|
||||||
sync_time_vars ();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Session::second_stage_init ()
|
|
||||||
{
|
|
||||||
AudioFileSource::set_peak_dir (_session_dir->peak_path());
|
|
||||||
|
|
||||||
if (_butler->start_thread()) {
|
if (_butler->start_thread()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start_midi_thread ()) {
|
if (start_midi_thread ()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_midi_machine_control ();
|
|
||||||
|
|
||||||
// set_state() will call setup_raid_path(), but if it's a new session we need
|
|
||||||
// to call setup_raid_path() here.
|
|
||||||
|
|
||||||
if (state_tree) {
|
|
||||||
if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setup_raid_path(_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we can't save till after ::when_engine_running() is called,
|
|
||||||
because otherwise we save state with no connections made.
|
|
||||||
therefore, we reset _state_of_the_state because ::set_state()
|
|
||||||
will have cleared it.
|
|
||||||
|
|
||||||
we also have to include Loading so that any events that get
|
|
||||||
generated between here and the end of ::when_engine_running()
|
|
||||||
will be processed directly rather than queued.
|
|
||||||
*/
|
|
||||||
|
|
||||||
_state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave|Loading);
|
|
||||||
|
|
||||||
_locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
|
|
||||||
_locations->added.connect_same_thread (*this, boost::bind (&Session::locations_added, this, _1));
|
|
||||||
setup_click_sounds (0);
|
setup_click_sounds (0);
|
||||||
setup_midi_control ();
|
setup_midi_control ();
|
||||||
|
|
||||||
/* Pay attention ... */
|
|
||||||
|
|
||||||
_engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
|
_engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
|
||||||
_engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
|
_engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
|
||||||
|
|
||||||
midi_clock = new MidiClockTicker ();
|
|
||||||
midi_clock->set_session (this);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
/* tempo map requires sample rate knowledge */
|
||||||
|
|
||||||
|
_tempo_map = new TempoMap (_current_frame_rate);
|
||||||
|
_tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
|
||||||
|
|
||||||
|
/* MidiClock requires a tempo map */
|
||||||
|
|
||||||
|
midi_clock = new MidiClockTicker ();
|
||||||
|
midi_clock->set_session (this);
|
||||||
|
|
||||||
|
/* crossfades require sample rate knowledge */
|
||||||
|
|
||||||
|
SndFileSource::setup_standard_crossfades (*this, frame_rate());
|
||||||
|
_engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
|
||||||
|
|
||||||
|
AudioDiskstream::allocate_working_buffers();
|
||||||
|
refresh_disk_space ();
|
||||||
|
|
||||||
|
/* we're finally ready to call set_state() ... all objects have
|
||||||
|
* been created, the engine is running.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (state_tree) {
|
||||||
|
if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// set_state() will call setup_raid_path(), but if it's a new session we need
|
||||||
|
// to call setup_raid_path() here.
|
||||||
|
setup_raid_path (_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ENGINE */
|
||||||
|
|
||||||
|
boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
|
||||||
|
boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
|
||||||
|
|
||||||
|
Config->map_parameters (ff);
|
||||||
|
config.map_parameters (ft);
|
||||||
|
|
||||||
when_engine_running ();
|
when_engine_running ();
|
||||||
}
|
|
||||||
|
|
||||||
/* handle this one in a different way than all others, so that its clear what happened */
|
_locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
|
||||||
|
_locations->added.connect_same_thread (*this, boost::bind (&Session::locations_added, this, _1));
|
||||||
catch (AudioEngine::PortRegistrationFailure& err) {
|
|
||||||
|
} catch (AudioEngine::PortRegistrationFailure& err) {
|
||||||
|
/* handle this one in a different way than all others, so that its clear what happened */
|
||||||
error << err.what() << endmsg;
|
error << err.what() << endmsg;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} catch (...) {
|
||||||
|
|
||||||
catch (...) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3516,6 +3510,9 @@ Session::load_diskstreams_2X (XMLNode const & node, int)
|
|||||||
void
|
void
|
||||||
Session::setup_midi_machine_control ()
|
Session::setup_midi_machine_control ()
|
||||||
{
|
{
|
||||||
|
_mmc = new MIDI::MachineControl;
|
||||||
|
_mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
|
||||||
|
|
||||||
_mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
|
_mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
|
||||||
_mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
|
_mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
|
||||||
_mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
|
_mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
|
||||||
|
Loading…
Reference in New Issue
Block a user