summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
authorHans Baier <hansfbaier@googlemail.com>2008-08-04 22:37:24 +0000
committerHans Baier <hansfbaier@googlemail.com>2008-08-04 22:37:24 +0000
commited990de6040215412baf8f448b1876d78bd9cc19 (patch)
tree196c6552040b0ad1c9c402cba2b4543ae39536ef /libs/ardour
parent44fd104ada0fbd8b76d34150e941d85d6de6f81b (diff)
* first implementation of MIDI Clock Slave support
git-svn-id: svn://localhost/ardour2/branches/3.0@3652 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/SConscript1
-rw-r--r--libs/ardour/ardour/ardour.h7
-rw-r--r--libs/ardour/ardour/configuration_vars.h6
-rw-r--r--libs/ardour/ardour/session.h188
-rw-r--r--libs/ardour/ardour/slave.h92
-rw-r--r--libs/ardour/ardour/types.h45
-rw-r--r--libs/ardour/enums.cc35
-rw-r--r--libs/ardour/globals.cc75
-rw-r--r--libs/ardour/session.cc664
-rw-r--r--libs/ardour/session_midi.cc221
-rw-r--r--libs/ardour/session_transport.cc210
-rw-r--r--libs/ardour/utils.cc65
12 files changed, 894 insertions, 715 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index b50aecbcb3..44f4718384 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -92,6 +92,7 @@ midi_stretch.cc
midi_track.cc
mix.cc
mtc_slave.cc
+midi_clock_slave.cc
named_selection.cc
note.cc
panner.cc
diff --git a/libs/ardour/ardour/ardour.h b/libs/ardour/ardour/ardour.h
index 6f653f10bf..fecd0fcf4e 100644
--- a/libs/ardour/ardour/ardour.h
+++ b/libs/ardour/ardour/ardour.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1999 Paul Davis
+ Copyright (C) 1999 Paul Davis
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
@@ -51,9 +51,9 @@ namespace ARDOUR {
int cleanup ();
std::string get_ardour_revision ();
-
+
void find_bindings_files (std::map<std::string,std::string>&);
-
+
const layer_t max_layer = UCHAR_MAX;
microseconds_t get_microseconds ();
@@ -82,6 +82,7 @@ namespace ARDOUR {
extern MIDI::Port* default_mmc_port;
extern MIDI::Port* default_mtc_port;
extern MIDI::Port* default_midi_port;
+extern MIDI::Port *default_midi_clock_port;
#endif /* __ardour_ardour_h__ */
diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h
index 4e2a14c07b..7a7a2ce419 100644
--- a/libs/ardour/ardour/configuration_vars.h
+++ b/libs/ardour/ardour/configuration_vars.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000-2007 Paul Davis
+ Copyright (C) 2000-2007 Paul Davis
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
@@ -30,11 +30,13 @@ CONFIG_VARIABLE (std::string, auditioner_output_right, "auditioner-output-right"
CONFIG_VARIABLE (std::string, mtc_port_name, "mtc-port-name", "default")
CONFIG_VARIABLE (std::string, mmc_port_name, "mmc-port-name", "default")
CONFIG_VARIABLE (std::string, midi_port_name, "midi-port-name", "default")
+CONFIG_VARIABLE (std::string, midi_clock_port_name, "midi-clock-port-name", "default")
CONFIG_VARIABLE (bool, trace_midi_input, "trace-midi-input", false)
CONFIG_VARIABLE (bool, trace_midi_output, "trace-midi-output", false)
CONFIG_VARIABLE (bool, send_mtc, "send-mtc", false)
CONFIG_VARIABLE (bool, send_mmc, "send-mmc", true)
CONFIG_VARIABLE (bool, mmc_control, "mmc-control", true)
+CONFIG_VARIABLE (bool, midi_clock_control, "midi-clock-control", false)
CONFIG_VARIABLE (bool, midi_feedback, "midi-feedback", false)
CONFIG_VARIABLE (uint8_t, mmc_receive_device_id, "mmc-receive-device-id", 0)
CONFIG_VARIABLE (uint8_t, mmc_send_device_id, "mmc-send-device-id", 0)
@@ -139,7 +141,7 @@ CONFIG_VARIABLE (nframes_t, over_length_short, "over-length-short", 2)
CONFIG_VARIABLE (nframes_t, over_length_long, "over-length-long", 10)
/* miscellany */
-
+
CONFIG_VARIABLE (bool, hiding_groups_deactivates_groups, "hiding-groups-deactivates-groups", true)
CONFIG_VARIABLE (bool, verify_remove_last_capture, "verify-remove-last-capture", true)
CONFIG_VARIABLE (bool, no_new_session_dialog, "no-new-session-dialog", false)
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index b718d751b4..00cbc9922e 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000 Paul Davis
+ Copyright (C) 2000 Paul Davis
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
@@ -46,8 +46,8 @@
#include <midi++/types.h>
#include <midi++/mmc.h>
-#include <pbd/stateful.h>
-#include <pbd/destructible.h>
+#include <pbd/stateful.h>
+#include <pbd/destructible.h>
#include <ardour/ardour.h>
#include <ardour/configuration.h>
@@ -150,7 +150,7 @@ class Session : public PBD::StatefulDestructible
InputConfigurationChange,
SetAudioRange,
SetPlayRange,
-
+
/* only one of each of these events
can be queued at any one time
*/
@@ -165,7 +165,7 @@ class Session : public PBD::StatefulDestructible
Replace,
Clear
};
-
+
Type type;
Action action;
nframes_t action_frame;
@@ -186,14 +186,14 @@ class Session : public PBD::StatefulDestructible
list<MusicRange> music_range;
Event(Type t, Action a, nframes_t when, nframes_t where, float spd, bool yn = false)
- : type (t),
+ : type (t),
action (a),
action_frame (when),
target_frame (where),
speed (spd),
yes_or_no (yn) {}
- void set_ptr (void* p) {
+ void set_ptr (void* p) {
ptr = p;
}
@@ -242,7 +242,7 @@ class Session : public PBD::StatefulDestructible
uint32_t n_physical_in,
uint32_t n_physical_out,
nframes_t initial_length);
-
+
virtual ~Session ();
string path() const { return _path; }
@@ -265,20 +265,20 @@ class Session : public PBD::StatefulDestructible
static sigc::signal<void> AutoBindingOff;
static sigc::signal<void,std::string> Dialog;
-
+
std::string sound_dir (bool with_path = true) const;
std::string peak_dir () const;
std::string dead_sound_dir () const;
std::string automation_dir () const;
std::string analysis_dir() const;
-
+
int ensure_subdirs ();
Glib::ustring peak_path (Glib::ustring) const;
static string change_audio_path_by_name (string oldpath, string oldname, string newname, bool destructive);
static string change_midi_path_by_name (string oldpath, string oldname, string newname, bool destructive);
-
+
string peak_path_from_audio_path (string) const;
string audio_path_from_name (string, uint32_t nchans, uint32_t chan, bool destructive);
string midi_path_from_name (string);
@@ -288,7 +288,7 @@ class Session : public PBD::StatefulDestructible
BufferSet& get_silent_buffers (ChanCount count = ChanCount::ZERO);
BufferSet& get_scratch_buffers (ChanCount count = ChanCount::ZERO);
BufferSet& get_mix_buffers (ChanCount count = ChanCount::ZERO);
-
+
void add_diskstream (boost::shared_ptr<Diskstream>);
boost::shared_ptr<Diskstream> diskstream_by_id (const PBD::ID& id);
boost::shared_ptr<Diskstream> diskstream_by_name (string name);
@@ -298,17 +298,17 @@ class Session : public PBD::StatefulDestructible
void refill_all_diskstream_buffers ();
uint32_t audio_diskstream_buffer_size() const { return audio_dstream_buffer_size; }
uint32_t midi_diskstream_buffer_size() const { return midi_dstream_buffer_size; }
-
+
uint32_t get_next_diskstream_id() const { return n_diskstreams(); }
uint32_t n_diskstreams() const;
-
+
typedef std::list<boost::shared_ptr<Diskstream> > DiskstreamList;
- typedef std::list<boost::shared_ptr<Route> > RouteList;
-
+ typedef std::list<boost::shared_ptr<Route> > RouteList;
+
boost::shared_ptr<RouteList> get_routes() const {
return routes.reader ();
}
-
+
uint32_t nroutes() const { return routes.reader()->size(); }
uint32_t ntracks () const;
uint32_t nbusses () const;
@@ -316,7 +316,7 @@ class Session : public PBD::StatefulDestructible
struct RoutePublicOrderSorter {
bool operator() (boost::shared_ptr<Route>, boost::shared_ptr<Route> b);
};
-
+
template<class T> void foreach_route (T *obj, void (T::*func)(Route&));
template<class T> void foreach_route (T *obj, void (T::*func)(boost::shared_ptr<Route>));
template<class T, class A> void foreach_route (T *obj, void (T::*func)(Route&, A), A arg);
@@ -327,7 +327,7 @@ class Session : public PBD::StatefulDestructible
bool route_name_unique (string) const;
- bool get_record_enabled() const {
+ bool get_record_enabled() const {
return (record_status () >= Enabled);
}
@@ -343,7 +343,7 @@ class Session : public PBD::StatefulDestructible
void maybe_enable_record ();
void disable_record (bool rt_context, bool force = false);
void step_back_from_record ();
-
+
void maybe_write_autosave ();
/* Proxy signal for region hidden changes */
@@ -351,9 +351,9 @@ class Session : public PBD::StatefulDestructible
sigc::signal<void,boost::shared_ptr<Region> > RegionHiddenChange;
/* Emitted when all i/o connections are complete */
-
+
sigc::signal<void> IOConnectionsComplete;
-
+
/* Record status signals */
sigc::signal<void> RecordStateChanged;
@@ -442,10 +442,10 @@ class Session : public PBD::StatefulDestructible
void remove_state (string snapshot_name);
void rename_state (string old_name, string new_name);
void remove_pending_capture_state ();
-
+
sigc::signal<void,string> StateSaved;
sigc::signal<void> StateReady;
-
+
vector<string*>* possible_states() const;
static vector<string*>* possible_states(string path);
@@ -499,14 +499,14 @@ class Session : public PBD::StatefulDestructible
std::list<boost::shared_ptr<AudioTrack> > new_audio_track (int input_channels, int output_channels, TrackMode mode = Normal, uint32_t how_many = 1);
RouteList new_audio_route (int input_channels, int output_channels, uint32_t how_many);
-
+
std::list<boost::shared_ptr<MidiTrack> > new_midi_track (TrackMode mode = Normal, uint32_t how_many = 1);
//boost::shared_ptr<Route> new_midi_route (uint32_t how_many = 1);
void remove_route (boost::shared_ptr<Route>);
void resort_routes ();
void resort_routes_using (boost::shared_ptr<RouteList>);
-
+
void set_remote_control_ids();
AudioEngine & engine() { return _engine; }
@@ -563,18 +563,18 @@ class Session : public PBD::StatefulDestructible
float transport_speed() const { return _transport_speed; }
bool transport_stopped() const { return _transport_speed == 0.0f; }
bool transport_rolling() const { return _transport_speed != 0.0f; }
-
+
void set_silent (bool yn);
bool silent () { return _silent; }
int jack_slave_sync (nframes_t);
TempoMap& tempo_map() { return *_tempo_map; }
-
+
/* region info */
void add_regions (std::vector<boost::shared_ptr<Region> >&);
-
+
sigc::signal<void,boost::weak_ptr<Region> > RegionAdded;
sigc::signal<void,std::vector<boost::weak_ptr<Region> >& > RegionsAdded;
sigc::signal<void,boost::weak_ptr<Region> > RegionRemoved;
@@ -584,7 +584,7 @@ class Session : public PBD::StatefulDestructible
string path_from_region_name (DataType type, string name, string identifier);
boost::shared_ptr<Region> find_whole_file_parent (boost::shared_ptr<Region const>);
-
+
void find_equivalent_playlist_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >& result);
boost::shared_ptr<Region> XMLRegionFactory (const XMLNode&, bool full);
@@ -597,16 +597,16 @@ class Session : public PBD::StatefulDestructible
struct import_status : public InterThreadInfo {
string doing_what;
-
+
/* control info */
SrcQuality quality;
volatile bool freeze;
std::vector<Glib::ustring> paths;
bool replace_existing_source;
-
+
/* result */
SourceList sources;
-
+
};
void import_audiofiles (import_status&);
@@ -640,7 +640,7 @@ class Session : public PBD::StatefulDestructible
"yes, delete this playlist" and 1 for "no, don't delete
this playlist.
*/
-
+
sigc::signal<int,boost::shared_ptr<ARDOUR::Playlist> > AskAboutPlaylistDeletion;
/* handlers should return 0 for "ignore the rate mismatch"
@@ -654,7 +654,7 @@ class Session : public PBD::StatefulDestructible
*/
static sigc::signal<int> AskAboutPendingState;
-
+
boost::shared_ptr<AudioFileSource> create_audio_source_for_session (ARDOUR::AudioDiskstream&, uint32_t which_channel, bool destructive);
boost::shared_ptr<MidiSource> create_midi_source_for_session (ARDOUR::MidiDiskstream&);
@@ -687,7 +687,7 @@ class Session : public PBD::StatefulDestructible
/* Curves and AutomationLists (TODO when they go away) */
void add_curve(Curve*);
void add_automation_list(AutomationList*);
-
+
/* fade curves */
float get_default_fade_length () const { return default_fade_msecs; }
@@ -701,7 +701,7 @@ class Session : public PBD::StatefulDestructible
void audition_region (boost::shared_ptr<Region>);
void cancel_audition ();
bool is_auditioning () const;
-
+
sigc::signal<void,bool> AuditionActive;
/* flattening stuff */
@@ -712,7 +712,7 @@ class Session : public PBD::StatefulDestructible
int freeze (InterThreadInfo&);
/* session-wide solo/mute/rec-enable */
-
+
bool soloing() const { return currently_soloing; }
void set_all_solo (bool);
@@ -720,7 +720,7 @@ class Session : public PBD::StatefulDestructible
sigc::signal<void,bool> SoloActive;
sigc::signal<void> SoloChanged;
-
+
void record_disenable_all ();
void record_enable_all ();
@@ -730,15 +730,15 @@ class Session : public PBD::StatefulDestructible
boost::shared_ptr<IO> master_out() const { return _master_out; }
/* insert/send management */
-
+
uint32_t n_port_inserts() const { return _port_inserts.size(); }
uint32_t n_plugin_inserts() const { return _plugin_inserts.size(); }
uint32_t n_sends() const { return _sends.size(); }
-
- static void set_disable_all_loaded_plugins (bool yn) {
+
+ static void set_disable_all_loaded_plugins (bool yn) {
_disable_all_loaded_plugins = yn;
}
- static bool get_disable_all_loaded_plugins() {
+ static bool get_disable_all_loaded_plugins() {
return _disable_all_loaded_plugins;
}
@@ -748,7 +748,7 @@ class Session : public PBD::StatefulDestructible
void mark_insert_id (uint32_t);
/* s/w "RAID" management */
-
+
nframes_t available_capture_duration();
/* I/O bundles */
@@ -767,23 +767,26 @@ class Session : public PBD::StatefulDestructible
int set_mtc_port (string port_tag);
int set_mmc_port (string port_tag);
int set_midi_port (string port_tag);
+ int set_midi_clock_port (string port_tag);
MIDI::Port *mtc_port() const { return _mtc_port; }
MIDI::Port *mmc_port() const { return _mmc_port; }
MIDI::Port *midi_port() const { return _midi_port; }
+ MIDI::Port *midi_clock_port() const { return _midi_clock_port; }
sigc::signal<void> MTC_PortChanged;
sigc::signal<void> MMC_PortChanged;
sigc::signal<void> MIDI_PortChanged;
+ sigc::signal<void> MIDIClock_PortChanged;
void set_trace_midi_input (bool, MIDI::Port* port = 0);
void set_trace_midi_output (bool, MIDI::Port* port = 0);
bool get_trace_midi_input(MIDI::Port *port = 0);
bool get_trace_midi_output(MIDI::Port *port = 0);
-
+
void set_mmc_receive_device_id (uint32_t id);
void set_mmc_send_device_id (uint32_t id);
-
+
/* Scrubbing */
void start_scrub (nframes_t where);
@@ -806,7 +809,7 @@ class Session : public PBD::StatefulDestructible
}
UndoHistory& history() { return _history; }
-
+
uint32_t undo_depth() const { return _history.undo_depth(); }
uint32_t redo_depth() const { return _history.redo_depth(); }
string next_undo() const { return _history.next_undo(); }
@@ -839,7 +842,7 @@ class Session : public PBD::StatefulDestructible
GlobalRouteBooleanState before, after;
Session& sess;
void* src;
-
+
};
class GlobalSoloStateCommand : public GlobalRouteStateCommand
@@ -896,7 +899,7 @@ class Session : public PBD::StatefulDestructible
/* clicking */
boost::shared_ptr<IO> click_io() { return _click_io; }
-
+
/* disk, buffer loads */
uint32_t playback_load ();
@@ -906,7 +909,7 @@ class Session : public PBD::StatefulDestructible
void reset_playback_load_min ();
void reset_capture_load_min ();
-
+
float read_data_rate () const;
float write_data_rate () const;
@@ -929,7 +932,7 @@ class Session : public PBD::StatefulDestructible
TransportContext,
ExportContext
};
-
+
/* VST support */
static long vst_callback (AEffect* effect,
@@ -938,7 +941,7 @@ class Session : public PBD::StatefulDestructible
long value,
void* ptr,
float opt);
-
+
typedef float (*compute_peak_t) (Sample *, nframes_t, float);
typedef void (*find_peaks_t) (Sample *, nframes_t, float *, float*);
typedef void (*apply_gain_to_buffer_t) (Sample *, nframes_t, float);
@@ -974,11 +977,11 @@ class Session : public PBD::StatefulDestructible
friend class Route;
void schedule_curve_reallocation ();
void update_latency_compensation (bool, bool);
-
+
private:
int create (bool& new_session, const string& mix_template, nframes_t initial_length);
void destroy ();
-
+
nframes_t compute_initial_length ();
enum SubState {
@@ -995,7 +998,7 @@ class Session : public PBD::StatefulDestructible
*/
typedef void (Session::*process_function_type)(nframes_t);
-
+
AudioEngine& _engine;
mutable gint processing_prohibited;
process_function_type process_function;
@@ -1039,13 +1042,13 @@ class Session : public PBD::StatefulDestructible
void update_latency_compensation_proxy (void* ignored);
void ensure_buffers (ChanCount howmany);
-
+
void process_scrub (nframes_t);
void process_without_events (nframes_t);
void process_with_events (nframes_t);
void process_audition (nframes_t);
int process_export (nframes_t, ARDOUR::ExportSpecification*);
-
+
/* slave tracking */
static const int delta_accumulator_size = 25;
@@ -1054,13 +1057,13 @@ class Session : public PBD::StatefulDestructible
long average_slave_delta;
int average_dir;
bool have_first_delta_accumulator;
-
+
enum SlaveState {
Stopped,
Waiting,
Running
};
-
+
SlaveState slave_state;
nframes_t slave_wait_end;
@@ -1116,6 +1119,7 @@ class Session : public PBD::StatefulDestructible
MIDI::Port* _mmc_port;
MIDI::Port* _mtc_port;
MIDI::Port* _midi_port;
+ MIDI::Port* _midi_clock_port;
string _path;
string _name;
bool session_send_mmc;
@@ -1153,7 +1157,7 @@ class Session : public PBD::StatefulDestructible
bool pending_locate_flush;
bool pending_abort;
bool pending_auto_loop;
-
+
Sample* butler_mixdown_buffer;
float* butler_gain_buffer;
pthread_t butler_thread;
@@ -1164,7 +1168,7 @@ class Session : public PBD::StatefulDestructible
int butler_request_pipe[2];
inline bool transport_work_requested() const { return g_atomic_int_get(&butler_should_do_transport_work); }
-
+
struct ButlerRequest {
enum Type {
Wake,
@@ -1191,8 +1195,8 @@ class Session : public PBD::StatefulDestructible
PostTransportInputChange = 0x20000,
PostTransportCurveRealloc = 0x40000
};
-
- static const PostTransportWork ProcessCannotProceedMask =
+
+ static const PostTransportWork ProcessCannotProceedMask =
PostTransportWork (PostTransportInputChange|
PostTransportSpeed|
PostTransportReverse|
@@ -1201,7 +1205,7 @@ class Session : public PBD::StatefulDestructible
PostTransportAudition|
PostTransportLocate|
PostTransportStop);
-
+
PostTransportWork post_transport_work;
void summon_butler ();
@@ -1264,7 +1268,7 @@ class Session : public PBD::StatefulDestructible
int midi_read (MIDI::Port *);
void enable_record ();
-
+
void increment_transport_position (uint32_t val) {
if (max_frames - val < _transport_frame) {
_transport_frame = max_frames;
@@ -1297,6 +1301,10 @@ class Session : public PBD::StatefulDestructible
void spp_continue (MIDI::Parser&);
void spp_stop (MIDI::Parser&);
+ void midi_clock_start (MIDI::Parser&);
+ void midi_clock_continue (MIDI::Parser&);
+ void midi_clock_stop (MIDI::Parser&);
+
void mmc_deferred_play (MIDI::MachineControl &);
void mmc_stop (MIDI::MachineControl &);
void mmc_step (MIDI::MachineControl &, int);
@@ -1327,7 +1335,7 @@ class Session : public PBD::StatefulDestructible
nframes_t outbound_mtc_smpte_frame;
SMPTE::Time transmitting_smpte_time;
int next_quarter_frame_to_send;
-
+
double _frames_per_smpte_frame; /* has to be floating point because of drop frame */
nframes_t _frames_per_hour;
nframes_t _smpte_frames_per_hour;
@@ -1339,28 +1347,28 @@ class Session : public PBD::StatefulDestructible
bool last_smpte_valid;
nframes_t last_smpte_when;
SMPTE::Time last_smpte;
-
+
bool _send_smpte_update; ///< Flag to send a full frame (SMPTE) MTC message this cycle
int send_full_time_code(nframes_t nframes);
int send_midi_time_code_for_cycle(nframes_t nframes);
nframes_t adjust_apparent_position (nframes_t frames);
-
+
void reset_record_status ();
-
+
int no_roll (nframes_t nframes, nframes_t offset);
-
+
bool non_realtime_work_pending() const { return static_cast<bool>(post_transport_work); }
bool process_can_proceed() const { return !(post_transport_work & ProcessCannotProceedMask); }
struct MIDIRequest {
-
+
enum Type {
PortChange,
Quit
};
-
+
Type type;
MIDIRequest () {}
@@ -1419,7 +1427,7 @@ class Session : public PBD::StatefulDestructible
/* disk-streams */
- SerializedRCUManager<DiskstreamList> diskstreams;
+ SerializedRCUManager<DiskstreamList> diskstreams;
uint32_t audio_dstream_buffer_size;
uint32_t midi_dstream_buffer_size;
@@ -1439,7 +1447,7 @@ class Session : public PBD::StatefulDestructible
bool solo_update_disabled;
bool currently_soloing;
-
+
void route_mute_changed (void *src);
void route_solo_changed (void *src, boost::weak_ptr<Route>);
void catch_up_on_solo ();
@@ -1452,7 +1460,7 @@ class Session : public PBD::StatefulDestructible
mutable Glib::Mutex region_lock;
typedef map<PBD::ID,boost::shared_ptr<Region> > RegionList;
RegionList regions;
-
+
void add_region (boost::shared_ptr<Region>);
void region_changed (Change, boost::weak_ptr<Region>);
void remove_region (boost::weak_ptr<Region>);
@@ -1460,7 +1468,7 @@ class Session : public PBD::StatefulDestructible
int load_regions (const XMLNode& node);
/* SOURCES */
-
+
mutable Glib::Mutex source_lock;
typedef std::map<PBD::ID,boost::shared_ptr<Source> > SourceMap;
@@ -1468,7 +1476,7 @@ class Session : public PBD::StatefulDestructible
public:
SourceMap get_sources() { return sources; }
-
+
private:
@@ -1478,7 +1486,7 @@ class Session : public PBD::StatefulDestructible
boost::shared_ptr<Source> XMLSourceFactory (const XMLNode&);
/* PLAYLISTS */
-
+
mutable Glib::Mutex playlist_lock;
typedef set<boost::shared_ptr<Playlist> > PlaylistList;
PlaylistList playlists;
@@ -1529,7 +1537,7 @@ class Session : public PBD::StatefulDestructible
int flatten_one_track (AudioTrack&, nframes_t start, nframes_t cnt);
/* INSERT AND SEND MANAGEMENT */
-
+
list<PortInsert *> _port_inserts;
list<PluginInsert *> _plugin_inserts;
list<Send *> _sends;
@@ -1547,8 +1555,8 @@ class Session : public PBD::StatefulDestructible
struct space_and_path {
uint32_t blocks; /* 4kB blocks */
string path;
-
- space_and_path() {
+
+ space_and_path() {
blocks = 0;
}
};
@@ -1558,14 +1566,14 @@ class Session : public PBD::StatefulDestructible
return a.blocks > b.blocks;
}
};
-
+
void setup_raid_path (string path);
vector<space_and_path> session_dirs;
vector<space_and_path>::iterator last_rr_session_dir;
uint32_t _total_free_4k_blocks;
Glib::Mutex space_lock;
-
+
string get_best_session_directory_for_new_source ();
void refresh_disk_space ();
@@ -1612,9 +1620,9 @@ class Session : public PBD::StatefulDestructible
nframes_t offset;
const Sample *data;
- Click (nframes_t s, nframes_t d, const Sample *b)
+ Click (nframes_t s, nframes_t d, const Sample *b)
: start (s), duration (d), data (b) { offset = 0; }
-
+
void *operator new(size_t ignored) {
return pool.alloc ();
};
@@ -1626,7 +1634,7 @@ class Session : public PBD::StatefulDestructible
private:
static Pool pool;
};
-
+
typedef list<Click*> Clicks;
Clicks clicks;
@@ -1649,7 +1657,7 @@ class Session : public PBD::StatefulDestructible
void click (nframes_t start, nframes_t nframes, nframes_t offset);
vector<Route*> master_outs;
-
+
/* range playback */
list<AudioRange> current_audio_range;
@@ -1659,7 +1667,7 @@ class Session : public PBD::StatefulDestructible
/* main outs */
uint32_t main_outs;
-
+
boost::shared_ptr<IO> _master_out;
boost::shared_ptr<IO> _control_out;
@@ -1702,10 +1710,10 @@ class Session : public PBD::StatefulDestructible
void config_changed (const char*);
XMLNode& get_control_protocol_state ();
-
+
void set_history_depth (uint32_t depth);
void sync_order_keys ();
-
+
static bool _disable_all_loaded_plugins;
};
diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h
index 509f8fa9d2..9df8574430 100644
--- a/libs/ardour/ardour/slave.h
+++ b/libs/ardour/ardour/slave.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2002 Paul Davis
+ Copyright (C) 2002 Paul Davis
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
@@ -50,6 +50,18 @@ class Slave {
virtual bool is_always_synced() const { return false; }
};
+struct SafeTime {
+ int guard1;
+ nframes_t position;
+ nframes_t timestamp;
+ int guard2;
+
+ SafeTime() {
+ guard1 = 0;
+ guard2 = 0;
+ timestamp = 0;
+ }
+};
class MTC_Slave : public Slave, public sigc::trackable {
public:
@@ -59,9 +71,9 @@ class MTC_Slave : public Slave, public sigc::trackable {
void rebind (MIDI::Port&);
bool speed_and_position (float&, nframes_t&);
- bool locked() const;
- bool ok() const;
- void handle_locate (const MIDI::byte*);
+ bool locked() const;
+ bool ok() const;
+ void handle_locate (const MIDI::byte*);
nframes_t resolution() const;
bool requires_seekahead () const { return true; }
@@ -72,27 +84,11 @@ class MTC_Slave : public Slave, public sigc::trackable {
std::vector<sigc::connection> connections;
bool can_notify_on_unknown_rate;
- struct SafeTime {
-
-
- int guard1;
- //SMPTE_Time mtc;
- nframes_t position;
- nframes_t timestamp;
- int guard2;
-
- SafeTime() {
- guard1 = 0;
- guard2 = 0;
- timestamp = 0;
- }
- };
-
- SafeTime current;
+ SafeTime current;
nframes_t mtc_frame; /* current time */
nframes_t last_inbound_frame; /* when we got it; audio clocked */
- float mtc_speed;
+ float mtc_speed;
nframes_t first_mtc_frame;
nframes_t first_mtc_time;
@@ -108,12 +104,56 @@ class MTC_Slave : public Slave, public sigc::trackable {
void read_current (SafeTime *) const;
};
-class ADAT_Slave : public Slave
+class MIDIClock_Slave : public Slave, public sigc::trackable {
+ public:
+ MIDIClock_Slave (Session&, MIDI::Port&, int ppqn = 24);
+ ~MIDIClock_Slave ();
+
+ void rebind (MIDI::Port&);
+ bool speed_and_position (float&, nframes_t&);
+
+ bool locked() const;
+ bool ok() const;
+ bool starting() const { return _starting; }
+
+ nframes_t resolution() const;
+ bool requires_seekahead () const { return true; }
+
+ private:
+ Session& session;
+ MIDI::Port* port;
+ std::vector<sigc::connection> connections;
+
+ int ppqn;
+ double one_ppqn_in_frames;
+
+ SafeTime current;
+ nframes_t midi_clock_frame; /* current time */
+ nframes_t last_inbound_frame; /* when we got it; audio clocked */
+
+ float midi_clock_speed;
+ nframes_t first_midi_clock_frame;
+ nframes_t first_midi_clock_time;
+
+ static const int32_t accumulator_size = 128;
+ float accumulator[accumulator_size];
+ int32_t accumulator_index;
+ bool have_first_accumulated_speed;
+
+ void reset ();
+ void start (MIDI::Parser& parser);
+ void stop (MIDI::Parser& parser);
+ void update_midi_clock (MIDI::Parser& parser);
+ void read_current (SafeTime *) const;
+ bool _starting;
+};
+
+class ADAT_Slave : public Slave
{
public:
ADAT_Slave () {}
~ADAT_Slave () {}
-
+
bool speed_and_position (float& speed, nframes_t& pos) {
speed = 0;
pos = 0;
@@ -126,12 +166,12 @@ class ADAT_Slave : public Slave
bool requires_seekahead () const { return true; }
};
-class JACK_Slave : public Slave
+class JACK_Slave : public Slave
{
public:
JACK_Slave (jack_client_t*);
~JACK_Slave ();
-
+
bool speed_and_position (float& speed, nframes_t& pos);
bool starting() const { return _starting; }
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index 9bfd93cdbf..d94683f427 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2002 Paul Davis
+ Copyright (C) 2002 Paul Davis
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
@@ -41,7 +41,7 @@
typedef int intptr_t;
#endif
-/* eventually, we'd like everything (including JACK) to
+/* eventually, we'd like everything (including JACK) to
move to this. for now, its a dedicated type.
*/
@@ -69,7 +69,7 @@ namespace ARDOUR {
OverlapNone, // no overlap
OverlapInternal, // the overlap is 100% with the object
OverlapStart, // overlap covers start, but ends within
- OverlapEnd, // overlap begins within and covers end
+ OverlapEnd, // overlap begins within and covers end
OverlapExternal // overlap extends to (at least) begin+end
};
@@ -128,12 +128,12 @@ namespace ARDOUR {
Normal,
Destructive
};
-
+
enum NoteMode {
Sustained,
Percussive
};
-
+
enum ChannelMode {
AllChannels = 0, ///< Pass through all channel information unmodified
FilterChannels, ///< Ignore events on certain channels
@@ -144,7 +144,7 @@ namespace ARDOUR {
Frames,
Beats
};
-
+
struct BBT_Time {
uint32_t bars;
uint32_t beats;
@@ -157,12 +157,12 @@ namespace ARDOUR {
}
/* we can't define arithmetic operators for BBT_Time, because
- the results depend on a TempoMap, but we can define
+ the results depend on a TempoMap, but we can define
a useful check on the less-than condition.
*/
bool operator< (const BBT_Time& other) const {
- return bars < other.bars ||
+ return bars < other.bars ||
(bars == other.bars && beats < other.beats) ||
(bars == other.bars && beats == other.beats && ticks < other.ticks);
}
@@ -170,7 +170,7 @@ namespace ARDOUR {
bool operator== (const BBT_Time& other) const {
return bars == other.bars && beats == other.beats && ticks == other.ticks;
}
-
+
};
enum SmpteFormat {
smpte_23976,
@@ -198,7 +198,7 @@ namespace ARDOUR {
SMPTE::Time smpte;
BBT_Time bbt;
- union {
+ union {
nframes_t frames;
double seconds;
};
@@ -210,10 +210,10 @@ namespace ARDOUR {
nframes_t start;
nframes_t end;
uint32_t id;
-
+
AudioRange (nframes_t s, nframes_t e, uint32_t i) : start (s), end (e) , id (i) {}
-
- nframes_t length() { return end - start + 1; }
+
+ nframes_t length() { return end - start + 1; }
bool operator== (const AudioRange& other) const {
return start == other.start && end == other.end && id == other.id;
@@ -227,12 +227,12 @@ namespace ARDOUR {
return ARDOUR::coverage (start, end, s, e);
}
};
-
+
struct MusicRange {
BBT_Time start;
BBT_Time end;
uint32_t id;
-
+
MusicRange (BBT_Time& s, BBT_Time& e, uint32_t i)
: start (s), end (e), id (i) {}
@@ -273,7 +273,7 @@ namespace ARDOUR {
Lock
};
- enum RegionPoint {
+ enum RegionPoint {
Start,
End,
SyncPoint
@@ -312,7 +312,7 @@ namespace ARDOUR {
FullCrossfade,
ShortCrossfade
};
-
+
enum LayerModel {
LaterHigher,
MoveAddHigher,
@@ -355,11 +355,11 @@ namespace ARDOUR {
struct PeakData {
typedef Sample PeakDatum;
-
+
PeakDatum min;
PeakDatum max;
};
-
+
enum PluginType {
AudioUnit,
LADSPA,
@@ -370,7 +370,8 @@ namespace ARDOUR {
enum SlaveSource {
None = 0,
MTC,
- JACK
+ JACK,
+ MIDIClock
};
enum ShuttleBehaviour {
@@ -399,8 +400,8 @@ namespace ARDOUR {
float time_fraction;
float pitch_fraction;
/* SoundTouch */
- bool quick_seek;
- bool antialias;
+ bool quick_seek;
+ bool antialias;
/* RubberBand */
int opts; // really RubberBandStretcher::Options
};
diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc
index 71b699396b..0781f8c8e1 100644
--- a/libs/ardour/enums.cc
+++ b/libs/ardour/enums.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000-2007 Paul Davis
+ Copyright (C) 2000-2007 Paul Davis
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
@@ -103,7 +103,7 @@ setup_enum_writer ()
REGISTER_ENUM (OverlapEnd);
REGISTER_ENUM (OverlapExternal);
REGISTER (_OverlapType);
-
+
REGISTER_ENUM (GainAutomation);
REGISTER_ENUM (PanAutomation);
REGISTER_ENUM (PluginAutomation);
@@ -126,22 +126,22 @@ setup_enum_writer ()
REGISTER_BITS (_AutoStyle);
REGISTER_ENUM (CaptureTime);
- REGISTER_ENUM (ExistingMaterial);
+ REGISTER_ENUM (ExistingMaterial);
REGISTER (_AlignStyle);
REGISTER_ENUM (MeterInput);
REGISTER_ENUM (MeterPreFader);
- REGISTER_ENUM (MeterPostFader);
+ REGISTER_ENUM (MeterPostFader);
REGISTER (_MeterPoint);
REGISTER_ENUM (Normal);
REGISTER_ENUM (Destructive);
REGISTER (_TrackMode);
-
+
REGISTER_ENUM (Sustained);
REGISTER_ENUM (Percussive);
REGISTER (_NoteMode);
-
+
REGISTER_ENUM (AllChannels);
REGISTER_ENUM (FilterChannels);
REGISTER_ENUM (ForceChannel);
@@ -155,7 +155,7 @@ setup_enum_writer ()
REGISTER_ENUM (MeterFalloffFaster);
REGISTER_ENUM (MeterFalloffFastest);
REGISTER (_MeterFalloff);
-
+
REGISTER_ENUM (MeterHoldOff);
REGISTER_ENUM (MeterHoldShort);
REGISTER_ENUM (MeterHoldMedium);
@@ -163,12 +163,12 @@ setup_enum_writer ()
REGISTER (_MeterHold);
REGISTER_ENUM (Slide);
- REGISTER_ENUM (Splice);
+ REGISTER_ENUM (Splice);
REGISTER (_EditMode);
REGISTER_ENUM (Start);
REGISTER_ENUM (End);
- REGISTER_ENUM (SyncPoint);
+ REGISTER_ENUM (SyncPoint);
REGISTER (_RegionPoint);
REGISTER_ENUM (PreFader);
@@ -197,11 +197,11 @@ setup_enum_writer ()
REGISTER_ENUM (LaterHigher);
REGISTER_ENUM (MoveAddHigher);
- REGISTER_ENUM (AddHigher);
+ REGISTER_ENUM (AddHigher);
REGISTER (_LayerModel);
REGISTER_ENUM (InverseMute);
- REGISTER_ENUM (SoloBus);
+ REGISTER_ENUM (SoloBus);
REGISTER (_SoloModel);
REGISTER_ENUM (AutoConnectPhysical);
@@ -219,7 +219,7 @@ setup_enum_writer ()
REGISTER_ENUM (CAF);
REGISTER_ENUM (AIFF);
REGISTER_ENUM (iXML);
- REGISTER_ENUM (RF64);
+ REGISTER_ENUM (RF64);
REGISTER (_HeaderFormat);
REGISTER_ENUM (AudioUnit);
@@ -229,15 +229,16 @@ setup_enum_writer ()
REGISTER_ENUM (None);
REGISTER_ENUM (MTC);
- REGISTER_ENUM (JACK);
+ REGISTER_ENUM (JACK);
+ REGISTER_ENUM (MIDIClock);
REGISTER (_SlaveSource);
REGISTER_ENUM (Sprung);
- REGISTER_ENUM (Wheel);
+ REGISTER_ENUM (Wheel);
REGISTER (_ShuttleBehaviour);
REGISTER_ENUM (Percentage);
- REGISTER_ENUM (Semitones);
+ REGISTER_ENUM (Semitones);
REGISTER (_ShuttleUnits);
REGISTER_CLASS_ENUM (Session, Disabled);
@@ -379,10 +380,10 @@ setup_enum_writer ()
REGISTER_CLASS_ENUM (Track, Frozen);
REGISTER_CLASS_ENUM (Track, UnFrozen);
REGISTER (_Track_FreezeState);
-
+
REGISTER_CLASS_ENUM (AutomationList, Discrete);
REGISTER_CLASS_ENUM (AutomationList, Linear);
REGISTER_CLASS_ENUM (AutomationList, Curved);
REGISTER (_AutomationList_InterpolationStyle);
-
+
}
diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc
index 02c4a5ced6..1397a7d959 100644
--- a/libs/ardour/globals.cc
+++ b/libs/ardour/globals.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000 Paul Davis
+ Copyright (C) 2000 Paul Davis
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
@@ -73,7 +73,7 @@
#if defined (__APPLE__)
#include <Carbon/Carbon.h> // For Gestalt
#endif
-
+
#include "i18n.h"
ARDOUR::Configuration* ARDOUR::Config = 0;
@@ -91,6 +91,7 @@ using namespace PBD;
MIDI::Port *default_mmc_port = 0;
MIDI::Port *default_mtc_port = 0;
MIDI::Port *default_midi_port = 0;
+MIDI::Port *default_midi_clock_port = 0;
Change ARDOUR::StartChanged = ARDOUR::new_change ();
Change ARDOUR::LengthChanged = ARDOUR::new_change ();
@@ -111,11 +112,11 @@ static int
setup_osc ()
{
/* no real cost to creating this object, and it avoids
- conditionals anywhere that uses it
+ conditionals anywhere that uses it
*/
-
+
osc = new OSC (Config->get_osc_port());
-
+
if (Config->get_use_osc ()) {
BootMessage (_("Starting OSC"));
return osc->start ();
@@ -125,7 +126,7 @@ setup_osc ()
}
#endif
-int
+int
setup_midi ()
{
if (Config->midi_ports.size() == 0) {
@@ -150,16 +151,20 @@ setup_midi ()
if (Config->get_mmc_port_name() != N_("default")) {
default_mmc_port = MIDI::Manager::instance()->port (Config->get_mmc_port_name());
- }
+ }
if (Config->get_mtc_port_name() != N_("default")) {
default_mtc_port = MIDI::Manager::instance()->port (Config->get_mtc_port_name());
- }
+ }
if (Config->get_midi_port_name() != N_("default")) {
default_midi_port = MIDI::Manager::instance()->port (Config->get_midi_port_name());
- }
-
+ }
+
+ if (Config->get_midi_clock_port_name() != N_("default")) {
+ default_midi_port = MIDI::Manager::instance()->port (Config->get_midi_clock_port_name());
+ }
+
/* If that didn't work, just use the first listed port */
if (default_mmc_port == 0) {
@@ -173,7 +178,11 @@ setup_midi ()
if (default_midi_port == 0) {
default_midi_port = first;
}
-
+
+ if (default_midi_clock_port == 0) {
+ default_midi_clock_port = first;
+ }
+
} else if (ports.size() == 1) {
first = ports.begin()->second;
@@ -183,21 +192,27 @@ setup_midi ()
default_mmc_port = first;
default_mtc_port = default_mmc_port;
default_midi_port = default_mmc_port;
+ default_midi_clock_port = default_mmc_port;
}
if (default_mmc_port == 0) {
- warning << string_compose (_("No MMC control (MIDI port \"%1\" not available)"), Config->get_mmc_port_name())
+ warning << string_compose (_("No MMC control (MIDI port \"%1\" not available)"), Config->get_mmc_port_name())
<< endmsg;
return 0;
- }
+ }
if (default_mtc_port == 0) {
- warning << string_compose (_("No MTC support (MIDI port \"%1\" not available)"), Config->get_mtc_port_name())
+ warning << string_compose (_("No MTC support (MIDI port \"%1\" not available)"), Config->get_mtc_port_name())
<< endmsg;
}
if (default_midi_port == 0) {
- warning << string_compose (_("No MIDI parameter support (MIDI port \"%1\" not available)"), Config->get_midi_port_name())
+ warning << string_compose (_("No MIDI parameter support (MIDI port \"%1\" not available)"), Config->get_midi_port_name())
+ << endmsg;
+ }
+
+ if (default_midi_clock_port == 0) {
+ warning << string_compose (_("No MIDI Clock support (MIDI port \"%1\" not available)"), Config->get_midi_clock_port_name())
<< endmsg;
}
@@ -331,7 +346,7 @@ ARDOUR::init (bool use_vst, bool try_optimization)
return -1;
}
#endif
-
+
/* Make VAMP look in our library ahead of anything else */
char *p = getenv ("VAMP_PATH");
@@ -339,7 +354,7 @@ ARDOUR::init (bool use_vst, bool try_optimization)
if (p) {
vamppath += ':';
vamppath += p;
- }
+ }
setenv ("VAMP_PATH", vamppath.c_str(), 1);
@@ -350,7 +365,7 @@ ARDOUR::init (bool use_vst, bool try_optimization)
/* singleton - first object is "it" */
new PluginManager ();
-
+
/* singleton - first object is "it" */
new ControlProtocolManager ();
ControlProtocolManager::instance().discover_control_protocols ();
@@ -359,7 +374,7 @@ ARDOUR::init (bool use_vst, bool try_optimization)
if ((node = Config->control_protocol_state()) != 0) {
ControlProtocolManager::instance().set_state (*node);
}
-
+
BoundsChanged = Change (StartChanged|PositionChanged|LengthChanged);
return 0;
@@ -430,7 +445,7 @@ ARDOUR::find_bindings_files (map<string,string>& files)
if (found.empty()) {
return;
}
-
+
for (vector<sys::path>::iterator x = found.begin(); x != found.end(); ++x) {
sys::path path = *x;
pair<string,string> namepath;
@@ -445,7 +460,7 @@ ARDOUR::LocaleGuard::LocaleGuard (const char* str)
old = strdup (setlocale (LC_NUMERIC, NULL));
if (strcmp (old, str)) {
setlocale (LC_NUMERIC, str);
- }
+ }
}
ARDOUR::LocaleGuard::~LocaleGuard ()
@@ -472,7 +487,7 @@ ARDOUR::setup_fpu ()
/* XXX use real code to determine if the processor supports
DenormalsAreZero and FlushToZero
*/
-
+
if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) {
return;
}
@@ -496,7 +511,7 @@ ARDOUR::setup_fpu ()
MXCSR |= 0x8000;
}
break;
-
+
case DenormalFTZDAZ:
if (fpu.has_flush_to_zero()) {
if (fpu.has_denormals_are_zero()) {
@@ -514,7 +529,7 @@ ARDOUR::setup_fpu ()
}
ARDOUR::OverlapType
-ARDOUR::coverage (nframes_t sa, nframes_t ea,
+ARDOUR::coverage (nframes_t sa, nframes_t ea,
nframes_t sb, nframes_t eb)
{
/* OverlapType returned reflects how the second (B)
@@ -539,7 +554,7 @@ ARDOUR::coverage (nframes_t sa, nframes_t ea,
|-----------------| B
- "B is internal to A"
+ "B is internal to A"
*/
#ifdef OLD_COVERAGE
@@ -555,7 +570,7 @@ ARDOUR::coverage (nframes_t sa, nframes_t ea,
----| B
-----------------------| B
--| B
-
+
"B overlaps the start of A"
*/
@@ -563,13 +578,13 @@ ARDOUR::coverage (nframes_t sa, nframes_t ea,
if ((eb >= sa) && (eb <= ea)) {
return OverlapStart;
}
- /*
+ /*
|---------------------| A
|----------------- B
- |----------------------- B
+ |----------------------- B
|- B
- "B overlaps the end of A"
+ "B overlaps the end of A"
*/
if ((sb > sa) && (sb <= ea)) {
@@ -577,7 +592,7 @@ ARDOUR::coverage (nframes_t sa, nframes_t ea,
}
/*
|--------------------| A
- -------------------------- B
+ -------------------------- B
|----------------------- B
----------------------| B
|--------------------| B
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index ff269cc931..1124b8960f 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1999-2004 Paul Davis
+ Copyright (C) 1999-2004 Paul Davis
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
@@ -131,11 +131,12 @@ Session::Session (AudioEngine &eng,
_mmc_port (default_mmc_port),
_mtc_port (default_mtc_port),
_midi_port (default_midi_port),
+ _midi_clock_port (default_midi_clock_port),
_session_dir (new SessionDirectory(fullpath)),
pending_events (2048),
post_transport_work((PostTransportWork)0),
_send_smpte_update (false),
- midi_requests (128),
+ midi_requests (128),
diskstreams (new DiskstreamList),
routes (new RouteList),
auditioner ((Auditioner*) 0),
@@ -148,7 +149,7 @@ Session::Session (AudioEngine &eng,
if (!eng.connected()) {
throw failed_constructor();
}
-
+
cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl;
n_physical_outputs = _engine.n_physical_outputs();
@@ -164,14 +165,14 @@ Session::Session (AudioEngine &eng,
throw failed_constructor ();
}
}
-
+
if (second_stage_init (new_session)) {
destroy ();
throw failed_constructor ();
}
-
+
store_recent_sessions(_name, _path);
-
+
bool was_dirty = dirty();
_state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
@@ -201,6 +202,7 @@ Session::Session (AudioEngine &eng,
_mmc_port (default_mmc_port),
_mtc_port (default_mtc_port),
_midi_port (default_midi_port),
+ _midi_clock_port (default_midi_clock_port),
_session_dir ( new SessionDirectory(fullpath)),
pending_events (2048),
post_transport_work((PostTransportWork)0),
@@ -244,31 +246,31 @@ Session::Session (AudioEngine &eng,
{
/* set up Master Out and Control Out if necessary */
-
+
RouteList rl;
int control_id = 1;
-
+
if (control_out_channels) {
shared_ptr<Route> r (new Route (*this, _("monitor"), -1, control_out_channels, -1, control_out_channels, Route::ControlOut));
r->set_remote_control_id (control_id++);
-
+
rl.push_back (r);
}
-
+
if (master_out_channels) {
shared_ptr<Route> r (new Route (*this, _("master"), -1, master_out_channels, -1, master_out_channels, Route::MasterOut));
r->set_remote_control_id (control_id);
-
+
rl.push_back (r);
} else {
/* prohibit auto-connect to master, because there isn't one */
output_ac = AutoConnectOption (output_ac & ~AutoConnectMaster);
}
-
+
if (!rl.empty()) {
add_routes (rl, false);
}
-
+
}
Config->set_input_auto_connect (input_ac);
@@ -278,9 +280,9 @@ Session::Session (AudioEngine &eng,
destroy ();
throw failed_constructor ();
}
-
+
store_recent_sessions (_name, _path);
-
+
_state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
Config->ParameterChanged.connect (mem_fun (*this, &Session::config_changed));
@@ -305,7 +307,7 @@ Session::destroy ()
_engine.remove_session ();
GoingAway (); /* EMIT SIGNAL */
-
+
/* do this */
notify_callbacks ();
@@ -315,14 +317,14 @@ Session::destroy ()
_history.clear ();
/* clear state tree so that no references to objects are held any more */
-
+
if (state_tree) {
delete state_tree;
}
terminate_butler_thread ();
//terminate_midi_thread ();
-
+
if (click_data && click_data != default_click) {
delete [] click_data;
}
@@ -338,9 +340,9 @@ Session::destroy ()
delete _mix_buffers;
AudioDiskstream::free_working_buffers();
-
+
Route::SyncOrderKeys.clear();
-
+
#undef TRACK_DESTRUCTION
#ifdef TRACK_DESTRUCTION
cerr << "delete named selections\n";
@@ -365,10 +367,10 @@ Session::destroy ()
++tmp;
(*i)->drop_references ();
-
+
i = tmp;
}
-
+
for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ) {
PlaylistList::iterator tmp;
@@ -376,17 +378,17 @@ Session::destroy ()
++tmp;
(*i)->drop_references ();
-
+
i = tmp;
}
-
+
playlists.clear ();
unused_playlists.clear ();
#ifdef TRACK_DESTRUCTION
cerr << "delete regions\n";
#endif /* TRACK_DESTRUCTION */
-
+
for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
RegionList::iterator tmp;
@@ -436,13 +438,13 @@ Session::destroy ()
tmp = i;
++tmp;
-
+
i->second->drop_references ();
-
+
i = tmp;
}
sources.clear ();
-
+
#ifdef TRACK_DESTRUCTION
cerr << "delete mix groups\n";
#endif /* TRACK_DESTRUCTION */
@@ -462,7 +464,7 @@ Session::destroy ()
#endif /* TRACK_DESTRUCTION */
for (list<RouteGroup *>::iterator i = edit_groups.begin(); i != edit_groups.end(); ) {
list<RouteGroup*>::iterator tmp;
-
+
tmp = i;
++tmp;
@@ -470,7 +472,7 @@ Session::destroy ()
i = tmp;
}
-
+
if (butler_mixdown_buffer) {
delete [] butler_mixdown_buffer;
}
@@ -497,7 +499,7 @@ Session::set_worst_io_latencies ()
}
boost::shared_ptr<RouteList> r = routes.reader ();
-
+
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
_worst_output_latency = max (_worst_output_latency, (*i)->output_latency());
_worst_input_latency = max (_worst_input_latency, (*i)->input_latency());
@@ -536,15 +538,15 @@ Session::when_engine_running ()
try {
XMLNode* child = 0;
-
+
_click_io.reset (new ClickIO (*this, "click", 0, 0, -1, -1));
if (state_tree && (child = find_named_node (*state_tree->root(), "Click")) != 0) {
/* existing state for Click */
-
+
if (_click_io->set_state (*child->children().front()) == 0) {
-
+
_clicking = Config->get_clicking ();
} else {
@@ -554,7 +556,7 @@ Session::when_engine_running ()
}
} else {
-
+
/* default state for Click */
first_physical_output = _engine.get_nth_physical_output (DataType::AUDIO, 0);
@@ -642,24 +644,24 @@ Session::when_engine_running ()
if (_master_out) {
/* create master/control ports */
-
+
if (_master_out) {
uint32_t n;
/* force the master to ignore any later call to this */
-
+
if (_master_out->pending_state_node) {
_master_out->ports_became_legal();
}
/* no panner resets till we are through */
-
+
_master_out->defer_pan_reset ();
-
+
while (_master_out->n_inputs().n_audio()
< _master_out->input_maximum().n_audio()) {
if (_master_out->add_input_port ("", this, DataType::AUDIO)) {
- error << _("cannot setup master inputs")
+ error << _("cannot setup master inputs")
<< endmsg;
break;
}
@@ -676,7 +678,7 @@ Session::when_engine_running ()
}
_master_out->allow_pan_reset ();
-
+
}
shared_ptr<AutoBundle> c (new AutoBundle (_("Master Out"), true));
@@ -686,8 +688,8 @@ Session::when_engine_running ()
c->set_port (n, _master_out->input(n)->name());
}
add_bundle (c);
- }
-
+ }
+
BootMessage (_("Setup signal flow and plugins"));
hookup_io ();
@@ -697,7 +699,7 @@ Session::when_engine_running ()
BootMessage (_("Catch up with send/insert state"));
insert_cnt = 0;
-
+
for (list<PortInsert*>::iterator i = _port_inserts.begin(); i != _port_inserts.end(); ++i) {
uint32_t id;
@@ -712,7 +714,7 @@ Session::when_engine_running ()
for (list<Send*>::iterator i = _sends.begin(); i != _sends.end(); ++i) {
uint32_t id;
-
+
if (sscanf ((*i)->name().c_str(), "%*s %u", &id) == 1) {
if (id > send_cnt) {
send_cnt = id;
@@ -720,7 +722,7 @@ Session::when_engine_running ()
}
}
-
+
_state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
/* hook us up to the engine */
@@ -736,7 +738,7 @@ Session::when_engine_running ()
osc->set_session (*this);
#endif
-
+
}
void
@@ -750,16 +752,16 @@ Session::hookup_io ()
if (auditioner == 0) {
-
+
/* we delay creating the auditioner till now because
it makes its own connections to ports.
the engine has to be running for this to work.
*/
-
+
try {
auditioner.reset (new Auditioner (*this));
}
-
+
catch (failed_constructor& err) {
warning << _("cannot create Auditioner: no auditioning of regions possible") << endmsg;
}
@@ -797,7 +799,7 @@ Session::hookup_io ()
cports.push_back (_control_out->input(n)->name());
}
- boost::shared_ptr<RouteList> r = routes.reader ();
+ boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator x = r->begin(); x != r->end(); ++x) {
(*x)->set_control_outs (cports);
@@ -808,7 +810,7 @@ Session::hookup_io ()
if (_bundle_xml_node) {
load_bundles (*_bundle_xml_node);
delete _bundle_xml_node;
- }
+ }
/* Tell all IO objects to connect themselves together */
@@ -839,10 +841,10 @@ Session::hookup_io ()
void
Session::playlist_length_changed ()
{
- /* we can't just increase end_location->end() if pl->get_maximum_extent()
+ /* we can't just increase end_location->end() if pl->get_maximum_extent()
if larger. if the playlist used to be the longest playlist,
and its now shorter, we have to decrease end_location->end(). hence,
- we have to iterate over all diskstreams and check the
+ we have to iterate over all diskstreams and check the
playlists currently in use.
*/
find_current_end ();
@@ -856,7 +858,7 @@ Session::diskstream_playlist_changed (boost::shared_ptr<Diskstream> dstream)
if ((playlist = dstream->playlist()) != 0) {
playlist->LengthChanged.connect (mem_fun (this, &Session::playlist_length_changed));
}
-
+
/* see comment in playlist_length_changed () */
find_current_end ();
}
@@ -909,7 +911,7 @@ Session::auto_punch_start_changed (Location* location)
/* capture start has been changed, so save new pending state */
save_state ("", true);
}
-}
+}
void
Session::auto_punch_end_changed (Location* location)
@@ -917,7 +919,7 @@ Session::auto_punch_end_changed (Location* location)
nframes_t when_to_stop = location->end();
// when_to_stop += _worst_output_latency + _worst_input_latency;
replace_event (Event::PunchOut, when_to_stop);
-}
+}
void
Session::auto_punch_changed (Location* location)
@@ -927,7 +929,7 @@ Session::auto_punch_changed (Location* location)
replace_event (Event::PunchIn, location->start());
//when_to_stop += _worst_output_latency + _worst_input_latency;
replace_event (Event::PunchOut, when_to_stop);
-}
+}
void
Session::auto_loop_changed (Location* location)
@@ -941,12 +943,12 @@ Session::auto_loop_changed (Location* location)
if (_transport_frame > location->end()) {
// relocate to beginning of loop
clear_events (Event::LocateRoll);
-
+
request_locate (location->start(), true);
}
else if (Config->get_seamless_loop() && !loop_changing) {
-
+
// schedule a locate-roll to refill the diskstreams at the
// previous loop end
loop_changing = true;
@@ -958,7 +960,7 @@ Session::auto_loop_changed (Location* location)
}
}
- }
+ }
last_loopend = location->end();
}
@@ -983,7 +985,7 @@ Session::set_auto_punch_location (Location* location)
if (location == 0) {
return;
}
-
+
if (location->end() <= location->start()) {
error << _("Session: you can't use that location for auto punch (start <= end)") << endmsg;
return;
@@ -992,7 +994,7 @@ Session::set_auto_punch_location (Location* location)
auto_punch_start_changed_connection.disconnect();
auto_punch_end_changed_connection.disconnect();
auto_punch_changed_connection.disconnect();
-
+
auto_punch_start_changed_connection = location->start_changed.connect (mem_fun (this, &Session::auto_punch_start_changed));
auto_punch_end_changed_connection = location->end_changed.connect (mem_fun (this, &Session::auto_punch_end_changed));
auto_punch_changed_connection = location->changed.connect (mem_fun (this, &Session::auto_punch_changed));
@@ -1018,7 +1020,7 @@ Session::set_auto_loop_location (Location* location)
remove_event (existing->end(), Event::AutoLoop);
auto_loop_location_changed (0);
}
-
+
set_dirty();
if (location == 0) {
@@ -1031,11 +1033,11 @@ Session::set_auto_loop_location (Location* location)
}
last_loopend = location->end();
-
+
auto_loop_start_changed_connection.disconnect();
auto_loop_end_changed_connection.disconnect();
auto_loop_changed_connection.disconnect();
-
+
auto_loop_start_changed_connection = location->start_changed.connect (mem_fun (this, &Session::auto_loop_changed));
auto_loop_end_changed_connection = location->end_changed.connect (mem_fun (this, &Session::auto_loop_changed));
auto_loop_changed_connection = location->changed.connect (mem_fun (this, &Session::auto_loop_changed));
@@ -1083,7 +1085,7 @@ Session::handle_locations_changed (Locations::LocationList& locations)
set_auto_loop_location (location);
set_loop = true;
}
-
+
}
if (!set_loop) {
@@ -1094,7 +1096,7 @@ Session::handle_locations_changed (Locations::LocationList& locations)
}
set_dirty();
-}
+}
void
Session::enable_record ()
@@ -1109,7 +1111,7 @@ Session::enable_record ()
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if ((*i)->record_enabled ()) {
- (*i)->monitor_input (true);
+ (*i)->monitor_input (true);
}
}
}
@@ -1141,14 +1143,14 @@ Session::disable_record (bool rt_context, bool force)
if (Config->get_monitoring_model() == HardwareMonitoring && Config->get_auto_input()) {
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
+
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if ((*i)->record_enabled ()) {
- (*i)->monitor_input (false);
+ (*i)->monitor_input (false);
}
}
}
-
+
RecordStateChanged (); /* emit signal */
if (!rt_context) {
@@ -1166,11 +1168,11 @@ Session::step_back_from_record ()
if (Config->get_monitoring_model() == HardwareMonitoring && Config->get_auto_input()) {
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
+
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if ((*i)->record_enabled ()) {
//cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
- (*i)->monitor_input (false);
+ (*i)->monitor_input (false);
}
}
}
@@ -1191,7 +1193,7 @@ Session::maybe_enable_record ()
if (_transport_speed) {
if (!Config->get_punch_in()) {
enable_record ();
- }
+ }
} else {
deliver_mmc (MIDI::MachineControl::cmdRecordPause, _transport_frame);
RecordStateChanged (); /* EMIT SIGNAL */
@@ -1208,7 +1210,7 @@ Session::audible_frame () const
nframes_t tf;
/* the first of these two possible settings for "offset"
- mean that the audible frame is stationary until
+ mean that the audible frame is stationary until
audio emerges from the latency compensation
"pseudo-pipeline".
@@ -1221,7 +1223,7 @@ Session::audible_frame () const
if (offset > current_block_size) {
offset -= current_block_size;
- } else {
+ } else {
/* XXX is this correct? if we have no external
physical connections and everything is internal
then surely this is zero? still, how
@@ -1251,7 +1253,7 @@ Session::audible_frame () const
/* MOVING */
/* take latency into account */
-
+
ret -= offset;
}
@@ -1262,7 +1264,7 @@ void
Session::set_frame_rate (nframes_t frames_per_second)
{
/** \fn void Session::set_frame_size(nframes_t)
- the AudioEngine object that calls this guarantees
+ the AudioEngine object that calls this guarantees
that it will not be called while we are also in
::process(). Its fine to do things that block
here.
@@ -1275,7 +1277,7 @@ Session::set_frame_rate (nframes_t frames_per_second)
Automatable::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * (0.001 * Config->get_automation_interval())));
clear_clicks ();
-
+
// XXX we need some equivalent to this, somehow
// SndFileSource::setup_standard_crossfades (frames_per_second);
@@ -1287,14 +1289,14 @@ Session::set_frame_rate (nframes_t frames_per_second)
void
Session::set_block_size (nframes_t nframes)
{
- /* the AudioEngine guarantees
+ /* the AudioEngine guarantees
that it will not be called while we are also in
::process(). It is therefore fine to do things that block
here.
*/
- {
-
+ {
+
current_block_size = nframes;
ensure_buffers(_scratch_buffers->available());
@@ -1311,7 +1313,7 @@ Session::set_block_size (nframes_t nframes)
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
(*i)->set_block_size (nframes);
}
-
+
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
(*i)->set_block_size (nframes);
@@ -1326,18 +1328,18 @@ Session::set_default_fade (float steepness, float fade_msecs)
{
#if 0
nframes_t fade_frames;
-
+
/* Don't allow fade of less 1 frame */
-
+
if (fade_msecs < (1000.0 * (1.0/_current_frame_rate))) {
fade_msecs = 0;
fade_frames = 0;
} else {
-
+
fade_frames = (nframes_t) floor (fade_msecs * _current_frame_rate * 0.001);
-
+
}
default_fade_msecs = fade_msecs;
@@ -1352,7 +1354,7 @@ Session::set_default_fade (float steepness, float fade_msecs)
set_dirty();
/* XXX have to do this at some point */
- /* foreach region using default fade, reset, then
+ /* foreach region using default fade, reset, then
refill_all_diskstream_buffers ();
*/
#endif
@@ -1388,7 +1390,7 @@ trace_terminal (shared_ptr<Route> r1, shared_ptr<Route> rbase)
if ((r1->fed_by.find (rbase) != r1->fed_by.end()) && (rbase->fed_by.find (r1) != rbase->fed_by.end())) {
info << string_compose(_("feedback loop setup between %1 and %2"), r1->name(), rbase->name()) << endmsg;
return;
- }
+ }
/* make a copy of the existing list of routes that feed r1 */
@@ -1452,45 +1454,45 @@ void
Session::resort_routes_using (shared_ptr<RouteList> r)
{
RouteList::iterator i, j;
-
+
for (i = r->begin(); i != r->end(); ++i) {
-
+
(*i)->fed_by.clear ();
-
+
for (j = r->begin(); j != r->end(); ++j) {
-
+
/* although routes can feed themselves, it will
cause an endless recursive descent if we
detect it. so don't bother checking for
self-feeding.
*/
-
+
if (*j == *i) {
continue;
}
-
+
if ((*j)->feeds (*i)) {
(*i)->fed_by.insert (*j);
- }
+ }
}
}
-
+
for (i = r->begin(); i != r->end(); ++i) {
trace_terminal (*i, *i);
}
-
+
RouteSorter cmp;
r->sort (cmp);
-
+
#if 0
cerr << "finished route resort\n";
-
+
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
cerr << " " << (*i)->name() << " signal order = " << (*i)->order_key ("signal") << endl;
}
cerr << endl;
#endif
-
+
}
list<boost::shared_ptr<MidiTrack> >
@@ -1505,7 +1507,7 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
//uint32_t control_id;
// FIXME: need physical I/O and autoconnect stuff for MIDI
-
+
/* count existing midi tracks */
{
@@ -1539,7 +1541,7 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
save, close,restart,add new route - first named route is now
Audio2)
*/
-
+
do {
++track_id;
@@ -1549,7 +1551,7 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
if (route_by_name (track_name) == 0) {
break;
}
-
+
} while (track_id < (UINT_MAX-1));
/*
@@ -1558,7 +1560,7 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
} else {
nphysical_in = 0;
}
-
+
if (Config->get_output_auto_connect() & AutoConnectPhysical) {
nphysical_out = min (n_physical_outputs, (uint32_t) physinputs.size());
} else {
@@ -1567,10 +1569,10 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
*/
shared_ptr<MidiTrack> track;
-
+
try {
track = boost::shared_ptr<MidiTrack>((new MidiTrack (*this, track_name, Route::Flag (0), mode)));
-
+
if (track->ensure_io (ChanCount(DataType::MIDI, 1), ChanCount(DataType::AUDIO, 1), false, this)) {
error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
goto failed;
@@ -1579,23 +1581,23 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
/*
if (nphysical_in) {
for (uint32_t x = 0; x < track->n_inputs().n_midi() && x < nphysical_in; ++x) {
-
+
port = "";
-
+
if (Config->get_input_auto_connect() & AutoConnectPhysical) {
port = physinputs[(channels_used+x)%nphysical_in];
- }
-
+ }
+
if (port.length() && track->connect_input (track->input (x), port, this)) {
break;
}
}
}
-
+
for (uint32_t x = 0; x < track->n_outputs().n_midi(); ++x) {
-
+
port = "";
-
+
if (nphysical_out && (Config->get_output_auto_connect() & AutoConnectPhysical)) {
port = physoutputs[(channels_used+x)%nphysical_out];
} else if (Config->get_output_auto_connect() & AutoConnectMaster) {
@@ -1603,18 +1605,18 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
port = _master_out->input (x%_master_out->n_inputs().n_midi())->name();
}
}
-
+
if (port.length() && track->connect_output (track->output (x), port, this)) {
break;
}
}
-
+
channels_used += track->n_inputs ().n_midi();
*/
track->midi_diskstream()->non_realtime_input_change();
-
+
track->DiskstreamChanged.connect (mem_fun (this, &Session::resort_routes));
//track->set_remote_control_id (control_id);
@@ -1629,7 +1631,7 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
/* we need to get rid of this, since the track failed to be created */
/* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */
- {
+ {
RCUWriter<DiskstreamList> writer (diskstreams);
boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
ds->remove (track->midi_diskstream());
@@ -1647,7 +1649,7 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
/* we need to get rid of this, since the track failed to be created */
/* XXX arguably, MidiTrack::MidiTrack should not do the Session::add_diskstream() */
- {
+ {
RCUWriter<DiskstreamList> writer (diskstreams);
boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
ds->remove (track->midi_diskstream());
@@ -1712,7 +1714,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
save, close,restart,add new route - first named route is now
Audio2)
*/
-
+
do {
++track_id;
@@ -1722,7 +1724,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
if (route_by_name (track_name) == 0) {
break;
}
-
+
} while (track_id < (UINT_MAX-1));
if (Config->get_input_auto_connect() & AutoConnectPhysical) {
@@ -1730,7 +1732,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
} else {
nphysical_in = 0;
}
-
+
if (Config->get_output_auto_connect() & AutoConnectPhysical) {
nphysical_out = min (n_physical_outputs, (uint32_t) physinputs.size());
} else {
@@ -1738,10 +1740,10 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
}
shared_ptr<AudioTrack> track;
-
+
try {
track = boost::shared_ptr<AudioTrack>((new AudioTrack (*this, track_name, Route::Flag (0), mode)));
-
+
if (track->ensure_io (ChanCount(DataType::AUDIO, input_channels), ChanCount(DataType::AUDIO, output_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
@@ -1751,23 +1753,23 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
if (nphysical_in) {
for (uint32_t x = 0; x < track->n_inputs().n_audio() && x < nphysical_in; ++x) {
-
+
port = "";
-
+
if (Config->get_input_auto_connect() & AutoConnectPhysical) {
port = physinputs[(channels_used+x)%nphysical_in];
- }
-
+ }
+
if (port.length() && track->connect_input (track->input (x), port, this)) {
break;
}
}
}
-
+
for (uint32_t x = 0; x < track->n_outputs().n_midi(); ++x) {
-
+
port = "";
-
+
if (nphysical_out && (Config->get_output_auto_connect() & AutoConnectPhysical)) {
port = physoutputs[(channels_used+x)%nphysical_out];
} else if (Config->get_output_auto_connect() & AutoConnectMaster) {
@@ -1775,16 +1777,16 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
port = _master_out->input (x%_master_out->n_inputs().n_audio())->name();
}
}
-
+
if (port.length() && track->connect_output (track->output (x), port, this)) {
break;
}
}
-
+
channels_used += track->n_inputs ().n_audio();
track->audio_diskstream()->non_realtime_input_change();
-
+
track->DiskstreamChanged.connect (mem_fun (this, &Session::resort_routes));
track->set_remote_control_id (control_id);
++control_id;
@@ -1800,7 +1802,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
/* we need to get rid of this, since the track failed to be created */
/* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */
- {
+ {
RCUWriter<DiskstreamList> writer (diskstreams);
boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
ds->remove (track->audio_diskstream());
@@ -1818,7 +1820,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
/* we need to get rid of this, since the track failed to be created */
/* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */
- {
+ {
RCUWriter<DiskstreamList> writer (diskstreams);
boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
ds->remove (track->audio_diskstream());
@@ -1847,14 +1849,14 @@ Session::set_remote_control_ids ()
shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if ( MixerOrdered == m) {
+ if ( MixerOrdered == m) {
long order = (*i)->order_key(N_("signal"));
(*i)->set_remote_control_id( order+1 );
} else if ( EditorOrdered == m) {
long order = (*i)->order_key(N_("editor"));
(*i)->set_remote_control_id( order+1 );
} else if ( UserOrdered == m) {
- //do nothing ... only changes to remote id's are initiated by user
+ //do nothing ... only changes to remote id's are initiated by user
}
}
}
@@ -1906,31 +1908,31 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
try {
shared_ptr<Route> bus (new Route (*this, bus_name, -1, -1, -1, -1, Route::Flag(0), DataType::AUDIO));
-
+
if (bus->ensure_io (ChanCount(DataType::AUDIO, input_channels), ChanCount(DataType::AUDIO, output_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
goto failure;
}
-
+
for (uint32_t x = 0; n_physical_inputs && x < bus->n_inputs().n_audio(); ++x) {
-
+
port = "";
if (Config->get_input_auto_connect() & AutoConnectPhysical) {
port = physinputs[((n+x)%n_physical_inputs)];
- }
-
+ }
+
if (port.length() && bus->connect_input (bus->input (x), port, this)) {
break;
}
}
-
+
for (uint32_t x = 0; n_physical_outputs && x < bus->n_outputs().n_audio(); ++x) {
-
+
port = "";
-
+
if (Config->get_output_auto_connect() & AutoConnectPhysical) {
port = physoutputs[((n+x)%n_physical_outputs)];
} else if (Config->get_output_auto_connect() & AutoConnectMaster) {
@@ -1938,18 +1940,18 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
port = _master_out->input (x%_master_out->n_inputs().n_audio())->name();
}
}
-
+
if (port.length() && bus->connect_output (bus->output (x), port, this)) {
break;
}
}
-
+
bus->set_remote_control_id (control_id);
++control_id;
ret.push_back (bus);
}
-
+
catch (failed_constructor &err) {
error << _("Session: could not create new audio route.") << endmsg;
@@ -1977,7 +1979,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
void
Session::add_routes (RouteList& new_routes, bool save)
{
- {
+ {
RCUWriter<RouteList> writer (routes);
shared_ptr<RouteList> r = writer.get_copy ();
r->insert (r->end(), new_routes.begin(), new_routes.end());
@@ -1985,18 +1987,18 @@ Session::add_routes (RouteList& new_routes, bool save)
}
for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
-
+
boost::weak_ptr<Route> wpr (*x);
(*x)->solo_changed.connect (sigc::bind (mem_fun (*this, &Session::route_solo_changed), wpr));
(*x)->mute_changed.connect (mem_fun (*this, &Session::route_mute_changed));
(*x)->output_changed.connect (mem_fun (*this, &Session::set_worst_io_latencies_x));
(*x)->processors_changed.connect (bind (mem_fun (*this, &Session::update_latency_compensation), false, false));
-
+
if ((*x)->is_master()) {
_master_out = (*x);
}
-
+
if ((*x)->is_control()) {
_control_out = (*x);
}
@@ -2017,7 +2019,7 @@ Session::add_routes (RouteList& new_routes, bool save)
for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
(*x)->set_control_outs (cports);
}
- }
+ }
set_dirty();
@@ -2033,7 +2035,7 @@ Session::add_diskstream (boost::shared_ptr<Diskstream> dstream)
{
/* need to do this in case we're rolling at the time, to prevent false underruns */
dstream->do_refill_with_alloc ();
-
+
dstream->set_block_size (current_block_size);
{
@@ -2041,7 +2043,7 @@ Session::add_diskstream (boost::shared_ptr<Diskstream> dstream)
boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
ds->push_back (dstream);
/* writer goes out of scope, copies ds back to main */
- }
+ }
dstream->PlaylistChanged.connect (sigc::bind (mem_fun (*this, &Session::diskstream_playlist_changed), dstream));
/* this will connect to future changes, and check the current length */
@@ -2054,10 +2056,10 @@ Session::add_diskstream (boost::shared_ptr<Diskstream> dstream)
void
Session::remove_route (shared_ptr<Route> route)
{
- {
+ {
RCUWriter<RouteList> writer (routes);
shared_ptr<RouteList> rs = writer.get_copy ();
-
+
rs->remove (route);
/* deleting the master out seems like a dumb
@@ -2082,17 +2084,17 @@ Session::remove_route (shared_ptr<Route> route)
}
update_route_solo_state ();
-
+
/* writer goes out of scope, forces route list update */
}
Track* t;
boost::shared_ptr<Diskstream> ds;
-
+
if ((t = dynamic_cast<Track*>(route.get())) != 0) {
ds = t->diskstream();
}
-
+
if (ds) {
{
@@ -2103,12 +2105,12 @@ Session::remove_route (shared_ptr<Route> route)
}
find_current_end ();
-
- // We need to disconnect the routes inputs and outputs
+
+ // We need to disconnect the routes inputs and outputs
route->disconnect_inputs (0);
route->disconnect_outputs (0);
-
+
update_latency_compensation (false, false);
set_dirty();
@@ -2127,7 +2129,7 @@ Session::remove_route (shared_ptr<Route> route)
if (save_state (_current_snapshot_name)) {
save_history (_current_snapshot_name);
}
-}
+}
void
Session::route_mute_changed (void* src)
@@ -2137,12 +2139,12 @@ Session::route_mute_changed (void* src)
void
Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
-{
+{
if (solo_update_disabled) {
// We know already
return;
}
-
+
bool is_track;
boost::shared_ptr<Route> route = wpr.lock ();
@@ -2153,46 +2155,46 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
}
is_track = (boost::dynamic_pointer_cast<AudioTrack>(route) != 0);
-
+
shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-
+
/* soloing a track mutes all other tracks, soloing a bus mutes all other busses */
-
+
if (is_track) {
-
+
/* don't mess with busses */
-
+
if (dynamic_cast<Track*>((*i).get()) == 0) {
continue;
}
-
+
} else {
-
+
/* don't mess with tracks */
-
+
if (dynamic_cast<Track*>((*i).get()) != 0) {
continue;
}
}
-
+
if ((*i) != route &&
((*i)->mix_group () == 0 ||
(*i)->mix_group () != route->mix_group () ||
!route->mix_group ()->is_active())) {
-
+
if ((*i)->soloed()) {
-
+
/* if its already soloed, and solo latching is enabled,
then leave it as it is.
*/
-
+
if (Config->get_solo_latched()) {
continue;
- }
+ }
}
-
+
/* do it */
solo_update_disabled = true;
@@ -2200,7 +2202,7 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
solo_update_disabled = false;
}
}
-
+
bool something_soloed = false;
bool same_thing_soloed = false;
bool signal = false;
@@ -2222,12 +2224,12 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
break;
}
}
-
+
if (something_soloed != currently_soloing) {
signal = true;
currently_soloing = something_soloed;
}
-
+
modify_solo_mute (is_track, same_thing_soloed);
if (signal) {
@@ -2251,7 +2253,7 @@ Session::update_route_solo_state ()
/* this is where we actually implement solo by changing
the solo mute setting of each track.
*/
-
+
shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
@@ -2276,7 +2278,7 @@ Session::update_route_solo_state ()
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
(*i)->set_solo_mute (false);
}
-
+
if (signal) {
SoloActive (false);
}
@@ -2297,11 +2299,11 @@ Session::modify_solo_mute (bool is_track, bool mute)
shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-
+
if (is_track) {
-
+
/* only alter track solo mute */
-
+
if (dynamic_cast<Track*>((*i).get())) {
if ((*i)->soloed()) {
(*i)->set_solo_mute (!mute);
@@ -2325,7 +2327,7 @@ Session::modify_solo_mute (bool is_track, bool mute)
/* don't mute master or control outs
in response to another bus solo
*/
-
+
if ((*i) != _master_out &&
(*i) != _control_out) {
(*i)->set_solo_mute (mute);
@@ -2335,7 +2337,7 @@ Session::modify_solo_mute (bool is_track, bool mute)
}
}
-}
+}
void
@@ -2347,8 +2349,8 @@ Session::catch_up_on_solo ()
has.
*/
update_route_solo_state();
-}
-
+}
+
shared_ptr<Route>
Session::route_by_name (string name)
{
@@ -2411,7 +2413,7 @@ nframes_t
Session::get_maximum_extent () const
{
nframes_t max = 0;
- nframes_t me;
+ nframes_t me;
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
@@ -2464,7 +2466,7 @@ Session::new_region_name (string old)
char buf[len];
if ((last_period = old.find_last_of ('.')) == string::npos) {
-
+
/* no period present - add one explicitly */
old += '.';
@@ -2492,7 +2494,7 @@ Session::new_region_name (string old)
break;
}
}
-
+
if (i == regions.end()) {
break;
}
@@ -2500,7 +2502,7 @@ Session::new_region_name (string old)
if (number != (UINT_MAX-1)) {
return buf;
- }
+ }
error << string_compose (_("cannot create new name for region \"%1\""), old) << endmsg;
return old;
@@ -2515,19 +2517,19 @@ Session::region_name (string& result, string base, bool newlevel) const
assert(base.find("/") == string::npos);
if (base == "") {
-
+
Glib::Mutex::Lock lm (region_lock);
snprintf (buf, sizeof (buf), "%d", (int)regions.size() + 1);
-
+
result = "region.";
result += buf;
} else {
/* XXX this is going to be slow. optimize me later */
-
+
if (newlevel) {
subbase = base;
} else {
@@ -2542,38 +2544,38 @@ Session::region_name (string& result, string base, bool newlevel) const
}
bool name_taken = true;
-
+
{
Glib::Mutex::Lock lm (region_lock);
-
+
for (int n = 1; n < 5000; ++n) {
-
+
result = subbase;
snprintf (buf, sizeof (buf), ".%d", n);
result += buf;
-
+
name_taken = false;
-
+
for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
if (i->second->name() == result) {
name_taken = true;
break;
}
}
-
+
if (!name_taken) {
break;
}
}
}
-
+
if (name_taken) {
fatal << string_compose(_("too many regions with names like %1"), base) << endmsg;
/*NOTREACHED*/
}
}
return 0;
-}
+}
void
Session::add_region (boost::shared_ptr<Region> region)
@@ -2582,49 +2584,49 @@ Session::add_region (boost::shared_ptr<Region> region)
v.push_back (region);
add_regions (v);
}
-
+
void
Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions)
{
bool added = false;
- {
+ {
Glib::Mutex::Lock lm (region_lock);
for (vector<boost::shared_ptr<Region> >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) {
-
+
boost::shared_ptr<Region> region = *ii;
-
+
if (region == 0) {
error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
} else {
-
+
RegionList::iterator x;
-
+
for (x = regions.begin(); x != regions.end(); ++x) {
-
+
if (region->region_list_equivalent (x->second)) {
break;
}
}
-
+
if (x == regions.end()) {
-
+
pair<RegionList::key_type,RegionList::mapped_type> entry;
-
+
entry.first = region->id();
entry.second = region;
-
+
pair<RegionList::iterator,bool> x = regions.insert (entry);
-
+
if (!x.second) {
return;
}
-
+
added = true;
- }
+ }
}
}
}
@@ -2632,9 +2634,9 @@ Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions)
/* mark dirty because something has changed even if we didn't
add the region to the region list.
*/
-
+
set_dirty();
-
+
if (added) {
vector<boost::weak_ptr<Region> > v;
@@ -2659,7 +2661,7 @@ Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions)
region->StateChanged.connect (sigc::bind (mem_fun (*this, &Session::region_changed), boost::weak_ptr<Region>(region)));
region->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_region), boost::weak_ptr<Region>(region)));
}
-
+
if (!v.empty()) {
RegionsAdded (v); /* EMIT SIGNAL */
}
@@ -2693,7 +2695,7 @@ Session::remove_region (boost::weak_ptr<Region> weak_region)
bool removed = false;
- {
+ {
Glib::Mutex::Lock lm (region_lock);
if ((i = regions.find (region->id())) != regions.end()) {
@@ -2718,7 +2720,7 @@ Session::find_whole_file_parent (boost::shared_ptr<Region const> child)
{
RegionList::iterator i;
boost::shared_ptr<Region> region;
-
+
Glib::Mutex::Lock lm (region_lock);
for (i = regions.begin(); i != regions.end(); ++i) {
@@ -2731,10 +2733,10 @@ Session::find_whole_file_parent (boost::shared_ptr<Region const> child)
return region;
}
}
- }
+ }
return boost::shared_ptr<Region> ();
-}
+}
void
Session::find_equivalent_playlist_regions (boost::shared_ptr<Region> region, vector<boost::shared_ptr<Region> >& result)
@@ -2747,12 +2749,12 @@ int
Session::destroy_region (boost::shared_ptr<Region> region)
{
vector<boost::shared_ptr<Source> > srcs;
-
+
{
if (region->playlist()) {
region->playlist()->destroy_region (region);
}
-
+
for (uint32_t n = 0; n < region->n_channels(); ++n) {
srcs.push_back (region->source (n));
}
@@ -2764,7 +2766,7 @@ Session::destroy_region (boost::shared_ptr<Region> region)
(*i)->mark_for_remove ();
(*i)->drop_references ();
-
+
cerr << "source was not used by any playlist\n";
}
@@ -2784,12 +2786,12 @@ int
Session::remove_last_capture ()
{
list<boost::shared_ptr<Region> > r;
-
+
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
+
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
list<boost::shared_ptr<Region> >& l = (*i)->last_capture_regions();
-
+
if (!l.empty()) {
r.insert (r.end(), l.begin(), l.end());
l.clear ();
@@ -2819,7 +2821,7 @@ Session::add_source (boost::shared_ptr<Source> source)
entry.first = source->id();
entry.second = source;
-
+
{
Glib::Mutex::Lock lm (source_lock);
result = sources.insert (entry);
@@ -2829,14 +2831,14 @@ Session::add_source (boost::shared_ptr<Source> source)
source->GoingAway.connect (sigc::bind (mem_fun (this, &Session::remove_source), boost::weak_ptr<Source> (source)));
set_dirty();
}
-
+
boost::shared_ptr<AudioFileSource> afs;
if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) {
if (Config->get_auto_analyse_audio()) {
Analyser::queue_source_for_analysis (source, false);
}
- }
+ }
}
void
@@ -2847,22 +2849,22 @@ Session::remove_source (boost::weak_ptr<Source> src)
if (!source) {
return;
- }
+ }
- {
+ {
Glib::Mutex::Lock lm (source_lock);
if ((i = sources.find (source->id())) != sources.end()) {
sources.erase (i);
- }
+ }
}
-
+
if (!_state_of_the_state & InCleanup) {
-
+
/* save state so we don't end up with a session file
referring to non-existent sources.
*/
-
+
save_state (_current_snapshot_name);
}
}
@@ -2893,8 +2895,8 @@ Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn)
if (afs && afs->path() == path && chn == afs->channel()) {
return afs;
- }
-
+ }
+
}
return boost::shared_ptr<Source>();
}
@@ -2917,14 +2919,14 @@ Session::change_audio_path_by_name (string path, string oldname, string newname,
/* note: we know (or assume) the old path is already valid */
if (destructive) {
-
+
/* destructive file sources have a name of the form:
/path/to/Tnnnn-NAME(%[LR])?.wav
-
+
the task here is to replace NAME with the new name.
*/
-
+
/* find last slash */
string dir;
@@ -2951,16 +2953,16 @@ Session::change_audio_path_by_name (string path, string oldname, string newname,
path += '-';
path += new_legalized;
path += ".wav"; /* XXX gag me with a spoon */
-
+
} else {
-
+
/* non-destructive file sources have a name of the form:
/path/to/NAME-nnnnn(%[LR])?.wav
-
+
the task here is to replace NAME with the new name.
*/
-
+
string dir;
string suffix;
string::size_type slash;
@@ -2982,7 +2984,7 @@ Session::change_audio_path_by_name (string path, string oldname, string newname,
}
suffix = path.substr (dash+1);
-
+
// Suffix is now everything after the dash. Now we need to eliminate
// the nnnnn part, which is done by either finding a '%' or a '.'
@@ -3085,7 +3087,7 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool
if (sys::exists(buf)) {
existing++;
- }
+ }
}
@@ -3112,7 +3114,7 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool
spath += '/';
string::size_type pos = foo.find_last_of ('/');
-
+
if (pos == string::npos) {
spath += foo;
} else {
@@ -3141,14 +3143,14 @@ Session::change_midi_path_by_name (string path, string oldname, string newname,
/* note: we know (or assume) the old path is already valid */
if (destructive) {
-
+
/* destructive file sources have a name of the form:
/path/to/Tnnnn-NAME(%[LR])?.wav
-
+
the task here is to replace NAME with the new name.
*/
-
+
/* find last slash */
string dir;
@@ -3175,16 +3177,16 @@ Session::change_midi_path_by_name (string path, string oldname, string newname,
path += '-';
path += new_legalized;
path += ".mid"; /* XXX gag me with a spoon */
-
+
} else {
-
+
/* non-destructive file sources have a name of the form:
/path/to/NAME-nnnnn(%[LR])?.wav
-
+
the task here is to replace NAME with the new name.
*/
-
+
string dir;
string suffix;
string::size_type slash;
@@ -3206,7 +3208,7 @@ Session::change_midi_path_by_name (string path, string oldname, string newname,
}
suffix = path.substr (dash+1);
-
+
// Suffix is now everything after the dash. Now we need to eliminate
// the nnnnn part, which is done by either finding a '%' or a '.'
@@ -3269,7 +3271,7 @@ Session::midi_path_from_name (string name)
for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
SessionDirectory sdir((*i).path);
-
+
sys::path p = sdir.midi_path();
p /= legalized;
@@ -3280,7 +3282,7 @@ Session::midi_path_from_name (string name)
if (sys::exists (buf)) {
existing++;
- }
+ }
}
if (existing == 0) {
@@ -3305,7 +3307,7 @@ Session::midi_path_from_name (string name)
spath += '/';
string::size_type pos = foo.find_last_of ('/');
-
+
if (pos == string::npos) {
spath += foo;
} else {
@@ -3314,12 +3316,12 @@ Session::midi_path_from_name (string name)
return spath;
}
-
+
boost::shared_ptr<MidiSource>
Session::create_midi_source_for_session (MidiDiskstream& ds)
{
string mpath = midi_path_from_name (ds.name());
-
+
return boost::dynamic_pointer_cast<SMFSource> (SourceFactory::createWritable (DataType::MIDI, *this, mpath, false, frame_rate()));
}
@@ -3351,7 +3353,7 @@ Session::add_playlist (boost::shared_ptr<Playlist> playlist)
return;
}
- {
+ {
Glib::Mutex::Lock lm (playlist_lock);
if (find (playlists.begin(), playlists.end(), playlist) == playlists.end()) {
playlists.insert (playlists.begin(), playlist);
@@ -3368,7 +3370,7 @@ Session::add_playlist (boost::shared_ptr<Playlist> playlist)
void
Session::get_playlists (vector<boost::shared_ptr<Playlist> >& s)
{
- {
+ {
Glib::Mutex::Lock lm (playlist_lock);
for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
s.push_back (*i);
@@ -3395,22 +3397,22 @@ Session::track_playlist (bool inuse, boost::weak_ptr<Playlist> wpl)
return;
}
- {
+ {
Glib::Mutex::Lock lm (playlist_lock);
if (!inuse) {
unused_playlists.insert (pl);
-
+
if ((x = playlists.find (pl)) != playlists.end()) {
playlists.erase (x);
}
-
+
} else {
playlists.insert (pl);
-
+
if ((x = unused_playlists.find (pl)) != unused_playlists.end()) {
unused_playlists.erase (x);
}
@@ -3431,7 +3433,7 @@ Session::remove_playlist (boost::weak_ptr<Playlist> weak_playlist)
return;
}
- {
+ {
Glib::Mutex::Lock lm (playlist_lock);
PlaylistList::iterator i;
@@ -3445,7 +3447,7 @@ Session::remove_playlist (boost::weak_ptr<Playlist> weak_playlist)
if (i != unused_playlists.end()) {
unused_playlists.erase (i);
}
-
+
}
set_dirty();
@@ -3453,7 +3455,7 @@ Session::remove_playlist (boost::weak_ptr<Playlist> weak_playlist)
PlaylistRemoved (playlist); /* EMIT SIGNAL */
}
-void
+void
Session::set_audition (boost::shared_ptr<Region> r)
{
pending_audition_region = r;
@@ -3510,7 +3512,7 @@ Session::remove_empty_sounds ()
vector<string> audio_filenames;
get_files_in_directory (_session_dir->sound_path(), audio_filenames);
-
+
Glib::Mutex::Lock lm (source_lock);
TapeFileMatcher tape_file_matcher;
@@ -3523,7 +3525,7 @@ Session::remove_empty_sounds ()
sys::path audio_file_path (_session_dir->sound_path());
audio_file_path /= *i;
-
+
if (AudioFileSource::is_empty (*this, audio_file_path.to_string())) {
try
@@ -3534,7 +3536,7 @@ Session::remove_empty_sounds ()
}
catch (const sys::filesystem_error& err)
{
- error << err.what() << endmsg;
+ error << err.what() << endmsg;
}
}
}
@@ -3555,7 +3557,7 @@ void
Session::set_all_solo (bool yn)
{
shared_ptr<RouteList> r = routes.reader ();
-
+
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (!(*i)->is_hidden()) {
(*i)->set_solo (yn, this);
@@ -3564,12 +3566,12 @@ Session::set_all_solo (bool yn)
set_dirty();
}
-
+
void
Session::set_all_mute (bool yn)
{
shared_ptr<RouteList> r = routes.reader ();
-
+
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (!(*i)->is_hidden()) {
(*i)->set_mute (yn, this);
@@ -3578,7 +3580,7 @@ Session::set_all_mute (bool yn)
set_dirty();
}
-
+
uint32_t
Session::n_diskstreams () const
{
@@ -3604,7 +3606,7 @@ Session::graph_reordered ()
if (_state_of_the_state & InitialConnecting) {
return;
}
-
+
/* every track/bus asked for this to be handled but it was deferred because
we were connecting. do it now.
*/
@@ -3613,10 +3615,10 @@ Session::graph_reordered ()
resort_routes ();
- /* force all diskstreams to update their capture offset values to
+ /* force all diskstreams to update their capture offset values to
reflect any changes in latencies within the graph.
*/
-
+
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
@@ -3640,7 +3642,7 @@ void
Session::record_enable_change_all (bool yn)
{
shared_ptr<RouteList> r = routes.reader ();
-
+
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
Track* at;
@@ -3648,7 +3650,7 @@ Session::record_enable_change_all (bool yn)
at->set_record_enable (yn, this);
}
}
-
+
/* since we don't keep rec-enable state, don't mark session dirty */
}
@@ -3681,7 +3683,7 @@ Session::remove_processor (Processor* processor)
Send* send;
PortInsert* port_insert;
PluginInsert* plugin_insert;
-
+
if ((port_insert = dynamic_cast<PortInsert *> (processor)) != 0) {
list<PortInsert*>::iterator x = find (_port_inserts.begin(), _port_inserts.end(), port_insert);
if (x != _port_inserts.end()) {
@@ -3722,7 +3724,7 @@ Session::available_capture_duration ()
sample_bytes_on_disk = 2.0;
break;
- default:
+ default:
/* impossible, but keep some gcc versions happy */
fatal << string_compose (_("programming error: %1"),
X_("illegal native file data format"))
@@ -3735,7 +3737,7 @@ Session::available_capture_duration ()
if (_total_free_4k_blocks * scale > (double) max_frames) {
return max_frames;
}
-
+
return (nframes_t) floor (_total_free_4k_blocks * scale);
}
@@ -3746,7 +3748,7 @@ Session::add_bundle (shared_ptr<Bundle> bundle)
Glib::Mutex::Lock guard (bundle_lock);
_bundles.push_back (bundle);
}
-
+
BundleAdded (bundle); /* EMIT SIGNAL */
set_dirty();
@@ -3760,7 +3762,7 @@ Session::remove_bundle (shared_ptr<Bundle> bundle)
{
Glib::Mutex::Lock guard (bundle_lock);
BundleList::iterator i = find (_bundles.begin(), _bundles.end(), bundle);
-
+
if (i != _bundles.end()) {
_bundles.erase (i);
removed = true;
@@ -3792,7 +3794,7 @@ void
Session::tempo_map_changed (Change ignored)
{
clear_clicks ();
-
+
for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
(*i)->update_after_tempo_map_change ();
}
@@ -3812,7 +3814,7 @@ Session::ensure_buffers (ChanCount howmany)
{
if (current_block_size == 0)
return; // too early? (is this ok?)
-
+
// We need at least 2 MIDI scratch buffers to mix/merge
if (howmany.n_midi() < 2)
howmany.set_midi(2);
@@ -3822,7 +3824,7 @@ Session::ensure_buffers (ChanCount howmany)
_scratch_buffers->ensure_buffers(howmany, current_block_size);
_mix_buffers->ensure_buffers(howmany, current_block_size);
_silent_buffers->ensure_buffers(howmany, current_block_size);
-
+
allocate_pan_automation_buffers (current_block_size, howmany.n_audio(), false);
}
@@ -3836,10 +3838,10 @@ Session::next_insert_id ()
if (!insert_bitset[n]) {
insert_bitset[n] = true;
return n;
-
+
}
}
-
+
/* none available, so resize and try again */
insert_bitset.resize (insert_bitset.size() + 16, false);
@@ -3856,10 +3858,10 @@ Session::next_send_id ()
if (!send_bitset[n]) {
send_bitset[n] = true;
return n;
-
+
}
}
-
+
/* none available, so resize and try again */
send_bitset.resize (send_bitset.size() + 16, false);
@@ -3907,7 +3909,7 @@ Session::named_selection_by_name (string name)
void
Session::add_named_selection (NamedSelection* named_selection)
{
- {
+ {
Glib::Mutex::Lock lm (named_selection_lock);
named_selections.insert (named_selections.begin(), named_selection);
}
@@ -3926,7 +3928,7 @@ Session::remove_named_selection (NamedSelection* named_selection)
{
bool removed = false;
- {
+ {
Glib::Mutex::Lock lm (named_selection_lock);
NamedSelectionList::iterator i = find (named_selections.begin(), named_selections.end(), named_selection);
@@ -3958,13 +3960,13 @@ bool
Session::route_name_unique (string n) const
{
shared_ptr<RouteList> r = routes.reader ();
-
+
for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
if ((*i)->name() == n) {
return false;
}
}
-
+
return true;
}
@@ -3992,7 +3994,7 @@ Session::allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, b
}
_pan_automation_buffer = new pan_t*[howmany];
-
+
for (uint32_t i = 0; i < howmany; ++i) {
_pan_automation_buffer[i] = new pan_t[nframes];
}
@@ -4021,7 +4023,7 @@ Session::freeze (InterThreadInfo& itt)
}
int
-Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t len,
+Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t len,
bool overwrite, vector<boost::shared_ptr<Source> >& srcs, InterThreadInfo& itt)
{
int ret = -1;
@@ -4041,9 +4043,9 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
const nframes_t chunk_size = (128 * 1024)/4;
g_atomic_int_set (&processing_prohibited, 1);
-
+
/* call tree *MUST* hold route_lock */
-
+
if ((playlist = track.diskstream()->playlist()) == 0) {
goto out;
}
@@ -4062,17 +4064,17 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
break;
}
}
-
+
if (x == 99999) {
error << string_compose (_("too many bounced versions of playlist \"%1\""), playlist->name()) << endmsg;
goto out;
}
-
+
try {
fsource = boost::dynamic_pointer_cast<AudioFileSource> (
SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate()));
}
-
+
catch (failed_constructor& err) {
error << string_compose (_("cannot create new audio file \"%1\" for %2"), buf, track.name()) << endmsg;
goto out;
@@ -4082,7 +4084,7 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
}
/* XXX need to flush all redirects */
-
+
position = start;
to_do = len;
@@ -4095,11 +4097,11 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
if (afs)
afs->prepare_for_peakfile_writes ();
}
-
+
while (to_do && !itt.cancel) {
-
+
this_chunk = min (to_do, chunk_size);
-
+
if (track.export_stuff (buffers, start, this_chunk)) {
goto out;
}
@@ -4107,45 +4109,45 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
uint32_t n = 0;
for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) {
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
-
+
if (afs) {
if (afs->write (buffers.get_audio(n).data(), this_chunk) != this_chunk) {
goto out;
}
}
}
-
+
start += this_chunk;
to_do -= this_chunk;
-
+
itt.progress = (float) (1.0 - ((double) to_do / len));
}
if (!itt.cancel) {
-
+
time_t now;
struct tm* xnow;
time (&now);
xnow = localtime (&now);
-
+
for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src) {
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
-
+
if (afs) {
afs->update_header (position, *xnow, now);
afs->flush_header ();
}
}
-
+
/* construct a region to represent the bounced material */
- boost::shared_ptr<Region> aregion = RegionFactory::create (srcs, 0, srcs.front()->length(),
+ boost::shared_ptr<Region> aregion = RegionFactory::create (srcs, 0, srcs.front()->length(),
region_name_from_path (srcs.front()->name(), true));
ret = 0;
}
-
+
out:
if (ret) {
for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
@@ -4161,7 +4163,7 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
} else {
for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
-
+
if (afs)
afs->done_with_peakfile_writes ();
}
@@ -4183,7 +4185,7 @@ Session::get_silent_buffers (ChanCount count)
_silent_buffers->get(*t, i).clear();
}
}
-
+
return *_silent_buffers;
}
@@ -4203,7 +4205,7 @@ Session::get_mix_buffers (ChanCount count)
return *_mix_buffers;
}
-uint32_t
+uint32_t
Session::ntracks () const
{
uint32_t n = 0;
@@ -4218,7 +4220,7 @@ Session::ntracks () const
return n;
}
-uint32_t
+uint32_t
Session::nbusses () const
{
uint32_t n = 0;
diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc
index b4938636a2..a807c5e98b 100644
--- a/libs/ardour/session_midi.cc
+++ b/libs/ardour/session_midi.cc
@@ -1,6 +1,6 @@
/*
- Copyright (C) 1999-2002 Paul Davis
+ Copyright (C) 1999-2002 Paul Davis
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
@@ -94,8 +94,14 @@ Session::use_config_midi_ports ()
set_midi_port ("");
}
+ if (default_midi_clock_port) {
+ set_midi_clock_port (default_midi_clock_port->name());
+ } else {
+ set_midi_clock_port ("");
+ }
+
return 0;
-}
+}
/***********************************************************************
@@ -190,7 +196,7 @@ Session::set_mmc_port (string port_tag)
delete mmc;
}
- mmc = new MIDI::MachineControl (*_mmc_port, 1.0,
+ mmc = new MIDI::MachineControl (*_mmc_port, 1.0,
MMC_CommandSignature,
MMC_ResponseSignature);
@@ -199,29 +205,29 @@ Session::set_mmc_port (string port_tag)
mmc->set_send_device_id (old_send_device_id);
}
- mmc->Play.connect
+ mmc->Play.connect
(mem_fun (*this, &Session::mmc_deferred_play));
- mmc->DeferredPlay.connect
+ mmc->DeferredPlay.connect
(mem_fun (*this, &Session::mmc_deferred_play));
- mmc->Stop.connect
+ mmc->Stop.connect
(mem_fun (*this, &Session::mmc_stop));
- mmc->FastForward.connect
+ mmc->FastForward.connect
(mem_fun (*this, &Session::mmc_fast_forward));
- mmc->Rewind.connect
+ mmc->Rewind.connect
(mem_fun (*this, &Session::mmc_rewind));
- mmc->Pause.connect
+ mmc->Pause.connect
(mem_fun (*this, &Session::mmc_pause));
- mmc->RecordPause.connect
+ mmc->RecordPause.connect
(mem_fun (*this, &Session::mmc_record_pause));
- mmc->RecordStrobe.connect
+ mmc->RecordStrobe.connect
(mem_fun (*this, &Session::mmc_record_strobe));
- mmc->RecordExit.connect
+ mmc->RecordExit.connect
(mem_fun (*this, &Session::mmc_record_exit));
- mmc->Locate.connect
+ mmc->Locate.connect
(mem_fun (*this, &Session::mmc_locate));
- mmc->Step.connect
+ mmc->Step.connect
(mem_fun (*this, &Session::mmc_step));
- mmc->Shuttle.connect
+ mmc->Shuttle.connect
(mem_fun (*this, &Session::mmc_shuttle));
mmc->TrackRecordStatusChange.connect
(mem_fun (*this, &Session::mmc_record_enable));
@@ -232,7 +238,7 @@ Session::set_mmc_port (string port_tag)
_mmc_port->input()->start.connect (mem_fun (*this, &Session::spp_start));
_mmc_port->input()->contineu.connect (mem_fun (*this, &Session::spp_continue));
_mmc_port->input()->stop.connect (mem_fun (*this, &Session::spp_stop));
-
+
Config->set_mmc_port_name (port_tag);
out:
@@ -261,9 +267,9 @@ Session::set_midi_port (string port_tag)
}
_midi_port = port;
-
+
/* XXX need something to forward this to control protocols ? or just
- use the signal below
+ use the signal below
*/
Config->set_midi_port_name (port_tag);
@@ -276,6 +282,52 @@ Session::set_midi_port (string port_tag)
return 0;
}
+int
+Session::set_midi_clock_port (string port_tag)
+{
+ MIDIClock_Slave *ms;
+
+ if (port_tag.length() == 0) {
+
+ if (_slave && ((ms = dynamic_cast<MIDIClock_Slave*> (_slave)) != 0)) {
+ error << _("Ardour is slaved to MIDI Clock - port cannot be reset") << endmsg;
+ return -1;
+ }
+
+ if (_midi_clock_port == 0) {
+ return 0;
+ }
+
+ _midi_clock_port = 0;
+ goto out;
+ }
+
+ MIDI::Port* port;
+
+ if ((port = MIDI::Manager::instance()->port (port_tag)) == 0) {
+ error << string_compose (_("unknown port %1 requested for MIDI Clock"), port_tag) << endl;
+ return -1;
+ }
+
+ _midi_clock_port = port;
+
+ if (_slave && ((ms = dynamic_cast<MIDIClock_Slave*> (_slave)) != 0)) {
+ ms->rebind (*port);
+ }
+
+ Config->set_midi_clock_port_name (port_tag);
+
+ _midi_clock_port->input()->start.connect (mem_fun (*this, &Session::midi_clock_start));
+ _midi_clock_port->input()->contineu.connect (mem_fun (*this, &Session::midi_clock_continue));
+ _midi_clock_port->input()->stop.connect (mem_fun (*this, &Session::midi_clock_stop));
+
+ out:
+ MIDIClock_PortChanged(); /* EMIT SIGNAL */
+ change_midi_ports ();
+ set_dirty();
+ return 0;
+}
+
void
Session::set_trace_midi_input (bool yn, MIDI::Port* port)
{
@@ -292,7 +344,7 @@ Session::set_trace_midi_input (bool yn, MIDI::Port* port)
input_parser->trace (yn, &cout, "input: ");
}
}
-
+
if (_mtc_port && _mtc_port != _mmc_port) {
if ((input_parser = _mtc_port->input()) != 0) {
input_parser->trace (yn, &cout, "input: ");
@@ -324,7 +376,7 @@ Session::set_trace_midi_output (bool yn, MIDI::Port* port)
output_parser->trace (yn, &cout, "output: ");
}
}
-
+
if (_mtc_port && _mtc_port != _mmc_port) {
if ((output_parser = _mtc_port->output()) != 0) {
output_parser->trace (yn, &cout, "output: ");
@@ -357,7 +409,7 @@ Session::get_trace_midi_input(MIDI::Port *port)
return input_parser->tracing();
}
}
-
+
if (_mtc_port) {
if ((input_parser = _mtc_port->input()) != 0) {
return input_parser->tracing();
@@ -389,7 +441,7 @@ Session::get_trace_midi_output(MIDI::Port *port)
return output_parser->tracing();
}
}
-
+
if (_mtc_port) {
if ((output_parser = _mtc_port->output()) != 0) {
return output_parser->tracing();
@@ -414,14 +466,14 @@ Session::setup_midi_control ()
next_quarter_frame_to_send = 0;
/* setup the MMC buffer */
-
+
mmc_buffer[0] = 0xf0; // SysEx
mmc_buffer[1] = 0x7f; // Real Time SysEx ID for MMC
mmc_buffer[2] = (mmc ? mmc->send_device_id() : 0x7f);
mmc_buffer[3] = 0x6; // MCC
/* Set up the qtr frame message */
-
+
mtc_msg[0] = 0xf1;
mtc_msg[2] = 0xf1;
mtc_msg[4] = 0xf1;
@@ -455,6 +507,28 @@ Session::spp_stop (Parser& ignored)
}
void
+Session::midi_clock_start (Parser& ignored)
+{
+ if (Config->get_midi_clock_control() && (Config->get_slave_source() == MIDIClock)) {
+ request_transport_speed (1.0);
+ }
+}
+
+void
+Session::midi_clock_continue (Parser& ignored)
+{
+ midi_clock_start (ignored);
+}
+
+void
+Session::midi_clock_stop (Parser& ignored)
+{
+ if (Config->get_midi_clock_control()) {
+ request_stop ();
+ }
+}
+
+void
Session::mmc_deferred_play (MIDI::MachineControl &mmc)
{
if (Config->get_mmc_control() && (Config->get_slave_source() != MTC)) {
@@ -473,7 +547,7 @@ Session::mmc_record_pause (MIDI::MachineControl &mmc)
void
Session::mmc_record_strobe (MIDI::MachineControl &mmc)
{
- if (!Config->get_mmc_control())
+ if (!Config->get_mmc_control())
return;
/* record strobe does an implicit "Play" command */
@@ -485,11 +559,11 @@ Session::mmc_record_strobe (MIDI::MachineControl &mmc)
its not the same as maybe_enable_record() though, because
that *can* switch to Recording, which we do not want.
*/
-
+
save_state ("", true);
g_atomic_int_set (&_record_status, Enabled);
RecordStateChanged (); /* EMIT SIGNAL */
-
+
request_transport_speed (1.0);
} else {
@@ -545,7 +619,7 @@ Session::mmc_step (MIDI::MachineControl &mmc, int steps)
struct timeval diff = { 0, 0 };
gettimeofday (&now, 0);
-
+
timersub (&now, &last_mmc_step, &diff);
gettimeofday (&now, 0);
@@ -554,10 +628,10 @@ Session::mmc_step (MIDI::MachineControl &mmc, int steps)
if (last_mmc_step.tv_sec != 0 && (diff.tv_usec + (diff.tv_sec * 1000000)) < _engine.usecs_per_cycle()) {
return;
}
-
+
double diff_secs = diff.tv_sec + (diff.tv_usec / 1000000.0);
double cur_speed = (((steps * 0.5) * smpte_frames_per_second()) / diff_secs) / smpte_frames_per_second();
-
+
if (_transport_speed == 0 || cur_speed * _transport_speed < 0) {
/* change direction */
step_speed = cur_speed;
@@ -568,13 +642,13 @@ Session::mmc_step (MIDI::MachineControl &mmc, int steps)
step_speed *= 0.25;
#if 0
- cerr << "delta = " << diff_secs
+ cerr << "delta = " << diff_secs
<< " ct = " << _transport_speed
<< " steps = " << steps
- << " new speed = " << cur_speed
+ << " new speed = " << cur_speed
<< " speed = " << step_speed
<< endl;
-#endif
+#endif
request_transport_speed (step_speed);
last_mmc_step = now;
@@ -617,10 +691,10 @@ Session::mmc_locate (MIDI::MachineControl &mmc, const MIDI::byte* mmc_tc)
smpte.frames = mmc_tc[3];
smpte.rate = smpte_frames_per_second();
smpte.drop = smpte_drop_frames();
-
+
// Also takes smpte offset into account:
smpte_to_sample( smpte, target_frame, true /* use_offset */, false /* use_subframes */ );
-
+
if (target_frame > max_frames) {
target_frame = max_frames;
}
@@ -667,7 +741,7 @@ Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled)
RouteList::iterator i;
boost::shared_ptr<RouteList> r = routes.reader();
-
+
for (i = r->begin(); i != r->end(); ++i) {
AudioTrack *at;
@@ -710,7 +784,7 @@ Session::send_full_time_code(nframes_t nframes)
if (_mtc_port == 0 || !session_send_mtc) {
return 0;
}
-
+
// Get smpte time for this transport frame
sample_to_smpte(_transport_frame, smpte, true /* use_offset */, false /* no subframes */);
@@ -763,31 +837,31 @@ Session::send_full_time_code(nframes_t nframes)
*/
int
Session::send_midi_time_code_for_cycle(nframes_t nframes)
-{
+{
assert (next_quarter_frame_to_send >= 0);
assert (next_quarter_frame_to_send <= 7);
-
+
if (_mtc_port == 0 || !session_send_mtc || transmitting_smpte_time.negative
/*|| (next_quarter_frame_to_send < 0)*/ ) {
// cerr << "(MTC) Not sending MTC\n";
return 0;
}
-
+
/* Duration of one quarter frame */
nframes_t quarter_frame_duration = ((long) _frames_per_smpte_frame) >> 2;
-
+
// cerr << "(MTC) TR: " << _transport_frame << " - SF: " << outbound_mtc_smpte_frame
// << " - NQ: " << next_quarter_frame_to_send << " - FD" << quarter_frame_duration << endl;
-
+
// FIXME: this should always be true
//assert((outbound_mtc_smpte_frame + (next_quarter_frame_to_send * quarter_frame_duration))
// > _transport_frame);
-
+
// Send quarter frames for this cycle
while (_transport_frame + nframes > (outbound_mtc_smpte_frame +
(next_quarter_frame_to_send * quarter_frame_duration))) {
-
+
// cerr << "(MTC) Next frame to send: " << next_quarter_frame_to_send << endl;
switch (next_quarter_frame_to_send) {
@@ -815,11 +889,11 @@ Session::send_midi_time_code_for_cycle(nframes_t nframes)
case 7:
mtc_msg[1] = 0x70 | (((mtc_smpte_bits|transmitting_smpte_time.hours) & 0xf0) >> 4);
break;
- }
-
+ }
+
const nframes_t msg_time = (outbound_mtc_smpte_frame
+ (quarter_frame_duration * next_quarter_frame_to_send));
-
+
// This message must fall within this block or something is broken
assert(msg_time >= _transport_frame);
assert(msg_time < _transport_frame + nframes);
@@ -828,7 +902,7 @@ Session::send_midi_time_code_for_cycle(nframes_t nframes)
assert(out_stamp < nframes);
if (_mtc_port->midimsg (mtc_msg, 2, out_stamp)) {
- error << string_compose(_("Session: cannot send quarter-frame MTC message (%1)"), strerror (errno))
+ error << string_compose(_("Session: cannot send quarter-frame MTC message (%1)"), strerror (errno))
<< endmsg;
return -1;
}
@@ -840,7 +914,7 @@ Session::send_midi_time_code_for_cycle(nframes_t nframes)
<< ", qfm = " << next_quarter_frame_to_send
<< ", stamp = " << out_stamp
<< ", delta = " << _transport_frame + out_stamp - last_time << endl;*/
-
+
// Increment quarter frame counter
next_quarter_frame_to_send++;
@@ -849,7 +923,7 @@ Session::send_midi_time_code_for_cycle(nframes_t nframes)
next_quarter_frame_to_send = 0;
// Increment smpte time twice
SMPTE::increment( transmitting_smpte_time );
- SMPTE::increment( transmitting_smpte_time );
+ SMPTE::increment( transmitting_smpte_time );
// Re-calculate timing of first quarter frame
//smpte_to_sample( transmitting_smpte_time, outbound_mtc_smpte_frame, true /* use_offset */, false );
outbound_mtc_smpte_frame += 8 * quarter_frame_duration;
@@ -880,7 +954,7 @@ Session::deliver_mmc (MIDI::MachineControl::Command cmd, nframes_t where)
mmc_buffer[nbytes++] = cmd;
// cerr << "delivering MMC, cmd = " << hex << (int) cmd << dec << endl;
-
+
switch (cmd) {
case MachineControl::cmdLocate:
smpte_time_subframes (where, smpte);
@@ -925,7 +999,7 @@ Session::deliver_mmc (MIDI::MachineControl::Command cmd, nframes_t where)
if (_mmc_port->midimsg (mmc_buffer, nbytes, 0)) {
error << string_compose(_("MMC: cannot send command %1%2%3"), &hex, cmd, &dec) << endmsg;
- }
+ }
}
}
@@ -959,7 +1033,7 @@ Session::mmc_step_timeout ()
}
/*---------------------------------------------------------------------------
- MIDI THREAD
+ MIDI THREAD
---------------------------------------------------------------------------*/
int
@@ -995,9 +1069,9 @@ Session::terminate_midi_thread ()
MIDIRequest* request = new MIDIRequest;
void* status;
-
+
request->type = MIDIRequest::Quit;
-
+
midi_requests.write (&request, 1);
poke_midi_thread ();
@@ -1042,14 +1116,14 @@ Session::midi_thread_work ()
memset (&rtparam, 0, sizeof (rtparam));
rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
-
+
if ((x = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
// do we care? not particularly.
- }
+ }
- /* set up the port vector; 4 is the largest possible size for now */
+ /* set up the port vector; 5 is the largest possible size for now */
- ports.assign (4, (MIDI::Port*) 0);
+ ports.assign (5, (MIDI::Port*) 0);
while (1) {
@@ -1078,6 +1152,15 @@ Session::midi_thread_work ()
nfds++;
}
+ cerr << "before handling midi clock port" << endl;
+ if (_midi_clock_port && (_midi_clock_port != _mmc_port || !Config->get_mmc_control()) && _midi_clock_port->selectable() >= 0) {
+ cerr << "inside handling midi clock port" << endl;
+ pfd[nfds].fd = _midi_clock_port->selectable();
+ pfd[nfds].events = POLLIN|POLLHUP|POLLERR;
+ ports[nfds] = _midi_clock_port;
+ nfds++;
+ }
+
/* if we are using MMC control, we obviously have to listen
the relevant port.
*/
@@ -1088,7 +1171,7 @@ Session::midi_thread_work ()
ports[nfds] = _midi_port;
nfds++;
}
-
+
if (!midi_timeouts.empty()) {
timeout = 100; /* 10msecs */
} else {
@@ -1121,7 +1204,7 @@ Session::midi_thread_work ()
if (pfd[0].revents & POLLIN) {
char foo[16];
-
+
// cerr << "MIDI request FIFO ready\n";
fds_ready++;
@@ -1154,13 +1237,13 @@ Session::midi_thread_work ()
// cerr << "rebind\n";
restart = true;
break;
-
+
case MIDIRequest::Quit:
delete request;
pthread_exit_pbd (0);
/*NOTREACHED*/
break;
-
+
default:
break;
}
@@ -1169,7 +1252,7 @@ Session::midi_thread_work ()
delete request;
}
- }
+ }
if (restart) {
continue;
@@ -1182,7 +1265,7 @@ Session::midi_thread_work ()
// error << string_compose(_("Transport: error polling MIDI port %1 (revents =%2%3%4"), p, &hex, pfd[p].revents, &dec) << endmsg;
break;
}
-
+
if (pfd[p].revents & POLLIN) {
fds_ready++;
ports[p]->parse ();
@@ -1190,19 +1273,19 @@ Session::midi_thread_work ()
}
/* timeout driven */
-
+
if (fds_ready < 2 && timeout != -1) {
for (MidiTimeoutList::iterator i = midi_timeouts.begin(); i != midi_timeouts.end(); ) {
-
+
MidiTimeoutList::iterator tmp;
tmp = i;
++tmp;
-
+
if (!(*i)()) {
midi_timeouts.erase (i);
}
-
+
i = tmp;
}
}
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index c86a868e56..61a741d0fb 100644
--- a/libs/ardour/session_transport.cc
+++ b/libs/ardour/session_transport.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1999-2003 Paul Davis
+ Copyright (C) 1999-2003 Paul Davis
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
@@ -55,7 +55,7 @@ Session::request_input_change_handling ()
if (!(_state_of_the_state & (InitialConnecting|Deletion))) {
Event* ev = new Event (Event::InputConfigurationChange, Event::Add, Event::Immediate, 0, 0.0);
queue_event (ev);
- }
+ }
}
void
@@ -112,7 +112,7 @@ Session::force_locate (nframes_t target_frame, bool with_roll)
void
Session::request_play_loop (bool yn)
{
- Event* ev;
+ Event* ev;
Location *location = _locations.auto_loop_location();
if (location == 0 && yn) {
@@ -135,7 +135,7 @@ void
Session::realtime_stop (bool abort)
{
/* assume that when we start, we'll be moving forwards */
-
+
// FIXME: where should this really be? [DR]
//send_full_time_code();
deliver_mmc (MIDI::MachineControl::cmdStop, _transport_frame);
@@ -174,7 +174,7 @@ Session::realtime_stop (bool abort)
disable_record (true);
reset_slave_state ();
-
+
_transport_speed = 0;
if (Config->get_use_video_sync()) {
@@ -221,7 +221,7 @@ Session::butler_transport_work ()
/* don't seek if locate will take care of that in non_realtime_stop() */
if (!(post_transport_work & PostTransportLocate)) {
-
+
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if (!(*i)->hidden()) {
if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) {
@@ -239,7 +239,7 @@ Session::butler_transport_work ()
}
}
}
-
+
if (post_transport_work & PostTransportLocate) {
non_realtime_locate ();
}
@@ -263,7 +263,7 @@ Session::butler_transport_work ()
if (post_transport_work & PostTransportAudition) {
non_realtime_set_audition ();
}
-
+
g_atomic_int_dec_and_test (&butler_should_do_transport_work);
}
@@ -293,7 +293,7 @@ Session::non_realtime_overwrite (int on_entry, bool& finished)
}
}
-
+
void
Session::non_realtime_locate ()
{
@@ -317,7 +317,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
saved = false;
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
+
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if ((*i)->get_captured_frames () != 0) {
did_record = true;
@@ -326,7 +326,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
}
/* stop and locate are merged here because they share a lot of common stuff */
-
+
time (&xnow);
now = localtime (&xnow);
@@ -340,10 +340,10 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
if (did_record) {
begin_reversible_command ("capture");
-
+
Location* loc = _locations.end_location();
bool change_end = false;
-
+
if (_transport_frame < loc->end()) {
/* stopped recording before current end */
@@ -353,15 +353,15 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
/* first capture for this session, move end back to where we are */
change_end = true;
- }
+ }
} else if (_transport_frame > loc->end()) {
-
+
/* stopped recording after the current end, extend it */
change_end = true;
}
-
+
if (change_end) {
XMLNode &before = loc->get_state();
loc->set_end(_transport_frame);
@@ -376,7 +376,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
(*i)->transport_stopped (*now, xnow, abort);
}
-
+
boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
@@ -384,25 +384,25 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
(*i)->set_pending_declick (0);
}
}
-
+
if (did_record) {
commit_reversible_command ();
- }
-
+ }
+
if (_engine.running()) {
update_latency_compensation (true, abort);
}
- if ((Config->get_slave_source() == None && Config->get_auto_return()) ||
- (post_transport_work & PostTransportLocate) ||
+ if ((Config->get_slave_source() == None && Config->get_auto_return()) ||
+ (post_transport_work & PostTransportLocate) ||
(_requested_return_frame >= 0) ||
synced_to_jack()) {
-
+
if (pending_locate_flush) {
flush_all_inserts ();
}
-
- if (((Config->get_slave_source() == None && Config->get_auto_return()) ||
+
+ if (((Config->get_slave_source() == None && Config->get_auto_return()) ||
synced_to_jack() ||
_requested_return_frame >= 0) &&
!(post_transport_work & PostTransportLocate)) {
@@ -421,12 +421,12 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
if (synced_to_jack() && !play_loop) {
do_locate = true;
}
-
+
if (do_locate) {
// cerr << "non-realtimestop: transport locate to " << _transport_frame << endl;
_engine.transport_locate (_transport_frame);
}
- }
+ }
#ifndef LEAVE_TRANSPORT_UNADJUSTED
}
@@ -475,7 +475,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
RecordStateChanged (); /* emit signal */
#endif
}
-
+
if ((post_transport_work & PostTransportLocate) && get_record_enabled()) {
/* capture start has been changed, so save pending state */
save_state ("", true);
@@ -485,7 +485,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
/* always try to get rid of this */
remove_pending_capture_state ();
-
+
/* save the current state of things if appropriate */
if (did_record && !saved) {
@@ -496,11 +496,11 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
DurationChanged (); /* EMIT SIGNAL */
}
- if (post_transport_work & PostTransportStop) {
+ if (post_transport_work & PostTransportStop) {
_play_range = false;
/* do not turn off autoloop on stop */
-
+
}
nframes_t tf = _transport_frame;
@@ -524,7 +524,7 @@ Session::check_declick_out ()
/* this is called after a process() iteration. if PendingDeclickOut was set,
it means that we were waiting to declick the output (which has just been
done) before doing something else. this is where we do that "something else".
-
+
note: called from the audio thread.
*/
@@ -544,11 +544,11 @@ void
Session::set_play_loop (bool yn)
{
/* Called from event-handling context */
-
+
if ((actively_recording() && yn) || _locations.auto_loop_location() == 0) {
return;
}
-
+
set_dirty();
if (yn && Config->get_seamless_loop() && synced_to_jack()) {
@@ -558,12 +558,12 @@ Session::set_play_loop (bool yn)
return;
}
-
+
if ((play_loop = yn)) {
Location *loc;
-
+
if ((loc = _locations.auto_loop_location()) != 0) {
if (Config->get_seamless_loop()) {
@@ -584,9 +584,9 @@ Session::set_play_loop (bool yn)
}
}
}
-
+
/* stick in the loop event */
-
+
Event* event = new Event (Event::AutoLoop, Event::Replace, loc->end(), loc->start(), 0.0f);
merge_event (event);
@@ -614,7 +614,7 @@ Session::set_play_loop (bool yn)
(*i)->set_loop (0);
}
}
-
+
}
}
@@ -689,17 +689,17 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
pending_locate_roll = with_roll;
pending_locate_flush = with_flush;
return;
- }
+ }
}
if (transport_rolling() && (!auto_play_legal || !Config->get_auto_play()) && !with_roll && !(synced_to_jack() && play_loop)) {
realtime_stop (false);
- }
+ }
if ( !with_loop || loop_changing) {
post_transport_work = PostTransportWork (post_transport_work | PostTransportLocate);
-
+
if (with_roll) {
post_transport_work = PostTransportWork (post_transport_work | PostTransportRoll);
}
@@ -711,13 +711,13 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
/* this is functionally what clear_clicks() does but with a tentative lock */
Glib::RWLock::WriterLock clickm (click_lock, Glib::TRY_LOCK);
-
+
if (clickm.locked()) {
-
+
for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) {
delete *i;
}
-
+
clicks.clear ();
}
}
@@ -752,7 +752,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
/* cancel looped playback if transport pos outside of loop range */
if (play_loop) {
Location* al = _locations.auto_loop_location();
-
+
if (al && (_transport_frame < al->start() || _transport_frame > al->end())) {
// cancel looping directly, this is called from event handling context
set_play_loop (false);
@@ -762,7 +762,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
// this is only necessary for seamless looping
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
+
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if ((*i)->record_enabled ()) {
// tell it we've looped, so it can deal with the record state
@@ -774,7 +774,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
TransportLooped(); // EMIT SIGNAL
}
}
-
+
loop_changing = false;
_send_smpte_update = true;
@@ -808,7 +808,7 @@ Session::set_transport_speed (float speed, bool abort)
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if ((*i)->record_enabled ()) {
//cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl;
- (*i)->monitor_input (true);
+ (*i)->monitor_input (true);
}
}
}
@@ -818,7 +818,7 @@ Session::set_transport_speed (float speed, bool abort)
} else {
stop_transport (abort);
}
-
+
} else if (transport_stopped() && speed == 1.0) {
/* we are stopped and we want to start rolling at speed 1 */
@@ -834,7 +834,7 @@ Session::set_transport_speed (float speed, bool abort)
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if (Config->get_auto_input() && (*i)->record_enabled ()) {
//cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
- (*i)->monitor_input (false);
+ (*i)->monitor_input (false);
}
}
}
@@ -868,7 +868,7 @@ Session::set_transport_speed (float speed, bool abort)
if (speed < 0.0f && _transport_frame == 0) {
return;
}
-
+
clear_clicks ();
/* if we are reversing relative to the current speed, or relative to the speed
@@ -878,17 +878,17 @@ Session::set_transport_speed (float speed, bool abort)
if ((_transport_speed && speed * _transport_speed < 0.0f) || (_last_transport_speed * speed < 0.0f) || (_last_transport_speed == 0.0f && speed < 0.0f)) {
post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse);
}
-
+
_last_transport_speed = _transport_speed;
_transport_speed = speed;
-
+
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
}
}
-
+
if (post_transport_work & (PostTransportSpeed|PostTransportReverse)) {
schedule_butler_transport_work ();
}
@@ -903,11 +903,11 @@ Session::stop_transport (bool abort)
if (_transport_speed == 0.0f) {
return;
}
-
- if (actively_recording() && !(transport_sub_state & StopPendingCapture) &&
- _worst_output_latency > current_block_size)
+
+ if (actively_recording() && !(transport_sub_state & StopPendingCapture) &&
+ _worst_output_latency > current_block_size)
{
-
+
/* we need to capture the audio that has still not yet been received by the system
at the time the stop is requested, so we have to roll past that time.
@@ -915,16 +915,16 @@ Session::stop_transport (bool abort)
block before the actual end. we'll declick in the subsequent block,
and then we'll really be stopped.
*/
-
- Event *ev = new Event (Event::StopOnce, Event::Replace,
+
+ Event *ev = new Event (Event::StopOnce, Event::Replace,
_transport_frame + _worst_output_latency - current_block_size,
0, 0, abort);
-
+
merge_event (ev);
transport_sub_state |= StopPendingCapture;
pending_abort = abort;
return;
- }
+ }
if ((transport_sub_state & PendingDeclickOut) == 0) {
@@ -944,7 +944,7 @@ Session::start_transport ()
_last_roll_location = _transport_frame;
/* if record status is Enabled, move it to Recording. if its
- already Recording, move it to Disabled.
+ already Recording, move it to Disabled.
*/
switch (record_status()) {
@@ -978,7 +978,7 @@ Session::actually_start_transport ()
transport_sub_state |= PendingDeclickIn;
_transport_speed = 1.0;
-
+
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
(*i)->realtime_set_speed ((*i)->speed(), true);
@@ -1012,7 +1012,7 @@ Session::post_transport ()
if (((Config->get_slave_source() == None && (auto_play_legal && Config->get_auto_play())) && !_exporting) || (post_transport_work & PostTransportRoll)) {
start_transport ();
-
+
} else {
transport_sub_state = 0;
}
@@ -1057,7 +1057,7 @@ Session::set_slave_source (SlaveSource src)
// if (src == JACK && Config->get_jack_time_master()) {
// return;
// }
-
+
if (_slave) {
delete _slave;
_slave = 0;
@@ -1071,7 +1071,7 @@ Session::set_slave_source (SlaveSource src)
case None:
stop_transport ();
break;
-
+
case MTC:
if (_mtc_port) {
try {
@@ -1088,15 +1088,33 @@ Session::set_slave_source (SlaveSource src)
}
_desired_transport_speed = _transport_speed;
break;
-
+
+ case MIDIClock:
+ if (_midi_clock_port) {
+ try {
+ _slave = new MIDIClock_Slave (*this, *_midi_clock_port, 24);
+ }
+
+ catch (failed_constructor& err) {
+ return;
+ }
+
+ } else {
+ error << _("No MIDI Clock port defined: MIDI Clock slaving is impossible.") << endmsg;
+ return;
+ }
+ _desired_transport_speed = _transport_speed;
+ break;
+
case JACK:
_slave = new JACK_Slave (_engine.jack());
_desired_transport_speed = _transport_speed;
break;
+
};
Config->set_slave_source (src);
-
+
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if (!(*i)->hidden()) {
@@ -1174,7 +1192,7 @@ Session::setup_auto_play ()
/* Called from event-processing context */
Event* ev;
-
+
_clear_event_type (Event::RangeStop);
_clear_event_type (Event::RangeLocate);
@@ -1183,48 +1201,48 @@ Session::setup_auto_play ()
}
list<AudioRange>::size_type sz = current_audio_range.size();
-
+
if (sz > 1) {
-
- list<AudioRange>::iterator i = current_audio_range.begin();
+
+ list<AudioRange>::iterator i = current_audio_range.begin();
list<AudioRange>::iterator next;
-
+
while (i != current_audio_range.end()) {
-
+
next = i;
++next;
-
+
/* locating/stopping is subject to delays for declicking.
*/
-
+
nframes_t requested_frame = (*i).end;
-
+
if (requested_frame > current_block_size) {
requested_frame -= current_block_size;
} else {
requested_frame = 0;
}
-
+
if (next == current_audio_range.end()) {
ev = new Event (Event::RangeStop, Event::Add, requested_frame, 0, 0.0f);
} else {
ev = new Event (Event::RangeLocate, Event::Add, requested_frame, (*next).start, 0.0f);
}
-
+
merge_event (ev);
-
+
i = next;
}
-
+
} else if (sz == 1) {
-
+
ev = new Event (Event::RangeStop, Event::Add, current_audio_range.front().end, 0, 0.0f);
merge_event (ev);
-
- }
+
+ }
/* now start rolling at the right place */
-
+
ev = new Event (Event::LocateRoll, Event::Add, Event::Immediate, current_audio_range.front().start, 0.0f, false);
merge_event (ev);
}
@@ -1254,14 +1272,14 @@ Session::engine_halted ()
/* there will be no more calls to process(), so
we'd better clean up for ourselves, right now.
- but first, make sure the butler is out of
+ but first, make sure the butler is out of
the picture.
*/
g_atomic_int_set (&butler_should_do_transport_work, 0);
post_transport_work = PostTransportWork (0);
stop_butler ();
-
+
realtime_stop (false);
non_realtime_stop (false, 0, ignored);
transport_sub_state = 0;
@@ -1282,7 +1300,7 @@ Session::xrun_recovery ()
*/
engine_halted();
- }
+ }
}
void
@@ -1299,15 +1317,15 @@ Session::update_latency_compensation (bool with_stop, bool abort)
boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-
+
if (with_stop) {
- (*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate),
+ (*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate),
(!(post_transport_work & PostTransportLocate) || pending_locate_flush));
}
-
+
nframes_t old_latency = (*i)->signal_latency ();
nframes_t track_latency = (*i)->update_total_latency ();
-
+
if (old_latency != track_latency) {
(*i)->update_port_total_latencies ();
update_jack = true;
@@ -1316,7 +1334,7 @@ Session::update_latency_compensation (bool with_stop, bool abort)
if (!(*i)->is_hidden() && ((*i)->active())) {
_worst_track_latency = max (_worst_track_latency, track_latency);
}
- }
+ }
if (update_jack) {
_engine.update_total_latencies ();
@@ -1330,7 +1348,7 @@ Session::update_latency_compensation (bool with_stop, bool abort)
/* reflect any changes in latencies into capture offsets
*/
-
+
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc
index f30f568f9d..58443bd005 100644
--- a/libs/ardour/utils.cc
+++ b/libs/ardour/utils.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000-2003 Paul Davis
+ Copyright (C) 2000-2003 Paul Davis
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
@@ -50,7 +50,7 @@ using namespace std;
using namespace PBD;
using Glib::ustring;
-ustring
+ustring
legalize_for_path (ustring str)
{
ustring::size_type pos;
@@ -97,7 +97,7 @@ string bump_name_once(std::string name)
char buf[32];
snprintf (buf, sizeof(buf), "%ld", version+1);
-
+
newname = name.substr (0, period+1);
newname += buf;
}
@@ -140,7 +140,7 @@ cmp_nocase (const string& s, const string& s2)
{
string::const_iterator p = s.begin();
string::const_iterator p2 = s2.begin();
-
+
while (p != s.end() && p2 != s2.end()) {
if (toupper(*p) != toupper(*p2)) {
return (toupper(*p) < toupper(*p2)) ? -1 : 1;
@@ -148,7 +148,7 @@ cmp_nocase (const string& s, const string& s2)
++p;
++p2;
}
-
+
return (s2.size() == s.size()) ? 0 : (s.size() < s2.size()) ? -1 : 1;
}
@@ -171,12 +171,12 @@ region_name_from_path (ustring path, bool strip_channels, bool add_channel_suffi
if (strip_channels) {
/* remove any "?R", "?L" or "?[a-z]" channel identifier */
-
+
ustring::size_type len = path.length();
-
- if (len > 3 && (path[len-2] == '%' || path[len-2] == '?' || path[len-2] == '.') &&
+
+ if (len > 3 && (path[len-2] == '%' || path[len-2] == '?' || path[len-2] == '.') &&
(path[len-1] == 'R' || path[len-1] == 'L' || (islower (path[len-1])))) {
-
+
path = path.substr (0, path.length() - 2);
}
}
@@ -184,7 +184,7 @@ region_name_from_path (ustring path, bool strip_channels, bool add_channel_suffi
if (add_channel_suffix) {
path += '%';
-
+
if (total > 2) {
path += (char) ('a' + this_one);
} else {
@@ -193,7 +193,7 @@ region_name_from_path (ustring path, bool strip_channels, bool add_channel_suffi
}
return path;
-}
+}
bool
path_is_paired (ustring path, ustring& pair_base)
@@ -207,7 +207,7 @@ path_is_paired (ustring path, ustring& pair_base)
}
/* remove filename suffixes etc. */
-
+
if ((pos = path.find_last_of ('.')) != string::npos) {
path = path.substr (0, pos);
}
@@ -216,13 +216,13 @@ path_is_paired (ustring path, ustring& pair_base)
/* look for possible channel identifier: "?R", "%R", ".L" etc. */
- if (len > 3 && (path[len-2] == '%' || path[len-2] == '?' || path[len-2] == '.') &&
+ if (len > 3 && (path[len-2] == '%' || path[len-2] == '?' || path[len-2] == '.') &&
(path[len-1] == 'R' || path[len-1] == 'L' || (islower (path[len-1])))) {
-
+
pair_base = path.substr (0, len-2);
return true;
- }
+ }
return false;
}
@@ -253,20 +253,20 @@ path_expand (ustring path)
wordfree (&expansion);
return ret;
-#else
+#else
return path;
#endif
}
#if defined(HAVE_COREAUDIO) || defined(HAVE_AUDIOUNITS)
-string
+string
CFStringRefToStdString(CFStringRef stringRef)
{
- CFIndex size =
- CFStringGetMaximumSizeForEncoding(CFStringGetLength(stringRef) ,
+ CFIndex size =
+ CFStringGetMaximumSizeForEncoding(CFStringGetLength(stringRef) ,
kCFStringEncodingUTF8);
char *buf = new char[size];
-
+
std::string result;
if(CFStringGetCString(stringRef, buf, size, kCFStringEncodingUTF8)) {
@@ -285,11 +285,11 @@ compute_equal_power_fades (nframes_t nframes, float* in, float* out)
step = 1.0/nframes;
in[0] = 0.0f;
-
+
for (nframes_t i = 1; i < nframes - 1; ++i) {
in[i] = in[i-1] + step;
}
-
+
in[nframes-1] = 1.0;
const float pan_law_attenuation = -3.0f;
@@ -340,11 +340,15 @@ string_to_slave_source (string str)
if (str == _("Internal")) {
return None;
}
-
+
if (str == _("MTC")) {
return MTC;
}
+ if (str == _("MIDI Clock")) {
+ return MIDIClock;
+ }
+
if (str == _("JACK")) {
return JACK;
}
@@ -363,11 +367,14 @@ slave_source_to_string (SlaveSource src)
case MTC:
return _("MTC");
-
+
+ case MIDIClock:
+ return _("MIDI Clock");
+
default:
case None:
return _("Internal");
-
+
}
}
@@ -449,7 +456,7 @@ meter_hold_to_float (MeterHold hold)
}
}
-AutoState
+AutoState
ARDOUR::string_to_auto_state (std::string str)
{
if (str == X_("Off")) {
@@ -467,7 +474,7 @@ ARDOUR::string_to_auto_state (std::string str)
return Touch;
}
-string
+string
ARDOUR::auto_state_to_string (AutoState as)
{
/* to be used only for XML serialization, no i18n done */
@@ -491,7 +498,7 @@ ARDOUR::auto_state_to_string (AutoState as)
return "";
}
-AutoStyle
+AutoStyle
ARDOUR::string_to_auto_style (std::string str)
{
if (str == X_("Absolute")) {
@@ -505,7 +512,7 @@ ARDOUR::string_to_auto_style (std::string str)
return Trim;
}
-string
+string
ARDOUR::auto_style_to_string (AutoStyle as)
{
/* to be used only for XML serialization, no i18n done */