diff options
Diffstat (limited to 'libs/ardour')
76 files changed, 4340 insertions, 1753 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index 58a2bbf825..98a1b362bb 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -14,7 +14,7 @@ ardour = env.Copy() domain = 'libardour' -ardour.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0) +ardour.Append(DOMAIN = domain, MAJOR = 2, MINOR = 0, MICRO = 0) ardour.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"") ardour.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED") ardour.Append(PACKAGE = domain) @@ -44,6 +44,7 @@ buffer_set.cc meter.cc amp.cc panner.cc +destructive_filesource.cc audiofilesource.cc audiofilter.cc audioregion.cc @@ -64,7 +65,6 @@ crossfade.cc curve.cc cycle_timer.cc default_click.cc -destructive_filesource.cc gain.cc gdither.cc globals.cc @@ -105,7 +105,6 @@ sndfile_helpers.cc sndfilesource.cc source.cc source_factory.cc -state_manager.cc tempo.cc utils.cc version.cc @@ -242,7 +241,7 @@ ardour = conf.Finish () ardour.Merge ([ libraries['core'], libraries['xml'], - libraries['sndfile'], + libraries['sndfile-ardour'], libraries['raptor'], libraries['lrdf'], libraries['samplerate'], @@ -260,8 +259,6 @@ if ardour['LIBLO']: if ardour['COREAUDIO'] or ardour['AUDIOUNITS']: ardour.Merge ([ libraries['appleutility'] ]) -ardour.VersionBuild(['version.cc', 'ardour/version.h'], 'SConscript') - def SharedAsmObjectEmitter(target, source, env): for tgt in target: tgt.attributes.shared = 1 @@ -291,7 +288,9 @@ if env['NLS']: env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libardour)) - + +env.Alias('version', ardour.VersionBuild(['version.cc', 'ardour/version.h'], [])) + env.Alias('tarball', env.Distribute (env['DISTTREE'], [ 'SConscript', 'i18n.h', 'gettext.h', 'sse_functions.s', 'sse_functions_64bit.s' ] + ardour_files + osc_files + vst_files + coreaudio_files + audiounit_files + diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h index 76b76b1061..4a95e094a9 100644 --- a/libs/ardour/ardour/audio_diskstream.h +++ b/libs/ardour/ardour/audio_diskstream.h @@ -77,6 +77,8 @@ class AudioDiskstream : public Diskstream } void set_record_enabled (bool yn); + int set_destructive (bool yn); + bool can_become_destructive (bool& requires_bounce) const; float peak_power(uint32_t n=0) { float x = channels[n].peak_power; diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h index fdf373a1cb..e87434b0fb 100644 --- a/libs/ardour/ardour/audio_track.h +++ b/libs/ardour/ardour/audio_track.h @@ -37,6 +37,9 @@ class AudioTrack : public Track AudioTrack (Session&, const XMLNode&); ~AudioTrack (); + int set_mode (TrackMode m); + bool can_use_mode (TrackMode m, bool& bounce_required); + int roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset, int declick, bool can_record, bool rec_monitors_input); @@ -63,6 +66,8 @@ class AudioTrack : public Track protected: XMLNode& state (bool full); + + int _set_state (const XMLNode&, bool call_base); private: int set_diskstream (boost::shared_ptr<AudioDiskstream>, void *); diff --git a/libs/ardour/ardour/audio_unit.h b/libs/ardour/ardour/audio_unit.h index 8a51580f27..88591ab845 100644 --- a/libs/ardour/ardour/audio_unit.h +++ b/libs/ardour/ardour/audio_unit.h @@ -1,6 +1,6 @@ /* Copyright (C) 2006 Paul Davis - Written by Taybin Rutkin + Written by Taybin Rutkin 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 diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h index af5f5cdb60..bd609a7d80 100644 --- a/libs/ardour/ardour/audiofilesource.h +++ b/libs/ardour/ardour/audiofilesource.h @@ -31,6 +31,7 @@ struct SoundFileInfo { uint16_t channels; int64_t length; std::string format_name; + int64_t timecode; }; class AudioFileSource : public AudioSource { @@ -81,6 +82,8 @@ class AudioFileSource : public AudioSource { void mark_take (string); string take_id() const { return _take_id; } + bool is_embedded() const { return _is_embedded; } + static void set_bwf_serial_number (int); static void set_search_path (string); @@ -93,6 +96,9 @@ class AudioFileSource : public AudioSource { XMLNode& get_state (); int set_state (const XMLNode&); + bool destructive() const { return (_flags & Destructive); } + virtual bool set_destructive (bool yn) { return false; } + /* this should really be protected, but C++ is getting stricter and creating slots from protected member functions is starting to cause issues. @@ -121,9 +127,12 @@ class AudioFileSource : public AudioSource { string _path; Flag _flags; string _take_id; - uint64_t timeline_position; + int64_t timeline_position; bool file_is_new; + bool _is_embedded; + static bool determine_embeddedness(string path); + static string peak_dir; static string search_path; @@ -133,7 +142,7 @@ class AudioFileSource : public AudioSource { static uint64_t header_position_offset; - virtual void set_timeline_position (nframes_t pos); + virtual void set_timeline_position (int64_t pos); virtual void set_header_timeline_position () = 0; bool find (std::string path, bool must_exist, bool& is_new); diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index e14cfd0180..53c7e68b82 100644 --- a/libs/ardour/ardour/audioregion.h +++ b/libs/ardour/ardour/audioregion.h @@ -110,6 +110,7 @@ class AudioRegion : public Region void set_fade_out (FadeShape, nframes_t); void set_envelope_active (bool yn); + void set_default_envelope (); int separate_by_channel (ARDOUR::Session&, vector<AudioRegion*>&) const; @@ -143,7 +144,6 @@ class AudioRegion : public Region void set_default_fades (); void set_default_fade_in (); void set_default_fade_out (); - void set_default_envelope (); void recompute_gain_at_end (); void recompute_gain_at_start (); @@ -157,8 +157,11 @@ class AudioRegion : public Region void recompute_at_start (); void recompute_at_end (); - void envelope_changed (Change); + void envelope_changed (); + void fade_in_changed (); + void fade_out_changed (); void source_offset_changed (); + void listen_to_my_curves (); mutable Curve _fade_in; FadeShape _fade_in_shape; @@ -171,6 +174,13 @@ class AudioRegion : public Region protected: int set_live_state (const XMLNode&, Change&, bool send); + + virtual bool verify_start (jack_nframes_t); + virtual bool verify_start_and_length (jack_nframes_t, jack_nframes_t); + virtual bool verify_start_mutable (jack_nframes_t&_start); + virtual bool verify_length (jack_nframes_t); + /*virtual void recompute_at_start () = 0; + virtual void recompute_at_end () = 0;*/ }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h index db82acf894..2ada255236 100644 --- a/libs/ardour/ardour/audiosource.h +++ b/libs/ardour/ardour/audiosource.h @@ -70,7 +70,7 @@ const nframes_t frames_per_peak = 256; uint32_t read_data_count() const { return _read_data_count; } uint32_t write_data_count() const { return _write_data_count; } - int read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const; + virtual int read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const; int build_peaks (); bool peaks_ready (sigc::slot<void>, sigc::connection&) const; diff --git a/libs/ardour/ardour/automation_event.h b/libs/ardour/ardour/automation_event.h index 22ab706f82..e5c194e683 100644 --- a/libs/ardour/ardour/automation_event.h +++ b/libs/ardour/ardour/automation_event.h @@ -33,7 +33,6 @@ #include <pbd/statefuldestructible.h> #include <ardour/ardour.h> -#include <ardour/state_manager.h> namespace ARDOUR { @@ -54,14 +53,15 @@ struct ControlEvent { }; - class AutomationList : public StateManager, public PBD::StatefulDestructible +class AutomationList : public PBD::StatefulDestructible { public: typedef std::list<ControlEvent*> AutomationEventList; typedef AutomationEventList::iterator iterator; typedef AutomationEventList::const_iterator const_iterator; - AutomationList(double default_value, bool no_state = false); + AutomationList (double default_value); + AutomationList (const XMLNode&); ~AutomationList(); AutomationList (const AutomationList&); @@ -85,8 +85,9 @@ struct ControlEvent { void reposition_for_rt_add (double when); void rt_add (double when, double value); - iterator add (double when, double value, iterator, bool ignore_mode = false); - void add (double when, double value, bool for_loading = false); + void add (double when, double value); + /* this should be private but old-school automation loading needs it in IO/Redirect */ + void fast_simple_add (double when, double value); void reset_range (double start, double end); void erase_range (double start, double end); @@ -151,13 +152,12 @@ struct ControlEvent { (obj.*method)(*this); } - UndoAction get_memento () const; - - virtual void store_state (XMLNode& node) const; - virtual void load_state (const XMLNode&); + sigc::signal<void> StateChanged; - XMLNode &get_state(void); + XMLNode& get_state(void); int set_state (const XMLNode &s); + XMLNode& state (bool full); + XMLNode& serialize_events (); void set_max_xval (double); double get_max_xval() const { return max_xval; } @@ -188,12 +188,6 @@ struct ControlEvent { protected: - struct State : public ARDOUR::StateManager::State { - AutomationEventList events; - - State (std::string why) : ARDOUR::StateManager::State (why) {} - }; - AutomationEventList events; mutable Glib::Mutex lock; bool _frozen; @@ -215,7 +209,6 @@ struct ControlEvent { double min_yval; double max_yval; double default_value; - bool no_state; iterator rt_insertion_point; double rt_pos; @@ -242,14 +235,12 @@ struct ControlEvent { virtual double unlocked_eval (double where); - Change restore_state (StateManager::State&); - StateManager::State* state_factory (std::string why) const; - virtual ControlEvent* point_factory (double,double) const; virtual ControlEvent* point_factory (const ControlEvent&) const; - AutomationList* cut_copy_clear (double, double, int op); + + int deserialize_events (const XMLNode&); }; } // namespace diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h index fe65e9d433..8044190066 100644 --- a/libs/ardour/ardour/configuration_vars.h +++ b/libs/ardour/ardour/configuration_vars.h @@ -80,7 +80,6 @@ CONFIG_VARIABLE (std::string, click_emphasis_sound, "click-emphasis-sound", "") CONFIG_VARIABLE (bool, auto_play, "auto-play", false) CONFIG_VARIABLE (bool, auto_return, "auto-return", false) CONFIG_VARIABLE (bool, auto_input, "auto-input", true) -CONFIG_VARIABLE (bool, auto_loop, "auto-loop", false) CONFIG_VARIABLE (bool, punch_in, "punch-in", false) CONFIG_VARIABLE (bool, punch_out, "punch-out", false) CONFIG_VARIABLE (bool, plugins_stop_with_transport, "plugins-stop-with-transport", false) diff --git a/libs/ardour/ardour/coreaudiosource.h b/libs/ardour/ardour/coreaudiosource.h index 668fe61102..bd69c78e18 100644 --- a/libs/ardour/ardour/coreaudiosource.h +++ b/libs/ardour/ardour/coreaudiosource.h @@ -38,6 +38,8 @@ class CoreAudioSource : public AudioFileSource { int flush_header () {return 0;}; void set_header_timeline_position () {}; + static int get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg); + protected: nframes_t read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const; nframes_t write_unlocked (Sample *dst, nframes_t cnt) { return 0; } @@ -50,7 +52,7 @@ class CoreAudioSource : public AudioFileSource { mutable nframes_t tmpbufsize; mutable Glib::Mutex _tmpbuf_lock; - void init (const string &str); + void init (string str); }; }; /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/curve.h b/libs/ardour/ardour/curve.h index 87893ca260..df984b74e0 100644 --- a/libs/ardour/ardour/curve.h +++ b/libs/ardour/ardour/curve.h @@ -51,9 +51,10 @@ class Curve : public AutomationList ~Curve (); Curve (const Curve& other); Curve (const Curve& other, double start, double end); + Curve (const XMLNode&); - bool rt_safe_get_vector (double x0, double x1, float *arg, size_t veclen); - void get_vector (double x0, double x1, float *arg, size_t veclen); + bool rt_safe_get_vector (double x0, double x1, float *arg, int32_t veclen); + void get_vector (double x0, double x1, float *arg, int32_t veclen); AutomationEventList::iterator closest_control_point_before (double xval); AutomationEventList::iterator closest_control_point_after (double xval); @@ -66,22 +67,20 @@ class Curve : public AutomationList ControlEvent* point_factory (double,double) const; ControlEvent* point_factory (const ControlEvent&) const; - Change restore_state (StateManager::State&); - private: AutomationList::iterator last_bound; double unlocked_eval (double where); double multipoint_eval (double x); - void _get_vector (double x0, double x1, float *arg, size_t veclen); + void _get_vector (double x0, double x1, float *arg, int32_t veclen); }; } // namespace ARDOUR extern "C" { - void curve_get_vector_from_c (void *arg, double, double, float*, size_t); + void curve_get_vector_from_c (void *arg, double, double, float*, int32_t); } #endif /* __ardour_curve_h__ */ diff --git a/libs/ardour/ardour/destructive_filesource.h b/libs/ardour/ardour/destructive_filesource.h index 1e75042ce9..2e6f5d0e57 100644 --- a/libs/ardour/ardour/destructive_filesource.h +++ b/libs/ardour/ardour/destructive_filesource.h @@ -48,6 +48,8 @@ class DestructiveFileSource : public SndFileSource { static void setup_standard_crossfades (nframes_t sample_rate); + int read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const; + protected: nframes_t write_unlocked (Sample *src, nframes_t cnt); @@ -66,7 +68,7 @@ class DestructiveFileSource : public SndFileSource { void init (); nframes_t crossfade (Sample* data, nframes_t cnt, int dir); - void set_timeline_position (nframes_t); + void set_timeline_position (int64_t); }; } diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h index 7a779b69bf..eb6d936222 100644 --- a/libs/ardour/ardour/diskstream.h +++ b/libs/ardour/ardour/diskstream.h @@ -90,7 +90,8 @@ class IO; virtual void set_record_enabled (bool yn) = 0; bool destructive() const { return _flags & Destructive; } - virtual void set_destructive (bool yn); + virtual int set_destructive (bool yn) { return -1; } + virtual bool can_become_destructive (bool& requires_bounce) const { return false; } bool hidden() const { return _flags & Hidden; } bool recordable() const { return _flags & Recordable; } @@ -137,6 +138,8 @@ class IO; void handle_input_change (IOChange, void *src); + void remove_region_from_last_capture (boost::weak_ptr<Region> wregion); + sigc::signal<void> RecordEnableChanged; sigc::signal<void> SpeedChanged; sigc::signal<void> ReverseChanged; @@ -223,6 +226,7 @@ class IO; virtual bool realtime_set_speed (double, bool global_change); std::list<boost::shared_ptr<Region> > _last_capture_regions; + virtual int use_pending_capture_data (XMLNode& node) = 0; virtual void get_input_sources () = 0; diff --git a/libs/ardour/ardour/insert.h b/libs/ardour/ardour/insert.h index 5d917a8c2c..217fd89885 100644 --- a/libs/ardour/ardour/insert.h +++ b/libs/ardour/ardour/insert.h @@ -89,15 +89,6 @@ class PortInsert : public Insert int32_t compute_output_streams (int32_t cnt) const; }; -struct PluginInsertState : public RedirectState -{ - PluginInsertState (std::string why) - : RedirectState (why) {} - ~PluginInsertState() {} - - PluginState plugin_state; -}; - class PluginInsert : public Insert { public: @@ -112,9 +103,6 @@ class PluginInsert : public Insert XMLNode& get_state(void); int set_state(const XMLNode&); - StateManager::State* state_factory (std::string why) const; - Change restore_state (StateManager::State&); - void run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset); void silence (nframes_t nframes, nframes_t offset); @@ -160,9 +148,7 @@ class PluginInsert : public Insert nframes_t latency(); void transport_stopped (nframes_t now); - - protected: - void store_state (PluginInsertState&) const; + void automation_snapshot (nframes_t now); private: diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h index 56566149c0..f7e1993bb2 100644 --- a/libs/ardour/ardour/io.h +++ b/libs/ardour/ardour/io.h @@ -36,7 +36,6 @@ #include <ardour/ardour.h> #include <ardour/utils.h> -#include <ardour/state_manager.h> #include <ardour/curve.h> #include <ardour/types.h> #include <ardour/data_type.h> @@ -65,7 +64,7 @@ class BufferSet; * An IO can contain ports of varying types, making routes/inserts/etc with * varied combinations of types (eg MIDI and audio) possible. */ -class IO : public PBD::StatefulDestructible, public ARDOUR::StateManager +class IO : public PBD::StatefulDestructible { public: @@ -74,7 +73,9 @@ class IO : public PBD::StatefulDestructible, public ARDOUR::StateManager IO (Session&, string name, int input_min = -1, int input_max = -1, int output_min = -1, int output_max = -1, - DataType default_type = DataType::AUDIO); + DataType default_type = DataType::AUDIO); + + IO (Session&, const XMLNode&, DataType default_type = DataType::AUDIO); virtual ~IO(); @@ -82,18 +83,12 @@ class IO : public PBD::StatefulDestructible, public ARDOUR::StateManager ChanCount input_maximum() const { return _input_maximum; } ChanCount output_minimum() const { return _output_minimum; } ChanCount output_maximum() const { return _output_maximum; } - + void set_input_minimum (ChanCount n); void set_input_maximum (ChanCount n); void set_output_minimum (ChanCount n); void set_output_maximum (ChanCount n); - // Do not write any new code using these - void set_input_minimum (int n); - void set_input_maximum (int n); - void set_output_minimum (int n); - void set_output_maximum (int n); - DataType default_type() const { return _default_type; } void set_default_type(DataType t) { _default_type = t; } @@ -187,9 +182,6 @@ class IO : public PBD::StatefulDestructible, public ARDOUR::StateManager XMLNode& get_state (void); int set_state (const XMLNode&); - virtual UndoAction get_memento() const; - - static int disable_connecting (void); static int enable_connecting (void); @@ -224,6 +216,14 @@ public: /* automation */ + static void set_automation_interval (jack_nframes_t frames) { + _automation_interval = frames; + } + + static jack_nframes_t automation_interval() { + return _automation_interval; + } + void clear_automation (); bool gain_automation_recording() const { @@ -245,6 +245,7 @@ public: sigc::signal<void> gain_automation_style_changed; virtual void transport_stopped (nframes_t now); + void automation_snapshot (nframes_t now); ARDOUR::Curve& gain_automation_curve () { return _gain_automation_curve; } @@ -304,10 +305,8 @@ public: GainControllable _gain_control; - /* state management */ - - Change restore_state (State&); - StateManager::State* state_factory (std::string why) const; + nframes_t last_automation_snapshot; + static nframes_t _automation_interval; AutoState _gain_automation_state; AutoStyle _gain_automation_style; @@ -315,11 +314,12 @@ public: bool apply_gain_automation; Curve _gain_automation_curve; - int save_automation (const string&); - int load_automation (const string&); - Glib::Mutex automation_lock; + virtual int set_automation_state (const XMLNode&); + virtual XMLNode& get_automation_state (); + virtual int load_automation (std::string path); + /* AudioTrack::deprecated_use_diskstream_connections() needs these */ int set_inputs (const string& str); diff --git a/libs/ardour/ardour/location.h b/libs/ardour/ardour/location.h index 1f1c02d67c..94f70bb4e8 100644 --- a/libs/ardour/ardour/location.h +++ b/libs/ardour/ardour/location.h @@ -36,7 +36,6 @@ #include <pbd/statefuldestructible.h> #include <ardour/ardour.h> -#include <ardour/state_manager.h> using std::string; @@ -131,7 +130,7 @@ class Location : public PBD::StatefulDestructible bool set_flag_internal (bool yn, Flags flag); }; -class Locations : public StateManager, public PBD::StatefulDestructible +class Locations : public PBD::StatefulDestructible { public: typedef std::list<Location *> LocationList; @@ -169,6 +168,7 @@ class Locations : public StateManager, public PBD::StatefulDestructible sigc::signal<void> changed; sigc::signal<void,Location*> added; sigc::signal<void,Location*> removed; + sigc::signal<void,Change> StateChanged; template<class T> void apply (T& obj, void (T::*method)(LocationList&)) { Glib::Mutex::Lock lm (lock); @@ -180,26 +180,14 @@ class Locations : public StateManager, public PBD::StatefulDestructible (obj.*method)(locations, arg); } - UndoAction get_memento () const; - private: - struct State : public ARDOUR::StateManager::State { - LocationList locations; - LocationList states; - - State (std::string why) : ARDOUR::StateManager::State (why) {} - }; - LocationList locations; Location *current_location; mutable Glib::Mutex lock; int set_current_unlocked (Location *); void location_changed (Location*); - - Change restore_state (StateManager::State&); - StateManager::State* state_factory (std::string why) const; }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h index e62121672f..583cc23de5 100644 --- a/libs/ardour/ardour/midi_diskstream.h +++ b/libs/ardour/ardour/midi_diskstream.h @@ -87,7 +87,7 @@ class MidiDiskstream : public Diskstream boost::shared_ptr<SMFSource> write_source () { return _write_source; } - void set_destructive (bool yn); // doom! + int set_destructive (bool yn); // doom! protected: friend class Session; diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h index a5c578b7cd..2fa39a37df 100644 --- a/libs/ardour/ardour/midi_region.h +++ b/libs/ardour/ardour/midi_region.h @@ -84,9 +84,6 @@ class MidiRegion : public Region friend class Playlist; private: - StateManager::State* state_factory (std::string why) const; - Change restore_state (StateManager::State&); - jack_nframes_t _read_at (const SourceList&, MidiRingBuffer& dst, jack_nframes_t position, jack_nframes_t dur, diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h index 6cffe01318..0347df5669 100644 --- a/libs/ardour/ardour/midi_track.h +++ b/libs/ardour/ardour/midi_track.h @@ -58,7 +58,7 @@ public: int use_diskstream (string name); int use_diskstream (const PBD::ID& id); - void set_mode (TrackMode m); + int set_mode (TrackMode m); void set_latency_delay (jack_nframes_t); diff --git a/libs/ardour/ardour/panner.h b/libs/ardour/ardour/panner.h index 5231120840..79bff7d2a5 100644 --- a/libs/ardour/ardour/panner.h +++ b/libs/ardour/ardour/panner.h @@ -85,18 +85,18 @@ class StreamPanner : public sigc::trackable, public Stateful virtual Curve& automation() = 0; - virtual int load (istream&, string path, uint32_t&) = 0; - - virtual int save (ostream&) const = 0; - sigc::signal<void> Changed; /* for position */ sigc::signal<void> StateChanged; /* for mute */ int set_state (const XMLNode&); virtual XMLNode& state (bool full_state) = 0; - + Panner & get_parent() { return parent; } + /* old school automation loading */ + + virtual int load (istream&, string path, uint32_t&) = 0; + protected: friend class Panner; Panner& parent; @@ -145,8 +145,6 @@ class BaseStereoPanner : public StreamPanner void distribute (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes); - int load (istream&, string path, uint32_t&); - int save (ostream&) const; void snapshot (nframes_t now); void transport_stopped (nframes_t frame); void set_automation_state (AutoState); @@ -154,6 +152,10 @@ class BaseStereoPanner : public StreamPanner Curve& automation() { return _automation; } + /* old school automation loading */ + + int load (istream&, string path, uint32_t&); + protected: float left; float right; @@ -207,10 +209,7 @@ class Multi2dPanner : public StreamPanner void distribute (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes); void distribute_automated (AudioBuffer& src, BufferSet& obufs, - nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers); - - int load (istream&, string path, uint32_t&); - int save (ostream&) const; + nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers); static StreamPanner* factory (Panner&); static string name; @@ -219,6 +218,10 @@ class Multi2dPanner : public StreamPanner XMLNode& get_state (void); int set_state (const XMLNode&); + /* old school automation loading */ + + int load (istream&, string path, uint32_t&); + private: Curve _automation; void update (); @@ -244,8 +247,6 @@ class Panner : public std::vector<StreamPanner*>, public Stateful, public sigc:: /// The fundamental Panner function void distribute(BufferSet& src, BufferSet& dest, nframes_t start_frame, nframes_t end_frames, nframes_t nframes, nframes_t offset); - void set_name (string); - bool bypassed() const { return _bypassed; } void set_bypassed (bool yn); @@ -265,9 +266,6 @@ class Panner : public std::vector<StreamPanner*>, public Stateful, public sigc:: AutoStyle automation_style() const; bool touching() const; - int load (); - int save () const; - XMLNode& get_state (void); XMLNode& state (bool full); int set_state (const XMLNode&); @@ -304,12 +302,14 @@ class Panner : public std::vector<StreamPanner*>, public Stateful, public sigc:: void set_position (float x, StreamPanner& orig); void set_position (float x, float y, StreamPanner& orig); void set_position (float x, float y, float z, StreamPanner& orig); - + + /* old school automation */ + + int load (); + private: void distribute_no_automation(BufferSet& src, BufferSet& dest, nframes_t nframes, nframes_t offset, gain_t gain_coeff); - - string automation_path; Session& _session; uint32_t current_outs; bool _linked; @@ -317,6 +317,11 @@ class Panner : public std::vector<StreamPanner*>, public Stateful, public sigc:: LinkDirection _link_direction; static float current_automation_version_number; + + /* old school automation handling */ + + std::string automation_path; + void set_name (std::string); }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h index 93b30f42ef..831c9b3905 100644 --- a/libs/ardour/ardour/playlist.h +++ b/libs/ardour/ardour/playlist.h @@ -63,8 +63,8 @@ class Playlist : public PBD::StatefulDestructible { void unref(); uint32_t refcnt() const { return _refcnt; } - const string& name() const { return _name; } - void set_name (const string& str); + std::string name() const { return _name; } + void set_name (std::string str); const DataType& data_type() const { return _type; } @@ -73,6 +73,7 @@ class Playlist : public PBD::StatefulDestructible { bool hidden() const { return _hidden; } bool empty() const; + uint32_t n_regions() const; nframes_t get_maximum_extent () const; layer_t top_layer() const; @@ -91,19 +92,15 @@ class Playlist : public PBD::StatefulDestructible { void duplicate (boost::shared_ptr<Region>, nframes_t position, float times); void nudge_after (nframes_t start, nframes_t distance, bool forwards); - boost::shared_ptr<Region> find_region (const PBD::ID&) const; - Playlist* cut (list<AudioRange>&, bool result_is_hidden = true); Playlist* copy (list<AudioRange>&, bool result_is_hidden = true); int paste (Playlist&, nframes_t position, float times); - uint32_t read_data_count() { return _read_data_count; } - - RegionList* regions_at (nframes_t frame); - RegionList* regions_touched (nframes_t start, nframes_t end); + RegionList* regions_at (nframes_t frame); + RegionList* regions_touched (nframes_t start, nframes_t end); + boost::shared_ptr<Region> find_region (const PBD::ID&) const; boost::shared_ptr<Region> top_region_at (nframes_t frame); - - boost::shared_ptr<Region> find_next_region (nframes_t frame, RegionPoint point, int dir); + boost::shared_ptr<Region> find_next_region (nframes_t frame, RegionPoint point, int dir); template<class T> void foreach_region (T *t, void (T::*func)(boost::shared_ptr<Region>, void *), void *arg); template<class T> void foreach_region (T *t, void (T::*func)(boost::shared_ptr<Region>)); diff --git a/libs/ardour/ardour/redirect.h b/libs/ardour/ardour/redirect.h index ae58fa9b70..79ae4516c5 100644 --- a/libs/ardour/ardour/redirect.h +++ b/libs/ardour/ardour/redirect.h @@ -47,14 +47,6 @@ namespace ARDOUR { class Session; -struct RedirectState : public StateManager::State { - RedirectState (string why) - : StateManager::State (why) {} - ~RedirectState () {} - - bool active; -}; - class Redirect : public IO { public: @@ -99,9 +91,6 @@ class Redirect : public IO XMLNode& get_state (void); int set_state (const XMLNode&); - StateManager::State* state_factory (string why) const; - Change restore_state (StateManager::State&); - void *get_gui () const { return _gui; } void set_gui (void *p) { _gui = p; } @@ -110,9 +99,6 @@ class Redirect : public IO return 1.0f; } - int load_automation (string path); - int save_automation (string path); - void what_has_automation (set<uint32_t>&) const; void what_has_visible_automation (set<uint32_t>&) const; const set<uint32_t>& what_can_be_automated () const { return can_automate_list; } @@ -137,15 +123,19 @@ class Redirect : public IO void can_automate (uint32_t); set<uint32_t> can_automate_list; - void store_state (RedirectState&) const; - virtual void automation_list_creation_callback (uint32_t, AutomationList&) {} + int set_automation_state (const XMLNode&); + XMLNode& get_automation_state (); + private: bool _active; Placement _placement; uint32_t _sort_key; void* _gui; /* generic, we don't know or care what this is */ + + int old_set_automation_state (const XMLNode&); + int load_automation (std::string path); }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index 627e556cad..88bb294e5d 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -144,6 +144,7 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro void special_set_position (nframes_t); void nudge_position (long, void *src); + bool at_natural_position () const; void move_to_natural_position (void *src); void trim_start (nframes_t new_position, void *src); @@ -171,7 +172,7 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro void set_playlist (ARDOUR::Playlist*); void source_deleted (boost::shared_ptr<Source>); - + boost::shared_ptr<Source> source (uint32_t n=0) const { return _sources[ (n < _sources.size()) ? n : 0 ]; } uint32_t n_channels() const { return _sources.size(); } @@ -185,7 +186,7 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro virtual int set_state (const XMLNode&); virtual int set_live_state (const XMLNode&, Change&, bool send); - boost::shared_ptr<Region> get_parent(); + virtual boost::shared_ptr<Region> get_parent() const; uint64_t last_layer_op() const { return _last_layer_op; } void set_last_layer_op (uint64_t when); @@ -214,10 +215,10 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro void maybe_uncopy (); void first_edit (); - bool verify_start (jack_nframes_t); - bool verify_start_and_length (jack_nframes_t, jack_nframes_t); - bool verify_start_mutable (jack_nframes_t&_start); - bool verify_length (jack_nframes_t); + virtual bool verify_start (jack_nframes_t); + virtual bool verify_start_and_length (jack_nframes_t, jack_nframes_t); + virtual bool verify_start_mutable (jack_nframes_t&_start); + virtual bool verify_length (jack_nframes_t); virtual void recompute_at_start () = 0; virtual void recompute_at_end () = 0; diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 5c71bb16d3..6bc37ee51e 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -72,8 +72,7 @@ class Route : public IO Route (Session&, std::string name, int input_min, int input_max, int output_min, int output_max, Flag flags = Flag(0), DataType default_type = DataType::AUDIO); - - Route (Session&, const XMLNode&); + Route (Session&, const XMLNode&, DataType default_type = DataType::AUDIO); virtual ~Route(); std::string comment() { return _comment; } @@ -205,11 +204,6 @@ class Route : public IO sigc::signal<void,void*> SelectedChanged; - /* undo */ - - UndoAction get_memento() const; - void set_state (state_id_t); - int set_control_outs (const vector<std::string>& ports); IO* control_outs() { return _control_outs; } @@ -238,6 +232,7 @@ class Route : public IO return _mute_control; } + void automation_snapshot (nframes_t now); void protect_automation (); void set_remote_control_id (uint32_t id); @@ -317,13 +312,14 @@ class Route : public IO sigc::connection input_signal_connection; - state_id_t _current_state_id; ChanCount redirect_max_outs; uint32_t _remote_control_id; uint32_t pans_required() const; ChanCount n_process_buffers (); + virtual int _set_state (const XMLNode&, bool call_base); + private: void init (); diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index f06c4117a6..039bf92362 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -359,7 +359,10 @@ class Session : public PBD::StatefulDestructible void request_bounded_roll (nframes_t start, nframes_t end); void request_stop (bool abort = false); void request_locate (nframes_t frame, bool with_roll = false); + void request_play_loop (bool yn); + bool get_play_loop () const { return play_loop; } + nframes_t last_transport_start() const { return _last_roll_location; } void goto_end () { request_locate (end_location->start(), false);} void goto_start () { request_locate (start_location->start(), false); } @@ -562,7 +565,8 @@ class Session : public PBD::StatefulDestructible string new_region_name (string); string path_from_region_name (string name, string identifier); - boost::shared_ptr<Region> find_whole_file_parent (Region&); + 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); @@ -646,6 +650,7 @@ class Session : public PBD::StatefulDestructible uint32_t n_playlists() const; template<class T> void foreach_playlist (T *obj, void (T::*func)(Playlist *)); + void get_playlists (std::vector<Playlist*>&); /* named selections */ @@ -757,16 +762,19 @@ class Session : public PBD::StatefulDestructible /* History (for editors, mixers, UIs etc.) */ void undo (uint32_t n) { - history.undo (n); + _history.undo (n); } + void redo (uint32_t n) { - history.redo (n); + _history.redo (n); } - 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(); } - string next_redo() const { return history.next_redo(); } + 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(); } + string next_redo() const { return _history.next_redo(); } void begin_reversible_command (string cmd_name); void commit_reversible_command (Command* cmd = 0); @@ -775,11 +783,11 @@ class Session : public PBD::StatefulDestructible current_trans->add_command (cmd); } - std::map<PBD::ID, PBD::StatefulDestructible*> registry; + std::map<PBD::ID, PBD::StatefulThingWithGoingAway*> registry; // these commands are implemented in libs/ardour/session_command.cc Command *memento_command_factory(XMLNode *n); - void register_with_memento_command_factory(PBD::ID, PBD::StatefulDestructible *); + void register_with_memento_command_factory(PBD::ID, PBD::StatefulThingWithGoingAway *); class GlobalSoloStateCommand : public Command { @@ -944,6 +952,8 @@ class Session : public PBD::StatefulDestructible private: int create (bool& new_session, string* mix_template, nframes_t initial_length); + nframes_t compute_initial_length (); + static const char* _template_suffix; static const char* _statefile_suffix; static const char* _pending_suffix; @@ -1566,7 +1576,7 @@ class Session : public PBD::StatefulDestructible void reverse_diskstream_buffers (); - UndoHistory history; + UndoHistory _history; UndoTransaction* current_trans; GlobalRouteBooleanState get_global_route_boolean (bool (Route::*method)(void) const); @@ -1658,7 +1668,7 @@ class Session : public PBD::StatefulDestructible void* ptr, float opt); - /* number of hardware audio ports we're using, + /* number of hardware ports we're using, based on max (requested,available) */ diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h index 50fd5e6839..1d07f6888d 100644 --- a/libs/ardour/ardour/sndfilesource.h +++ b/libs/ardour/ardour/sndfilesource.h @@ -36,10 +36,7 @@ class SndFileSource : public AudioFileSource { /* constructor to be called for new in-session files */ SndFileSource (Session&, std::string path, SampleFormat samp_format, HeaderFormat hdr_format, nframes_t rate, - Flag flags = AudioFileSource::Flag (AudioFileSource::Writable| - AudioFileSource::Removable| - AudioFileSource::RemovableIfEmpty| - AudioFileSource::CanRename)); + Flag flags = SndFileSource::default_writable_flags); /* constructor to be called for existing in-session files */ @@ -53,6 +50,18 @@ class SndFileSource : public AudioFileSource { nframes_t natural_position () const; + nframes_t last_capture_start_frame() const; + void mark_capture_start (nframes_t); + void mark_capture_end (); + void clear_capture_marks(); + + bool set_destructive (bool yn); + + static void setup_standard_crossfades (nframes_t sample_rate); + static const AudioFileSource::Flag default_writable_flags; + + static int get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg); + protected: void set_header_timeline_position (); @@ -69,10 +78,32 @@ class SndFileSource : public AudioFileSource { mutable float *interleave_buf; mutable nframes_t interleave_bufsize; - void init (const string &str); + void init (string str); int open(); void close(); int setup_broadcast_info (nframes_t when, struct tm&, time_t); + + /* destructive */ + + static nframes_t xfade_frames; + static gain_t* out_coefficient; + static gain_t* in_coefficient; + + bool _capture_start; + bool _capture_end; + nframes_t capture_start_frame; + nframes_t file_pos; // unit is frames + nframes_t xfade_out_count; + nframes_t xfade_in_count; + Sample* xfade_buf; + + nframes_t crossfade (Sample* data, nframes_t cnt, int dir); + void set_timeline_position (int64_t); + nframes_t destructive_write_unlocked (Sample *dst, nframes_t cnt); + nframes_t nondestructive_write_unlocked (Sample *dst, nframes_t cnt); + void handle_header_position_change (); + + static int64_t get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists); }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h index 8bf66f8b8d..e94b1af54f 100644 --- a/libs/ardour/ardour/source.h +++ b/libs/ardour/ardour/source.h @@ -22,6 +22,7 @@ #define __ardour_source_h__ #include <string> +#include <set> #include <sigc++/signal.h> @@ -33,6 +34,7 @@ namespace ARDOUR { class Session; +class Playlist; class Source : public PBD::StatefulDestructible { @@ -57,22 +59,34 @@ class Source : public PBD::StatefulDestructible virtual void mark_for_remove() = 0; virtual void mark_streaming_write_completed () = 0; - + XMLNode& get_state (); int set_state (const XMLNode&); + void use () { _in_use++; } + void disuse () { if (_in_use) { _in_use--; } } + + void add_playlist (ARDOUR::Playlist*); + void remove_playlist (ARDOUR::Playlist*); + + uint32_t used() const; + + static sigc::signal<void,Source*> SourceCreated; protected: void update_length (jack_nframes_t pos, jack_nframes_t cnt); - + Session& _session; string _name; DataType _type; time_t _timestamp; jack_nframes_t _length; + std::set<ARDOUR::Playlist*> _playlists; + private: + uint32_t _in_use; }; } diff --git a/libs/ardour/ardour/state_manager.h b/libs/ardour/ardour/state_manager.h deleted file mode 100644 index e123b2cb37..0000000000 --- a/libs/ardour/ardour/state_manager.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __ardour_state_manager_h__ -#define __ardour_state_manager_h__ - -#include <list> -#include <string> -#include <set> - -#include <sigc++/signal.h> - -#include <ardour/ardour.h> - -namespace ARDOUR { - -typedef uint32_t state_id_t; - -class StateManager : public virtual sigc::trackable -{ - public: - struct State { - std::string operation; - State (std::string why) : operation (why) {} - virtual ~State() {} - }; - - typedef std::list<State*> StateMap; - - StateManager (); - virtual ~StateManager (); - - virtual void drop_all_states (); - virtual void use_state (state_id_t); - virtual void save_state (std::string why); - - sigc::signal<void,Change> StateChanged; - - state_id_t _current_state_id; - - virtual bool should_save_state () const { return true; } - - static void prohibit_save (); - static void allow_save (const char* why, bool dosave); - - protected: - static bool _allow_save; - static sigc::signal<void,const char*> SaveAllowed; - - StateMap states; - - virtual Change restore_state (State&) = 0; - virtual State* state_factory (std::string why) const = 0; - virtual void send_state_changed (Change); -}; - -} // namespace ARDOUR - -#endif /* __ardour_state_manager_h__ */ diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index 7cdbe56cf2..f8751b5d2b 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -34,7 +34,6 @@ #include <sigc++/signal.h> #include <ardour/ardour.h> -#include <ardour/state_manager.h> class XMLNode; @@ -162,17 +161,7 @@ class TempoSection : public MetricSection, public Tempo { typedef list<MetricSection*> Metrics; -class TempoMapState : public StateManager::State { - public: - TempoMapState (std::string why) - : StateManager::State (why) { - metrics = new Metrics; - } - - Metrics *metrics; -}; - -class TempoMap : public StateManager, public PBD::StatefulDestructible +class TempoMap : public PBD::StatefulDestructible { public: @@ -246,8 +235,6 @@ class TempoMap : public StateManager, public PBD::StatefulDestructible void dump (std::ostream&) const; void clear (); - UndoAction get_memento() const; - /* this is a helper class that we use to be able to keep track of which meter *AND* tempo are in effect at a given point in time. @@ -279,6 +266,8 @@ class TempoMap : public StateManager, public PBD::StatefulDestructible Metric metric_at (nframes_t) const; void bbt_time_with_metric (nframes_t, BBT_Time&, const Metric&) const; + sigc::signal<void,ARDOUR::Change> StateChanged; + private: static Tempo _default_tempo; static Meter _default_meter; @@ -309,16 +298,6 @@ class TempoMap : public StateManager, public PBD::StatefulDestructible int move_metric_section (MetricSection&, const BBT_Time& to); void do_insert (MetricSection* section); - - Change restore_state (StateManager::State&); - StateManager::State* state_factory (std::string why) const; - - bool in_set_state; - - /* override state_manager::save_state so we can check in_set_state */ - - void save_state (std::string why); - }; }; /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h index 243d0db46d..d7a2da2f46 100644 --- a/libs/ardour/ardour/track.h +++ b/libs/ardour/ardour/track.h @@ -39,6 +39,11 @@ class Track : public Route int set_name (string str, void *src); + TrackMode mode () const { return _mode; } + virtual int set_mode (TrackMode m) { return false; } + virtual bool can_use_mode (TrackMode m, bool& bounce_required) { return false; } + sigc::signal<void> TrackModeChanged; + virtual int roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset, int declick, bool can_record, bool rec_monitors_input) = 0; @@ -57,9 +62,6 @@ class Track : public Route virtual int use_diskstream (string name) = 0; virtual int use_diskstream (const PBD::ID& id) = 0; - TrackMode mode() const { return _mode; } - void set_mode (TrackMode m); - nframes_t update_total_latency(); void set_latency_delay (nframes_t); @@ -88,7 +90,6 @@ class Track : public Route void set_meter_point (MeterPoint, void* src); - sigc::signal<void> ModeChanged; sigc::signal<void> DiskstreamChanged; sigc::signal<void> FreezeChange; diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 61e5f35c95..1138b5208f 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -89,11 +89,17 @@ namespace ARDOUR { Play = 0x4 }; + std::string auto_state_to_string (AutoState); + AutoState string_to_auto_state (std::string); + enum AutoStyle { Absolute = 0x1, Trim = 0x2 }; + std::string auto_style_to_string (AutoStyle); + AutoStyle string_to_auto_style (std::string); + enum AlignStyle { CaptureTime, ExistingMaterial diff --git a/libs/ardour/ardour/vst_plugin.h b/libs/ardour/ardour/vst_plugin.h index 7b8246868c..8034341bcc 100644 --- a/libs/ardour/ardour/vst_plugin.h +++ b/libs/ardour/ardour/vst_plugin.h @@ -31,7 +31,6 @@ #include <sigc++/signal.h> #include <pbd/stateful.h> #include <jack/types.h> -#include <ardour/plugin_state.h> #include <ardour/plugin.h> using std::string; diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index f08d38a9b9..9c5f5233b7 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -383,7 +383,7 @@ AudioDiskstream::setup_destructive_playlist () void AudioDiskstream::use_destructive_playlist () { - /* this is called from the XML-based constructor. when its done, + /* this is called from the XML-based constructor or ::set_destructive. when called, we already have a playlist and a region, but we need to set up our sources for write. we use the sources associated with the (presumed single, full-extent) region. @@ -402,6 +402,10 @@ AudioDiskstream::use_destructive_playlist () throw failed_constructor(); } + /* be sure to stretch the region out to the maximum length */ + + region->set_length (max_frames - region->position(), this); + uint32_t n; ChannelList::iterator chan; @@ -409,6 +413,10 @@ AudioDiskstream::use_destructive_playlist () (*chan).write_source = boost::dynamic_pointer_cast<AudioFileSource>(region->source (n)); assert((*chan).write_source); (*chan).write_source->set_allow_remove_if_empty (false); + + /* this might be false if we switched modes, so force it */ + + (*chan).write_source->set_destructive (true); } /* the source list will never be reset for a destructive track */ @@ -1544,6 +1552,9 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca } else { + string whole_file_region_name; + whole_file_region_name = region_name_from_path (channels[0].write_source->name()); + /* Register a new region with the Session that describes the entire source. Do this first so that any sub-regions will obviously be @@ -1552,7 +1563,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca try { boost::shared_ptr<Region> rx (RegionFactory::create (srcs, channels[0].write_source->last_capture_start_frame(), total_capture, - region_name_from_path (channels[0].write_source->name()), + whole_file_region_name, 0, AudioRegion::Flag (AudioRegion::DefaultFlags|AudioRegion::Automatic|AudioRegion::WholeFile))); region = boost::dynamic_pointer_cast<AudioRegion> (rx); @@ -1575,7 +1586,8 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca for (buffer_position = channels[0].write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) { string region_name; - _session.region_name (region_name, channels[0].write_source->name(), false); + + _session.region_name (region_name, whole_file_region_name, false); // cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add region " << region_name << endl; @@ -1589,9 +1601,9 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca continue; /* XXX is this OK? */ } - _last_capture_regions.push_back (region); + region->GoingAway.connect (bind (mem_fun (*this, &Diskstream::remove_region_from_last_capture), boost::weak_ptr<Region>(region))); - // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl; + _last_capture_regions.push_back (region); i_am_the_modifier++; _playlist->add_region (region, (*ci)->start); @@ -2234,3 +2246,70 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node) return 0; } + +int +AudioDiskstream::set_destructive (bool yn) +{ + bool bounce_ignored; + + if (yn != destructive()) { + + if (yn) { + /* requestor should already have checked this and + bounced if necessary and desired + */ + if (!can_become_destructive (bounce_ignored)) { + return -1; + } + _flags |= Destructive; + use_destructive_playlist (); + } else { + _flags &= ~Destructive; + reset_write_sources (true, true); + } + } + + return 0; +} + +bool +AudioDiskstream::can_become_destructive (bool& requires_bounce) const +{ + if (!_playlist) { + requires_bounce = false; + return false; + } + + /* is there only one region ? */ + + if (_playlist->n_regions() != 1) { + requires_bounce = true; + return false; + } + + boost::shared_ptr<Region> first = _playlist->find_next_region (_session.current_start_frame(), Start, 1); + assert (first); + + /* do the source(s) for the region cover the session start position ? */ + + if (first->position() != _session.current_start_frame()) { + if (first->start() > _session.current_start_frame()) { + requires_bounce = true; + return false; + } + } + + /* is the source used by only 1 playlist ? */ + + boost::shared_ptr<AudioRegion> afirst = boost::dynamic_pointer_cast<AudioRegion> (first); + + assert (afirst); + + if (afirst->source()->used() > 1) { + requires_bounce = true; + return false; + } + + requires_bounce = false; + return true; +} diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc index 94b80df178..335cb020ae 100644 --- a/libs/ardour/audio_playlist.cc +++ b/libs/ardour/audio_playlist.cc @@ -546,7 +546,7 @@ AudioPlaylist::set_state (const XMLNode& node) } thaw (); - in_set_state++; + in_set_state--; return 0; } @@ -639,12 +639,10 @@ AudioPlaylist::destroy_region (boost::shared_ptr<Region> region) { RegionLock rlock (this); - RegionList::iterator i; - RegionList::iterator tmp; - for (i = regions.begin(); i != regions.end(); ) { + for (RegionList::iterator i = regions.begin(); i != regions.end(); ) { - tmp = i; + RegionList::iterator tmp = i; ++tmp; if ((*i) == region) { @@ -654,6 +652,21 @@ AudioPlaylist::destroy_region (boost::shared_ptr<Region> region) i = tmp; } + + for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) { + + set<boost::shared_ptr<Region> >::iterator xtmp = x; + ++xtmp; + + if ((*x) == region) { + all_regions.erase (x); + changed = true; + } + + x = xtmp; + } + + region->set_playlist (0); } for (c = _crossfades.begin(); c != _crossfades.end(); ) { diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc index a6cbce2c1e..f2681aceba 100644 --- a/libs/ardour/audio_track.cc +++ b/libs/ardour/audio_track.cc @@ -65,7 +65,7 @@ AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode AudioTrack::AudioTrack (Session& sess, const XMLNode& node) : Track (sess, node) { - set_state (node); + _set_state (node, false); } AudioTrack::~AudioTrack () @@ -73,6 +73,37 @@ AudioTrack::~AudioTrack () } int +AudioTrack::set_mode (TrackMode m) +{ + if (m != _mode) { + + if (_diskstream->set_destructive (m == Destructive)) { + return -1; + } + + _mode = m; + + TrackModeChanged (); /* EMIT SIGNAL */ + } + + return 0; +} + +bool +AudioTrack::can_use_mode (TrackMode m, bool& bounce_required) +{ + switch (m) { + case Normal: + bounce_required = false; + return true; + + case Destructive: + default: + return _diskstream->can_become_destructive (bounce_required); + } +} + +int AudioTrack::deprecated_use_diskstream_connections () { boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream(); @@ -88,10 +119,10 @@ AudioTrack::deprecated_use_diskstream_connections () diskstream->deprecated_io_node = 0; - set_input_minimum (-1); - set_input_maximum (-1); - set_output_minimum (-1); - set_output_maximum (-1); + set_input_minimum (ChanCount::ZERO); + set_input_maximum (ChanCount::INFINITE); + set_output_minimum (ChanCount::ZERO); + set_output_maximum (ChanCount::INFINITE); if ((prop = node.property ("gain")) != 0) { set_gain (atof (prop->value().c_str()), this); @@ -188,11 +219,19 @@ AudioTrack::audio_diskstream() const int AudioTrack::set_state (const XMLNode& node) { + return _set_state (node, true); +} + +int +AudioTrack::_set_state (const XMLNode& node, bool call_base) +{ const XMLProperty *prop; XMLNodeConstIterator iter; - if (Route::set_state (node)) { - return -1; + if (call_base) { + if (Route::_set_state (node, call_base)) { + return -1; + } } if ((prop = node.property (X_("mode"))) != 0) { @@ -494,6 +533,16 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t transport_frame; boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream(); + { + Glib::RWLock::ReaderLock lm (redirect_lock, Glib::TRY_LOCK); + if (lm.locked()) { + // automation snapshot can also be called from the non-rt context + // and it uses the redirect list, so we take the lock out here + automation_snapshot (start_frame); + } + } + + if (n_outputs().get_total() == 0 && _redirects.empty()) { return 0; } @@ -761,7 +810,7 @@ AudioTrack::freeze (InterThreadInfo& itt) return; } - if (_session.write_one_audio_track (*this, 0, _session.current_end_frame(), true, srcs, itt)) { + if (_session.write_one_audio_track (*this, _session.current_start_frame(), _session.current_end_frame(), true, srcs, itt)) { return; } @@ -780,8 +829,7 @@ AudioTrack::freeze (InterThreadInfo& itt) FreezeRecordInsertInfo* frii = new FreezeRecordInsertInfo ((*r)->get_state(), insert); frii->id = insert->id(); - frii->memento = (*r)->get_memento(); - + _freeze_record.insert_info.push_back (frii); /* now deactivate the insert */ @@ -802,7 +850,7 @@ AudioTrack::freeze (InterThreadInfo& itt) false)); new_playlist->set_orig_diskstream_id (diskstream->id()); - new_playlist->add_region (region, 0); + new_playlist->add_region (region, _session.current_start_frame()); new_playlist->set_frozen (true); region->set_locked (true); diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 70541fce55..b0cd64c8d1 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -21,6 +21,7 @@ #include <unistd.h> #include <cerrno> #include <vector> +#include <exception> #include <glibmm/timer.h> #include <pbd/pthread_utils.h> diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc index 3078521466..16cb990ec2 100644 --- a/libs/ardour/audiofilesource.cc +++ b/libs/ardour/audiofilesource.cc @@ -36,7 +36,6 @@ #include <ardour/audiofilesource.h> #include <ardour/sndfile_helpers.h> #include <ardour/sndfilesource.h> -#include <ardour/destructive_filesource.h> #include <ardour/session.h> #include <ardour/source_factory.h> @@ -66,6 +65,7 @@ AudioFileSource::AudioFileSource (Session& s, string idstr, Flag flags) : AudioSource (s, idstr), _flags (flags) { /* constructor used for existing external to session files. file must exist already */ + _is_embedded = AudioFileSource::determine_embeddedness (idstr); if (init (idstr, true)) { throw failed_constructor (); @@ -77,6 +77,7 @@ AudioFileSource::AudioFileSource (Session& s, std::string path, Flag flags, Samp : AudioSource (s, path), _flags (flags) { /* constructor used for new internal-to-session files. file cannot exist */ + _is_embedded = false; if (init (path, false)) { throw failed_constructor (); @@ -106,6 +107,12 @@ AudioFileSource::~AudioFileSource () } bool +AudioFileSource::determine_embeddedness (std::string path) +{ + return (path.find("/") == 0); +} + +bool AudioFileSource::removable () const { return (_flags & Removable) && ((_flags & RemoveAtDestroy) || ((_flags & RemovableIfEmpty) && length() == 0)); @@ -170,80 +177,16 @@ bool AudioFileSource::get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg) { #ifdef HAVE_COREAUDIO - OSStatus err = noErr; - FSRef ref; - ExtAudioFileRef af = 0; - size_t size; - CFStringRef name; - - err = FSPathMakeRef ((UInt8*)path.c_str(), &ref, 0); - if (err != noErr) { - ExtAudioFileDispose (af); - goto libsndfile; - } - - err = ExtAudioFileOpen(&ref, &af); - if (err != noErr) { - ExtAudioFileDispose (af); - goto libsndfile; + if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) { + return true; } - - AudioStreamBasicDescription absd; - memset(&absd, 0, sizeof(absd)); - size = sizeof(AudioStreamBasicDescription); - err = ExtAudioFileGetProperty(af, - kExtAudioFileProperty_FileDataFormat, &size, &absd); - if (err != noErr) { - ExtAudioFileDispose (af); - goto libsndfile; - } - - _info.samplerate = absd.mSampleRate; - _info.channels = absd.mChannelsPerFrame; - - size = sizeof(_info.length); - err = ExtAudioFileGetProperty(af, kExtAudioFileProperty_FileLengthFrames, &size, &_info.length); - if (err != noErr) { - ExtAudioFileDispose (af); - goto libsndfile; - } - - size = sizeof(CFStringRef); - err = AudioFormatGetProperty( - kAudioFormatProperty_FormatName, sizeof(absd), &absd, &size, &name); - if (err != noErr) { - ExtAudioFileDispose (af); - goto libsndfile; - } - - _info.format_name = CFStringRefToStdString(name); - - ExtAudioFileDispose (af); - return true; - -libsndfile: #endif // HAVE_COREAUDIO - SNDFILE *sf; - SF_INFO sf_info; - - sf_info.format = 0; // libsndfile says to clear this before sf_open(). - - if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) { - char errbuf[256]; - error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1); - return false; + if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) { + return true; } - sf_close (sf); - - _info.samplerate = sf_info.samplerate; - _info.channels = sf_info.channels; - _info.length = sf_info.frames; - _info.format_name = string_compose("Format: %1, %2", - sndfile_major_format(sf_info.format), - sndfile_minor_format(sf_info.format)); - return true; + return false; } XMLNode& @@ -277,6 +220,17 @@ AudioFileSource::set_state (const XMLNode& node) } + if ((prop = node.property (X_("name"))) != 0) { + _is_embedded = AudioFileSource::determine_embeddedness (prop->value()); + } else { + _is_embedded = false; + } + + if ((prop = node.property (X_("destructive"))) != 0) { + /* old style, from the period when we had DestructiveFileSource */ + _flags = Flag (_flags | Destructive); + } + return 0; } @@ -318,6 +272,11 @@ AudioFileSource::mark_take (string id) int AudioFileSource::move_to_trash (const string trash_dir_name) { + if (is_embedded()) { + cerr << "tried to move an embedded region to trash" << endl; + return -1; + } + string newpath; if (!writable()) { @@ -465,7 +424,11 @@ AudioFileSource::find (string pathstr, bool must_exist, bool& isnew) /* external files and/or very very old style sessions include full paths */ _path = pathstr; - _name = pathstr.substr (pathstr.find_last_of ('/') + 1); + if (is_embedded()) { + _name = pathstr; + } else { + _name = pathstr.substr (pathstr.find_last_of ('/') + 1); + } if (access (_path.c_str(), R_OK) != 0) { @@ -521,7 +484,7 @@ AudioFileSource::handle_header_position_change () } void -AudioFileSource::set_timeline_position (nframes_t pos) +AudioFileSource::set_timeline_position (int64_t pos) { timeline_position = pos; } diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 0f4e3807b1..939f9c02dd 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -75,7 +75,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n set_default_fades (); set_default_envelope (); - _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed)); + listen_to_my_curves (); } /* Basic AudioRegion constructor (one channel) */ @@ -95,7 +95,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n set_default_fades (); set_default_envelope (); - _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed)); + listen_to_my_curves (); } /* Basic AudioRegion constructor (many channels) */ @@ -110,7 +110,7 @@ AudioRegion::AudioRegion (SourceList& srcs, nframes_t start, nframes_t length, c set_default_fades (); set_default_envelope (); - _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed)); + listen_to_my_curves (); } @@ -148,7 +148,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t _scale_amplitude = other->_scale_amplitude; - _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed)); + listen_to_my_curves (); assert(_type == DataType::AUDIO); } @@ -165,7 +165,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other) _fade_in_disabled = 0; _fade_out_disabled = 0; - _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed)); + listen_to_my_curves (); assert(_type == DataType::AUDIO); } @@ -187,7 +187,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod throw failed_constructor(); } - _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed)); + listen_to_my_curves (); assert(_type == DataType::AUDIO); } @@ -205,16 +205,69 @@ AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node) throw failed_constructor(); } - _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed)); + listen_to_my_curves (); assert(_type == DataType::AUDIO); } AudioRegion::~AudioRegion () { - cerr << "====== " << _name << " DESTRUCTOR @ " << this << endl; - notify_callbacks (); - GoingAway (); /* EMIT SIGNAL */ +} + +void +AudioRegion::listen_to_my_curves () +{ + _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed)); + _fade_in.StateChanged.connect (mem_fun (*this, &AudioRegion::fade_in_changed)); + _fade_out.StateChanged.connect (mem_fun (*this, &AudioRegion::fade_out_changed)); +} + +bool +AudioRegion::verify_length (nframes_t len) +{ + boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source()); + + if (afs && afs->destructive()) { + return true; + } else { + return Region::verify_length(len); + } +} + +bool +AudioRegion::verify_start_and_length (nframes_t new_start, nframes_t new_length) +{ + boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source()); + + if (afs && afs->destructive()) { + return true; + } else { + return verify_start_and_length(new_start, new_length); + } +} + +bool +AudioRegion::verify_start (nframes_t pos) +{ + boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source()); + + if (afs && afs->destructive()) { + return true; + } else { + return verify_start(pos); + } +} + +bool +AudioRegion::verify_start_mutable (nframes_t& new_start) +{ + boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source()); + + if (afs && afs->destructive()) { + return true; + } else { + return verify_start_mutable(new_start); + } } void @@ -239,7 +292,7 @@ AudioRegion::read_peaks (PeakData *buf, nframes_t npeaks, nframes_t offset, nfra if (chan_n >= _sources.size()) { return 0; } - + if (audio_source(chan_n)->read_peaks (buf, npeaks, offset, cnt, samples_per_unit)) { return 0; } else { @@ -450,7 +503,7 @@ AudioRegion::state (bool full) if ((_flags & DefaultFadeIn)) { child->add_property (X_("default"), X_("yes")); } else { - _fade_in.store_state (*child); + child->add_child_nocopy (_fade_in.get_state ()); } child->add_property (X_("active"), _fade_in_disabled ? X_("no") : X_("yes")); @@ -460,9 +513,9 @@ AudioRegion::state (bool full) if ((_flags & DefaultFadeOut)) { child->add_property (X_("default"), X_("yes")); } else { - _fade_out.store_state (*child); + child->add_child_nocopy (_fade_out.get_state ()); } - + child->add_property (X_("active"), _fade_out_disabled ? X_("no") : X_("yes")); } @@ -473,6 +526,7 @@ AudioRegion::state (bool full) // If there are only two points, the points are in the start of the region and the end of the region // so, if they are both at 1.0f, that means the default region. + if (_envelope.size() == 2 && _envelope.front()->value == 1.0f && _envelope.back()->value==1.0f) { @@ -484,7 +538,7 @@ AudioRegion::state (bool full) if (default_env) { child->add_property ("default", "yes"); } else { - _envelope.store_state (*child); + child->add_child_nocopy (_envelope.get_state ()); } } else { @@ -545,34 +599,28 @@ AudioRegion::set_live_state (const XMLNode& node, Change& what_changed, bool sen _envelope.clear (); - if ((prop = child->property ("default")) != 0) { + if ((prop = child->property ("default")) != 0 || _envelope.set_state (*child)) { set_default_envelope (); - } else { - _envelope.load_state (*child); } _envelope.set_max_xval (_length); _envelope.truncate_end (_length); - + } else if (child->name() == "FadeIn") { _fade_in.clear (); - if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0) { + if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0 || _fade_in.set_state (*child)) { set_default_fade_in (); - } else { - _fade_in.load_state (*child); - } + } } else if (child->name() == "FadeOut") { _fade_out.clear (); - if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0) { + if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0 || _fade_out.set_state (*child)) { set_default_fade_out (); - } else { - _fade_out.load_state (*child); - } + } } } @@ -1030,7 +1078,19 @@ AudioRegion::normalize_to (float target_dB) } void -AudioRegion::envelope_changed (Change ignored) +AudioRegion::fade_in_changed () +{ + send_change (FadeInChanged); +} + +void +AudioRegion::fade_out_changed () +{ + send_change (FadeOutChanged); +} + +void +AudioRegion::envelope_changed () { send_change (EnvelopeChanged); } @@ -1083,8 +1143,10 @@ AudioRegion::speed_mismatch (float sr) const void AudioRegion::source_offset_changed () { - if (boost::dynamic_pointer_cast<DestructiveFileSource>(_sources.front())) { - set_start (source()->natural_position(), this); + boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(_sources.front()); + + if (afs && afs->destructive()) { + // set_start (source()->natural_position(), this); set_position (source()->natural_position(), this); } } diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc index 419fe9240c..93165b7fe4 100644 --- a/libs/ardour/audiosource.cc +++ b/libs/ardour/audiosource.cc @@ -368,26 +368,29 @@ AudioSource::initialize_peakfile (bool newfile, string audio_path) error << string_compose(_("AudioSource: cannot stat peakfile \"%1\""), peakpath) << endmsg; return -1; } - } else { - /* we found it in the peaks dir */ - } - - if (statbuf.st_size == 0) { _peaks_built = false; + } else { - // Check if the audio file has changed since the peakfile was built. - struct stat stat_file; - int err = stat (audio_path.c_str(), &stat_file); - if (!err && stat_file.st_mtime > statbuf.st_mtime){ + /* we found it in the peaks dir, so check it out */ + + if (statbuf.st_size == 0) { _peaks_built = false; } else { - _peaks_built = true; + // Check if the audio file has changed since the peakfile was built. + struct stat stat_file; + int err = stat (audio_path.c_str(), &stat_file); + + if (!err && stat_file.st_mtime > statbuf.st_mtime){ + _peaks_built = false; + } else { + _peaks_built = true; + } } } } - + if (!newfile && !_peaks_built && _build_missing_peakfiles && _build_peakfiles) { build_peaks_from_scratch (); } diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc index f286b11607..5cc2f50e38 100644 --- a/libs/ardour/automation_event.cc +++ b/libs/ardour/automation_event.cc @@ -22,9 +22,11 @@ #include <climits> #include <float.h> #include <cmath> +#include <sstream> #include <algorithm> #include <sigc++/bind.h> #include <ardour/automation_event.h> +#include <pbd/convert.h> #include "i18n.h" @@ -46,14 +48,13 @@ static void dumpit (const AutomationList& al, string prefix = "") } #endif -AutomationList::AutomationList (double defval, bool with_state) +AutomationList::AutomationList (double defval) { _frozen = false; changed_when_thawed = false; _state = Off; _style = Absolute; _touching = false; - no_state = with_state; min_yval = FLT_MIN; max_yval = FLT_MAX; max_xval = 0; // means "no limit" @@ -63,10 +64,6 @@ AutomationList::AutomationList (double defval, bool with_state) lookup_cache.left = -1; lookup_cache.range.first = events.end(); - if (!no_state) { - save_state (_("initial")); - } - AutomationListCreated(this); } @@ -83,7 +80,6 @@ AutomationList::AutomationList (const AutomationList& other) _touching = other._touching; _dirty = false; rt_insertion_point = events.end(); - no_state = other.no_state; lookup_cache.left = -1; lookup_cache.range.first = events.end(); @@ -111,7 +107,6 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl _touching = other._touching; _dirty = false; rt_insertion_point = events.end(); - no_state = other.no_state; lookup_cache.left = -1; lookup_cache.range.first = events.end(); @@ -128,32 +123,36 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl delete section; mark_dirty (); + AutomationListCreated(this); } -AutomationList::~AutomationList() +AutomationList::AutomationList (const XMLNode& node) { - std::set<ControlEvent*> all_events; - AutomationList::State* asp; + _frozen = false; + changed_when_thawed = false; + _touching = false; + min_yval = FLT_MIN; + max_yval = FLT_MAX; + max_xval = 0; // means "no limit" + _dirty = false; + _state = Off; + _style = Absolute; + rt_insertion_point = events.end(); + lookup_cache.left = -1; + lookup_cache.range.first = events.end(); + + set_state (node); - GoingAway (); + AutomationListCreated(this); +} +AutomationList::~AutomationList() +{ + GoingAway (); + for (AutomationEventList::iterator x = events.begin(); x != events.end(); ++x) { - all_events.insert (*x); - } - - for (StateMap::iterator i = states.begin(); i != states.end(); ++i) { - - if ((asp = dynamic_cast<AutomationList::State*> (*i)) != 0) { - - for (AutomationEventList::iterator x = asp->events.begin(); x != asp->events.end(); ++x) { - all_events.insert (*x); - } - } - } - - for (std::set<ControlEvent*>::iterator i = all_events.begin(); i != all_events.end(); ++i) { - delete (*i); + delete (*x); } } @@ -194,7 +193,7 @@ AutomationList::maybe_signal_changed () if (_frozen) { changed_when_thawed = true; } else { - StateChanged (Change (0)); + StateChanged (); } } @@ -236,9 +235,6 @@ AutomationList::clear () { Glib::Mutex::Lock lm (lock); events.clear (); - if (!no_state) { - save_state (_("cleared")); - } mark_dirty (); } @@ -270,7 +266,6 @@ void AutomationList::_x_scale (double factor) (*i)->when = floor ((*i)->when * factor); } - save_state ("x-scaled"); mark_dirty (); } @@ -370,12 +365,19 @@ AutomationList::rt_add (double when, double value) maybe_signal_changed (); } +void +AutomationList::fast_simple_add (double when, double value) +{ + /* to be used only for loading pre-sorted data from saved state */ + events.insert (events.end(), point_factory (when, value)); +} + #undef last_rt_insertion_point void -AutomationList::add (double when, double value, bool for_loading) +AutomationList::add (double when, double value) { - /* this is for graphical editing and loading data from storage */ + /* this is for graphical editing */ { Glib::Mutex::Lock lm (lock); @@ -407,15 +409,9 @@ AutomationList::add (double when, double value, bool for_loading) } mark_dirty (); - - if (!no_state && !for_loading) { - save_state (_("added event")); - } } - if (!for_loading) { - maybe_signal_changed (); - } + maybe_signal_changed (); } void @@ -425,9 +421,6 @@ AutomationList::erase (AutomationList::iterator i) Glib::Mutex::Lock lm (lock); events.erase (i); reposition_for_rt_add (0); - if (!no_state) { - save_state (_("removed event")); - } mark_dirty (); } maybe_signal_changed (); @@ -440,9 +433,6 @@ AutomationList::erase (AutomationList::iterator start, AutomationList::iterator Glib::Mutex::Lock lm (lock); events.erase (start, end); reposition_for_rt_add (0); - if (!no_state) { - save_state (_("removed multiple events")); - } mark_dirty (); } maybe_signal_changed (); @@ -471,10 +461,6 @@ AutomationList::reset_range (double start, double endt) reset = true; - if (!no_state) { - save_state (_("removed range")); - } - mark_dirty (); } } @@ -502,9 +488,6 @@ AutomationList::erase_range (double start, double endt) events.erase (s, e); reposition_for_rt_add (0); erased = true; - if (!no_state) { - save_state (_("removed range")); - } mark_dirty (); } @@ -532,10 +515,6 @@ AutomationList::move_range (iterator start, iterator end, double xdelta, double ++start; } - if (!no_state) { - save_state (_("event range adjusted")); - } - mark_dirty (); } @@ -554,10 +533,6 @@ AutomationList::modify (iterator iter, double when, double val) Glib::Mutex::Lock lm (lock); (*iter)->when = when; (*iter)->value = val; - if (!no_state) { - save_state (_("event adjusted")); - } - mark_dirty (); } @@ -609,44 +584,10 @@ AutomationList::thaw () { _frozen = false; if (changed_when_thawed) { - StateChanged(Change(0)); /* EMIT SIGNAL */ + StateChanged(); /* EMIT SIGNAL */ } } -StateManager::State* -AutomationList::state_factory (std::string why) const -{ - State* state = new State (why); - - for (AutomationEventList::const_iterator x = events.begin(); x != events.end(); ++x) { - state->events.push_back (point_factory (**x)); - } - - return state; -} - -Change -AutomationList::restore_state (StateManager::State& state) -{ - { - Glib::Mutex::Lock lm (lock); - State* lstate = dynamic_cast<State*> (&state); - - events.clear (); - for (AutomationEventList::const_iterator x = lstate->events.begin(); x != lstate->events.end(); ++x) { - events.push_back (point_factory (**x)); - } - } - - return Change (0); -} - -UndoAction -AutomationList::get_memento () const -{ - return sigc::bind (mem_fun (*(const_cast<AutomationList*> (this)), &StateManager::use_state), _current_state_id); -} - void AutomationList::set_max_xval (double x) { @@ -670,10 +611,6 @@ AutomationList::truncate_end (double last_coordinate) double last_val; if (events.empty()) { - fatal << _("programming error:") - << "AutomationList::truncate_end() called on an empty list" - << endmsg; - /*NOTREACHED*/ return; } @@ -1083,9 +1020,6 @@ AutomationList::cut_copy_clear (double start, double end, int op) if (changed) { reposition_for_rt_add (0); - if (!no_state) { - save_state (_("cut/copy/clear")); - } } mark_dirty (); @@ -1115,10 +1049,6 @@ AutomationList::copy (iterator start, iterator end) x = tmp; } - - if (!no_state) { - save_state (_("copy")); - } } return nal; @@ -1183,11 +1113,6 @@ AutomationList::paste (AutomationList& alist, double pos, float times) } reposition_for_rt_add (0); - - if (!no_state) { - save_state (_("paste")); - } - mark_dirty (); } @@ -1207,64 +1132,220 @@ AutomationList::point_factory (const ControlEvent& other) const return new ControlEvent (other); } -void -AutomationList::store_state (XMLNode& node) const +XMLNode& +AutomationList::get_state () { + return state (true); +} + +XMLNode& +AutomationList::state (bool full) +{ + XMLNode* root = new XMLNode (X_("AutomationList")); + char buf[64]; LocaleGuard lg (X_("POSIX")); - for (const_iterator i = const_begin(); i != const_end(); ++i) { - char buf[64]; - - XMLNode *pointnode = new XMLNode ("point"); - - snprintf (buf, sizeof (buf), "%" PRIu32, (nframes_t) floor ((*i)->when)); - pointnode->add_property ("x", buf); - snprintf (buf, sizeof (buf), "%.12g", (*i)->value); - pointnode->add_property ("y", buf); + root->add_property ("id", _id.to_s()); - node.add_child_nocopy (*pointnode); + snprintf (buf, sizeof (buf), "%.12g", default_value); + root->add_property ("default", buf); + snprintf (buf, sizeof (buf), "%.12g", min_yval); + root->add_property ("min_yval", buf); + snprintf (buf, sizeof (buf), "%.12g", max_yval); + root->add_property ("max_yval", buf); + snprintf (buf, sizeof (buf), "%.12g", max_xval); + root->add_property ("max_xval", buf); + + if (full) { + root->add_property ("state", auto_state_to_string (_state)); + } else { + /* never save anything but Off for automation state to a template */ + root->add_property ("state", auto_state_to_string (Off)); } + + root->add_property ("style", auto_style_to_string (_style)); + + if (!events.empty()) { + root->add_child_nocopy (serialize_events()); + } + + return *root; } -void -AutomationList::load_state (const XMLNode& node) +XMLNode& +AutomationList::serialize_events () { - const XMLNodeList& elist = node.children(); - XMLNodeConstIterator i; - XMLProperty* prop; - nframes_t x; - double y; + XMLNode* node = new XMLNode (X_("events")); + stringstream str; + + for (iterator xx = events.begin(); xx != events.end(); ++xx) { + str << (double) (*xx)->when; + str << ' '; + str <<(double) (*xx)->value; + str << '\n'; + } + + /* XML is a bit wierd */ + + XMLNode* content_node = new XMLNode (X_("foo")); /* it gets renamed by libxml when we set content */ + content_node->set_content (str.str()); + + node->add_child_nocopy (*content_node); + + return *node; +} + +int +AutomationList::deserialize_events (const XMLNode& node) +{ + if (node.children().empty()) { + return -1; + } + + XMLNode* content_node = node.children().front(); + if (content_node->content().empty()) { + return -1; + } + + freeze (); clear (); - for (i = elist.begin(); i != elist.end(); ++i) { - - if ((prop = (*i)->property ("x")) == 0) { - error << _("automation list: no x-coordinate stored for control point (point ignored)") << endmsg; - continue; + stringstream str (content_node->content()); + + double x; + double y; + bool ok = true; + + while (str) { + str >> x; + if (!str) { + break; } - x = atoi (prop->value().c_str()); - - if ((prop = (*i)->property ("y")) == 0) { - error << _("automation list: no y-coordinate stored for control point (point ignored)") << endmsg; - continue; + str >> y; + if (!str) { + ok = false; + break; } - y = atof (prop->value().c_str()); - - add (x, y); + fast_simple_add (x, y); + } + + if (!ok) { + clear (); + error << _("automation list: cannot load coordinates from XML, all points ignored") << endmsg; + } else { + mark_dirty (); + reposition_for_rt_add (0); + maybe_signal_changed (); } -} -XMLNode &AutomationList::get_state () -{ - XMLNode *node = new XMLNode("AutomationList"); - store_state(*node); - return *node; + thaw (); + return 0; } -int AutomationList::set_state(const XMLNode &s) +int +AutomationList::set_state (const XMLNode& node) { - load_state(s); - return 0; + XMLNodeList nlist = node.children(); + XMLNode* nsos; + XMLNodeIterator niter; + const XMLProperty* prop; + + if (node.name() == X_("events")) { + /* partial state setting*/ + return deserialize_events (node); + } + + if (node.name() == X_("Envelope") || node.name() == X_("FadeOut") || node.name() == X_("FadeIn")) { + + if ((nsos = node.child (X_("AutomationList")))) { + /* new school in old school clothing */ + return set_state (*nsos); + } + + /* old school */ + + const XMLNodeList& elist = node.children(); + XMLNodeConstIterator i; + XMLProperty* prop; + jack_nframes_t x; + double y; + + clear (); + + for (i = elist.begin(); i != elist.end(); ++i) { + + if ((prop = (*i)->property ("x")) == 0) { + error << _("automation list: no x-coordinate stored for control point (point ignored)") << endmsg; + continue; + } + x = atoi (prop->value().c_str()); + + if ((prop = (*i)->property ("y")) == 0) { + error << _("automation list: no y-coordinate stored for control point (point ignored)") << endmsg; + continue; + } + y = atof (prop->value().c_str()); + + add (x, y); + } + + return 0; + } + + if (node.name() != X_("AutomationList") ) { + error << string_compose (_("AutomationList: passed XML node called %1, not \"AutomationList\" - ignored"), node.name()) << endmsg; + return -1; + } + + if ((prop = node.property ("id")) != 0) { + _id = prop->value (); + /* update session AL list */ + AutomationListCreated(this); + } + + if ((prop = node.property (X_("default"))) != 0){ + default_value = atof (prop->value()); + } else { + default_value = 0.0; + } + + if ((prop = node.property (X_("style"))) != 0) { + _style = string_to_auto_style (prop->value()); + } else { + _style = Absolute; + } + + if ((prop = node.property (X_("state"))) != 0) { + _state = string_to_auto_state (prop->value()); + } else { + _state = Off; + } + + if ((prop = node.property (X_("min_yval"))) != 0) { + min_yval = atof (prop->value ()); + } else { + min_yval = FLT_MIN; + } + + if ((prop = node.property (X_("max_yval"))) != 0) { + max_yval = atof (prop->value ()); + } else { + max_yval = FLT_MAX; + } + + if ((prop = node.property (X_("max_xval"))) != 0) { + max_xval = atof (prop->value ()); + } else { + max_xval = 0; // means "no limit ; + } + + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { + if ((*niter)->name() == X_("events")) { + deserialize_events (*(*niter)); + } + } + + return 0; } diff --git a/libs/ardour/control_protocol_manager.cc b/libs/ardour/control_protocol_manager.cc index 1ff6c28ef3..a715254747 100644 --- a/libs/ardour/control_protocol_manager.cc +++ b/libs/ardour/control_protocol_manager.cc @@ -36,6 +36,13 @@ ControlProtocolManager::~ControlProtocolManager() } control_protocols.clear (); + + + for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) { + delete (*p); + } + + control_protocol_info.clear(); } @@ -68,6 +75,12 @@ ControlProtocolManager::drop_session () delete *p; } control_protocols.clear (); + + for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) { + delete *p; + } + + control_protocol_info.clear(); } } @@ -122,6 +135,15 @@ ControlProtocolManager::teardown (ControlProtocolInfo& cpi) list<ControlProtocol*>::iterator p = find (control_protocols.begin(), control_protocols.end(), cpi.protocol); if (p != control_protocols.end()) { control_protocols.erase (p); + } else { + cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocols" << endl; + } + + list<ControlProtocolInfo*>::iterator p2 = find (control_protocol_info.begin(), control_protocol_info.end(), &cpi); + if (p2 != control_protocol_info.end()) { + control_protocol_info.erase (p2); + } else { + cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocol_info" << endl; } } diff --git a/libs/ardour/coreaudiosource.cc b/libs/ardour/coreaudiosource.cc index c8cbb7a40d..3c81b18fd4 100644 --- a/libs/ardour/coreaudiosource.cc +++ b/libs/ardour/coreaudiosource.cc @@ -43,7 +43,7 @@ CoreAudioSource::CoreAudioSource (Session& s, const string& idstr, Flag flags) } void -CoreAudioSource::init (const string& idstr) +CoreAudioSource::init (string idstr) { string::size_type pos; @@ -84,10 +84,6 @@ CoreAudioSource::init (const string& idstr) error << string_compose ("CoreAudioSource: %1 (%2)", cax.mOperation, name()) << endmsg; throw failed_constructor (); } - - if (_build_peakfiles) { - _need_peakfile = true; - } } CoreAudioSource::~CoreAudioSource () @@ -189,3 +185,53 @@ CoreAudioSource::update_header (nframes_t when, struct tm&, time_t) { return 0; } + +int +CoreAudioSource::get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg) +{ + FSRef ref; + ExtAudioFileRef af = 0; + size_t size; + CFStringRef name; + int ret = -1; + + if (FSPathMakeRef ((UInt8*)path.c_str(), &ref, 0) != noErr) { + goto out; + } + + if (ExtAudioFileOpen(&ref, &af) != noErr) { + goto out; + } + + AudioStreamBasicDescription absd; + memset(&absd, 0, sizeof(absd)); + size = sizeof(AudioStreamBasicDescription); + if (ExtAudioFileGetProperty (af, kExtAudioFileProperty_FileDataFormat, &size, &absd) != noErr) { + goto out; + } + + _info.samplerate = absd.mSampleRate; + _info.channels = absd.mChannelsPerFrame; + + size = sizeof(_info.length); + if (ExtAudioFileGetProperty(af, kExtAudioFileProperty_FileLengthFrames, &size, &_info.length) != noErr) { + goto out; + } + + size = sizeof(CFStringRef); + if (AudioFormatGetProperty(kAudioFormatProperty_FormatName, sizeof(absd), &absd, &size, &name) != noErr) { + goto out; + } + + _info.format_name = CFStringRefToStdString(name); + + // XXX it would be nice to find a way to get this information if it exists + + _info.timecode = 0; + ret = 0; + + out: + ExtAudioFileDispose (af); + return ret; + +} diff --git a/libs/ardour/curve.cc b/libs/ardour/curve.cc index 7d62c5bc94..8465094775 100644 --- a/libs/ardour/curve.cc +++ b/libs/ardour/curve.cc @@ -40,14 +40,11 @@ using namespace ARDOUR; using namespace sigc; using namespace PBD; -sigc::signal<void, Curve*> Curve::CurveCreated; - Curve::Curve (double minv, double maxv, double canv, bool nostate) - : AutomationList (canv, nostate) + : AutomationList (canv) { min_yval = minv; max_yval = maxv; - CurveCreated(this); } Curve::Curve (const Curve& other) @@ -55,7 +52,6 @@ Curve::Curve (const Curve& other) { min_yval = other.min_yval; max_yval = other.max_yval; - CurveCreated(this); } Curve::Curve (const Curve& other, double start, double end) @@ -63,7 +59,11 @@ Curve::Curve (const Curve& other, double start, double end) { min_yval = other.min_yval; max_yval = other.max_yval; - CurveCreated(this); +} + +Curve::Curve (const XMLNode& node) + : AutomationList (node) +{ } Curve::~Curve () @@ -73,7 +73,7 @@ Curve::~Curve () void Curve::solve () { - size_t npoints; + uint32_t npoints; if (!_dirty) { return; @@ -88,7 +88,7 @@ Curve::solve () double x[npoints]; double y[npoints]; - size_t i; + uint32_t i; AutomationEventList::iterator xx; for (i = 0, xx = events.begin(); xx != events.end(); ++xx, ++i) { @@ -207,7 +207,7 @@ Curve::solve () } bool -Curve::rt_safe_get_vector (double x0, double x1, float *vec, size_t veclen) +Curve::rt_safe_get_vector (double x0, double x1, float *vec, int32_t veclen) { Glib::Mutex::Lock lm (lock, Glib::TRY_LOCK); @@ -220,19 +220,19 @@ Curve::rt_safe_get_vector (double x0, double x1, float *vec, size_t veclen) } void -Curve::get_vector (double x0, double x1, float *vec, size_t veclen) +Curve::get_vector (double x0, double x1, float *vec, int32_t veclen) { Glib::Mutex::Lock lm (lock); _get_vector (x0, x1, vec, veclen); } void -Curve::_get_vector (double x0, double x1, float *vec, size_t veclen) +Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) { double rx, dx, lx, hx, max_x, min_x; - size_t i; - size_t original_veclen; - size_t npoints; + int32_t i; + int32_t original_veclen; + int32_t npoints; if ((npoints = events.size()) == 0) { for (i = 0; i < veclen; ++i) { @@ -263,7 +263,7 @@ Curve::_get_vector (double x0, double x1, float *vec, size_t veclen) */ double frac = (min_x - x0) / (x1 - x0); - size_t subveclen = (size_t) floor (veclen * frac); + int32_t subveclen = (int32_t) floor (veclen * frac); subveclen = min (subveclen, veclen); @@ -281,7 +281,7 @@ Curve::_get_vector (double x0, double x1, float *vec, size_t veclen) double frac = (x1 - max_x) / (x1 - x0); - size_t subveclen = lrintf (original_veclen * frac); + int32_t subveclen = (int32_t) floor (original_veclen * frac); float val; @@ -435,18 +435,10 @@ Curve::point_factory (const ControlEvent& other) const return new CurvePoint (other.when, other.value); } -Change -Curve::restore_state (StateManager::State& state) -{ - mark_dirty (); - return AutomationList::restore_state (state); -} - - extern "C" { void -curve_get_vector_from_c (void *arg, double x0, double x1, float* vec, size_t vecsize) +curve_get_vector_from_c (void *arg, double x0, double x1, float* vec, int32_t vecsize) { static_cast<Curve*>(arg)->get_vector (x0, x1, vec, vecsize); } diff --git a/libs/ardour/destructive_filesource.cc b/libs/ardour/destructive_filesource.cc index e160ffd608..fcd85bfe8f 100644 --- a/libs/ardour/destructive_filesource.cc +++ b/libs/ardour/destructive_filesource.cc @@ -55,8 +55,10 @@ typedef off_t off64_t; #include <fcntl.h> #include <pbd/error.h> +#include <pbd/stacktrace.h> #include <ardour/destructive_filesource.h> #include <ardour/utils.h> +#include <ardour/session.h> #include "i18n.h" @@ -289,7 +291,7 @@ DestructiveFileSource::write_unlocked (Sample* data, nframes_t cnt) _capture_end = false; /* move to the correct location place */ - file_pos = capture_start_frame; + file_pos = capture_start_frame - timeline_position; // split cnt in half nframes_t subcnt = cnt / 2; @@ -343,17 +345,16 @@ DestructiveFileSource::write_unlocked (Sample* data, nframes_t cnt) } else { /* in the middle of recording */ - if (write_float (data, file_pos, cnt) != cnt) { return 0; } } - + old_file_pos = file_pos; update_length (file_pos, cnt); file_pos += cnt; - + if (_build_peakfiles) { PeakBuildRecord *pbr = 0; @@ -409,7 +410,15 @@ DestructiveFileSource::handle_header_position_change () } void -DestructiveFileSource::set_timeline_position (nframes_t pos) +DestructiveFileSource::set_timeline_position (int64_t) { //destructive track timeline postion does not change except at instantion or when header_position_offset (session start) changes } + +int +DestructiveFileSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit) const +{ + // cerr << _name << " read peaks at " << start << " for " << cnt << " tpos = " << timeline_position << endl; + return AudioFileSource::read_peaks (peaks, npeaks, start, cnt, samples_per_unit); +} + diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc index e9f8499981..5f6f3956cf 100644 --- a/libs/ardour/diskstream.cc +++ b/libs/ardour/diskstream.cc @@ -390,14 +390,14 @@ Diskstream::set_name (string str) } void -Diskstream::set_destructive (bool yn) +Diskstream::remove_region_from_last_capture (boost::weak_ptr<Region> wregion) { - if (yn != destructive()) { - reset_write_sources (true, true); - if (yn) { - _flags |= Destructive; - } else { - _flags &= ~Destructive; - } + boost::shared_ptr<Region> region (wregion.lock()); + + if (!region) { + return; } + + _last_capture_regions.remove (region); } + diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 9b5bea9d3a..f92660470c 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -128,6 +128,8 @@ setup_midi (AudioEngine& engine ) } MIDI::Manager::instance()->add_port (request); + + nports++; } if (nports > 1) { diff --git a/libs/ardour/i18n.h b/libs/ardour/i18n.h index 71a3dccab8..5d68c79edd 100644 --- a/libs/ardour/i18n.h +++ b/libs/ardour/i18n.h @@ -2,6 +2,7 @@ #define __i18n_h__ #include <pbd/compose.h> +#include <pbd/convert.h> #include "gettext.h" #include <vector> @@ -10,5 +11,6 @@ #define _(Text) dgettext (PACKAGE,Text) #define N_(Text) gettext_noop (Text) #define X_(Text) Text +#define I18N(Array) PBD::internationalize (PACKAGE, Array) #endif // __i18n_h__ diff --git a/libs/ardour/insert.cc b/libs/ardour/insert.cc index b557017ec7..034b043763 100644 --- a/libs/ardour/insert.cc +++ b/libs/ardour/insert.cc @@ -85,8 +85,6 @@ PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug, Placemen init (); - save_state (_("initial state")); - { Glib::Mutex::Lock em (_session.engine().process_lock()); IO::MoreChannels (max(input_streams(), output_streams())); @@ -104,8 +102,6 @@ PluginInsert::PluginInsert (Session& s, const XMLNode& node) set_automatable (); - save_state (_("initial state")); - _plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed)); { @@ -129,8 +125,6 @@ PluginInsert::PluginInsert (const PluginInsert& other) init (); - save_state (_("initial state")); - RedirectCreated (this); /* EMIT SIGNAL */ } @@ -325,6 +319,23 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off } void +PluginInsert::automation_snapshot (nframes_t now) +{ + map<uint32_t,AutomationList*>::iterator li; + + for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) { + + AutomationList *alist = ((*li).second); + if (alist != 0 && alist->automation_write ()) { + + float val = _plugins[0]->get_parameter ((*li).first); + alist->rt_add (now, val); + last_automation_snapshot = now; + } + } +} + +void PluginInsert::transport_stopped (nframes_t now) { map<uint32_t,AutomationList*>::iterator li; @@ -785,35 +796,6 @@ PluginInsert::latency() return _plugins[0]->latency (); } -void -PluginInsert::store_state (PluginInsertState& state) const -{ - Redirect::store_state (state); - _plugins[0]->store_state (state.plugin_state); -} - -Change -PluginInsert::restore_state (StateManager::State& state) -{ - PluginInsertState* pistate = dynamic_cast<PluginInsertState*> (&state); - - Redirect::restore_state (state); - - _plugins[0]->restore_state (pistate->plugin_state); - - return Change (0); -} - -StateManager::State* -PluginInsert::state_factory (std::string why) const -{ - PluginInsertState* state = new PluginInsertState (why); - - store_state (*state); - - return state; -} - ARDOUR::PluginType PluginInsert::type () { @@ -851,7 +833,6 @@ PortInsert::PortInsert (Session& s, Placement p) : Insert (s, p, 1, -1, 1, -1) { init (); - save_state (_("initial state")); RedirectCreated (this); /* EMIT SIGNAL */ } @@ -859,7 +840,6 @@ PortInsert::PortInsert (const PortInsert& other) : Insert (other._session, other.placement(), 1, -1, 1, -1) { init (); - save_state (_("initial state")); RedirectCreated (this); /* EMIT SIGNAL */ } @@ -1013,10 +993,10 @@ PortInsert::configure_io (int32_t ignored_magic, int32_t in, int32_t out) to the number of input ports we need. */ - set_output_maximum (in); - set_output_minimum (in); - set_input_maximum (out); - set_input_minimum (out); + set_output_maximum (ChanCount(_default_type, in)); + set_output_minimum (ChanCount(_default_type, in)); + set_input_maximum (ChanCount(_default_type, out)); + set_input_minimum (ChanCount(_default_type, out)); if (in < 0) { in = n_outputs ().get(_default_type); @@ -1026,8 +1006,7 @@ PortInsert::configure_io (int32_t ignored_magic, int32_t in, int32_t out) out = n_inputs ().get(_default_type); } - // FIXME - return ensure_io (ChanCount(_default_type, in), ChanCount(_default_type, out), false, this); + return ensure_io (ChanCount(_default_type, out), ChanCount(_default_type, in), false, this); } int32_t diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index af5473368b..60e7ec3f42 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -60,7 +60,7 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -static float current_automation_version_number = 1.0; +nframes_t IO::_automation_interval = 0; const string IO::state_node_name = "IO"; bool IO::connecting_legal = false; @@ -137,6 +137,8 @@ IO::IO (Session& s, string name, apply_gain_automation = false; + last_automation_snapshot = 0; + _gain_automation_state = Off; _gain_automation_style = Absolute; @@ -149,6 +151,43 @@ IO::IO (Session& s, string name, // Connect to our own MoreChannels signal to connect output buffers IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers)); + + _session.add_controllable (&_gain_control); +} + +IO::IO (Session& s, const XMLNode& node, DataType dt) + : _session (s), + _output_buffers(new BufferSet()), + _default_type (dt), + _gain_control (X_("gaincontrol"), *this), + _gain_automation_curve (0, 0, 0) // all reset in set_state() +{ + // FIXME: hack + _meter = new PeakMeter (_session); + + _panner = 0; + deferred_state = 0; + no_panner_reset = false; + _desired_gain = 1.0; + _gain = 1.0; + _input_connection = 0; + _output_connection = 0; + + apply_gain_automation = false; + + set_state (node); + + { + // IO::Meter is emitted from another thread so the + // Meter signal must be protected. + Glib::Mutex::Lock guard (m_meter_signal_lock); + m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter)); + } + + // Connect to our own MoreChannels signal to connect output buffers + IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers)); + + _session.add_controllable (&_gain_control); } IO::~IO () @@ -1234,67 +1273,21 @@ IO::state (bool full_state) /* automation */ if (full_state) { + + XMLNode* autonode = new XMLNode (X_("Automation")); + autonode->add_child_nocopy (get_automation_state()); + node->add_child_nocopy (*autonode); + snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state()); } else { /* never store anything except Off for automation state in a template */ snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off); } - node->add_property ("automation-state", buf); - snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style()); - node->add_property ("automation-style", buf); - - /* XXX same for pan etc. */ return *node; } int -IO::connecting_became_legal () -{ - int ret; - - if (pending_state_node == 0) { - fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg; - /*NOTREACHED*/ - return -1; - } - - connection_legal_c.disconnect (); - - ret = make_connections (*pending_state_node); - - if (ports_legal) { - delete pending_state_node; - pending_state_node = 0; - } - - return ret; -} - -int -IO::ports_became_legal () -{ - int ret; - - if (pending_state_node == 0) { - fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg; - /*NOTREACHED*/ - return -1; - } - - port_legal_c.disconnect (); - - ret = create_ports (*pending_state_node); - - if (connecting_legal) { - delete pending_state_node; - pending_state_node = 0; - } - - return ret; -} - -int IO::set_state (const XMLNode& node) { const XMLProperty* prop; @@ -1312,7 +1305,7 @@ IO::set_state (const XMLNode& node) if ((prop = node.property ("name")) != 0) { _name = prop->value(); - _panner->set_name (_name); + /* used to set panner name with this, but no more */ } if ((prop = node.property ("id")) != 0) { @@ -1338,32 +1331,29 @@ IO::set_state (const XMLNode& node) _gain = _desired_gain; } + if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) { + /* old school automation handling */ + } + for (iter = node.children().begin(); iter != node.children().end(); ++iter) { if ((*iter)->name() == "Panner") { + if (_panner == 0) { + _panner = new Panner (_name, _session); + } _panner->set_state (**iter); } + if ((*iter)->name() == X_("Automation")) { + + set_automation_state (*(*iter)->children().front()); + } + if ((*iter)->name() == X_("gaincontrol")) { _gain_control.set_state (**iter); - _session.add_controllable (&_gain_control); } } - if ((prop = node.property ("automation-state")) != 0) { - - long int x; - x = strtol (prop->value().c_str(), 0, 16); - set_gain_automation_state (AutoState (x)); - } - - if ((prop = node.property ("automation-style")) != 0) { - - long int x; - x = strtol (prop->value().c_str(), 0, 16); - set_gain_automation_style (AutoStyle (x)); - } - if (ports_legal) { if (create_ports (node)) { @@ -1396,10 +1386,147 @@ IO::set_state (const XMLNode& node) pending_state_node = new XMLNode (node); } + last_automation_snapshot = 0; + return 0; } int +IO::set_automation_state (const XMLNode& node) +{ + return _gain_automation_curve.set_state (node); +} + +XMLNode& +IO::get_automation_state () +{ + return (_gain_automation_curve.get_state ()); +} + +int +IO::load_automation (string path) +{ + string fullpath; + ifstream in; + char line[128]; + uint32_t linecnt = 0; + float version; + LocaleGuard lg (X_("POSIX")); + + fullpath = _session.automation_dir(); + fullpath += path; + + in.open (fullpath.c_str()); + + if (!in) { + fullpath = _session.automation_dir(); + fullpath += _session.snap_name(); + fullpath += '-'; + fullpath += path; + + in.open (fullpath.c_str()); + + if (!in) { + error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg; + return -1; + } + } + + clear_automation (); + + while (in.getline (line, sizeof(line), '\n')) { + char type; + jack_nframes_t when; + double value; + + if (++linecnt == 1) { + if (memcmp (line, "version", 7) == 0) { + if (sscanf (line, "version %f", &version) != 1) { + error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg; + return -1; + } + } else { + error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg; + return -1; + } + + continue; + } + + if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) { + warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg; + continue; + } + + switch (type) { + case 'g': + _gain_automation_curve.fast_simple_add (when, value); + break; + + case 's': + break; + + case 'm': + break; + + case 'p': + /* older (pre-1.0) versions of ardour used this */ + break; + + default: + warning << _("dubious automation event found (and ignored)") << endmsg; + } + } + + return 0; +} + +int +IO::connecting_became_legal () +{ + int ret; + + if (pending_state_node == 0) { + fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg; + /*NOTREACHED*/ + return -1; + } + + connection_legal_c.disconnect (); + + ret = make_connections (*pending_state_node); + + if (ports_legal) { + delete pending_state_node; + pending_state_node = 0; + } + + return ret; +} +int +IO::ports_became_legal () +{ + int ret; + + if (pending_state_node == 0) { + fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg; + /*NOTREACHED*/ + return -1; + } + + port_legal_c.disconnect (); + + ret = create_ports (*pending_state_node); + + if (connecting_legal) { + delete pending_state_node; + pending_state_node = 0; + } + + return ret; +} + +int IO::create_ports (const XMLNode& node) { const XMLProperty* prop; @@ -1702,42 +1829,6 @@ IO::set_name (string name, void* src) } void -IO::set_input_minimum (int n) -{ - if (n < 0) - _input_minimum = ChanCount::ZERO; - else - _input_minimum = ChanCount(_default_type, n); -} - -void -IO::set_input_maximum (int n) -{ - if (n < 0) - _input_maximum = ChanCount::INFINITE; - else - _input_maximum = ChanCount(_default_type, n); -} - -void -IO::set_output_minimum (int n) -{ - if (n < 0) - _output_minimum = ChanCount::ZERO; - else - _output_minimum = ChanCount(_default_type, n); -} - -void -IO::set_output_maximum (int n) -{ - if (n < 0) - _output_maximum = ChanCount::INFINITE; - else - _output_maximum = ChanCount(_default_type, n); -} - -void IO::set_input_minimum (ChanCount n) { _input_minimum = n; @@ -2046,25 +2137,6 @@ IO::GainControllable::get_value (void) const return direct_gain_to_control (io.effective_gain()); } -UndoAction -IO::get_memento() const -{ - return sigc::bind (mem_fun (*(const_cast<IO *>(this)), &StateManager::use_state), _current_state_id); -} - -Change -IO::restore_state (StateManager::State& state) -{ - return Change (0); -} - -StateManager::State* -IO::state_factory (std::string why) const -{ - StateManager::State* state = new StateManager::State (why); - return state; -} - void IO::setup_peak_meters() { @@ -2096,118 +2168,6 @@ IO::meter () _meter->meter(); } -int -IO::save_automation (const string& path) -{ - string fullpath; - ofstream out; - - fullpath = _session.automation_dir(); - fullpath += path; - - out.open (fullpath.c_str()); - - if (!out) { - error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg; - return -1; - } - - out << X_("version ") << current_automation_version_number << endl; - - /* XXX use apply_to_points to get thread safety */ - - for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) { - out << "g " << (nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl; - } - - _panner->save (); - - return 0; -} - -int -IO::load_automation (const string& path) -{ - string fullpath; - ifstream in; - char line[128]; - uint32_t linecnt = 0; - float version; - LocaleGuard lg (X_("POSIX")); - - fullpath = _session.automation_dir(); - fullpath += path; - - in.open (fullpath.c_str()); - - if (!in) { - fullpath = _session.automation_dir(); - fullpath += _session.snap_name(); - fullpath += '-'; - fullpath += path; - in.open (fullpath.c_str()); - if (!in) { - error << string_compose(_("%1: cannot open automation event file \"%2\" (%2)"), _name, fullpath, strerror (errno)) << endmsg; - return -1; - } - } - - clear_automation (); - - while (in.getline (line, sizeof(line), '\n')) { - char type; - nframes_t when; - double value; - - if (++linecnt == 1) { - if (memcmp (line, "version", 7) == 0) { - if (sscanf (line, "version %f", &version) != 1) { - error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg; - return -1; - } - } else { - error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg; - return -1; - } - - if (version != current_automation_version_number) { - error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg; - return -1; - } - - continue; - } - - if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) { - warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg; - continue; - } - - switch (type) { - case 'g': - _gain_automation_curve.add (when, value, true); - break; - - case 's': - break; - - case 'm': - break; - - case 'p': - /* older (pre-1.0) versions of ardour used this */ - break; - - default: - warning << _("dubious automation event found (and ignored)") << endmsg; - } - } - - _gain_automation_curve.save_state (_("loaded from disk")); - - return 0; -} - void IO::clear_automation () { @@ -2226,6 +2186,7 @@ IO::set_gain_automation_state (AutoState state) if (state != _gain_automation_curve.automation_state()) { changed = true; + last_automation_snapshot = 0; _gain_automation_curve.set_automation_state (state); if (state != Off) { @@ -2324,16 +2285,27 @@ IO::end_pan_touch (uint32_t which) } void +IO::automation_snapshot (nframes_t now) +{ + if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) { + + if (gain_automation_recording()) { + _gain_automation_curve.rt_add (now, gain()); + } + + _panner->snapshot (now); + + last_automation_snapshot = now; + } +} + +void IO::transport_stopped (nframes_t frame) { _gain_automation_curve.reposition_for_rt_add (frame); if (_gain_automation_curve.automation_state() != Off) { - if (gain_automation_recording()) { - _gain_automation_curve.save_state (_("automation write/touch")); - } - /* the src=0 condition is a special signal to not propagate automation gain changes into the mix group when locating. */ diff --git a/libs/ardour/location.cc b/libs/ardour/location.cc index 39331cfda6..e09a59d42f 100644 --- a/libs/ardour/location.cc +++ b/libs/ardour/location.cc @@ -372,27 +372,16 @@ Locations::Locations () { current_location = 0; - save_state (_("initial")); } Locations::~Locations () { - std::set<Location*> all_locations; - - for (StateMap::iterator siter = states.begin(); siter != states.end(); ++siter) { - - State* lstate = dynamic_cast<State*> (*siter); - - for (LocationList::iterator liter = lstate->locations.begin(); liter != lstate->locations.end(); ++liter) { - all_locations.insert (*liter); - } - - for (LocationList::iterator siter = lstate->states.begin(); siter != lstate->states.end(); ++siter) { - all_locations.insert (*siter); - } + for (LocationList::iterator i = locations.begin(); i != locations.end(); ) { + LocationList::iterator tmp = i; + ++tmp; + delete *i; + i = tmp; } - - set_delete (&all_locations); } int @@ -431,22 +420,22 @@ Locations::clear () { { Glib::Mutex::Lock lm (lock); - LocationList::iterator tmp; + for (LocationList::iterator i = locations.begin(); i != locations.end(); ) { - tmp = i; + + LocationList::iterator tmp = i; ++tmp; + if (!(*i)->is_end() && !(*i)->is_start()) { locations.erase (i); } + i = tmp; } - locations.clear (); current_location = 0; } - save_state (_("clear")); - changed (); /* EMIT SIGNAL */ current_changed (0); /* EMIT SIGNAL */ } @@ -470,8 +459,6 @@ Locations::clear_markers () } } - save_state (_("clear markers")); - changed (); /* EMIT SIGNAL */ } @@ -498,8 +485,6 @@ Locations::clear_ranges () current_location = 0; } - save_state (_("clear ranges")); - changed (); /* EMIT SIGNAL */ current_changed (0); /* EMIT SIGNAL */ } @@ -516,8 +501,6 @@ Locations::add (Location *loc, bool make_current) } } - save_state (_("add")); - added (loc); /* EMIT SIGNAL */ if (make_current) { @@ -554,9 +537,8 @@ Locations::remove (Location *loc) } if (was_removed) { - save_state (_("remove")); - - removed (loc); /* EMIT SIGNAL */ + + removed (loc); /* EMIT SIGNAL */ if (was_current) { current_changed (0); /* EMIT SIGNAL */ @@ -569,7 +551,6 @@ Locations::remove (Location *loc) void Locations::location_changed (Location* loc) { - save_state (X_("location changed")); changed (); /* EMIT SIGNAL */ } @@ -599,7 +580,10 @@ Locations::set_state (const XMLNode& node) } nlist = node.children(); - + + locations.clear (); + current_location = 0; + { Glib::Mutex::Lock lm (lock); @@ -809,45 +793,6 @@ Locations::auto_punch_location () const return 0; } -StateManager::State* -Locations::state_factory (std::string why) const -{ - State* state = new State (why); - - state->locations = locations; - - for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) { - state->states.push_back (new Location (**i)); - } - - return state; -} - -Change -Locations::restore_state (StateManager::State& state) -{ - { - Glib::Mutex::Lock lm (lock); - State* lstate = dynamic_cast<State*> (&state); - - locations = lstate->locations; - LocationList& states = lstate->states; - LocationList::iterator l, s; - - for (l = locations.begin(), s = states.begin(); s != states.end(); ++s, ++l) { - (*l) = (*s); - } - } - - return Change (0); -} - -UndoAction -Locations::get_memento () const -{ - return sigc::bind (mem_fun (*(const_cast<Locations*> (this)), &StateManager::use_state), _current_state_id); -} - uint32_t Locations::num_range_markers () const { diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index 8247aac217..b1ec7da965 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -295,11 +295,12 @@ MidiDiskstream::use_copy_playlist () /** Overloaded from parent to die horribly */ -void +int MidiDiskstream::set_destructive (bool yn) { assert( ! destructive()); assert( ! yn); + return -1; } void diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index 36e5e05116..d33d19ce67 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -106,7 +106,6 @@ MidiRegion::MidiRegion (SourceList& srcs, const XMLNode& node) MidiRegion::~MidiRegion () { - GoingAway (); /* EMIT SIGNAL */ } jack_nframes_t diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index f6d0a22019..a18d0c20ce 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -619,14 +619,21 @@ MidiTrack::unfreeze () FreezeChange (); /* EMIT SIGNAL */ } -void +int MidiTrack::set_mode (TrackMode m) { - if (_diskstream) { - if (_mode != m) { - _mode = m; - _diskstream->set_destructive (m == Destructive); - ModeChanged(); + assert(_diskstream); + + if (m != _mode) { + + if (_diskstream->set_destructive (m == Destructive)) { + return -1; } + + _mode = m; + + TrackModeChanged (); /* EMIT SIGNAL */ } + + return 0; } diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc index 0f6e78f84b..ee8e100e4a 100644 --- a/libs/ardour/panner.cc +++ b/libs/ardour/panner.cc @@ -75,6 +75,8 @@ StreamPanner::StreamPanner (Panner& p) { _muted = false; + parent.session().add_controllable (&_control); + x = 0.5; y = 0.5; z = 0.5; @@ -210,11 +212,6 @@ BaseStereoPanner::transport_stopped (nframes_t frame) _automation.reposition_for_rt_add (frame); if (_automation.automation_state() != Off) { - - if (_automation.automation_write()) { - _automation.save_state (_("automation write pass")); - } - set_position (_automation.eval (frame)); } } @@ -239,29 +236,6 @@ BaseStereoPanner::set_automation_state (AutoState state) } int -BaseStereoPanner::save (ostream& out) const -{ - LocaleGuard lg (X_("POSIX")); - - /* force a single format for numeric data to ease session interchange - across national boundaries. - */ - - out << "begin" << endl; - - for (AutomationList::const_iterator i = _automation.const_begin(); i != _automation.const_end(); ++i) { - out << '\t' << (nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl; - if (!out) { - error << string_compose (_("error writing pan automation file (%s)"), strerror (errno)) << endmsg; - return -1; - } - } - out << "end" << endl; - - return 0; -} - -int BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt) { char line[128]; @@ -270,7 +244,7 @@ BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt) _automation.clear (); while (in.getline (line, sizeof (line), '\n')) { - nframes_t when; + jack_nframes_t when; double value; ++linecnt; @@ -284,13 +258,12 @@ BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt) continue; } - _automation.add (when, value, true); + _automation.fast_simple_add (when, value); } /* now that we are done loading */ - _automation.save_state (_("loaded from disk")); - _automation.StateChanged (Change (0)); + _automation.StateChanged (); return 0; } @@ -543,17 +516,13 @@ EqualPowerStereoPanner::state (bool full_state) snprintf (buf, sizeof (buf), "%.12g", x); root->add_property (X_("x"), buf); root->add_property (X_("type"), EqualPowerStereoPanner::name); - if (full_state) { - snprintf (buf, sizeof (buf), "0x%x", _automation.automation_state()); - } else { - /* never store automation states other than off in a template */ - snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off); - } - root->add_property (X_("automation-state"), buf); - snprintf (buf, sizeof (buf), "0x%x", _automation.automation_style()); - root->add_property (X_("automation-style"), buf); + + XMLNode* autonode = new XMLNode (X_("Automation")); + autonode->add_child_nocopy (_automation.state (full_state)); + root->add_child_nocopy (*autonode); StreamPanner::add_state (*root); + root->add_child_nocopy (_control.get_state ()); return *root; @@ -563,7 +532,6 @@ int EqualPowerStereoPanner::set_state (const XMLNode& node) { const XMLProperty* prop; - int x; float pos; LocaleGuard lg (X_("POSIX")); @@ -572,29 +540,24 @@ EqualPowerStereoPanner::set_state (const XMLNode& node) set_position (pos, true); } - if ((prop = node.property (X_("automation-state")))) { - sscanf (prop->value().c_str(), "0x%x", &x); - _automation.set_automation_state ((AutoState) x); - - if (x != Off) { - set_position (_automation.eval (parent.session().transport_frame())); - } - } - - if ((prop = node.property (X_("automation-style")))) { - sscanf (prop->value().c_str(), "0x%x", &x); - _automation.set_automation_style ((AutoStyle) x); - } - StreamPanner::set_state (node); for (XMLNodeConstIterator iter = node.children().begin(); iter != node.children().end(); ++iter) { + if ((*iter)->name() == X_("panner")) { + _control.set_state (**iter); - parent.session().add_controllable (&_control); + + } else if ((*iter)->name() == X_("Automation")) { + + _automation.set_state (*((*iter)->children().front())); + + if (_automation.automation_state() != Off) { + set_position (_automation.eval (parent.session().transport_frame())); + } } } - + return 0; } @@ -765,12 +728,6 @@ Multi2dPanner::load (istream& in, string path, uint32_t& linecnt) return 0; } -int -Multi2dPanner::save (ostream& out) const -{ - return 0; -} - XMLNode& Multi2dPanner::get_state (void) { @@ -790,6 +747,8 @@ Multi2dPanner::state (bool full_state) root->add_property (X_("y"), buf); root->add_property (X_("type"), Multi2dPanner::name); + /* XXX no meaningful automation yet */ + return *root; } @@ -827,6 +786,7 @@ Panner::Panner (string name, Session& s) : _session (s) { set_name (name); + _linked = false; _link_direction = SameDirection; _bypassed = false; @@ -857,17 +817,6 @@ Panner::set_link_direction (LinkDirection ld) } void -Panner::set_name (string str) -{ - automation_path = _session.automation_dir(); - automation_path += _session.snap_name(); - automation_path += "-pan-"; - automation_path += legalize_for_path (str); - automation_path += ".automation"; -} - - -void Panner::set_bypassed (bool yn) { if (yn != _bypassed) { @@ -883,7 +832,6 @@ Panner::reset (uint32_t nouts, uint32_t npans) uint32_t n; bool changed = false; - if (nouts < 2 || (nouts == outputs.size() && npans == size())) { return; } @@ -1095,102 +1043,6 @@ Panner::clear_automation () _session.set_dirty (); } -int -Panner::save () const -{ - ofstream out (automation_path.c_str()); - - if (!out) { - error << string_compose (_("cannot open pan automation file \"%1\" for saving (%2)"), automation_path, strerror (errno)) - << endmsg; - return -1; - } - - out << X_("version ") << current_automation_version_number << endl; - - for (vector<StreamPanner*>::const_iterator i = begin(); i != end(); ++i) { - if ((*i)->save (out)) { - return -1; - } - } - - return 0; -} - -int -Panner::load () -{ - char line[128]; - uint32_t linecnt = 0; - float version; - iterator sp; - LocaleGuard lg (X_("POSIX")); - - if (automation_path.length() == 0) { - return 0; - } - - if (access (automation_path.c_str(), F_OK)) { - return 0; - } - - ifstream in (automation_path.c_str()); - - if (!in) { - error << string_compose (_("cannot open pan automation file %1 (%2)"), - automation_path, strerror (errno)) - << endmsg; - return -1; - } - - sp = begin(); - - while (in.getline (line, sizeof(line), '\n')) { - - if (++linecnt == 1) { - if (memcmp (line, X_("version"), 7) == 0) { - if (sscanf (line, "version %f", &version) != 1) { - error << string_compose(_("badly formed version number in pan automation event file \"%1\""), automation_path) << endmsg; - return -1; - } - } else { - error << string_compose(_("no version information in pan automation event file \"%1\" (first line = %2)"), - automation_path, line) << endmsg; - return -1; - } - - if (version != current_automation_version_number) { - error << string_compose(_("mismatched pan automation event file version (%1)"), version) << endmsg; - return -1; - } - - continue; - } - - if (strlen (line) == 0 || line[0] == '#') { - continue; - } - - if (strcmp (line, "begin") == 0) { - - if (sp == end()) { - error << string_compose (_("too many panner states found in pan automation file %1"), - automation_path) - << endmsg; - return -1; - } - - if ((*sp)->load (in, automation_path, linecnt)) { - return -1; - } - - ++sp; - } - } - - return 0; -} - struct PanPlugins { string name; uint32_t nouts; @@ -1215,10 +1067,6 @@ Panner::state (bool full) XMLNode* root = new XMLNode (X_("Panner")); char buf[32]; - for (iterator p = begin(); p != end(); ++p) { - root->add_child_nocopy ((*p)->state (full)); - } - root->add_property (X_("linked"), (_linked ? "yes" : "no")); snprintf (buf, sizeof (buf), "%d", _link_direction); root->add_property (X_("link_direction"), buf); @@ -1235,10 +1083,8 @@ Panner::state (bool full) root->add_child_nocopy (*onode); } - if (full) { - if (save () == 0) { - root->add_property (X_("automation"), Glib::path_get_basename (automation_path)); - } + for (vector<StreamPanner*>::const_iterator i = begin(); i != end(); ++i) { + root->add_child_nocopy ((*i)->state (full)); } return *root; @@ -1329,7 +1175,7 @@ Panner::set_state (const XMLNode& node) } } - /* don't try to load automation if it wasn't marked as existing */ + /* don't try to do old-school automation loading if it wasn't marked as existing */ if ((prop = node.property (X_("automation")))) { @@ -1629,3 +1475,83 @@ Panner::distribute (BufferSet& inbufs, BufferSet& outbufs, nframes_t start_frame } } +/* old school automation handling */ + +void +Panner::set_name (string str) +{ + automation_path = _session.automation_dir(); + automation_path += _session.snap_name(); + automation_path += "-pan-"; + automation_path += legalize_for_path (str); + automation_path += ".automation"; +} + +int +Panner::load () +{ + char line[128]; + uint32_t linecnt = 0; + float version; + iterator sp; + LocaleGuard lg (X_("POSIX")); + + if (automation_path.length() == 0) { + return 0; + } + + if (access (automation_path.c_str(), F_OK)) { + return 0; + } + + ifstream in (automation_path.c_str()); + + if (!in) { + error << string_compose (_("cannot open pan automation file %1 (%2)"), + automation_path, strerror (errno)) + << endmsg; + return -1; + } + + sp = begin(); + + while (in.getline (line, sizeof(line), '\n')) { + + if (++linecnt == 1) { + if (memcmp (line, X_("version"), 7) == 0) { + if (sscanf (line, "version %f", &version) != 1) { + error << string_compose(_("badly formed version number in pan automation event file \"%1\""), automation_path) << endmsg; + return -1; + } + } else { + error << string_compose(_("no version information in pan automation event file \"%1\" (first line = %2)"), + automation_path, line) << endmsg; + return -1; + } + + continue; + } + + if (strlen (line) == 0 || line[0] == '#') { + continue; + } + + if (strcmp (line, "begin") == 0) { + + if (sp == end()) { + error << string_compose (_("too many panner states found in pan automation file %1"), + automation_path) + << endmsg; + return -1; + } + + if ((*sp)->load (in, automation_path, linecnt)) { + return -1; + } + + ++sp; + } + } + + return 0; +} diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index ee60a53d66..d439cf1265 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -90,10 +90,8 @@ Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide init (hide); _name = "unnamed"; /* reset by set_state */ - - if (set_state (node)) { - throw failed_constructor(); - } + + /* derived class calls set_state() */ } Playlist::Playlist (const Playlist& other, string namestr, bool hide) @@ -264,11 +262,19 @@ Playlist::Playlist (Playlist& pl) Playlist::~Playlist () { + { + RegionLock rl (this); + + for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) { + (*i)->set_playlist (0); + } + } + /* GoingAway must be emitted by derived classes */ } void -Playlist::set_name (const string& str) +Playlist::set_name (string str) { /* in a typical situation, a playlist is being used by one diskstream and also is referenced by the @@ -563,8 +569,6 @@ Playlist::remove_region_internal (boost::shared_ptr<Region>region, bool delay_so RegionList::iterator i; nframes_t old_length = 0; - cerr << "removing region " << region->name() << " holding = " << holding_state() << endl; - if (!holding_state()) { old_length = _get_maximum_extent(); } @@ -1140,6 +1144,7 @@ Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr<Region> wea return; } + /* this makes a virtual call to the right kind of playlist ... */ region_changed (what_changed, region); @@ -1259,6 +1264,7 @@ Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir) boost::shared_ptr<Region> ret; nframes_t closest = max_frames; + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { nframes_t distance; @@ -1280,7 +1286,7 @@ Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir) switch (dir) { case 1: /* forwards */ - if (pos > frame) { + if (pos >= frame) { if ((distance = pos - frame) < closest) { closest = distance; ret = r; @@ -1291,7 +1297,7 @@ Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir) default: /* backwards */ - if (pos < frame) { + if (pos <= frame) { if ((distance = frame - pos) < closest) { closest = distance; ret = r; @@ -1455,13 +1461,21 @@ Playlist::state (bool full_state) bool Playlist::empty() const { + RegionLock rlock (const_cast<Playlist *>(this), false); return regions.empty(); } -ARDOUR::nframes_t +uint32_t +Playlist::n_regions() const +{ + RegionLock rlock (const_cast<Playlist *>(this), false); + return regions.size(); +} + +nframes_t Playlist::get_maximum_extent () const { - RegionLock rlock (const_cast<Playlist *>(this)); + RegionLock rlock (const_cast<Playlist *>(this), false); return _get_maximum_extent (); } @@ -1488,7 +1502,7 @@ Playlist::bump_name (string name, Session &session) do { newname = Playlist::bump_name_once (newname); - } while (session.playlist_by_name(newname)!=NULL); + } while (session.playlist_by_name (newname)!=NULL); return newname; } diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc index bdd4d0ada6..b24b2619d3 100644 --- a/libs/ardour/plugin_manager.cc +++ b/libs/ardour/plugin_manager.cc @@ -86,7 +86,6 @@ PluginManager::PluginManager () } refresh (); - if (_manager == 0) { _manager = this; } @@ -109,7 +108,7 @@ PluginManager::ladspa_refresh () _ladspa_plugin_info.clear (); if (ladspa_path.length() == 0) { - ladspa_path = "/usr/local/lib/ladspa:/usr/lib/ladspa"; + ladspa_path = "/usr/local/lib64/ladspa:/usr/local/lib/ladspa:/usr/lib64/ladspa:/usr/lib/ladspa:/Library/Audio/Plug-Ins/LADSPA"; } ladspa_discover_from_path (ladspa_path); diff --git a/libs/ardour/po/sv_SE.po b/libs/ardour/po/sv_SE.po new file mode 100644 index 0000000000..ddc7f108bb --- /dev/null +++ b/libs/ardour/po/sv_SE.po @@ -0,0 +1,2025 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR "Paul Davis" +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: ardour\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-10-03 00:39+0200\n" +"PO-Revision-Date: 2006-10-03 01:09+GMT+1\n" +"Last-Translator: Petter Sundlöf <petter.sundlof@findus.dhs.org>\n" +"Language-Team: Swedish <sv@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: libs/ardour/diskstream.cc:258 +msgid "Location \"%1\" not valid for track loop (start >= end)" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:298 +msgid "AudioDiskstream: Playlist \"%1\" isn't an audio playlist" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:349 +msgid "AudioDiskstream %1: there is no existing playlist to make a copy of!" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:924 libs/ardour/audio_diskstream.cc:935 +msgid "" +"AudioDiskstream %1: when refilling, cannot read %2 from playlist at frame %3" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:1069 +msgid "AudioDiskstream %1: cannot read %2 from playlist at frame %3" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:1412 libs/ardour/audio_diskstream.cc:1429 +msgid "AudioDiskstream %1: cannot write to disk" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:1473 +msgid "AudioDiskstream \"%1\": cannot flush captured data to disk!" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:1563 +msgid "%1: could not create region for complete audio file" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:1587 +msgid "AudioDiskstream: could not create region for captured audio!" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:1643 +msgid "programmer error: %1" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:1929 +msgid "AudioDiskstream: channel %1 out of range" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:1952 +msgid "%1:%2 new capture file not initialized correctly" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:2178 +msgid "%1: cannot restore pending capture source file %2" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:2200 +msgid "%1: incorrect number of pending sources listed - ignoring them all" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:2215 +msgid "%1: cannot create whole-file region from pending capture sources" +msgstr "" + +#: libs/ardour/audio_diskstream.cc:2227 +msgid "%1: cannot create region from pending capture sources" +msgstr "" + +#: libs/ardour/audio_library.cc:92 +msgid "channels" +msgstr "" + +#: libs/ardour/audio_library.cc:93 +msgid "samplerate" +msgstr "" + +#: libs/ardour/audio_library.cc:94 +msgid "resolution" +msgstr "" + +#: libs/ardour/audio_library.cc:95 +msgid "format" +msgstr "" + +#: libs/ardour/audio_library.cc:102 +msgid "Could not open %1. Audio Library not saved" +msgstr "" + +#: libs/ardour/audio_playlist.cc:53 libs/ardour/audio_playlist.cc:63 +#: libs/ardour/audio_playlist.cc:74 libs/ardour/audio_playlist.cc:121 +#: libs/ardour/insert.cc:84 libs/ardour/insert.cc:103 +#: libs/ardour/insert.cc:128 libs/ardour/insert.cc:862 +#: libs/ardour/insert.cc:870 libs/ardour/send.cc:39 libs/ardour/send.cc:53 +#: libs/ardour/send.cc:62 libs/ardour/session_state.cc:1128 +#: libs/ardour/session_state.cc:1170 +msgid "initial state" +msgstr "" + +#: libs/ardour/audio_playlist.cc:261 libs/ardour/audio_playlist.cc:743 +msgid "" +"programming error: non-audio Region passed to remove_overlap in audio " +"playlist" +msgstr "" + +#: libs/ardour/audio_playlist.cc:388 +msgid "" +"programming error: non-audio Region tested for overlap in audio playlist" +msgstr "" + +#: libs/ardour/audio_playlist.cc:851 +msgid "xfade change" +msgstr "" + +#: libs/ardour/audio_playlist.cc:874 +msgid "region modified" +msgstr "" + +#: libs/ardour/audio_track.cc:105 libs/ardour/io.cc:1696 +#: libs/ardour/io.cc:1762 +msgid "Unknown connection \"%1\" listed for input of %2" +msgstr "" + +#: libs/ardour/audio_track.cc:107 libs/ardour/io.cc:1698 +#: libs/ardour/io.cc:1764 +msgid "in 1" +msgstr "" + +#: libs/ardour/audio_track.cc:108 libs/ardour/io.cc:1699 +#: libs/ardour/io.cc:1765 +msgid "No input connections available as a replacement" +msgstr "" + +#: libs/ardour/audio_track.cc:112 libs/ardour/io.cc:1703 +#: libs/ardour/io.cc:1769 +msgid "Connection %1 was not available - \"in 1\" used instead" +msgstr "" + +#: libs/ardour/audio_track.cc:121 libs/ardour/io.cc:1778 +msgid "improper input channel list in XML node (%1)" +msgstr "" + +#: libs/ardour/audio_track.cc:162 libs/ardour/audio_track.cc:175 +msgid "AudioTrack: audio diskstream \"%1\" not known by session" +msgstr "" + +#: libs/ardour/audio_track.cc:216 +msgid "programming error: AudioTrack given state without diskstream!" +msgstr "" + +#: libs/ardour/audioengine.cc:146 +msgid "cannot activate JACK client" +msgstr "" + +#: libs/ardour/audioengine.cc:421 +msgid "register input port called before engine was started" +msgstr "" + +#: libs/ardour/audioengine.cc:457 +msgid "register output port called before engine was started" +msgstr "" + +#: libs/ardour/audioengine.cc:539 +msgid "connect called before engine was started" +msgstr "" + +#: libs/ardour/audioengine.cc:555 +msgid "AudioEngine: cannot connect %1 (%2) to %3 (%4)" +msgstr "" + +#: libs/ardour/audioengine.cc:568 libs/ardour/audioengine.cc:597 +msgid "disconnect called before engine was started" +msgstr "" + +#: libs/ardour/audioengine.cc:655 +msgid "get_port_by_name() called before engine was started" +msgstr "" + +#: libs/ardour/audioengine.cc:699 +msgid "get_ports called before engine was started" +msgstr "" + +#: libs/ardour/audioengine.cc:817 +msgid "get_nth_physical called before engine was started" +msgstr "" + +#: libs/ardour/audioengine.cc:845 +msgid "get_port_total_latency() called with no JACK client connection" +msgstr "" + +#: libs/ardour/audioengine.cc:851 +msgid "get_port_total_latency() called before engine was started" +msgstr "" + +#: libs/ardour/audioengine.cc:982 +msgid "Unable to connect to JACK server" +msgstr "" + +#: libs/ardour/audioengine.cc:985 +msgid "Could not connect to JACK server as \"%1\"" +msgstr "" + +#: libs/ardour/audioengine.cc:990 +msgid "JACK server started" +msgstr "" + +#: libs/ardour/audioengine.cc:1024 +msgid "cannot shutdown connection to JACK" +msgstr "" + +#: libs/ardour/audioengine.cc:1049 +msgid "failed to connect to JACK" +msgstr "" + +#: libs/ardour/audioengine.cc:1067 +msgid "could not reregister %1" +msgstr "" + +#: libs/ardour/audioengine.cc:1125 +msgid "could not reconnect %1 and %2 (err = %3)" +msgstr "" + +#: libs/ardour/audiofilesource.cc:355 libs/ardour/session_state.cc:2575 +msgid "" +"there are already 1000 files with names like %1; versioning discontinued" +msgstr "" + +#: libs/ardour/audiofilesource.cc:369 libs/ardour/session_state.cc:2589 +msgid "cannot rename audio file source from %1 to %2 (%3)" +msgstr "" + +#: libs/ardour/audiofilesource.cc:376 libs/ardour/session_state.cc:2604 +msgid "cannot remove peakfile %1 for %2 (%3)" +msgstr "" + +#: libs/ardour/audiofilesource.cc:420 +msgid "FileSource: search path not set" +msgstr "" + +#: libs/ardour/audiofilesource.cc:444 +msgid "" +"FileSource: \"%1\" is ambigous when searching %2\n" +"\t" +msgstr "" + +#: libs/ardour/audiofilesource.cc:450 +msgid "Filesource: cannot find required file (%1): while searching %2" +msgstr "" + +#: libs/ardour/audiofilesource.cc:473 +msgid "Filesource: cannot find required file (%1): %2" +msgstr "" + +#: libs/ardour/audiofilesource.cc:478 +msgid "Filesource: cannot check for existing file (%1): %2" +msgstr "" + +#: libs/ardour/audiofilesource.cc:534 libs/ardour/insert.cc:532 +#: libs/ardour/session.cc:1967 libs/ardour/sndfilesource.cc:109 +msgid "programming error: %1" +msgstr "" + +#: libs/ardour/audiofilesource.cc:540 +msgid "" +"Programming error! Ardour tried to rename a file over another file! It's " +"safe to continue working, but please report this to the developers." +msgstr "" + +#: libs/ardour/audiofilesource.cc:545 +msgid "cannot rename audio file for %1 to %2" +msgstr "" + +#: libs/ardour/audiofilter.cc:47 +msgid "audiofilter: error creating name for new audio file based on %1" +msgstr "" + +#: libs/ardour/audiofilter.cc:57 +msgid "audiofilter: error creating new audio file %1 (%2)" +msgstr "" + +#: libs/ardour/audioregion.cc:888 libs/ardour/audioregion.cc:950 +msgid "fade in change" +msgstr "" + +#: libs/ardour/audioregion.cc:1321 +#, c-format +msgid "normalized to %.2fdB" +msgstr "" + +#: libs/ardour/audioregion.cc:1339 +msgid "envelope change" +msgstr "" + +#: libs/ardour/audiosource.cc:144 +msgid "poll on peak request pipe failed (%1)" +msgstr "" + +#: libs/ardour/audiosource.cc:151 +msgid "Error on peak thread request pipe" +msgstr "" + +#: libs/ardour/audiosource.cc:184 +msgid "Error reading from peak request pipe" +msgstr "" + +#: libs/ardour/audiosource.cc:216 libs/ardour/session_butler.cc:80 +#: libs/ardour/session_midi.cc:1073 +msgid "Cannot create transport request signal pipe (%1)" +msgstr "" + +#: libs/ardour/audiosource.cc:221 libs/ardour/audiosource.cc:226 +msgid "UI: cannot set O_NONBLOCK on peak request pipe (%1)" +msgstr "" + +#: libs/ardour/audiosource.cc:231 +msgid "AudioSource: could not create peak thread" +msgstr "" + +#: libs/ardour/audiosource.cc:326 +msgid "cannot rename peakfile for %1 from %2 to %3 (%4)" +msgstr "" + +#: libs/ardour/audiosource.cc:368 +msgid "AudioSource: cannot stat peakfile \"%1\"" +msgstr "" + +#: libs/ardour/audiosource.cc:466 +msgid "cannot read sample data for unscaled peak computation" +msgstr "" + +#: libs/ardour/audiosource.cc:486 libs/ardour/audiosource.cc:557 +#: libs/ardour/audiosource.cc:793 libs/ardour/audiosource.cc:882 +msgid "AudioSource: cannot open peakpath \"%1\" (%2)" +msgstr "" + +#: libs/ardour/audiosource.cc:657 +msgid "AudioSource[%1]: peak read - cannot read %2 samples at offset %3" +msgstr "" + +#: libs/ardour/audiosource.cc:804 +msgid "%1: could not write read raw data for peak computation (%2)" +msgstr "" + +#: libs/ardour/audiosource.cc:829 +msgid "%1: could not write peak file data (%2)" +msgstr "" + +#: libs/ardour/auditioner.cc:118 +msgid "Auditioning of non-audio regions not yet supported" +msgstr "" + +#: libs/ardour/automation_event.cc:67 libs/ardour/location.cc:375 +#: libs/ardour/tempo.cc:226 +msgid "initial" +msgstr "" + +#: libs/ardour/automation_event.cc:240 +msgid "cleared" +msgstr "" + +#: libs/ardour/automation_event.cc:412 +msgid "added event" +msgstr "" + +#: libs/ardour/automation_event.cc:429 +msgid "removed event" +msgstr "" + +#: libs/ardour/automation_event.cc:444 +msgid "removed multiple events" +msgstr "" + +#: libs/ardour/automation_event.cc:475 libs/ardour/automation_event.cc:506 +msgid "removed range" +msgstr "" + +#: libs/ardour/automation_event.cc:536 +msgid "event range adjusted" +msgstr "" + +#: libs/ardour/automation_event.cc:558 +msgid "event adjusted" +msgstr "" + +#: libs/ardour/automation_event.cc:673 libs/ardour/automation_event.cc:778 +#: libs/ardour/panner.cc:889 +msgid "programming error:" +msgstr "" + +#: libs/ardour/automation_event.cc:1087 +msgid "cut/copy/clear" +msgstr "" + +#: libs/ardour/automation_event.cc:1120 +msgid "copy" +msgstr "" + +#: libs/ardour/automation_event.cc:1188 libs/ardour/playlist.cc:960 +msgid "paste" +msgstr "" + +#: libs/ardour/automation_event.cc:1243 +msgid "" +"automation list: no x-coordinate stored for control point (point ignored)" +msgstr "" + +#: libs/ardour/automation_event.cc:1249 +msgid "" +"automation list: no y-coordinate stored for control point (point ignored)" +msgstr "" + +#: libs/ardour/configuration.cc:87 +msgid "loading system configuration file %1" +msgstr "" + +#: libs/ardour/configuration.cc:90 +msgid "Ardour: cannot read system configuration file \"%1\"" +msgstr "" + +#: libs/ardour/configuration.cc:97 +msgid "Ardour: system configuration file \"%1\" not loaded successfully." +msgstr "" + +#: libs/ardour/configuration.cc:111 +msgid "loading user configuration file %1" +msgstr "" + +#: libs/ardour/configuration.cc:114 +msgid "Ardour: cannot read configuration file \"%1\"" +msgstr "" + +#: libs/ardour/configuration.cc:121 +msgid "Ardour: user configuration file \"%1\" not loaded successfully." +msgstr "" + +#: libs/ardour/configuration.cc:141 +msgid "Config file %1 not saved" +msgstr "" + +#: libs/ardour/configuration.cc:226 +msgid "ill-formed MIDI port specification in ardour rcfile (ignored)" +msgstr "" + +#: libs/ardour/connection.cc:183 +msgid "Node for Connection has no \"name\" property" +msgstr "" + +#: libs/ardour/connection.cc:191 +msgid "Node for Connection has no \"connections\" property" +msgstr "" + +#: libs/ardour/connection.cc:227 libs/ardour/io.cc:1838 +msgid "IO: badly formed string in XML node for inputs \"%1\"" +msgstr "" + +#: libs/ardour/connection.cc:232 libs/ardour/io.cc:1843 +msgid "bad input string in XML node \"%1\"" +msgstr "" + +#: libs/ardour/control_protocol_manager.cc:84 +msgid "control protocol name \"%1\" has no descriptor" +msgstr "" + +#: libs/ardour/control_protocol_manager.cc:89 +msgid "control protocol name \"%1\" could not be initialized" +msgstr "" + +#: libs/ardour/control_protocol_manager.cc:145 +msgid "Instantiating mandatory control protocol %1" +msgstr "" + +#: libs/ardour/control_protocol_manager.cc:179 +msgid "Control protocol %1 not usable" +msgstr "" + +#: libs/ardour/control_protocol_manager.cc:192 +msgid "Control surface protocol discovered: \"%1\"" +msgstr "" + +#: libs/ardour/control_protocol_manager.cc:210 +msgid "ControlProtocolManager: cannot load module \"%1\" (%2)" +msgstr "" + +#: libs/ardour/control_protocol_manager.cc:218 +msgid "ControlProtocolManager: module \"%1\" has no descriptor function." +msgstr "" + +#: libs/ardour/crossfade.cc:120 +msgid "Crossfade: no \"in\" region in state" +msgstr "" + +#: libs/ardour/crossfade.cc:127 +msgid "Crossfade: no \"in\" region %1 found in playlist %2" +msgstr "" + +#: libs/ardour/crossfade.cc:137 +msgid "Crossfade: no \"out\" region in state" +msgstr "" + +#: libs/ardour/crossfade.cc:144 +msgid "Crossfade: no \"out\" region %1 found in playlist %2" +msgstr "" + +#: libs/ardour/crossfade.cc:491 +msgid "active changed" +msgstr "" + +#: libs/ardour/crossfade.cc:740 +msgid "old-style crossfade information - no position information" +msgstr "" + +#: libs/ardour/curve.cc:117 libs/ardour/globals.cc:348 +#: libs/ardour/insert.cc:454 libs/ardour/session.cc:2432 +#: libs/ardour/session.cc:2486 +msgid "programming error: " +msgstr "" + +#: libs/ardour/cycle_timer.cc:37 +msgid "CycleTimer::get_mhz(): can't open /proc/cpuinfo" +msgstr "" + +#: libs/ardour/cycle_timer.cc:49 +msgid "CycleTimer::get_mhz(): cannot locate cpu MHz in /proc/cpuinfo" +msgstr "" + +#: libs/ardour/cycle_timer.cc:72 +msgid "cannot locate cpu MHz in /proc/cpuinfo" +msgstr "" + +#: libs/ardour/destructive_filesource.cc:200 +msgid "DestructiveFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)" +msgstr "" + +#: libs/ardour/destructive_filesource.cc:213 +#: libs/ardour/destructive_filesource.cc:258 +#: libs/ardour/destructive_filesource.cc:265 +msgid "DestructiveFileSource: \"%1\" bad write (%2)" +msgstr "" + +#: libs/ardour/destructive_filesource.cc:403 +msgid "" +"Filesource: start time is already set for existing file (%1): Cannot change " +"start time." +msgstr "" + +#: libs/ardour/globals.cc:110 +msgid "no MIDI ports specified: no MMC or MTC control possible" +msgstr "" + +#: libs/ardour/globals.cc:125 +msgid "MIDI port specifications for \"%1\" are not understandable." +msgstr "" + +#: libs/ardour/globals.cc:138 libs/ardour/globals.cc:142 +#: libs/ardour/globals.cc:146 +msgid "default" +msgstr "" + +#: libs/ardour/globals.cc:174 +msgid "No MMC control (MIDI port \"%1\" not available)" +msgstr "" + +#: libs/ardour/globals.cc:180 +msgid "No MTC support (MIDI port \"%1\" not available)" +msgstr "" + +#: libs/ardour/globals.cc:185 +msgid "No MIDI parameter support (MIDI port \"%1\" not available)" +msgstr "" + +#: libs/ardour/import.cc:77 +msgid "Import: cannot open input sound file \"%1\"" +msgstr "" + +#: libs/ardour/import.cc:82 +msgid "resampling audio" +msgstr "" + +#: libs/ardour/import.cc:86 +msgid "Import: cannot open converted sound file \"%1\"" +msgstr "" + +#: libs/ardour/import.cc:91 +msgid "Import: error while resampling sound file \"%1\"" +msgstr "" + +#: libs/ardour/import.cc:145 +msgid "Session::import_audiofile: cannot open new file source for channel %1" +msgstr "" + +#: libs/ardour/import.cc:163 +msgid "converting audio" +msgstr "" + +#: libs/ardour/import.cc:195 +msgid "building region" +msgstr "" + +#: libs/ardour/import.cc:197 +msgid "building regions" +msgstr "" + +#: libs/ardour/import.cc:309 +msgid "Import/SRC: could not open input file: %1" +msgstr "" + +#: libs/ardour/import.cc:317 +msgid "Import/SRC: could not open output file: %1" +msgstr "" + +#: libs/ardour/import.cc:326 +msgid "Import: src_new() failed : %1" +msgstr "" + +#: libs/ardour/import.cc:354 +msgid "Import: %1" +msgstr "" + +#: libs/ardour/insert.cc:651 libs/ardour/insert.cc:960 +msgid "XML node describing insert is missing the `type' field" +msgstr "" + +#: libs/ardour/insert.cc:660 +msgid "unknown plugin type %1 in plugin insert state" +msgstr "" + +#: libs/ardour/insert.cc:672 +msgid "XML node describing insert is missing the `id' field" +msgstr "" + +#: libs/ardour/insert.cc:685 +msgid "" +"Found a reference to a plugin (\"%1\") that is unknown.\n" +"Perhaps it was removed or moved since it was last used." +msgstr "" + +#: libs/ardour/insert.cc:723 libs/ardour/insert.cc:977 +msgid "XML node describing insert is missing a Redirect node" +msgstr "" + +#: libs/ardour/insert.cc:728 +msgid "XML node describing a plugin insert is missing the `%1' information" +msgstr "" + +#: libs/ardour/insert.cc:752 +msgid "PluginInsert: Auto: no ladspa port number" +msgstr "" + +#: libs/ardour/insert.cc:759 +msgid "PluginInsert: Auto: port id out of range" +msgstr "" + +#: libs/ardour/insert.cc:775 +msgid "XML node describing a port automation is missing the `%1' information" +msgstr "" + +#: libs/ardour/insert.cc:878 +msgid "PortInsert: cannot add input port" +msgstr "" + +#: libs/ardour/insert.cc:883 +msgid "PortInsert: cannot add output port" +msgstr "" + +#: libs/ardour/insert.cc:965 +msgid "non-port insert XML used for port plugin insert" +msgstr "" + +#: libs/ardour/io.cc:603 +msgid "IO: cannot disconnect input port %1 from %2" +msgstr "" + +#: libs/ardour/io.cc:671 +msgid "IO: cannot disconnect output port %1 from %2" +msgstr "" + +#: libs/ardour/io.cc:822 libs/ardour/io.cc:1177 libs/ardour/io.cc:1303 +#, c-format +msgid "%s/out" +msgstr "" + +#: libs/ardour/io.cc:824 libs/ardour/io.cc:1179 libs/ardour/io.cc:1305 +#: libs/ardour/io.cc:2688 +#, c-format +msgid "%s/out %u" +msgstr "" + +#: libs/ardour/io.cc:828 libs/ardour/io.cc:1184 libs/ardour/io.cc:1309 +msgid "IO: cannot register output port %1" +msgstr "" + +#: libs/ardour/io.cc:934 libs/ardour/io.cc:1037 libs/ardour/io.cc:1143 +#, c-format +msgid "%s/in" +msgstr "" + +#: libs/ardour/io.cc:936 libs/ardour/io.cc:1040 libs/ardour/io.cc:1146 +#: libs/ardour/io.cc:2658 +#, c-format +msgid "%s/in %u" +msgstr "" + +#: libs/ardour/io.cc:940 libs/ardour/io.cc:1046 libs/ardour/io.cc:1151 +msgid "IO: cannot register input port %1" +msgstr "" + +#: libs/ardour/io.cc:1551 +msgid "IO::connecting_became_legal() called without a pending state node" +msgstr "" + +#: libs/ardour/io.cc:1574 +msgid "IO::ports_became_legal() called without a pending state node" +msgstr "" + +#: libs/ardour/io.cc:1603 +msgid "incorrect XML node \"%1\" passed to IO object" +msgstr "" + +#: libs/ardour/io.cc:1719 libs/ardour/io.cc:1787 +msgid "Unknown connection \"%1\" listed for output of %2" +msgstr "" + +#: libs/ardour/io.cc:1721 libs/ardour/io.cc:1789 +msgid "out 1" +msgstr "" + +#: libs/ardour/io.cc:1722 libs/ardour/io.cc:1790 +msgid "No output connections available as a replacement" +msgstr "" + +#: libs/ardour/io.cc:1726 libs/ardour/io.cc:1794 +msgid "Connection %1 was not available - \"out 1\" used instead" +msgstr "" + +#: libs/ardour/io.cc:1740 +msgid "%1: cannot create I/O ports" +msgstr "" + +#: libs/ardour/io.cc:1803 +msgid "improper output channel list in XML node (%1)" +msgstr "" + +#: libs/ardour/io.cc:1888 +msgid "IO: badly formed string in XML node for outputs \"%1\"" +msgstr "" + +#: libs/ardour/io.cc:1893 +msgid "IO: bad output string in XML node \"%1\"" +msgstr "" + +#: libs/ardour/io.cc:2391 +msgid "%1: could not open automation event file \"%2\"" +msgstr "" + +#: libs/ardour/io.cc:2430 +msgid "%1: cannot open automation event file \"%2\" (%2)" +msgstr "" + +#: libs/ardour/io.cc:2445 +msgid "badly formed version number in automation event file \"%1\"" +msgstr "" + +#: libs/ardour/io.cc:2449 +msgid "no version information in automation event file \"%1\"" +msgstr "" + +#: libs/ardour/io.cc:2454 +msgid "mismatched automation event file version (%1)" +msgstr "" + +#: libs/ardour/io.cc:2462 +msgid "badly formatted automation event record at line %1 of %2 (ignored)" +msgstr "" + +#: libs/ardour/io.cc:2482 +msgid "dubious automation event found (and ignored)" +msgstr "" + +#: libs/ardour/io.cc:2486 libs/ardour/panner.cc:288 +#: libs/ardour/redirect.cc:148 +msgid "loaded from disk" +msgstr "" + +#: libs/ardour/io.cc:2630 +msgid "automation write/touch" +msgstr "" + +#: libs/ardour/ladspa_plugin.cc:87 +msgid "LADSPA: module has no descriptor function." +msgstr "" + +#: libs/ardour/ladspa_plugin.cc:92 +msgid "LADSPA: plugin has gone away since discovery!" +msgstr "" + +#: libs/ardour/ladspa_plugin.cc:99 +msgid "LADSPA: \"%1\" cannot be used, since it cannot do inplace processing" +msgstr "" + +#: libs/ardour/ladspa_plugin.cc:315 +msgid "" +"illegal parameter number used with plugin \"%1\". This mayindicate a change " +"in the plugin design, and presets may beinvalid" +msgstr "" + +#: libs/ardour/ladspa_plugin.cc:394 +msgid "Bad node sent to LadspaPlugin::set_state" +msgstr "" + +#: libs/ardour/ladspa_plugin.cc:407 +msgid "LADSPA: no ladspa port number" +msgstr "" + +#: libs/ardour/ladspa_plugin.cc:413 +msgid "LADSPA: no ladspa port data" +msgstr "" + +#: libs/ardour/ladspa_plugin.cc:653 +msgid "LADSPA: cannot load module from \"%1\"" +msgstr "" + +#: libs/ardour/location.cc:295 +msgid "incorrect XML node passed to Location::set_state" +msgstr "" + +#: libs/ardour/location.cc:300 +msgid "XML node for Location has no ID information" +msgstr "" + +#: libs/ardour/location.cc:306 +msgid "XML node for Location has no name information" +msgstr "" + +#: libs/ardour/location.cc:313 +msgid "XML node for Location has no start information" +msgstr "" + +#: libs/ardour/location.cc:324 +msgid "XML node for Location has no end information" +msgstr "" + +#: libs/ardour/location.cc:333 +msgid "XML node for Location has no flags information" +msgstr "" + +#: libs/ardour/location.cc:421 +msgid "Locations: attempt to use unknown location as selected location" +msgstr "" + +#: libs/ardour/location.cc:448 libs/ardour/playlist.cc:1204 +msgid "clear" +msgstr "" + +#: libs/ardour/location.cc:473 +msgid "clear markers" +msgstr "" + +#: libs/ardour/location.cc:501 +msgid "clear ranges" +msgstr "" + +#: libs/ardour/location.cc:519 +msgid "add" +msgstr "" + +#: libs/ardour/location.cc:557 +msgid "remove" +msgstr "" + +#: libs/ardour/location.cc:597 +msgid "incorrect XML mode passed to Locations::set_state" +msgstr "" + +#: libs/ardour/location.cc:615 +msgid "could not load location from session file - ignored" +msgstr "" + +#: libs/ardour/mtc_slave.cc:196 +msgid "MTC Slave: atomic read of current time failed, sleeping!" +msgstr "" + +#: libs/ardour/named_selection.cc:77 +msgid "Chunk %1 uses an unknown playlist \"%2\"" +msgstr "" + +#: libs/ardour/named_selection.cc:80 +msgid "Chunk %1 contains misformed playlist information" +msgstr "" + +#: libs/ardour/panner.cc:211 +msgid "automation write pass" +msgstr "" + +#: libs/ardour/panner.cc:251 +#, c-format +msgid "error writing pan automation file (%s)" +msgstr "" + +#: libs/ardour/panner.cc:279 +msgid "" +"badly formatted pan automation event record at line %1 of %2 (ignored) [%3]" +msgstr "" + +#: libs/ardour/panner.cc:794 +msgid "badly-formed positional data for Multi2dPanner - ignored" +msgstr "" + +#: libs/ardour/panner.cc:1083 +msgid "cannot open pan automation file \"%1\" for saving (%2)" +msgstr "" + +#: libs/ardour/panner.cc:1119 +msgid "cannot open pan automation file %1 (%2)" +msgstr "" + +#: libs/ardour/panner.cc:1132 +msgid "badly formed version number in pan automation event file \"%1\"" +msgstr "" + +#: libs/ardour/panner.cc:1136 +msgid "" +"no version information in pan automation event file \"%1\" (first line = %2)" +msgstr "" + +#: libs/ardour/panner.cc:1142 +msgid "mismatched pan automation event file version (%1)" +msgstr "" + +#: libs/ardour/panner.cc:1156 +msgid "too many panner states found in pan automation file %1" +msgstr "" + +#: libs/ardour/panner.cc:1297 +msgid "Unknown panner plugin \"%1\" found in pan state - ignored" +msgstr "" + +#: libs/ardour/panner.cc:1303 +msgid "panner plugin node has no type information!" +msgstr "" + +#: libs/ardour/playlist.cc:251 +msgid "playlist const copy constructor called" +msgstr "" + +#: libs/ardour/playlist.cc:257 +msgid "playlist non-const copy constructor called" +msgstr "" + +#: libs/ardour/playlist.cc:498 +msgid "add region" +msgstr "" + +#: libs/ardour/playlist.cc:550 +msgid "replace region" +msgstr "" + +#: libs/ardour/playlist.cc:563 +msgid "remove region" +msgstr "" + +#: libs/ardour/playlist.cc:635 +msgid "separate" +msgstr "" + +#: libs/ardour/playlist.cc:899 +msgid "cut" +msgstr "" + +#: libs/ardour/playlist.cc:989 +msgid "duplicate" +msgstr "" + +#: libs/ardour/playlist.cc:1044 +msgid "split" +msgstr "" + +#: libs/ardour/playlist.cc:1121 +msgid "%1: bounds changed received for region (%2)not in playlist" +msgstr "" + +#: libs/ardour/playlist.cc:1377 +msgid "Playlist: cannot create region from state file" +msgstr "" + +#: libs/ardour/playlist.cc:1737 +msgid "nudged" +msgstr "" + +#: libs/ardour/playlist_factory.cc:40 +msgid "" +"programming error: Playlist::copyPlaylist called with unknown Playlist type" +msgstr "" + +#: libs/ardour/plugin.cc:218 +msgid "Could not locate HOME. Preset not saved." +msgstr "" + +#: libs/ardour/plugin.cc:228 libs/ardour/plugin.cc:234 +msgid "Could not create %1. Preset not saved. (%2)" +msgstr "" + +#: libs/ardour/plugin.cc:239 +msgid "Error saving presets file %1." +msgstr "" + +#: libs/ardour/plugin_manager.cc:192 +msgid "Could not parse rdf file: %1" +msgstr "" + +#: libs/ardour/plugin_manager.cc:232 +msgid "LADSPA: cannot load module \"%1\" (%2)" +msgstr "" + +#: libs/ardour/plugin_manager.cc:239 +msgid "LADSPA: module \"%1\" has no descriptor function." +msgstr "" + +#: libs/ardour/plugin_manager.cc:295 libs/ardour/plugin_manager.cc:307 +msgid "Unknown" +msgstr "" + +#: libs/ardour/plugin_manager.cc:380 +msgid "" +"VST plugin %1 does not support processReplacing, and so cannot be used in " +"ardour at this time" +msgstr "" + +#: libs/ardour/recent_sessions.cc:44 +msgid "cannot open recent session file %1 (%2)" +msgstr "" + +#: libs/ardour/redirect.cc:77 +msgid "programming error: unknown Redirect type in Redirect::Clone!\n" +msgstr "" + +#: libs/ardour/redirect.cc:102 libs/ardour/utils.cc:194 +msgid "pre" +msgstr "" + +#: libs/ardour/redirect.cc:104 libs/ardour/utils.cc:197 +msgid "post" +msgstr "" + +#: libs/ardour/redirect.cc:107 +msgid "Redirect: unknown placement string \"%1\" (ignored)" +msgstr "" + +#: libs/ardour/redirect.cc:125 +msgid "%1: cannot open %2 to load automation data (%3)" +msgstr "" + +#: libs/ardour/redirect.cc:154 +msgid "%1: cannot load automation data from %2" +msgstr "" + +#: libs/ardour/redirect.cc:175 +msgid "%1: cannot open %2 to store automation data (%3)" +msgstr "" + +#: libs/ardour/redirect.cc:194 libs/ardour/redirect.cc:201 +msgid "%1: could not save automation state to %2" +msgstr "" + +#: libs/ardour/redirect.cc:246 +msgid "Could not get state from Redirect (%1). Problem with save_automation" +msgstr "" + +#: libs/ardour/redirect.cc:296 +msgid "incorrect XML node \"%1\" passed to Redirect object" +msgstr "" + +#: libs/ardour/redirect.cc:318 +msgid "%1: Automation node has no path property" +msgstr "" + +#: libs/ardour/redirect.cc:343 +msgid "XML node describing an IO is missing an IO node" +msgstr "" + +#: libs/ardour/redirect.cc:348 +msgid "XML node describing a redirect is missing the `active' field" +msgstr "" + +#: libs/ardour/redirect.cc:358 +msgid "XML node describing a redirect is missing the `placement' field" +msgstr "" + +#: libs/ardour/redirect.cc:467 +msgid "active_changed" +msgstr "" + +#: libs/ardour/region.cc:901 +msgid "Session: XMLNode describing a Region is incomplete (no id)" +msgstr "" + +#: libs/ardour/region.cc:908 +msgid "Session: XMLNode describing a Region is incomplete (no name)" +msgstr "" + +#: libs/ardour/region_factory.cc:53 libs/ardour/region_factory.cc:70 +msgid "" +"programming error: RegionFactory::create() called with unknown Region type" +msgstr "" + +#: libs/ardour/route.cc:81 libs/ardour/session.cc:1434 +#: libs/ardour/session.cc:1440 libs/ardour/session.cc:3064 +msgid "signal" +msgstr "" + +#: libs/ardour/route.cc:1407 +msgid "Could not get state of route. Problem with save_automation" +msgstr "" + +#: libs/ardour/route.cc:1459 +msgid "Send construction failed" +msgstr "" + +#: libs/ardour/route.cc:1481 +msgid "unknown Insert type \"%1\"; ignored" +msgstr "" + +#: libs/ardour/route.cc:1487 +msgid "Insert XML node has no type property" +msgstr "" + +#: libs/ardour/route.cc:1492 +msgid "insert could not be created. Ignored." +msgstr "" + +#: libs/ardour/route.cc:1508 +msgid "Bad node sent to Route::set_state() [%1]" +msgstr "" + +#: libs/ardour/route.cc:1572 +msgid "Route %1: unknown edit group \"%2 in saved state (ignored)" +msgstr "" + +#: libs/ardour/route.cc:1588 libs/ardour/route.cc:1592 +msgid "badly formed order key string in state file! [%1] ... ignored." +msgstr "" + +#: libs/ardour/route.cc:1673 libs/ardour/route.cc:1761 +msgid "[control]" +msgstr "" + +#: libs/ardour/route.cc:1693 +msgid "Route %1: unknown mix group \"%2 in saved state (ignored)" +msgstr "" + +#: libs/ardour/send.cc:99 +msgid "XML node describing a send is missing a Redirect node" +msgstr "" + +#: libs/ardour/session.cc:111 +msgid "Could not resolve path: %1 (%2)" +msgstr "" + +#: libs/ardour/session.cc:123 +msgid "cannot check session path %1 (%2)" +msgstr "" + +#: libs/ardour/session.cc:153 +msgid "cannot check statefile %1 (%2)" +msgstr "" + +#: libs/ardour/session.cc:189 +msgid "%1 is not an Ardour snapshot file" +msgstr "" + +#: libs/ardour/session.cc:206 +msgid "cannot determine current working directory (%1)" +msgstr "" + +#: libs/ardour/session.cc:223 +msgid "unknown file type for session %1" +msgstr "" + +#: libs/ardour/session.cc:343 +msgid "monitor" +msgstr "" + +#: libs/ardour/session.cc:351 +msgid "master" +msgstr "" + +#: libs/ardour/session.cc:633 +msgid "could not setup Click I/O" +msgstr "" + +#: libs/ardour/session.cc:654 +msgid "cannot setup Click I/O" +msgstr "" + +#: libs/ardour/session.cc:676 +msgid "cannot create Auditioner: no auditioning of regions possible" +msgstr "" + +#: libs/ardour/session.cc:688 +#, c-format +msgid "out %<PRIu32>" +msgstr "" + +#: libs/ardour/session.cc:700 +#, c-format +msgid "in %<PRIu32>" +msgstr "" + +#: libs/ardour/session.cc:714 +#, c-format +msgid "out %<PRIu32>+%<PRIu32>" +msgstr "" + +#: libs/ardour/session.cc:728 +#, c-format +msgid "in %<PRIu32>+%<PRIu32>" +msgstr "" + +#: libs/ardour/session.cc:761 +msgid "cannot setup master inputs" +msgstr "" + +#: libs/ardour/session.cc:769 +msgid "cannot setup master outputs" +msgstr "" + +#: libs/ardour/session.cc:780 +msgid "Master Out" +msgstr "" + +#: libs/ardour/session.cc:852 +msgid "cannot setup control inputs" +msgstr "" + +#: libs/ardour/session.cc:860 +msgid "cannot set up master outputs" +msgstr "" + +#: libs/ardour/session.cc:1043 +msgid "Session: you can't use that location for auto punch (start <= end)" +msgstr "" + +#: libs/ardour/session.cc:1080 +msgid "Session: you can't use a mark for auto loop" +msgstr "" + +#: libs/ardour/session.cc:1452 +msgid "feedback loop setup between %1 and %2" +msgstr "" + +#: libs/ardour/session.cc:1629 libs/ardour/session.cc:1750 +msgid "cannot configure %1 in/%2 out configuration for new audio track" +msgstr "" + +#: libs/ardour/session.cc:1687 +msgid "Session: could not create new audio track." +msgstr "" + +#: libs/ardour/session.cc:1800 +msgid "Session: could not create new audio route." +msgstr "" + +#: libs/ardour/session.cc:2319 +msgid "cannot create new name for region \"%1\"" +msgstr "" + +#: libs/ardour/session.cc:2383 +msgid "too many regions with names like %1" +msgstr "" + +#: libs/ardour/session.cc:2883 +msgid "There are already %1 recordings for %2, which I consider too many." +msgstr "" + +#: libs/ardour/session.cc:3085 +msgid "Cannot compile tape track regexp for use (%1)" +msgstr "" + +#: libs/ardour/session.cc:3232 +msgid "programming error: unknown type of Insert created!" +msgstr "" + +#: libs/ardour/session.cc:3238 +msgid "programming error: unknown type of Redirect created!" +msgstr "" + +#: libs/ardour/session.cc:3261 +msgid "programming error: unknown type of Insert deleted!" +msgstr "" + +#: libs/ardour/session.cc:3267 +msgid "programming error: unknown type of Redirect deleted!" +msgstr "" + +#: libs/ardour/session.cc:3573 +msgid "too many bounced versions of playlist \"%1\"" +msgstr "" + +#: libs/ardour/session.cc:3582 +msgid "cannot create new audio file \"%1\" for %2" +msgstr "" + +#: libs/ardour/session_butler.cc:85 libs/ardour/session_butler.cc:90 +msgid "UI: cannot set O_NONBLOCK on butler request pipe (%1)" +msgstr "" + +#: libs/ardour/session_butler.cc:95 +msgid "Session: could not create butler thread" +msgstr "" + +#: libs/ardour/session_butler.cc:183 +msgid "poll on butler request pipe failed (%1)" +msgstr "" + +#: libs/ardour/session_butler.cc:190 +msgid "Error on butler thread request pipe: fd=%1 err=%2" +msgstr "" + +#: libs/ardour/session_butler.cc:231 +msgid "Error reading from butler request pipe" +msgstr "" + +#: libs/ardour/session_butler.cc:268 +msgid "Butler read ahead failure on dstream %1" +msgstr "" + +#: libs/ardour/session_butler.cc:311 +msgid "Butler write-behind failure on dstream %1" +msgstr "" + +#: libs/ardour/session_click.cc:160 +msgid "cannot open click soundfile %1 (%2)" +msgstr "" + +#: libs/ardour/session_click.cc:169 +msgid "cannot read data from click soundfile" +msgstr "" + +#: libs/ardour/session_click.cc:196 +msgid "cannot open click emphasis soundfile %1 (%2)" +msgstr "" + +#: libs/ardour/session_click.cc:204 +msgid "cannot read data from click emphasis soundfile" +msgstr "" + +#: libs/ardour/session_command.cc:49 +msgid "Tried to reconstitute a MementoCommand with no contents, failing. id=" +msgstr "" + +#: libs/ardour/session_command.cc:95 +msgid "could not reconstitute MementoCommand from XMLNode. id=" +msgstr "" + +#: libs/ardour/session_events.cc:161 +msgid "Session: cannot have two events of type %1 at the same frame (%2)." +msgstr "" + +#: libs/ardour/session_events.cc:422 +msgid "Programming error: illegal event type in process_event (%1)" +msgstr "" + +#: libs/ardour/session_export.cc:63 +msgid "Export: no output file specified" +msgstr "" + +#: libs/ardour/session_export.cc:164 libs/ardour/session_export.cc:169 +msgid "illegal frame range in export specification" +msgstr "" + +#: libs/ardour/session_export.cc:174 +msgid "Bad data width size. Report me!" +msgstr "" + +#: libs/ardour/session_export.cc:204 +msgid "Export: cannot open output file \"%1\" (%2)" +msgstr "" + +#: libs/ardour/session_export.cc:214 +msgid "cannot initialize sample rate conversion: %1" +msgstr "" + +#: libs/ardour/session_export.cc:316 +msgid "an error occured during sample rate conversion: %1" +msgstr "" + +#: libs/ardour/session_export.cc:327 +msgid "warning, leftover frames overflowed, glitches might occur in output" +msgstr "" + +#: libs/ardour/session_export.cc:418 +msgid "Export: could not write data to output file (%1)" +msgstr "" + +#: libs/ardour/session_export.cc:502 +msgid "%1: cannot seek to %2 for export" +msgstr "" + +#: libs/ardour/session_midi.cc:95 +msgid "Ardour is slaved to MTC - port cannot be reset" +msgstr "" + +#: libs/ardour/session_midi.cc:110 +msgid "unknown port %1 requested for MTC" +msgstr "" + +#: libs/ardour/session_midi.cc:435 +msgid "Error reading from MIDI port %1" +msgstr "" + +#: libs/ardour/session_midi.cc:804 +msgid "Session: could not send full MIDI time code" +msgstr "" + +#: libs/ardour/session_midi.cc:863 +msgid "Session: cannot send quarter-frame MTC message (%1)" +msgstr "" + +#: libs/ardour/session_midi.cc:971 +msgid "MMC: cannot send command %1%2%3" +msgstr "" + +#: libs/ardour/session_midi.cc:1078 +msgid "UI: cannot set O_NONBLOCK on signal read pipe (%1)" +msgstr "" + +#: libs/ardour/session_midi.cc:1083 +msgid "UI: cannot set O_NONBLOCK on signal write pipe (%1)" +msgstr "" + +#: libs/ardour/session_midi.cc:1088 +msgid "Session: could not create transport thread" +msgstr "" + +#: libs/ardour/session_midi.cc:1117 +msgid "cannot send signal to midi thread! (%1)" +msgstr "" + +#: libs/ardour/session_midi.cc:1212 +msgid "MIDI thread poll failed (%1)" +msgstr "" + +#: libs/ardour/session_midi.cc:1224 +msgid "Error on transport thread request pipe" +msgstr "" + +#: libs/ardour/session_midi.cc:1251 +msgid "Error reading from transport request pipe" +msgstr "" + +#: libs/ardour/session_process.cc:104 +msgid "Session: error in no roll for %1" +msgstr "" + +#: libs/ardour/session_state.cc:103 +msgid "Could not use path %1 (%s)" +msgstr "" + +#: libs/ardour/session_state.cc:131 +msgid "end" +msgstr "" + +#: libs/ardour/session_state.cc:132 +msgid "start" +msgstr "" + +#: libs/ardour/session_state.cc:443 +msgid "Session: cannot create session dir \"%1\" (%2)" +msgstr "" + +#: libs/ardour/session_state.cc:450 +msgid "Session: cannot create session peakfile dir \"%1\" (%2)" +msgstr "" + +#: libs/ardour/session_state.cc:457 +msgid "Session: cannot create session sounds dir \"%1\" (%2)" +msgstr "" + +#: libs/ardour/session_state.cc:464 +msgid "Session: cannot create session dead sounds dir \"%1\" (%2)" +msgstr "" + +#: libs/ardour/session_state.cc:471 +msgid "Session: cannot create session automation dir \"%1\" (%2)" +msgstr "" + +#: libs/ardour/session_state.cc:500 +msgid "Could not open %1 for writing mix template" +msgstr "" + +#: libs/ardour/session_state.cc:506 +msgid "Could not open mix template %1 for reading" +msgstr "" + +#: libs/ardour/session_state.cc:548 +msgid "Session: could not load diskstream via XML state" +msgstr "" + +#: libs/ardour/session_state.cc:597 +msgid "could not backup old state file, current state not saved." +msgstr "" + +#: libs/ardour/session_state.cc:612 +msgid "state could not be saved to %1" +msgstr "" + +#: libs/ardour/session_state.cc:619 +msgid "could not remove corrupt state file %1" +msgstr "" + +#: libs/ardour/session_state.cc:623 +msgid "could not restore state file from backup %1" +msgstr "" + +#: libs/ardour/session_state.cc:693 +msgid "%1: session state information file \"%2\" doesn't exist!" +msgstr "" + +#: libs/ardour/session_state.cc:704 libs/ardour/session_state.cc:2824 +msgid "Could not understand ardour file %1" +msgstr "" + +#: libs/ardour/session_state.cc:988 +msgid "programming error: Session: incorrect XML node sent to set_state()" +msgstr "" + +#: libs/ardour/session_state.cc:1047 +msgid "Session: XML state has no options section" +msgstr "" + +#: libs/ardour/session_state.cc:1051 +msgid "Session: XML state has no sources section" +msgstr "" + +#: libs/ardour/session_state.cc:1058 +msgid "Session: XML state has no Regions section" +msgstr "" + +#: libs/ardour/session_state.cc:1065 +msgid "Session: XML state has no playlists section" +msgstr "" + +#: libs/ardour/session_state.cc:1084 +msgid "Session: XML state has no diskstreams section" +msgstr "" + +#: libs/ardour/session_state.cc:1091 +msgid "Session: XML state has no connections section" +msgstr "" + +#: libs/ardour/session_state.cc:1098 +msgid "Session: XML state has no locations section" +msgstr "" + +#: libs/ardour/session_state.cc:1131 +msgid "Session: XML state has no edit groups section" +msgstr "" + +#: libs/ardour/session_state.cc:1138 +msgid "Session: XML state has no mix groups section" +msgstr "" + +#: libs/ardour/session_state.cc:1145 +msgid "Session: XML state has no Tempo Map section" +msgstr "" + +#: libs/ardour/session_state.cc:1152 +msgid "Session: XML state has no routes section" +msgstr "" + +#: libs/ardour/session_state.cc:1159 +msgid "Session: XML state has no click section" +msgstr "" + +#: libs/ardour/session_state.cc:1202 +msgid "Session: cannot create Route from XML description." +msgstr "" + +#: libs/ardour/session_state.cc:1243 +msgid "Session: cannot create Region from XML description." +msgstr "" + +#: libs/ardour/session_state.cc:1271 +msgid "Session: XMLNode describing a AudioRegion is incomplete (no source)" +msgstr "" + +#: libs/ardour/session_state.cc:1279 libs/ardour/session_state.cc:1300 +msgid "" +"Session: XMLNode describing a AudioRegion references an unknown source id =%1" +msgstr "" + +#: libs/ardour/session_state.cc:1285 libs/ardour/session_state.cc:1306 +msgid "" +"Session: XMLNode describing a AudioRegion references a non-audio source id =%" +"1" +msgstr "" + +#: libs/ardour/session_state.cc:1377 +msgid "Session: cannot create Source from XML description." +msgstr "" + +#: libs/ardour/session_state.cc:1396 +msgid "" +"Found a sound file that cannot be used by Ardour. Talk to the progammers." +msgstr "" + +#: libs/ardour/session_state.cc:1418 +msgid "Could not create mix templates directory \"%1\" (%2)" +msgstr "" + +#: libs/ardour/session_state.cc:1432 +msgid "Template \"%1\" already exists - new version not created" +msgstr "" + +#: libs/ardour/session_state.cc:1439 +msgid "mix template not saved" +msgstr "" + +#: libs/ardour/session_state.cc:1498 +msgid "cannot create session directory \"%1\"; ignored" +msgstr "" + +#: libs/ardour/session_state.cc:1509 +msgid "cannot create sounds directory \"%1\"; ignored" +msgstr "" + +#: libs/ardour/session_state.cc:1518 +msgid "cannot create dead sounds directory \"%1\"; ignored" +msgstr "" + +#: libs/ardour/session_state.cc:1527 +msgid "cannot create peak file directory \"%1\"; ignored" +msgstr "" + +#: libs/ardour/session_state.cc:1659 libs/ardour/session_state.cc:1680 +msgid "Session: cannot create Playlist from XML description." +msgstr "" + +#: libs/ardour/session_state.cc:1719 +msgid "Session: cannot create Named Selection from XML description." +msgstr "" + +#: libs/ardour/session_state.cc:1872 +msgid "Unknown node \"%1\" found in Connections list from state file" +msgstr "" + +#: libs/ardour/session_state.cc:2677 +msgid "cannot remove dead sound file %1 (%2)" +msgstr "" + +#: libs/ardour/session_state.cc:2778 +msgid "could not backup old history file, current history not saved." +msgstr "" + +#: libs/ardour/session_state.cc:2786 +msgid "history could not be saved to %1" +msgstr "" + +#: libs/ardour/session_state.cc:2794 +msgid "could not remove corrupt history file %1" +msgstr "" + +#: libs/ardour/session_state.cc:2798 +msgid "could not restore history file from backup %1" +msgstr "" + +#: libs/ardour/session_state.cc:2816 +msgid "Loading history from '%1'." +msgstr "" + +#: libs/ardour/session_state.cc:2819 +msgid "%1: session history file \"%2\" doesn't exist!" +msgstr "" + +#: libs/ardour/session_state.cc:2861 +msgid "Couldn't figure out how to make a Command out of a %1 XMLNode." +msgstr "" + +#: libs/ardour/session_time.cc:370 +msgid "Unknown JACK transport state %1 in sync callback" +msgstr "" + +#: libs/ardour/session_timefx.cc:79 +msgid "tempoize: error creating name for new audio file based on %1" +msgstr "" + +#: libs/ardour/session_timefx.cc:88 +msgid "tempoize: error creating new audio file %1 (%2)" +msgstr "" + +#: libs/ardour/session_timefx.cc:113 +msgid "tempoize: error reading data from %1" +msgstr "" + +#: libs/ardour/session_timefx.cc:126 libs/ardour/session_timefx.cc:138 +msgid "error writing tempo-adjusted data to %1" +msgstr "" + +#: libs/ardour/session_timefx.cc:144 +msgid "timefx code failure. please notify ardour-developers." +msgstr "" + +#: libs/ardour/session_transport.cc:117 +msgid "Cannot loop - no loop range defined" +msgstr "" + +#: libs/ardour/session_transport.cc:474 +msgid "" +"Seamless looping cannot be supported while Ardour is using JACK transport.\n" +"Recommend changing the configured options" +msgstr "" + +#: libs/ardour/session_transport.cc:743 +msgid "" +"Global varispeed cannot be supported while Ardour is connected to JACK " +"transport control" +msgstr "" + +#: libs/ardour/session_transport.cc:933 +msgid "please stop the transport before adjusting slave settings" +msgstr "" + +#: libs/ardour/session_transport.cc:966 +msgid "No MTC port defined: MTC slaving is impossible." +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:15 +msgid "WAV" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:16 +msgid "AIFF" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:17 +msgid "raw (no header)" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:18 +msgid "PAF (Ensoniq Paris)" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:19 +msgid "AU (Sun/NeXT)" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:20 +msgid "IRCAM" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:21 +msgid "W64 (64 bit WAV)" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:26 +msgid ".wav" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:27 +msgid ".aiff" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:28 +msgid ".raw" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:29 +msgid ".paf" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:30 +msgid ".au" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:31 +msgid ".ircam" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:32 +msgid ".w64" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:47 +msgid "16 bit" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:48 +msgid "24 bit" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:49 +msgid "32 bit" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:50 +msgid "8 bit" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:51 +msgid "float" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:64 +msgid "Little-endian (Intel)" +msgstr "" + +#: libs/ardour/sndfile_helpers.cc:65 +msgid "Big-endian (Mac)" +msgstr "" + +#: libs/ardour/sndfilesource.cc:143 +msgid "FileSource: cannot get host information for BWF header (%1)" +msgstr "" + +#: libs/ardour/sndfilesource.cc:167 +msgid "" +"cannot set broadcast info for audio file %1 (%2); dropping broadcast info " +"for this file" +msgstr "" + +#: libs/ardour/sndfilesource.cc:216 +msgid "SndFileSource: cannot open file \"%1\" for %2 (%3)" +msgstr "" + +#: libs/ardour/sndfilesource.cc:222 +msgid "" +"SndFileSource: file only contains %1 channels; %2 is invalid as a channel " +"number" +msgstr "" + +#: libs/ardour/sndfilesource.cc:327 +msgid "SndFileSource: could not seek to frame %1 within %2 (%3)" +msgstr "" + +#: libs/ardour/sndfilesource.cc:378 +msgid "programming error: %1 %2" +msgstr "" + +#: libs/ardour/sndfilesource.cc:486 libs/ardour/sndfilesource.cc:507 +msgid "" +"cannot set broadcast info for audio file %1; Dropping broadcast info for " +"this file" +msgstr "" + +#: libs/ardour/sndfilesource.cc:521 +msgid "%1: cannot seek to %2" +msgstr "" + +#: libs/ardour/state_manager.cc:47 +msgid "cleared history" +msgstr "" + +#: libs/ardour/state_manager.cc:60 +msgid "" +"programming error: illegal state ID (%1) passed to StateManager::set_state() " +"(range = 0-%2)" +msgstr "" + +#: libs/ardour/tempo.cc:67 +msgid "TempoSection XML node has no \"start\" property" +msgstr "" + +#: libs/ardour/tempo.cc:75 +msgid "TempoSection XML node has an illegal \"start\" value" +msgstr "" + +#: libs/ardour/tempo.cc:82 +msgid "TempoSection XML node has no \"beats-per-minute\" property" +msgstr "" + +#: libs/ardour/tempo.cc:87 +msgid "TempoSection XML node has an illegal \"beats_per_minute\" value" +msgstr "" + +#: libs/ardour/tempo.cc:92 +msgid "TempoSection XML node has no \"movable\" property" +msgstr "" + +#: libs/ardour/tempo.cc:131 +msgid "MeterSection XML node has no \"start\" property" +msgstr "" + +#: libs/ardour/tempo.cc:139 +msgid "MeterSection XML node has an illegal \"start\" value" +msgstr "" + +#: libs/ardour/tempo.cc:146 +msgid "MeterSection XML node has no \"beats-per-bar\" property" +msgstr "" + +#: libs/ardour/tempo.cc:151 +msgid "MeterSection XML node has an illegal \"beats-per-bar\" value" +msgstr "" + +#: libs/ardour/tempo.cc:156 +msgid "MeterSection XML node has no \"note-type\" property" +msgstr "" + +#: libs/ardour/tempo.cc:161 +msgid "MeterSection XML node has an illegal \"note-type\" value" +msgstr "" + +#: libs/ardour/tempo.cc:166 +msgid "MeterSection XML node has no \"movable\" property" +msgstr "" + +#: libs/ardour/tempo.cc:259 +msgid "move metric" +msgstr "" + +#: libs/ardour/tempo.cc:330 +msgid "metric removed" +msgstr "" + +#: libs/ardour/tempo.cc:373 +msgid "add tempo" +msgstr "" + +#: libs/ardour/tempo.cc:402 +msgid "replace tempo" +msgstr "" + +#: libs/ardour/tempo.cc:435 +msgid "add meter" +msgstr "" + +#: libs/ardour/tempo.cc:463 +msgid "replaced meter" +msgstr "" + +#: libs/ardour/tempo.cc:483 libs/ardour/tempo.cc:499 +msgid "programming error: no tempo section in tempo map!" +msgstr "" + +#: libs/ardour/tempo.cc:538 +msgid "programming error: unhandled MetricSection type" +msgstr "" + +#: libs/ardour/tempo.cc:1265 libs/ardour/tempo.cc:1277 +msgid "Tempo map: could not set new state, restoring old one." +msgstr "" + +#: libs/ardour/tempo.cc:1301 +msgid "load XML data" +msgstr "" + +#: libs/ardour/utils.cc:237 +msgid "illegal or badly-formed string used for path (%1)" +msgstr "" + +#: libs/ardour/utils.cc:242 +msgid "path (%1) is ambiguous" +msgstr "" + +#: libs/ardour/utils.cc:304 libs/ardour/utils.cc:323 +msgid "Splice Edit" +msgstr "Fogredigering" + +#: libs/ardour/utils.cc:306 libs/ardour/utils.cc:319 +msgid "Slide Edit" +msgstr "Glidredigering" + +#: libs/ardour/utils.cc:309 +msgid "programming error: unknown edit mode string \"%1\"" +msgstr "" + +#: libs/ardour/utils.cc:330 libs/ardour/utils.cc:359 +msgid "Internal" +msgstr "Intern" + +#: libs/ardour/utils.cc:334 libs/ardour/utils.cc:355 +msgid "MTC" +msgstr "" + +#: libs/ardour/utils.cc:338 libs/ardour/utils.cc:352 +msgid "JACK" +msgstr "" + +#: libs/ardour/utils.cc:342 +msgid "programming error: unknown slave source string \"%1\"" +msgstr "" + +#: libs/ardour/vst_plugin.cc:178 +msgid "cannot create VST chunk directory: %1" +msgstr "" + +#: libs/ardour/vst_plugin.cc:186 +msgid "cannot check VST chunk directory: %1" +msgstr "" + +#: libs/ardour/vst_plugin.cc:193 +msgid "%1 exists but is not a directory" +msgstr "" + +#: libs/ardour/vst_plugin.cc:231 +msgid "Bad node sent to VSTPlugin::set_state" +msgstr "" + +#: libs/ardour/vst_plugin.cc:334 libs/ardour/vst_plugin.cc:345 +msgid "no support for presets using chunks at this time" +msgstr "" + +#: libs/ardour/vst_plugin.cc:495 +msgid "VST: cannot load module from \"%1\"" +msgstr "" + +#: libs/ardour/vst_plugin.cc:500 +msgid "You asked ardour to not use any VST plugins" +msgstr "" + +#: libs/ardour/audio_unit.cc:48 +msgid "AudioUnit: Could not convert CAComponent to CAAudioUnit" +msgstr "" diff --git a/libs/ardour/redirect.cc b/libs/ardour/redirect.cc index 09d650b069..adad79e2a3 100644 --- a/libs/ardour/redirect.cc +++ b/libs/ardour/redirect.cc @@ -108,101 +108,77 @@ Redirect::set_placement (const string& str, void *src) } } +/* NODE STRUCTURE + + <Automation [optionally with visible="...." ]> + <parameter-N> + <AutomationList id=N> + <events> + X1 Y1 + X2 Y2 + .... + </events> + </parameter-N> + <Automation> +*/ + int -Redirect::load_automation (string path) -{ - string fullpath; +Redirect::set_automation_state (const XMLNode& node) +{ + Glib::Mutex::Lock lm (_automation_lock); - if (path[0] == '/') { // legacy - fullpath = path; - } else { - fullpath = _session.automation_dir(); - fullpath += path; - } - ifstream in (fullpath.c_str()); + parameter_automation.clear (); - if (!in) { - warning << string_compose(_("%1: cannot open %2 to load automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg; - return 1; - } + XMLNodeList nlist = node.children(); + XMLNodeIterator niter; - Glib::Mutex::Lock lm (_automation_lock); - set<uint32_t> tosave; - parameter_automation.clear (); + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { + uint32_t param; - while (in) { - double when; - double value; - uint32_t port; + if (sscanf ((*niter)->name().c_str(), "parameter-%" PRIu32, ¶m) != 1) { + error << string_compose (_("%2: badly formatted node name in XML automation state, ignored"), _name) << endmsg; + continue; + } - in >> port; if (!in) break; - in >> when; if (!in) goto bad; - in >> value; if (!in) goto bad; - - AutomationList& al = automation_list (port); - al.add (when, value); - tosave.insert (port); - } - - for (set<uint32_t>::iterator i = tosave.begin(); i != tosave.end(); ++i) { - automation_list (*i).save_state (_("loaded from disk")); + AutomationList& al = automation_list (param); + if (al.set_state (*(*niter)->children().front())) { + goto bad; + } } - + return 0; bad: - error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg; + error << string_compose(_("%1: cannot load automation data from XML"), _name) << endmsg; parameter_automation.clear (); return -1; } -int -Redirect::save_automation (string path) +XMLNode& +Redirect::get_automation_state () { Glib::Mutex::Lock lm (_automation_lock); + XMLNode* node = new XMLNode (X_("Automation")); string fullpath; if (parameter_automation.empty()) { - return 1; - } - - fullpath = _session.automation_dir(); - fullpath += path; - - ofstream out (fullpath.c_str()); - - if (!out) { - error << string_compose(_("%1: cannot open %2 to store automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg; - return -1; + return *node; } - AutomationList::const_iterator i; map<uint32_t,AutomationList*>::iterator li; for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) { - for (i = (*li).second->begin(); i != (*li).second->end(); ++i) { - - out << (*li).first << ' ' << (*i)->when << ' ' << (*i)->value << endl; - - if (!out) { - break; - } - } + + XMLNode* child; - if (i != (*li).second->end()) { - unlink (fullpath.c_str()); - error << string_compose(_("%1: could not save automation state to %2"), _name, fullpath) << endmsg; - return -1; - } - } - - if (li != parameter_automation.end()) { - unlink (fullpath.c_str()); - error << string_compose(_("%1: could not save automation state to %2"), _name, fullpath) << endmsg; - return -1; + char buf[64]; + stringstream str; + snprintf (buf, sizeof (buf), "parameter-%" PRIu32, li->first); + child = new XMLNode (buf); + child->add_child_nocopy (li->second->get_state ()); } - return 0; + return *node; } XMLNode& @@ -214,7 +190,6 @@ Redirect::get_state (void) XMLNode& Redirect::state (bool full_state) { - char buf[64]; XMLNode* node = new XMLNode (state_node_name); stringstream sstr; @@ -228,65 +203,24 @@ Redirect::state (bool full_state) if (full_state) { - string path; - string legal_name; + XMLNode& automation = get_automation_state(); - path = _session.snap_name(); - path += "-redirect-"; - id().print (buf, sizeof (buf)); - path += buf; - path += ".automation"; - - /* XXX we didn't ask for a state save, we asked for the current state. - FIX ME! - */ - - switch (save_automation (path)) { - case -1: - error << string_compose(_("Could not get state from Redirect (%1). Problem with save_automation"), _name) << endmsg; - break; - - case 0: - XMLNode *aevents = node->add_child("Automation"); - - for (set<uint32_t>::iterator x = visible_parameter_automation.begin(); x != visible_parameter_automation.end(); ++x) { - if (x != visible_parameter_automation.begin()) { - sstr << ' '; - } - sstr << *x; + for (set<uint32_t>::iterator x = visible_parameter_automation.begin(); x != visible_parameter_automation.end(); ++x) { + if (x != visible_parameter_automation.begin()) { + sstr << ' '; } - - aevents->add_property ("path", path); - aevents->add_property ("visible", sstr.str()); - break; + sstr << *x; } - } - return *node; -} + automation.add_property ("visible", sstr.str()); -void -Redirect::what_has_automation (set<uint32_t>& s) const -{ - Glib::Mutex::Lock lm (_automation_lock); - map<uint32_t,AutomationList*>::const_iterator li; - - for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) { - s.insert ((*li).first); + node->add_child_nocopy (automation); } -} -void -Redirect::what_has_visible_automation (set<uint32_t>& s) const -{ - Glib::Mutex::Lock lm (_automation_lock); - set<uint32_t>::const_iterator li; - - for (li = visible_parameter_automation.begin(); li != visible_parameter_automation.end(); ++li) { - s.insert (*li); - } + return *node; } + int Redirect::set_state (const XMLNode& node) { @@ -308,14 +242,15 @@ Redirect::set_state (const XMLNode& node) IO::set_state (**niter); have_io = true; - } else if ((*niter)->name() == "Automation") { + } else if ((*niter)->name() == X_("Automation")) { + XMLProperty *prop; if ((prop = (*niter)->property ("path")) != 0) { - load_automation (prop->value()); + old_set_automation_state (*(*niter)); } else { - warning << string_compose(_("%1: Automation node has no path property"), _name) << endmsg; + set_automation_state (*(*niter)); } if ((prop = (*niter)->property ("visible")) != 0) { @@ -364,6 +299,102 @@ Redirect::set_state (const XMLNode& node) return 0; } +int +Redirect::old_set_automation_state (const XMLNode& node) +{ + const XMLProperty *prop; + + if ((prop = node.property ("path")) != 0) { + load_automation (prop->value()); + } else { + warning << string_compose(_("%1: Automation node has no path property"), _name) << endmsg; + } + + if ((prop = node.property ("visible")) != 0) { + uint32_t what; + stringstream sstr; + + visible_parameter_automation.clear (); + + sstr << prop->value(); + while (1) { + sstr >> what; + if (sstr.fail()) { + break; + } + mark_automation_visible (what, true); + } + } + + return 0; +} + +int +Redirect::load_automation (string path) +{ + string fullpath; + + if (path[0] == '/') { // legacy + fullpath = path; + } else { + fullpath = _session.automation_dir(); + fullpath += path; + } + ifstream in (fullpath.c_str()); + + if (!in) { + warning << string_compose(_("%1: cannot open %2 to load automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg; + return 1; + } + + Glib::Mutex::Lock lm (_automation_lock); + set<uint32_t> tosave; + parameter_automation.clear (); + + while (in) { + double when; + double value; + uint32_t port; + + in >> port; if (!in) break; + in >> when; if (!in) goto bad; + in >> value; if (!in) goto bad; + + AutomationList& al = automation_list (port); + al.add (when, value); + tosave.insert (port); + } + + return 0; + + bad: + error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg; + parameter_automation.clear (); + return -1; +} + + +void +Redirect::what_has_automation (set<uint32_t>& s) const +{ + Glib::Mutex::Lock lm (_automation_lock); + map<uint32_t,AutomationList*>::const_iterator li; + + for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) { + s.insert ((*li).first); + } +} + +void +Redirect::what_has_visible_automation (set<uint32_t>& s) const +{ + Glib::Mutex::Lock lm (_automation_lock); + set<uint32_t>::const_iterator li; + + for (li = visible_parameter_automation.begin(); li != visible_parameter_automation.end(); ++li) { + s.insert (*li); + } +} AutomationList& Redirect::automation_list (uint32_t parameter) { @@ -437,34 +468,9 @@ Redirect::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_even } void -Redirect::store_state (RedirectState& state) const -{ - state.active = _active; -} - -Change -Redirect::restore_state (StateManager::State& state) -{ - RedirectState* rstate = dynamic_cast<RedirectState*> (&state); - set_active (rstate->active, this); - return Change (0); -} - -StateManager::State* -Redirect::state_factory (std::string why) const -{ - RedirectState* state = new RedirectState (why); - - store_state (*state); - - return state; -} - -void Redirect::set_active (bool yn, void* src) { _active = yn; - save_state (_("active_changed")); active_changed (this, src); _session.set_dirty (); } diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index 3853559e10..6d8c71b563 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -265,13 +265,43 @@ Region::Region (boost::shared_ptr<Source> src, const XMLNode& node) Region::~Region () { - /* derived classes must call notify_callbacks() and then emit GoingAway */ + if (_playlist) { + for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { + (*i)->remove_playlist (_playlist); + } + } + + notify_callbacks (); + GoingAway (); /* EMIT SIGNAL */ } void Region::set_playlist (Playlist* pl) { - _playlist = pl; + if (pl == _playlist) { + return; + } + + Playlist* old_playlist = _playlist; + + if (pl) { + if (old_playlist) { + for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { + (*i)->remove_playlist (old_playlist); + (*i)->add_playlist (_playlist); + } + } else { + for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { + (*i)->add_playlist (_playlist); + } + } + } else { + if (old_playlist) { + for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { + (*i)->remove_playlist (old_playlist); + } + } + } } void @@ -337,6 +367,24 @@ Region::first_edit () } } +bool +Region::at_natural_position () const +{ + if (!_playlist) { + return false; + } + + boost::shared_ptr<Region> whole_file_region = get_parent(); + + if (whole_file_region) { + if (_position == whole_file_region->position() + _start) { + return true; + } + } + + return false; +} + void Region::move_to_natural_position (void *src) { @@ -1180,14 +1228,17 @@ Region::verify_start_mutable (jack_nframes_t& new_start) } boost::shared_ptr<Region> -Region::get_parent() +Region::get_parent() const { - boost::shared_ptr<Region> r; - if (_playlist) { - r = _playlist->session().find_whole_file_parent (*this); + boost::shared_ptr<Region> r; + boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this()); + + if (grrr2 && (r = _playlist->session().find_whole_file_parent (grrr2))) { + return boost::static_pointer_cast<Region> (r); + } } - return r; + return boost::shared_ptr<Region>(); } diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 308dbb57cb..5314c99632 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -63,13 +63,13 @@ Route::Route (Session& sess, string name, int input_min, int input_max, int outp init (); } -Route::Route (Session& sess, const XMLNode& node) - : IO (sess, "route"), +Route::Route (Session& sess, const XMLNode& node, DataType default_type) + : IO (sess, *node.child ("IO"), default_type), _solo_control (X_("solo"), *this, ToggleControllable::SoloControl), _mute_control (X_("mute"), *this, ToggleControllable::MuteControl) { init (); - set_state (node); + _set_state (node, false); } void @@ -1313,7 +1313,6 @@ XMLNode& Route::state(bool full_state) { XMLNode *node = new XMLNode("Route"); - XMLNode *aevents; RedirectList:: iterator i; char buf[32]; @@ -1374,26 +1373,6 @@ Route::state(bool full_state) cmt->add_content (_comment); } - if (full_state) { - string path; - - path = _session.snap_name(); - path += "-gain-"; - path += legalize_for_path (_name); - path += ".automation"; - - /* XXX we didn't ask for a state save, we asked for the current state. - FIX ME! - */ - - if (save_automation (path)) { - error << _("Could not get state of route. Problem with save_automation") << endmsg; - } - - aevents = node->add_child ("Automation"); - aevents->add_property ("path", path); - } - for (i = _redirects.begin(); i != _redirects.end(); ++i) { node->add_child_nocopy((*i)->state (full_state)); } @@ -1481,6 +1460,12 @@ Route::add_redirect_from_xml (const XMLNode& node) int Route::set_state (const XMLNode& node) { + return _set_state (node, true); +} + +int +Route::_set_state (const XMLNode& node, bool call_base) +{ XMLNodeList nlist; XMLNodeConstIterator niter; XMLNode *child; @@ -1492,7 +1477,7 @@ Route::set_state (const XMLNode& node) return -1; } - if ((prop = node.property ("flags")) != 0) { + if ((prop = node.property (X_("flags"))) != 0) { int x; sscanf (prop->value().c_str(), "0x%x", &x); _flags = Flag (x); @@ -1500,20 +1485,20 @@ Route::set_state (const XMLNode& node) _flags = Flag (0); } - if ((prop = node.property ("default-type")) != 0) { + if ((prop = node.property (X_("default-type"))) != 0) { _default_type = DataType(prop->value()); assert(_default_type != DataType::NIL); } - if ((prop = node.property ("phase-invert")) != 0) { + if ((prop = node.property (X_("phase-invert"))) != 0) { set_phase_invert(prop->value()=="yes"?true:false, this); } - if ((prop = node.property ("active")) != 0) { + if ((prop = node.property (X_("active"))) != 0) { set_active (prop->value() == "yes"); } - if ((prop = node.property ("muted")) != 0) { + if ((prop = node.property (X_("muted"))) != 0) { bool yn = prop->value()=="yes"?true:false; /* force reset of mute status */ @@ -1523,7 +1508,7 @@ Route::set_state (const XMLNode& node) mute_gain = desired_mute_gain; } - if ((prop = node.property ("soloed")) != 0) { + if ((prop = node.property (X_("soloed"))) != 0) { bool yn = prop->value()=="yes"?true:false; /* force reset of solo status */ @@ -1533,23 +1518,23 @@ Route::set_state (const XMLNode& node) solo_gain = desired_solo_gain; } - if ((prop = node.property ("mute-affects-pre-fader")) != 0) { + if ((prop = node.property (X_("mute-affects-pre-fader"))) != 0) { _mute_affects_pre_fader = (prop->value()=="yes")?true:false; } - if ((prop = node.property ("mute-affects-post-fader")) != 0) { + if ((prop = node.property (X_("mute-affects-post-fader"))) != 0) { _mute_affects_post_fader = (prop->value()=="yes")?true:false; } - if ((prop = node.property ("mute-affects-control-outs")) != 0) { + if ((prop = node.property (X_("mute-affects-control-outs"))) != 0) { _mute_affects_control_outs = (prop->value()=="yes")?true:false; } - if ((prop = node.property ("mute-affects-main-outs")) != 0) { + if ((prop = node.property (X_("mute-affects-main-outs"))) != 0) { _mute_affects_main_outs = (prop->value()=="yes")?true:false; } - if ((prop = node.property ("edit-group")) != 0) { + if ((prop = node.property (X_("edit-group"))) != 0) { RouteGroup* edit_group = _session.edit_group_by_name(prop->value()); if(edit_group == 0) { error << string_compose(_("Route %1: unknown edit group \"%2 in saved state (ignored)"), _name, prop->value()) << endmsg; @@ -1558,7 +1543,7 @@ Route::set_state (const XMLNode& node) } } - if ((prop = node.property ("order-keys")) != 0) { + if ((prop = node.property (X_("order-keys"))) != 0) { long n; @@ -1595,7 +1580,7 @@ Route::set_state (const XMLNode& node) delete deferred_state; } - deferred_state = new XMLNode("deferred state"); + deferred_state = new XMLNode(X_("deferred state")); /* set parent class properties before anything else */ @@ -1603,7 +1588,7 @@ Route::set_state (const XMLNode& node) child = *niter; - if (child->name() == IO::state_node_name) { + if (child->name() == IO::state_node_name && call_base) { IO::set_state (*child); break; @@ -1614,7 +1599,7 @@ Route::set_state (const XMLNode& node) child = *niter; - if (child->name() == "Send") { + if (child->name() == X_("Send")) { if (!IO::ports_legal) { @@ -1625,7 +1610,7 @@ Route::set_state (const XMLNode& node) add_redirect_from_xml (*child); } - } else if (child->name() == "Insert") { + } else if (child->name() == X_("Insert")) { if (!IO::ports_legal) { @@ -1636,21 +1621,13 @@ Route::set_state (const XMLNode& node) add_redirect_from_xml (*child); } - } else if (child->name() == "Automation") { - - XMLPropertyList plist; - XMLPropertyConstIterator piter; - XMLProperty *prop; + } else if (child->name() == X_("Automation")) { - plist = child->properties(); - for (piter = plist.begin(); piter != plist.end(); ++piter) { - prop = *piter; - if (prop->name() == "path") { - load_automation (prop->value()); - } + if ((prop = child->property (X_("path"))) != 0) { + load_automation (prop->value()); } - } else if (child->name() == "ControlOuts") { + } else if (child->name() == X_("ControlOuts")) { string coutname = _name; coutname += _("[control]"); @@ -1658,25 +1635,25 @@ Route::set_state (const XMLNode& node) _control_outs = new IO (_session, coutname); _control_outs->set_state (**(child->children().begin())); - } else if (child->name() == "Comment") { + } else if (child->name() == X_("Comment")) { /* XXX this is a terrible API design in libxml++ */ XMLNode *cmt = *(child->children().begin()); _comment = cmt->content(); - } else if (child->name() == "extra") { + } else if (child->name() == X_("extra")) { _extra_xml = new XMLNode (*child); - } else if (child->name() == "solo") { + } else if (child->name() == X_("solo")) { _solo_control.set_state (*child); _session.add_controllable (&_solo_control); - } else if (child->name() == "mute") { + } else if (child->name() == X_("mute")) { _mute_control.set_state (*child); _session.add_controllable (&_mute_control); } } - if ((prop = node.property ("mix-group")) != 0) { + if ((prop = node.property (X_("mix-group"))) != 0) { RouteGroup* mix_group = _session.mix_group_by_name(prop->value()); if (mix_group == 0) { error << string_compose(_("Route %1: unknown mix group \"%2 in saved state (ignored)"), _name, prop->value()) << endmsg; @@ -1936,6 +1913,10 @@ Route::handle_transport_stopped (bool abort_ignored, bool did_locate, bool can_f { Glib::RWLock::ReaderLock lm (redirect_lock); + if (!did_locate) { + automation_snapshot (now); + } + for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) { if (Config->get_plugins_stop_with_transport() && can_flush_redirects) { @@ -1952,19 +1933,6 @@ Route::handle_transport_stopped (bool abort_ignored, bool did_locate, bool can_f _roll_delay = _initial_delay; } -UndoAction -Route::get_memento() const -{ - void (Route::*pmf)(state_id_t) = &Route::set_state; - return sigc::bind (mem_fun (*(const_cast<Route *>(this)), pmf), _current_state_id); -} - -void -Route::set_state (state_id_t id) -{ - return; -} - void Route::input_change_handler (IOChange change, void *ignored) { @@ -2048,6 +2016,15 @@ int Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset, int declick, bool can_record, bool rec_monitors_input) { + { + Glib::RWLock::ReaderLock lm (redirect_lock, Glib::TRY_LOCK); + if (lm.locked()) { + // automation snapshot can also be called from the non-rt context + // and it uses the redirect list, so we take the lock out here + automation_snapshot (_session.transport_frame()); + } + } + if ((n_outputs().get_total() == 0 && _redirects.empty()) || n_inputs().get_total() == 0 || !_active) { silence (nframes, offset); return 0; @@ -2181,6 +2158,16 @@ Route::set_latency_delay (nframes_t longest_session_latency) } } +void +Route::automation_snapshot (nframes_t now) +{ + IO::automation_snapshot (now); + + for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) { + (*i)->automation_snapshot (now); + } +} + Route::ToggleControllable::ToggleControllable (std::string name, Route& s, ToggleType tp) : Controllable (name), route (s), type(tp) { diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc index 2c2a152416..73dbf11ad5 100644 --- a/libs/ardour/send.cc +++ b/libs/ardour/send.cc @@ -37,7 +37,6 @@ Send::Send (Session& s, Placement p) : Redirect (s, s.next_send_name(), p) { _metering = false; - save_state (_("initial state")); RedirectCreated (this); /* EMIT SIGNAL */ } @@ -50,7 +49,6 @@ Send::Send (Session& s, const XMLNode& node) throw failed_constructor(); } - save_state (_("initial state")); RedirectCreated (this); /* EMIT SIGNAL */ } @@ -58,7 +56,6 @@ Send::Send (const Send& other) : Redirect (other._session, other._session.next_send_name(), other.placement()) { _metering = false; - save_state (_("initial state")); RedirectCreated (this); /* EMIT SIGNAL */ } @@ -77,7 +74,7 @@ XMLNode& Send::state(bool full) { XMLNode *node = new XMLNode("Send"); - node->add_child_nocopy (Redirect::state(full)); + node->add_child_nocopy (Redirect::state (full)); return *node; } @@ -86,11 +83,15 @@ Send::set_state(const XMLNode& node) { XMLNodeList nlist = node.children(); XMLNodeIterator niter; - + + /* Send has regular IO automation (gain, pan) */ + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { if ((*niter)->name() == Redirect::state_node_name) { Redirect::set_state (**niter); break; + } else if ((*niter)->name() == X_("Automation")) { + IO::set_automation_state (*(*niter)); } } diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 11cb658008..1b7c3be6dd 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -288,7 +288,7 @@ Session::Session (AudioEngine &eng, new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)); if (new_session) { - if (create (new_session, mix_template, _engine.frame_rate() * 60 * 5)) { + if (create (new_session, mix_template, compute_initial_length())) { cerr << "create failed\n"; throw failed_constructor (); } @@ -342,12 +342,21 @@ Session::Session (AudioEngine &eng, cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (2)" << endl; - n_physical_outputs = max (requested_physical_out, _engine.n_physical_outputs()); - n_physical_inputs = max (requested_physical_in, _engine.n_physical_inputs()); + n_physical_outputs = _engine.n_physical_outputs(); + n_physical_inputs = _engine.n_physical_inputs(); + + if (n_physical_inputs) { + n_physical_inputs = max (requested_physical_in, n_physical_inputs); + } + + if (n_physical_outputs) { + n_physical_outputs = max (requested_physical_out, n_physical_outputs); + } first_stage_init (fullpath, snapshot_name); new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)); + if (new_session) { if (create (new_session, 0, initial_length)) { throw failed_constructor (); @@ -410,7 +419,7 @@ Session::~Session () /* clear history so that no references to objects are held any more */ - history.clear (); + _history.clear (); /* clear state tree so that no references to objects are held any more */ @@ -1331,8 +1340,10 @@ Session::set_frame_rate (nframes_t frames_per_second) sync_time_vars(); + Route::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * 0.25)); + // XXX we need some equivalent to this, somehow - // DestructiveFileSource::setup_standard_crossfades (frames_per_second); + // SndFileSource::setup_standard_crossfades (frames_per_second); set_dirty(); @@ -1824,12 +1835,12 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ << endmsg; } - for (uint32_t x = 0; x < bus->n_inputs().get(DataType::AUDIO); ++x) { + for (uint32_t x = 0; n_physical_inputs && x < bus->n_inputs().get(DataType::AUDIO); ++x) { port = ""; - + if (Config->get_input_auto_connect() & AutoConnectPhysical) { - port = physinputs[((n+x)%n_physical_inputs)]; + port = physinputs[((n+x)%n_physical_inputs)]; } if (port.length() && bus->connect_input (bus->input (x), port, this)) { @@ -1837,7 +1848,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ } } - for (uint32_t x = 0; x < bus->n_outputs().get(DataType::AUDIO); ++x) { + for (uint32_t x = 0; n_physical_outputs && x < bus->n_outputs().get(DataType::AUDIO); ++x) { port = ""; @@ -1950,8 +1961,9 @@ Session::remove_route (shared_ptr<Route> route) { RCUWriter<RouteList> writer (routes); shared_ptr<RouteList> rs = writer.get_copy (); - rs->remove (route); + rs->remove (route); + /* deleting the master out seems like a dumb idea, but its more of a UI policy issue than our concern. @@ -2564,7 +2576,7 @@ Session::remove_region (boost::weak_ptr<Region> weak_region) } boost::shared_ptr<Region> -Session::find_whole_file_parent (Region& child) +Session::find_whole_file_parent (boost::shared_ptr<Region const> child) { RegionList::iterator i; boost::shared_ptr<Region> region; @@ -2577,13 +2589,13 @@ Session::find_whole_file_parent (Region& child) if (region->whole_file()) { - if (child.source_equivalent (region)) { + if (child->source_equivalent (region)) { return region; } } } - return boost::shared_ptr<AudioRegion> (); + return boost::shared_ptr<Region> (); } void @@ -2596,32 +2608,38 @@ Session::find_equivalent_playlist_regions (boost::shared_ptr<Region> region, vec int Session::destroy_region (boost::shared_ptr<Region> region) { - boost::shared_ptr<AudioRegion> aregion; - - if ((aregion = boost::dynamic_pointer_cast<AudioRegion> (region)) == 0) { - return 0; - } - - if (aregion->playlist()) { - aregion->playlist()->destroy_region (region); - } - vector<boost::shared_ptr<Source> > srcs; - - for (uint32_t n = 0; n < aregion->n_channels(); ++n) { - srcs.push_back (aregion->source (n)); + + { + boost::shared_ptr<AudioRegion> aregion; + + if ((aregion = boost::dynamic_pointer_cast<AudioRegion> (region)) == 0) { + return 0; + } + + if (aregion->playlist()) { + aregion->playlist()->destroy_region (region); + } + + for (uint32_t n = 0; n < aregion->n_channels(); ++n) { + srcs.push_back (aregion->source (n)); + } } + region->drop_references (); + for (vector<boost::shared_ptr<Source> >::iterator i = srcs.begin(); i != srcs.end(); ++i) { - - if ((*i).use_count() == 1) { - boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*i); + if (!(*i)->used()) { + boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*i); + if (afs) { (afs)->mark_for_remove (); } (*i)->drop_references (); + + cerr << "source was not used by any playlist\n"; } } @@ -3198,6 +3216,20 @@ Session::add_playlist (Playlist* playlist) } void +Session::get_playlists (vector<Playlist*>& s) +{ + { + Glib::Mutex::Lock lm (playlist_lock); + for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) { + s.push_back (*i); + } + for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) { + s.push_back (*i); + } + } +} + +void Session::track_playlist (Playlist* pl, bool inuse) { PlaylistList::iterator x; @@ -3970,13 +4002,14 @@ Session::nbusses () const } void -Session::add_curve(Curve *curve) +Session::add_automation_list(AutomationList *al) { - curves[curve->id()] = curve; + automation_lists[al->id()] = al; } -void -Session::add_automation_list(AutomationList *al) +nframes_t +Session::compute_initial_length () { - automation_lists[al->id()] = al; + return _engine.frame_rate() * 60 * 5; } + diff --git a/libs/ardour/session_click.cc b/libs/ardour/session_click.cc index 5fd6d70983..f09c7232d7 100644 --- a/libs/ardour/session_click.cc +++ b/libs/ardour/session_click.cc @@ -84,7 +84,7 @@ Session::click (nframes_t start, nframes_t nframes, nframes_t offset) break; } } - + run_clicks: memset (buf, 0, sizeof (Sample) * nframes); diff --git a/libs/ardour/session_command.cc b/libs/ardour/session_command.cc index d71ba34fc7..5816f1c6b7 100644 --- a/libs/ardour/session_command.cc +++ b/libs/ardour/session_command.cc @@ -3,9 +3,13 @@ #include <pbd/memento_command.h> #include <ardour/diskstream.h> #include <ardour/playlist.h> +#include <ardour/audioplaylist.h> +#include <ardour/audio_track.h> #include <ardour/tempo.h> #include <ardour/audiosource.h> #include <ardour/audioregion.h> +#include <ardour/midi_source.h> +#include <ardour/midi_region.h> #include <pbd/error.h> using namespace PBD; #include "i18n.h" @@ -13,7 +17,7 @@ using namespace PBD; namespace ARDOUR { -void Session::register_with_memento_command_factory(PBD::ID id, StatefulDestructible *ptr) +void Session::register_with_memento_command_factory(PBD::ID id, PBD::StatefulThingWithGoingAway *ptr) { registry[id] = ptr; } @@ -49,41 +53,37 @@ Command *Session::memento_command_factory(XMLNode *n) { error << _("Tried to reconstitute a MementoCommand with no contents, failing. id=") << id.to_s() << endmsg; return 0; - } - - - /* create command */ - string obj_T = n->children().front()->name(); - if (obj_T == "AudioRegion" || obj_T == "MidiRegion" || obj_T == "Region") { + } + + /* create command */ + string obj_T = n->property ("type_name")->value(); + if (obj_T == typeid (AudioRegion).name() || obj_T == typeid (MidiRegion).name() || obj_T == typeid (Region).name()) { if (regions.count(id)) return new MementoCommand<Region>(*regions[id], before, after); - } else if (obj_T == "AudioSource" || obj_T == "MidiSource") { + } else if (obj_T == typeid (AudioSource).name() || obj_T == typeid (MidiSource).name()) { if (sources.count(id)) return new MementoCommand<Source>(*sources[id], before, after); - } else if (obj_T == "Location") { + } else if (obj_T == typeid (Location).name()) { return new MementoCommand<Location>(*_locations.get_location_by_id(id), before, after); - } else if (obj_T == "Locations") { + } else if (obj_T == typeid (Locations).name()) { return new MementoCommand<Locations>(_locations, before, after); - } else if (obj_T == "TempoMap") { + } else if (obj_T == typeid (TempoMap).name()) { return new MementoCommand<TempoMap>(*_tempo_map, before, after); - } else if (obj_T == "Playlist" || obj_T == "AudioPlaylist") { + } else if (obj_T == typeid (Playlist).name() || obj_T == typeid (AudioPlaylist).name()) { if (Playlist *pl = playlist_by_name(child->property("name")->value())) return new MementoCommand<Playlist>(*pl, before, after); - } else if (obj_T == "Route") { // includes AudioTrack + } else if (obj_T == typeid (Route).name() || obj_T == typeid (AudioTrack).name()) { return new MementoCommand<Route>(*route_by_id(id), before, after); - } else if (obj_T == "Curve") { - if (curves.count(id)) - return new MementoCommand<Curve>(*curves[id], before, after); - } else if (obj_T == "AutomationList") { + } else if (obj_T == typeid (Curve).name() || obj_T == typeid (AutomationList).name()) { if (automation_lists.count(id)) return new MementoCommand<AutomationList>(*automation_lists[id], before, after); } else if (registry.count(id)) { // For Editor and AutomationLine which are off-limits here - return new MementoCommand<StatefulDestructible>(*registry[id], before, after); + return new MementoCommand<PBD::StatefulThingWithGoingAway>(*registry[id], before, after); } /* we failed */ - error << _("could not reconstitute MementoCommand from XMLNode. id=") << id.to_s() << endmsg; - return 0; + error << string_compose (_("could not reconstitute MementoCommand from XMLNode. object type = %1 id = %2"), obj_T, id.to_s()) << endmsg; + return 0 ; } // solo diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index ff79a47e6b..bcc9b730ba 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -195,7 +195,7 @@ Session::first_stage_init (string fullpath, string snapshot_name) /* default short fade = 15ms */ Crossfade::set_short_xfade_length ((nframes_t) floor (Config->get_short_xfade_seconds() * frame_rate())); - DestructiveFileSource::setup_standard_crossfades (frame_rate()); + SndFileSource::setup_standard_crossfades (frame_rate()); last_mmc_step.tv_sec = 0; last_mmc_step.tv_usec = 0; @@ -250,10 +250,9 @@ Session::first_stage_init (string fullpath, string snapshot_name) Playlist::PlaylistCreated.connect (mem_fun (*this, &Session::add_playlist)); Redirect::RedirectCreated.connect (mem_fun (*this, &Session::add_redirect)); NamedSelection::NamedSelectionCreated.connect (mem_fun (*this, &Session::add_named_selection)); - Curve::CurveCreated.connect (mem_fun (*this, &Session::add_curve)); AutomationList::AutomationListCreated.connect (mem_fun (*this, &Session::add_automation_list)); - Controllable::GoingAway.connect (mem_fun (*this, &Session::remove_controllable)); + Controllable::Destroyed.connect (mem_fun (*this, &Session::remove_controllable)); IO::MoreChannels.connect (mem_fun (*this, &Session::ensure_buffers)); @@ -533,7 +532,6 @@ Session::create (bool& new_session, string* mix_template, nframes_t initial_leng _state_of_the_state = Clean; if (save_state (_current_snapshot_name)) { - save_history (_current_snapshot_name); return -1; } @@ -858,13 +856,15 @@ Session::state(bool full_state) boost::shared_ptr<AudioFileSource> fs; if ((fs = boost::dynamic_pointer_cast<AudioFileSource> (siter->second)) != 0) { - boost::shared_ptr<DestructiveFileSource> dfs = boost::dynamic_pointer_cast<DestructiveFileSource> (fs); /* Don't save sources that are empty, unless they're destructive (which are OK if they are empty, because we will re-use them every time.) */ - if ( ! dfs && siter->second->length() == 0) { - continue; + + if (!fs->destructive()) { + if (fs->length() == 0) { + continue; + } } } @@ -898,7 +898,20 @@ Session::state(bool full_state) } } - node->add_child_nocopy (_locations.get_state()); + if (full_state) { + node->add_child_nocopy (_locations.get_state()); + } else { + // for a template, just create a new Locations, populate it + // with the default start and end, and get the state for that. + Locations loc; + Location* start = new Location(0, 0, _("start"), Location::Flags ((Location::IsMark|Location::IsStart))); + Location* end = new Location(0, 0, _("end"), Location::Flags ((Location::IsMark|Location::IsEnd))); + start->set_end(0); + loc.add (start); + end->set_end(compute_initial_length()); + loc.add (end); + node->add_child_nocopy (loc.get_state()); + } child = node->add_child ("Connections"); { @@ -1026,8 +1039,6 @@ Session::set_state (const XMLNode& node) return -1; } - StateManager::prohibit_save (); - if ((prop = node.property ("name")) != 0) { _name = prop->value (); } @@ -1058,11 +1069,11 @@ Session::set_state (const XMLNode& node) Path extra Options/Config + Locations Sources AudioRegions AudioDiskstreams Connections - Locations Routes EditGroups MixGroups @@ -1085,6 +1096,39 @@ Session::set_state (const XMLNode& node) error << _("Session: XML state has no options section") << endmsg; } + if ((child = find_named_node (node, "Locations")) == 0) { + error << _("Session: XML state has no locations section") << endmsg; + goto out; + } else if (_locations.set_state (*child)) { + goto out; + } + + Location* location; + + if ((location = _locations.auto_loop_location()) != 0) { + set_auto_loop_location (location); + } + + if ((location = _locations.auto_punch_location()) != 0) { + set_auto_punch_location (location); + } + + if ((location = _locations.end_location()) == 0) { + _locations.add (end_location); + } else { + delete end_location; + end_location = location; + } + + if ((location = _locations.start_location()) == 0) { + _locations.add (start_location); + } else { + delete start_location; + start_location = location; + } + + AudioFileSource::set_header_position_offset (start_location->start()); + if ((child = find_named_node (node, "Sources")) == 0) { error << _("Session: XML state has no sources section") << endmsg; goto out; @@ -1132,39 +1176,6 @@ Session::set_state (const XMLNode& node) goto out; } - if ((child = find_named_node (node, "Locations")) == 0) { - error << _("Session: XML state has no locations section") << endmsg; - goto out; - } else if (_locations.set_state (*child)) { - goto out; - } - - Location* location; - - if ((location = _locations.auto_loop_location()) != 0) { - set_auto_loop_location (location); - } - - if ((location = _locations.auto_punch_location()) != 0) { - set_auto_punch_location (location); - } - - if ((location = _locations.end_location()) == 0) { - _locations.add (end_location); - } else { - delete end_location; - end_location = location; - } - - if ((location = _locations.start_location()) == 0) { - _locations.add (start_location); - } else { - delete start_location; - start_location = location; - } - - _locations.save_state (_("initial state")); - if ((child = find_named_node (node, "EditGroups")) == 0) { error << _("Session: XML state has no edit groups section") << endmsg; goto out; @@ -1209,8 +1220,6 @@ Session::set_state (const XMLNode& node) _state_of_the_state = Clean; - StateManager::allow_save (_("initial state"), true); - if (state_was_pending) { save_state (_current_snapshot_name); remove_pending_capture_state (); @@ -1220,8 +1229,6 @@ Session::set_state (const XMLNode& node) return 0; out: - /* we failed, re-enable state saving but don't actually save internal state */ - StateManager::allow_save (X_("ignored"), false); return ret; } @@ -2210,7 +2217,7 @@ Session::commit_reversible_command (Command *cmd) gettimeofday (&now, 0); current_trans->set_timestamp (now); - history.add (current_trans); + _history.add (current_trans); } Session::GlobalRouteBooleanState @@ -2568,6 +2575,8 @@ Session::cleanup_sources (Session::cleanup_report& rep) capture files. */ + cerr << "checking out source " << i->second->name() << " use_count = " << i->second.use_count() << endl; + if (i->second.use_count() == 1 && i->second->length() > 0) { dead_sources.push_back (i->second); @@ -2757,7 +2766,7 @@ Session::cleanup_sources (Session::cleanup_report& rep) /* dump the history list */ - history.clear (); + _history.clear (); /* save state so we don't end up a session file referring to non-existent sources. @@ -2908,7 +2917,7 @@ Session::save_history (string snapshot_name) string xml_path; string bak_path; - tree.set_root (&history.get_state()); + tree.set_root (&_history.get_state()); if (snapshot_name.empty()) { snapshot_name = _current_snapshot_name; @@ -2935,14 +2944,13 @@ Session::save_history (string snapshot_name) * possible to fix. */ - if (unlink (xml_path.c_str())) - { - error << string_compose (_("could not remove corrupt history file %1"), xml_path) << endmsg; + if (unlink (xml_path.c_str())) { + error << string_compose (_("could not remove corrupt history file %1"), xml_path) << endmsg; } else { - if (rename (bak_path.c_str(), xml_path.c_str())) - { - error << string_compose (_("could not restore history file from backup %1"), bak_path) << endmsg; - } + if (rename (bak_path.c_str(), xml_path.c_str())) + { + error << string_compose (_("could not restore history file from backup %1"), bak_path) << endmsg; + } } return -1; @@ -2972,7 +2980,7 @@ Session::restore_history (string snapshot_name) } /* replace history */ - history.clear(); + _history.clear(); for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) { @@ -3005,7 +3013,7 @@ Session::restore_history (string snapshot_name) } } - history.add (ut); + _history.add (ut); } return 0; @@ -3137,6 +3145,10 @@ Session::config_changed (const char* parameter_name) if (_mtc_port != 0) { session_send_mtc = Config->get_send_mtc(); + if (session_send_mtc) { + /* mark us ready to send */ + next_quarter_frame_to_send = 0; + } } } else if (PARAM_IS ("send-mmc")) { diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 004261fe8e..e9c4e3785f 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -125,7 +125,7 @@ Session::request_play_loop (bool yn) if (!yn && Config->get_seamless_loop() && transport_rolling()) { // request an immediate locate to refresh the diskstreams // after disabling looping - request_locate (_transport_frame-1, true); + request_locate (_transport_frame-1, false); } } @@ -377,9 +377,6 @@ Session::non_realtime_stop (bool abort) } } } - - //FIXME - //deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame); #ifdef LEAVE_TRANSPORT_UNADJUSTED } diff --git a/libs/ardour/sndfile_helpers.cc b/libs/ardour/sndfile_helpers.cc index b308a74c36..4cf644e0e0 100644 --- a/libs/ardour/sndfile_helpers.cc +++ b/libs/ardour/sndfile_helpers.cc @@ -106,11 +106,11 @@ sndfile_endian_format_from_string (string str) string sndfile_file_ending_from_string (string str) -{ +{ static vector<string> file_endings; if (file_endings.empty()) { - file_endings = PBD::internationalize((const char **) sndfile_file_endings_strings); + file_endings = I18N((const char **) sndfile_file_endings_strings); } for (int n = 0; sndfile_header_formats_strings[n]; ++n) { diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc index fcc6a33d81..a30bfcf49b 100644 --- a/libs/ardour/sndfilesource.cc +++ b/libs/ardour/sndfilesource.cc @@ -28,6 +28,8 @@ #include <glibmm/miscutils.h> #include <ardour/sndfilesource.h> +#include <ardour/sndfile_helpers.h> +#include <ardour/utils.h> #include "i18n.h" @@ -35,6 +37,14 @@ using namespace std; using namespace ARDOUR; using namespace PBD; +gain_t* SndFileSource::out_coefficient = 0; +gain_t* SndFileSource::in_coefficient = 0; +nframes_t SndFileSource::xfade_frames = 64; +const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSource::Flag (AudioFileSource::Writable| + AudioFileSource::Removable| + AudioFileSource::RemovableIfEmpty| + AudioFileSource::CanRename); + SndFileSource::SndFileSource (Session& s, const XMLNode& node) : AudioFileSource (s, node) { @@ -164,22 +174,32 @@ SndFileSource::SndFileSource (Session& s, string idstr, SampleFormat sfmt, Heade } void -SndFileSource::init (const string& idstr) +SndFileSource::init (string idstr) { string::size_type pos; string file; + // lets try to keep the object initalizations here at the top + xfade_buf = 0; interleave_buf = 0; interleave_bufsize = 0; sf = 0; _broadcast_info = 0; + string tmp_name; + if ((pos = idstr.find_last_of (':')) == string::npos) { channel = 0; - _name = Glib::path_get_basename (idstr); + tmp_name = idstr; } else { channel = atoi (idstr.substr (pos+1).c_str()); - _name = Glib::path_get_basename (idstr.substr (0, pos)); + tmp_name = idstr.substr (0, pos); + } + + if (is_embedded()) { + _name = tmp_name; + } else { + _name = Glib::path_get_basename (tmp_name); } /* although libsndfile says we don't need to set this, @@ -187,6 +207,17 @@ SndFileSource::init (const string& idstr) */ memset (&_info, 0, sizeof(_info)); + + _capture_start = false; + _capture_end = false; + file_pos = 0; + + if (destructive()) { + xfade_buf = new Sample[xfade_frames]; + timeline_position = header_position_offset; + } + + AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change)); } int @@ -212,27 +243,14 @@ SndFileSource::open () _broadcast_info = new SF_BROADCAST_INFO; memset (_broadcast_info, 0, sizeof (*_broadcast_info)); - /* lookup broadcast info */ - - if (sf_command (sf, SFC_GET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) { - - /* if the file has data but no broadcast info, then clearly, there is no broadcast info */ - - if (_length) { - delete _broadcast_info; - _broadcast_info = 0; - _flags = Flag (_flags & ~Broadcast); - } - - set_timeline_position (header_position_offset); + bool timecode_info_exists; - } else { - - /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits - of the time reference. - */ + set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists)); - set_timeline_position ( _broadcast_info->time_reference_low ); + if (!timecode_info_exists) { + delete _broadcast_info; + _broadcast_info = 0; + _flags = Flag (_flags & ~Broadcast); } if (writable()) { @@ -266,6 +284,10 @@ SndFileSource::~SndFileSource () if (_broadcast_info) { delete _broadcast_info; } + + if (xfade_buf) { + delete [] xfade_buf; + } } float @@ -352,6 +374,16 @@ SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const nframes_t SndFileSource::write_unlocked (Sample *data, nframes_t cnt) { + if (destructive()) { + return destructive_write_unlocked (data, cnt); + } else { + return nondestructive_write_unlocked (data, cnt); + } +} + +nframes_t +SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt) +{ if (!writable()) { return 0; } @@ -403,6 +435,117 @@ SndFileSource::write_unlocked (Sample *data, nframes_t cnt) return cnt; } +nframes_t +SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt) +{ + nframes_t old_file_pos; + + if (!writable()) { + return 0; + } + + if (_capture_start && _capture_end) { + + /* start and end of capture both occur within the data we are writing, + so do both crossfades. + */ + + _capture_start = false; + _capture_end = false; + + /* move to the correct location place */ + file_pos = capture_start_frame - timeline_position; + + // split cnt in half + nframes_t subcnt = cnt / 2; + nframes_t ofilepos = file_pos; + + // fade in + if (crossfade (data, subcnt, 1) != subcnt) { + return 0; + } + + file_pos += subcnt; + Sample * tmpdata = data + subcnt; + + // fade out + subcnt = cnt - subcnt; + if (crossfade (tmpdata, subcnt, 0) != subcnt) { + return 0; + } + + file_pos = ofilepos; // adjusted below + + } else if (_capture_start) { + + /* start of capture both occur within the data we are writing, + so do the fade in + */ + + _capture_start = false; + _capture_end = false; + + /* move to the correct location place */ + file_pos = capture_start_frame - timeline_position; + + if (crossfade (data, cnt, 1) != cnt) { + return 0; + } + + } else if (_capture_end) { + + /* end of capture both occur within the data we are writing, + so do the fade out + */ + + _capture_start = false; + _capture_end = false; + + if (crossfade (data, cnt, 0) != cnt) { + return 0; + } + + } else { + + /* in the middle of recording */ + + if (write_float (data, file_pos, cnt) != cnt) { + return 0; + } + } + + old_file_pos = file_pos; + update_length (file_pos, cnt); + file_pos += cnt; + + if (_build_peakfiles) { + PeakBuildRecord *pbr = 0; + + if (pending_peak_builds.size()) { + pbr = pending_peak_builds.back(); + } + + if (pbr && pbr->frame + pbr->cnt == old_file_pos) { + + /* the last PBR extended to the start of the current write, + so just extend it again. + */ + + pbr->cnt += cnt; + } else { + pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt)); + } + + _peaks_built = false; + } + + if (_build_peakfiles) { + queue_for_peaks (shared_from_this ()); + } + + return cnt; +} + int SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow) { @@ -499,8 +642,10 @@ SndFileSource::set_header_timeline_position () nframes_t SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt) { - if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) != frame_pos) { - error << string_compose (_("%1: cannot seek to %2"), _path, frame_pos) << endmsg; + if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) { + char errbuf[256]; + sf_error_str (0, errbuf, sizeof (errbuf) - 1); + error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg; return 0; } @@ -516,3 +661,286 @@ SndFileSource::natural_position() const { return timeline_position; } + +bool +SndFileSource::set_destructive (bool yn) +{ + if (yn) { + _flags = Flag (_flags | Destructive); + if (!xfade_buf) { + xfade_buf = new Sample[xfade_frames]; + } + clear_capture_marks (); + timeline_position = header_position_offset; + } else { + _flags = Flag (_flags & ~Destructive); + timeline_position = 0; + /* leave xfade buf alone in case we need it again later */ + } + + return true; +} + +void +SndFileSource::clear_capture_marks () +{ + _capture_start = false; + _capture_end = false; +} + +void +SndFileSource::mark_capture_start (nframes_t pos) +{ + if (destructive()) { + if (pos < timeline_position) { + _capture_start = false; + } else { + _capture_start = true; + capture_start_frame = pos; + } + } +} + +void +SndFileSource::mark_capture_end() +{ + if (destructive()) { + _capture_end = true; + } +} + +nframes_t +SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in) +{ + nframes_t xfade = min (xfade_frames, cnt); + nframes_t nofade = cnt - xfade; + Sample* fade_data = 0; + nframes_t fade_position = 0; // in frames + ssize_t retval; + nframes_t file_cnt; + + if (fade_in) { + fade_position = file_pos; + fade_data = data; + } else { + fade_position = file_pos + nofade; + fade_data = data + nofade; + } + + if (fade_position > _length) { + + /* read starts beyond end of data, just memset to zero */ + + file_cnt = 0; + + } else if (fade_position + xfade > _length) { + + /* read ends beyond end of data, read some, memset the rest */ + + file_cnt = _length - fade_position; + + } else { + + /* read is entirely within data */ + + file_cnt = xfade; + } + + if (file_cnt) { + + if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) { + if (retval >= 0 && errno == EAGAIN) { + /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you. + * short or no data there */ + memset (xfade_buf, 0, xfade * sizeof(Sample)); + } else { + error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg; + return 0; + } + } + } + + if (file_cnt != xfade) { + nframes_t delta = xfade - file_cnt; + memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta); + } + + if (nofade && !fade_in) { + if (write_float (data, file_pos, nofade) != nofade) { + error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; + return 0; + } + } + + if (xfade == xfade_frames) { + + nframes_t n; + + /* use the standard xfade curve */ + + if (fade_in) { + + /* fade new material in */ + + for (n = 0; n < xfade; ++n) { + xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]); + } + + } else { + + + /* fade new material out */ + + for (n = 0; n < xfade; ++n) { + xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]); + } + } + + } else if (xfade < xfade_frames) { + + gain_t in[xfade]; + gain_t out[xfade]; + + /* short xfade, compute custom curve */ + + compute_equal_power_fades (xfade, in, out); + + for (nframes_t n = 0; n < xfade; ++n) { + xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]); + } + + } else if (xfade) { + + /* long xfade length, has to be computed across several calls */ + + } + + if (xfade) { + if (write_float (xfade_buf, fade_position, xfade) != xfade) { + error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; + return 0; + } + } + + if (fade_in && nofade) { + if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) { + error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; + return 0; + } + } + + return cnt; +} + +nframes_t +SndFileSource::last_capture_start_frame () const +{ + if (destructive()) { + return capture_start_frame; + } else { + return 0; + } +} + +void +SndFileSource::handle_header_position_change () +{ + if (destructive()) { + if ( _length != 0 ) { + error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg; + //in the future, pop up a dialog here that allows user to regenerate file with new start offset + } else if (writable()) { + timeline_position = header_position_offset; + set_header_timeline_position (); //this will get flushed if/when the file is recorded to + } + } +} + +void +SndFileSource::setup_standard_crossfades (nframes_t rate) +{ + /* This static method is assumed to have been called by the Session + before any DFS's are created. + */ + + xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate); + + if (out_coefficient) { + delete [] out_coefficient; + } + + if (in_coefficient) { + delete [] in_coefficient; + } + + out_coefficient = new gain_t[xfade_frames]; + in_coefficient = new gain_t[xfade_frames]; + + compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient); +} + +void +SndFileSource::set_timeline_position (int64_t pos) +{ + // destructive track timeline postion does not change + // except at instantion or when header_position_offset + // (session start) changes + + if (!destructive()) { + AudioFileSource::set_timeline_position (pos); + } +} + +int +SndFileSource::get_soundfile_info (string path, SoundFileInfo& info, string& error_msg) +{ + SNDFILE *sf; + SF_INFO sf_info; + SF_BROADCAST_INFO binfo; + bool timecode_exists; + + sf_info.format = 0; // libsndfile says to clear this before sf_open(). + + if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) { + char errbuf[256]; + error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1); + return false; + } + + info.samplerate = sf_info.samplerate; + info.channels = sf_info.channels; + info.length = sf_info.frames; + info.format_name = string_compose("Format: %1, %2", + sndfile_major_format(sf_info.format), + sndfile_minor_format(sf_info.format)); + + memset (&binfo, 0, sizeof (binfo)); + info.timecode = get_timecode_info (sf, &binfo, timecode_exists); + + if (!timecode_exists) { + info.timecode = 0; + } + + sf_close (sf); + + return true; +} + +int64_t +SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists) +{ + if (sf_command (sf, SFC_GET_BROADCAST_INFO, binfo, sizeof (*binfo)) != SF_TRUE) { + exists = false; + return (header_position_offset); + } + + /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits + of the time reference. + */ + + exists = true; + int64_t ret = (uint32_t) binfo->time_reference_high; + ret <<= 32; + ret |= (uint32_t) binfo->time_reference_low; + return ret; +} diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc index 86ca0c55f2..8f0afd3507 100644 --- a/libs/ardour/source.cc +++ b/libs/ardour/source.cc @@ -34,6 +34,7 @@ #include <pbd/pthread_utils.h> #include <ardour/source.h> +#include <ardour/playlist.h> #include "i18n.h" @@ -51,6 +52,7 @@ Source::Source (Session& s, string name, DataType type) _name = name; _timestamp = 0; _length = 0; + _in_use = 0; } Source::Source (Session& s, const XMLNode& node) @@ -59,6 +61,7 @@ Source::Source (Session& s, const XMLNode& node) { _timestamp = 0; _length = 0; + _in_use = 0; if (set_state (node) || _type == DataType::NIL) { throw failed_constructor(); @@ -127,3 +130,24 @@ Source::update_length (jack_nframes_t pos, jack_nframes_t cnt) } } +void +Source::add_playlist (Playlist* pl) +{ + _playlists.insert (pl); +} + +void +Source::remove_playlist (Playlist* pl) +{ + std::set<Playlist*>::iterator x; + + if ((x = _playlists.find (pl)) != _playlists.end()) { + _playlists.erase (x); + } +} + +uint32_t +Source::used () const +{ + return _playlists.size(); +} diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc index e9564a6193..001af609dc 100644 --- a/libs/ardour/source_factory.cc +++ b/libs/ardour/source_factory.cc @@ -110,7 +110,7 @@ SourceFactory::create (Session& s, const XMLNode& node) return ret; } - + return boost::shared_ptr<Source>(); } @@ -163,7 +163,6 @@ SourceFactory::create (Session& s, const XMLNode& node) boost::shared_ptr<Source> SourceFactory::createReadable (DataType type, Session& s, string idstr, AudioFileSource::Flag flags, bool announce) { -<<<<<<< .working if (type == DataType::AUDIO) { if (flags & Destructive) { boost::shared_ptr<Source> ret (new DestructiveFileSource (s, idstr, flags)); @@ -197,7 +196,7 @@ SourceFactory::createReadable (DataType type, Session& s, string idstr, AudioFil return ret; } - + return boost::shared_ptr<Source>(); } @@ -220,9 +219,6 @@ SourceFactory::createReadable (DataType type, Session& s, string idstr, AudioFil } else if (type == DataType::MIDI) { boost::shared_ptr<Source> ret (new SMFSource (s, idstr, SMFSource::Flag(0))); // FIXME: flags? - if (setup_peakfile (ret)) { - return boost::shared_ptr<Source>(); - } if (announce) { SourceCreated (ret); } @@ -239,7 +235,6 @@ boost::shared_ptr<Source> SourceFactory::createWritable (DataType type, Session& s, std::string path, bool destructive, nframes_t rate, bool announce) { /* this might throw failed_constructor(), which is OK */ - if (type == DataType::AUDIO) { if (destructive) { diff --git a/libs/ardour/sse_functions_64bit.s b/libs/ardour/sse_functions_64bit.s index 997852eb5b..0242db3e77 100644 --- a/libs/ardour/sse_functions_64bit.s +++ b/libs/ardour/sse_functions_64bit.s @@ -602,3 +602,8 @@ x86_sse_compute_peak: .size x86_sse_compute_peak, .-x86_sse_compute_peak #; end proc + +#ifdef __ELF__ +.section .note.GNU-stack,"",%progbits +#endif + diff --git a/libs/ardour/state_manager.cc b/libs/ardour/state_manager.cc deleted file mode 100644 index 153773ed30..0000000000 --- a/libs/ardour/state_manager.cc +++ /dev/null @@ -1,91 +0,0 @@ -#include <pbd/error.h> -#include <ardour/state_manager.h> - -#include "i18n.h" - -using namespace ARDOUR; -using namespace std; -using namespace PBD; - -bool StateManager::_allow_save = true; -sigc::signal<void,const char*> StateManager::SaveAllowed; - -StateManager::StateManager () -{ - _current_state_id = 0; -} - -StateManager::~StateManager() -{ -} - -void -StateManager::prohibit_save () -{ - _allow_save = false; -} - -void -StateManager::allow_save (const char* why, bool do_save) -{ - _allow_save = true; - if (do_save) { - SaveAllowed (why); - SaveAllowed.slots().erase (SaveAllowed.slots().begin(), SaveAllowed.slots().end()); - } -} - -void -StateManager::drop_all_states () -{ - for (StateMap::iterator i = states.begin(); i != states.end(); ++i) { - delete *i; - } - - states.clear (); - - save_state (_("cleared history")); -} - -void -StateManager::use_state (state_id_t id) -{ - Change what_changed; - state_id_t n; - StateMap::iterator i; - - for (n = 0, i = states.begin(); n < id && i != states.end(); ++n, ++i); - - if (n != id || i == states.end()) { - fatal << string_compose (_("programming error: illegal state ID (%1) passed to " - "StateManager::set_state() (range = 0-%2)"), id, states.size()-1) - << endmsg; - /*NOTREACHED*/ - return; - } - - what_changed = restore_state (**i); - _current_state_id = id; - send_state_changed (what_changed); -} - -void -StateManager::save_state (std::string why) -{ - if (!should_save_state()) - return; - - if (!_allow_save) { - SaveAllowed.connect (mem_fun (*this, &StateManager::save_state)); - return; - } - - states.push_back (state_factory (why)); - _current_state_id = states.size() - 1; -} - -void -StateManager::send_state_changed (Change what_changed) -{ - StateChanged (what_changed); -} diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc index 3cc5420c67..0ff94324bb 100644 --- a/libs/ardour/tempo.cc +++ b/libs/ardour/tempo.cc @@ -206,7 +206,6 @@ TempoMap::TempoMap (nframes_t fr) _frame_rate = fr; last_bbt_valid = false; BBT_Time start; - in_set_state = false; start.bars = 1; start.beats = 1; @@ -222,8 +221,6 @@ TempoMap::TempoMap (nframes_t fr) metrics->push_back (t); metrics->push_back (m); - - save_state (_("initial")); } TempoMap::~TempoMap () @@ -256,7 +253,6 @@ TempoMap::move_metric_section (MetricSection& section, const BBT_Time& when) section.set_start (corrected); metrics->sort (cmp); timestamp_metrics (); - save_state (_("move metric")); return 0; } @@ -265,7 +261,7 @@ void TempoMap::move_tempo (TempoSection& tempo, const BBT_Time& when) { if (move_metric_section (tempo, when) == 0) { - send_state_changed (Change (0)); + StateChanged (Change (0)); } } @@ -273,7 +269,7 @@ void TempoMap::move_meter (MeterSection& meter, const BBT_Time& when) { if (move_metric_section (meter, when) == 0) { - send_state_changed (Change (0)); + StateChanged (Change (0)); } } @@ -301,7 +297,7 @@ TempoMap::remove_tempo (const TempoSection& tempo) } if (removed) { - send_state_changed (Change (0)); + StateChanged (Change (0)); } } @@ -325,14 +321,10 @@ TempoMap::remove_meter (const MeterSection& tempo) } } } - - if (removed) { - save_state (_("metric removed")); - } } if (removed) { - send_state_changed (Change (0)); + StateChanged (Change (0)); } } @@ -369,11 +361,9 @@ TempoMap::add_tempo (const Tempo& tempo, BBT_Time where) where.ticks = 0; do_insert (new TempoSection (where, tempo.beats_per_minute())); - - save_state (_("add tempo")); } - send_state_changed (Change (0)); + StateChanged (Change (0)); } void @@ -397,14 +387,10 @@ TempoMap::replace_tempo (TempoSection& existing, const Tempo& replacement) break; } } - - if (replaced) { - save_state (_("replace tempo")); - } } if (replaced) { - send_state_changed (Change (0)); + StateChanged (Change (0)); } } @@ -431,11 +417,9 @@ TempoMap::add_meter (const Meter& meter, BBT_Time where) where.ticks = 0; do_insert (new MeterSection (where, meter.beats_per_bar(), meter.note_divisor())); - - save_state (_("add meter")); } - send_state_changed (Change (0)); + StateChanged (Change (0)); } void @@ -458,14 +442,10 @@ TempoMap::replace_meter (MeterSection& existing, const Meter& replacement) break; } } - - if (replaced) { - save_state (_("replaced meter")); - } } if (replaced) { - send_state_changed (Change (0)); + StateChanged (Change (0)); } } @@ -1071,6 +1051,9 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const double beat_frame; double beat_frames; double frames_per_bar; + double delta_bars; + double delta_beats; + double dummy; nframes_t limit; meter = &first_meter (); @@ -1100,6 +1083,10 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const Now start generating points. */ + beats_per_bar = meter->beats_per_bar (); + frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate); + beat_frames = tempo->frames_per_beat (_frame_rate); + if (meter->frame() > tempo->frame()) { bar = meter->start().bars; beat = meter->start().beats; @@ -1110,12 +1097,21 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const current = tempo->frame(); } + /* initialize current to point to the bar/beat just prior to the + lower frame bound passed in. assumes that current is initialized + above to be on a beat. + */ + + delta_bars = (lower-current) / frames_per_bar; + delta_beats = modf(delta_bars, &dummy) * beats_per_bar; + current += (floor(delta_bars) * frames_per_bar) + (floor(delta_beats) * beat_frames); + + // adjust bars and beats too + bar += (uint32_t) (floor(delta_bars)); + beat += (uint32_t) (floor(delta_beats)); + points = new BBTPointList; - beats_per_bar = meter->beats_per_bar (); - frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate); - beat_frames = tempo->frames_per_beat (_frame_rate); - do { if (i == metrics->end()) { @@ -1197,6 +1193,10 @@ TempoMap::get_points (nframes_t lower, nframes_t upper) const beat = 1; } + beats_per_bar = meter->beats_per_bar (); + frames_per_bar = meter->frames_per_bar (*tempo, _frame_rate); + beat_frames = tempo->frames_per_beat (_frame_rate); + ++i; } @@ -1246,8 +1246,6 @@ TempoMap::set_state (const XMLNode& node) XMLNodeConstIterator niter; Metrics old_metrics (*metrics); - in_set_state = true; - metrics->clear(); nlist = node.children(); @@ -1287,20 +1285,9 @@ TempoMap::set_state (const XMLNode& node) metrics->sort (cmp); timestamp_metrics (); } - - in_set_state = false; } - /* This state needs to be saved. This string will never be a part of the - object's history though, because the allow_save flag is false during - session load. This state will eventually be tagged "initial state", - by a call to StateManager::allow_save from Session::set_state. - - If this state is not saved, there is no way to reach it through undo actions. - */ - save_state(_("load XML data")); - - send_state_changed (Change (0)); + StateChanged (Change (0)); return 0; } @@ -1323,65 +1310,3 @@ TempoMap::dump (std::ostream& o) const } } -UndoAction -TempoMap::get_memento () const -{ - return sigc::bind (mem_fun (*(const_cast<TempoMap *> (this)), &StateManager::use_state), _current_state_id); -} - -Change -TempoMap::restore_state (StateManager::State& state) -{ - Glib::RWLock::ReaderLock lm (lock); - - TempoMapState* tmstate = dynamic_cast<TempoMapState*> (&state); - - /* We can't just set the metrics pointer to the address of the metrics list - stored in the state, cause this would ruin this state for restoring in - the future. If they have the same address, they are the same list. - Thus we need to copy all the elements from the state metrics list to the - current metrics list. - */ - metrics->clear(); - for (Metrics::iterator i = tmstate->metrics->begin(); i != tmstate->metrics->end(); ++i) { - TempoSection *ts; - MeterSection *ms; - - if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) { - metrics->push_back (new TempoSection (*ts)); - } else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) { - metrics->push_back (new MeterSection (*ms)); - } - } - - last_bbt_valid = false; - - return Change (0); -} - -StateManager::State* -TempoMap::state_factory (std::string why) const -{ - TempoMapState* state = new TempoMapState (why); - - for (Metrics::iterator i = metrics->begin(); i != metrics->end(); ++i) { - TempoSection *ts; - MeterSection *ms; - - if ((ts = dynamic_cast<TempoSection*>(*i)) != 0) { - state->metrics->push_back (new TempoSection (*ts)); - } else if ((ms = dynamic_cast<MeterSection*>(*i)) != 0) { - state->metrics->push_back (new MeterSection (*ms)); - } - } - - return state; -} - -void -TempoMap::save_state (std::string why) -{ - if (!in_set_state) { - StateManager::save_state (why); - } -} diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index 053a866256..a5484813f9 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -50,8 +50,8 @@ Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, Data } Track::Track (Session& sess, const XMLNode& node, DataType default_type) - : Route (sess, "to be renamed", 0, 0, -1, -1, Route::Flag(0), default_type) - , _rec_enable_control (*this) + : Route (sess, node), + _rec_enable_control (*this) { _freeze_record.state = NoFreeze; _declickable = true; @@ -183,18 +183,6 @@ Track::set_record_enable (bool yn, void *src) _rec_enable_control.Changed (); } -void -Track::set_mode (TrackMode m) -{ - if (_diskstream) { - if (_mode != m) { - _mode = m; - _diskstream->set_destructive (m == Destructive); - ModeChanged(); - } - } -} - int Track::set_name (string str, void *src) { diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc index 9a841e81b4..9c94d32241 100644 --- a/libs/ardour/utils.cc +++ b/libs/ardour/utils.cc @@ -38,6 +38,7 @@ #endif #include <pbd/error.h> +#include <pbd/stacktrace.h> #include <pbd/xml++.h> #include <ardour/utils.h> @@ -221,7 +222,7 @@ region_name_from_path (string path) /* remove any "?R", "?L" or "?[a-z]" channel identifier */ string::size_type len = path.length(); - + if (len > 3 && (path[len-2] == '%' || path[len-2] == '?') && (path[len-1] == 'R' || path[len-1] == 'L' || (islower (path[len-1])))) { @@ -299,7 +300,7 @@ compute_equal_power_fades (nframes_t nframes, float* in, float* out) const float pan_law_attenuation = -3.0f; const float scale = 2.0f - 4.0f * powf (10.0f,pan_law_attenuation/20.0f); - for (unsigned long n = 0; n < nframes; ++n) { + for (nframes_t n = 0; n < nframes; ++n) { float inVal = in[n]; float outVal = 1 - inVal; out[n] = outVal * (scale * outVal + 1.0f - scale); @@ -407,3 +408,82 @@ meter_hold_to_float (MeterHold hold) return 200.0f; } } + +AutoState +ARDOUR::string_to_auto_state (std::string str) +{ + if (str == X_("Off")) { + return Off; + } else if (str == X_("Play")) { + return Play; + } else if (str == X_("Write")) { + return Write; + } else if (str == X_("Touch")) { + return Touch; + } + + fatal << string_compose (_("programming error: %1 %2"), "illegal AutoState string: ", str) << endmsg; + /*NOTREACHED*/ + return Touch; +} + +string +ARDOUR::auto_state_to_string (AutoState as) +{ + /* to be used only for XML serialization, no i18n done */ + + switch (as) { + case Off: + return X_("Off"); + break; + case Play: + return X_("Play"); + break; + case Write: + return X_("Write"); + break; + case Touch: + return X_("Touch"); + } + + fatal << string_compose (_("programming error: %1 %2"), "illegal AutoState type: ", as) << endmsg; + /*NOTREACHED*/ + return ""; +} + +AutoStyle +ARDOUR::string_to_auto_style (std::string str) +{ + if (str == X_("Absolute")) { + return Absolute; + } else if (str == X_("Trim")) { + return Trim; + } + + fatal << string_compose (_("programming error: %1 %2"), "illegal AutoStyle string: ", str) << endmsg; + /*NOTREACHED*/ + return Trim; +} + +string +ARDOUR::auto_style_to_string (AutoStyle as) +{ + /* to be used only for XML serialization, no i18n done */ + + switch (as) { + case Absolute: + return X_("Absolute"); + break; + case Trim: + return X_("Trim"); + break; + } + + fatal << string_compose (_("programming error: %1 %2"), "illegal AutoStyle type: ", as) << endmsg; + /*NOTREACHED*/ + return ""; +} + +extern "C" { + void c_stacktrace() { stacktrace (cerr); } +} diff --git a/libs/ardour/vst_plugin.cc b/libs/ardour/vst_plugin.cc index 800c5a9856..5d7a303fc6 100644 --- a/libs/ardour/vst_plugin.cc +++ b/libs/ardour/vst_plugin.cc @@ -110,16 +110,6 @@ VSTPlugin::set_block_size (nframes_t nframes) activate (); } -void -VSTPlugin::store_state (PluginState& state) -{ -} - -void -VSTPlugin::restore_state (PluginState& state) -{ -} - float VSTPlugin::default_value (uint32_t port) { |