From 022818b4a796f52c0a91eea42e65aec0bc7bed43 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Tue, 17 Feb 2009 02:11:49 +0000 Subject: Fix the horrible mess that was anything related to sources and paths. Most significant changes: - Factor out FileSource from AudioFileSource, use for SMFSource too - Explicitly pass embedded rather than mysterious name mangling or whatever - Destroy a ton of duplicated or very-nearly-duplicated code - Clean up and document all that weird source stuff in session.cc git-svn-id: svn://localhost/ardour2/branches/3.0@4609 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/SConscript | 2 +- libs/ardour/ardour/audiofilesource.h | 87 +++---- libs/ardour/ardour/audiosource.h | 6 +- libs/ardour/ardour/file_source.h | 83 +++++++ libs/ardour/ardour/midi_source.h | 10 +- libs/ardour/ardour/route.h | 117 +++++----- libs/ardour/ardour/session.h | 116 +++++----- libs/ardour/ardour/silentfilesource.h | 27 ++- libs/ardour/ardour/smf_source.h | 72 +++--- libs/ardour/ardour/sndfilesource.h | 18 +- libs/ardour/ardour/source.h | 20 +- libs/ardour/ardour/source_factory.h | 6 +- libs/ardour/audio_diskstream.cc | 21 +- libs/ardour/audio_library.cc | 1 - libs/ardour/audiofilesource.cc | 417 +++------------------------------ libs/ardour/audiosource.cc | 12 +- libs/ardour/configuration.cc | 2 +- libs/ardour/file_source.cc | 419 ++++++++++++++++++++++++++++++++++ libs/ardour/filter.cc | 4 +- libs/ardour/import.cc | 11 +- libs/ardour/midi_source.cc | 15 +- libs/ardour/session.cc | 283 +++++++---------------- libs/ardour/session_state.cc | 34 +-- libs/ardour/silentfilesource.cc | 39 ---- libs/ardour/smf_source.cc | 299 +++--------------------- libs/ardour/sndfilesource.cc | 33 +-- libs/ardour/source.cc | 46 +++- libs/ardour/source_factory.cc | 18 +- libs/evoral/evoral/SMF.hpp | 4 +- libs/evoral/src/SMF.cpp | 10 +- 30 files changed, 966 insertions(+), 1266 deletions(-) create mode 100644 libs/ardour/ardour/file_source.h create mode 100644 libs/ardour/file_source.cc delete mode 100644 libs/ardour/silentfilesource.cc (limited to 'libs') diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index 83b7d659b5..d30c276840 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -86,6 +86,7 @@ export_status.cc export_timespan.cc export_utilities.cc filename_extensions.cc +file_source.cc filesystem_paths.cc filter.cc find_session.cc @@ -152,7 +153,6 @@ session_state_utils.cc session_time.cc session_transport.cc session_utils.cc -silentfilesource.cc smf_source.cc sndfile_helpers.cc sndfileimportable.cc diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h index 249651c3cf..2b59de63ca 100644 --- a/libs/ardour/ardour/audiofilesource.h +++ b/libs/ardour/ardour/audiofilesource.h @@ -21,18 +21,12 @@ #define __ardour_audiofilesource_h__ #include - #include - #include +#include namespace ARDOUR { -class non_existent_source : public std::exception { - public: - virtual const char *what() const throw() { return "audio file does not exist"; } -}; - struct SoundFileInfo { float samplerate; uint16_t channels; @@ -41,107 +35,78 @@ struct SoundFileInfo { int64_t timecode; }; -class AudioFileSource : public AudioSource { - public: +class AudioFileSource : public AudioSource, public FileSource { +public: virtual ~AudioFileSource (); bool set_name (const std::string& newname) { return (set_source_name(newname, destructive()) == 0); } - int set_source_name (Glib::ustring newname, bool destructive); - Glib::ustring path() const { return _path; } Glib::ustring peak_path (Glib::ustring audio_path); Glib::ustring find_broken_peakfile (Glib::ustring missing_peak_path, Glib::ustring audio_path); - uint16_t channel() const { return _channel; } - static void set_peak_dir (Glib::ustring dir) { peak_dir = dir; } static bool get_soundfile_info (Glib::ustring path, SoundFileInfo& _info, std::string& error); - static bool safe_file_extension (Glib::ustring path); - - void set_allow_remove_if_empty (bool yn); - void mark_for_remove(); + bool safe_file_extension (const Glib::ustring& path) const { + return safe_audio_file_extension(path); + } /* this block of methods do nothing for regular file sources, but are significant for files used in destructive recording. */ virtual nframes_t last_capture_start_frame() const { return 0; } - virtual void mark_capture_start (nframes_t) {} - virtual void mark_capture_end () {} - virtual void clear_capture_marks() {} - virtual bool one_of_several_channels () const { return false; } + virtual void mark_capture_start (nframes_t) {} + virtual void mark_capture_end () {} + virtual void clear_capture_marks() {} + virtual bool one_of_several_channels () const { return false; } virtual int update_header (nframes_t when, struct tm&, time_t) = 0; virtual int flush_header () = 0; - int move_to_trash (const Glib::ustring& trash_dir_name); - - static bool is_empty (Session&, Glib::ustring path); void mark_streaming_write_completed (); - void mark_take (Glib::ustring); - Glib::ustring 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 (Glib::ustring string); - static void set_header_position_offset (nframes_t offset ); - int setup_peakfile (); XMLNode& get_state (); int set_state (const XMLNode&); - bool destructive() const { return (_flags & Destructive); } - virtual bool set_destructive (bool yn) { return false; } - bool can_truncate_peaks() const { return !destructive(); } - bool can_be_analysed() const { return _length > 0; } - - void mark_immutable (); + bool can_truncate_peaks() const { return !destructive(); } + bool can_be_analysed() const { return _length > 0; } + static bool safe_audio_file_extension (const Glib::ustring& path); + + static bool is_empty (Session&, Glib::ustring path); + + static void set_bwf_serial_number (int); + static void set_header_position_offset (nframes_t offset ); + static sigc::signal HeaderPositionOffsetChanged; - protected: - +protected: /** Constructor to be called for existing external-to-session files */ - AudioFileSource (Session&, Glib::ustring path, Source::Flag flags); + AudioFileSource (Session&, const Glib::ustring& path, bool embedded, Source::Flag flags); /** Constructor to be called for new in-session files */ - AudioFileSource (Session&, Glib::ustring path, Source::Flag flags, + AudioFileSource (Session&, const Glib::ustring& path, bool embedded, Source::Flag flags, SampleFormat samp_format, HeaderFormat hdr_format); /** Constructor to be called for existing in-session files */ - AudioFileSource (Session&, const XMLNode&, bool must_exit = true); + AudioFileSource (Session&, const XMLNode&, bool must_exist = true); - int init (Glib::ustring idstr, bool must_exist); - - static bool determine_embeddedness (Glib::ustring path); + int init (const Glib::ustring& idstr, bool must_exist); - virtual void set_timeline_position (int64_t pos); virtual void set_header_timeline_position () = 0; virtual void handle_header_position_change () {} - - bool find (Glib::ustring& path, bool must_exist, bool& is_new, uint16_t& chan); - bool removable() const; - bool writable() const { return _flags & Writable; } + + int move_dependents_to_trash(); static Sample* get_interleave_buffer (nframes_t size); - Glib::ustring _path; - Glib::ustring _take_id; - int64_t _timeline_position; - bool _file_is_new; - uint16_t _channel; - bool _is_embedded; - static Glib::ustring peak_dir; - static Glib::ustring search_path; static char bwf_country_code[3]; static char bwf_organization_code[4]; diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h index 43273301b1..eff21b898c 100644 --- a/libs/ardour/ardour/audiosource.h +++ b/libs/ardour/ardour/audiosource.h @@ -43,7 +43,7 @@ using std::vector; namespace ARDOUR { -class AudioSource : public Source, public boost::enable_shared_from_this +class AudioSource : virtual public Source, public boost::enable_shared_from_this { public: AudioSource (Session&, Glib::ustring name); @@ -68,7 +68,6 @@ class AudioSource : public Source, public boost::enable_shared_from_this +#include +#include + +namespace ARDOUR { + +class MissingSource : public std::exception { +public: + virtual const char *what() const throw() { return "source file does not exist"; } +}; + +/** A source associated with a file on disk somewhere */ +class FileSource : virtual public Source { +public: + const Glib::ustring& path() const { return _path; } + + virtual bool safe_file_extension (const Glib::ustring& path) const = 0; + + int move_to_trash (const Glib::ustring& trash_dir_name); + void mark_take (const Glib::ustring& id); + void mark_immutable (); + + const Glib::ustring& take_id () const { return _take_id; } + bool is_embedded () const { return _is_embedded; } + uint16_t channel() const { return _channel; } + + int set_state (const XMLNode&); + + int set_source_name (const Glib::ustring& newname, bool destructive); + + static void set_search_path (DataType type, const Glib::ustring& path); + +protected: + FileSource (Session& session, DataType type, + const Glib::ustring& path, bool embedded, + Source::Flag flags = Source::Flag(0)); + + FileSource (Session& session, const XMLNode& node, bool must_exist); + + virtual int init (const Glib::ustring& idstr, bool must_exist); + + virtual int move_dependents_to_trash() { return 0; } + + bool find (DataType type, const Glib::ustring& path, + bool must_exist, bool& is_new, uint16_t& chan); + + bool removable () const; + + Glib::ustring _path; + Glib::ustring _take_id; + bool _file_is_new; + uint16_t _channel; + bool _is_embedded; + + static map search_paths; +}; + +} // namespace ARDOUR + +#endif /* __ardour_filesource_h__ */ + diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h index 0dedb3282d..0bc431a8d8 100644 --- a/libs/ardour/ardour/midi_source.h +++ b/libs/ardour/ardour/midi_source.h @@ -38,7 +38,7 @@ class MidiModel; template class MidiRingBuffer; /** Source for MIDI data */ -class MidiSource : public Source +class MidiSource : virtual public Source { public: typedef double TimeType; @@ -60,14 +60,10 @@ class MidiSource : public Source virtual void append_event_unlocked_beats(const Evoral::Event& ev) = 0; virtual void append_event_unlocked_frames(const Evoral::Event& ev) = 0; - virtual void mark_for_remove() = 0; virtual void mark_streaming_midi_write_started (NoteMode mode, nframes_t start_time); virtual void mark_streaming_write_started (); virtual void mark_streaming_write_completed (); - uint64_t timeline_position () { return _timeline_position; } - void set_timeline_position (nframes_t when); - virtual void session_saved(); std::string captured_for() const { return _captured_for; } @@ -90,6 +86,8 @@ class MidiSource : public Source virtual void destroy_model() = 0; void set_note_mode(NoteMode mode); + + void set_timeline_position (int64_t pos); boost::shared_ptr model() { return _model; } void set_model(boost::shared_ptr m) { _model = m; } @@ -106,9 +104,7 @@ class MidiSource : public Source nframes_t stamp_offset, nframes_t negative_stamp_offset) const = 0; virtual nframes_t write_unlocked (MidiRingBuffer& dst, nframes_t cnt) = 0; - mutable Glib::Mutex _lock; std::string _captured_for; - uint64_t _timeline_position; mutable uint32_t _read_data_count; ///< modified in read() mutable uint32_t _write_data_count; ///< modified in write() diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 98b7fa0d64..217ce36fe9 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -70,7 +70,6 @@ class Route : public IO ControlOut = 0x4 }; - 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&, DataType default_type = DataType::AUDIO); @@ -91,14 +90,15 @@ class Route : public IO /* these are the core of the API of a Route. see the protected sections as well */ - 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); + 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); + + virtual int no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, + nframes_t offset, bool state_changing, bool can_record, bool rec_monitors_input); - virtual int no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, - nframes_t offset, bool state_changing, bool can_record, bool rec_monitors_input); + virtual int silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, + nframes_t offset, bool can_record, bool rec_monitors_input); - virtual int silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, - nframes_t offset, bool can_record, bool rec_monitors_input); virtual void toggle_monitor_input (); virtual bool can_record() { return false; } virtual void set_record_enable (bool yn, void *src) {} @@ -136,8 +136,8 @@ class Route : public IO void drop_mix_group (void *); RouteGroup *mix_group () { return _mix_group; } - virtual void set_meter_point (MeterPoint, void *src); - MeterPoint meter_point() const { return _meter_point; } + virtual void set_meter_point (MeterPoint, void *src); + MeterPoint meter_point() const { return _meter_point; } /* Processors */ @@ -271,56 +271,53 @@ class Route : public IO void curve_reallocate (); protected: - Flag _flags; - - /* tight cache-line access here is more important than sheer speed of - access. - */ - - bool _muted : 1; - bool _soloed : 1; - bool _solo_safe : 1; - bool _recordable : 1; - bool _mute_affects_pre_fader : 1; - bool _mute_affects_post_fader : 1; - bool _mute_affects_control_outs : 1; - bool _mute_affects_main_outs : 1; - bool _silent : 1; - bool _declickable : 1; - int _pending_declick; + nframes_t check_initial_delay (nframes_t, nframes_t&, nframes_t&); - MeterPoint _meter_point; - - gain_t solo_gain; - gain_t mute_gain; - gain_t desired_solo_gain; - gain_t desired_mute_gain; - - - - nframes_t _initial_delay; - nframes_t _roll_delay; - ProcessorList _processors; - Glib::RWLock _processor_lock; - IO *_control_outs; - Glib::Mutex _control_outs_lock; - RouteGroup *_edit_group; - RouteGroup *_mix_group; - std::string _comment; - bool _have_internal_generator; + void passthru (nframes_t start_frame, nframes_t end_frame, + nframes_t nframes, nframes_t offset, int declick, bool meter_inputs); - boost::shared_ptr _solo_control; - boost::shared_ptr _mute_control; + virtual void process_output_buffers (BufferSet& bufs, + nframes_t start_frame, nframes_t end_frame, + nframes_t nframes, nframes_t offset, bool with_processors, int declick, + bool meter); + + Flag _flags; + int _pending_declick; + MeterPoint _meter_point; + + gain_t solo_gain; + gain_t mute_gain; + gain_t desired_solo_gain; + gain_t desired_mute_gain; - nframes_t check_initial_delay (nframes_t, nframes_t&, nframes_t&); + nframes_t _initial_delay; + nframes_t _roll_delay; + ProcessorList _processors; + Glib::RWLock _processor_lock; + IO *_control_outs; + Glib::Mutex _control_outs_lock; + RouteGroup *_edit_group; + RouteGroup *_mix_group; + std::string _comment; + bool _have_internal_generator; - void passthru (nframes_t start_frame, nframes_t end_frame, - nframes_t nframes, nframes_t offset, int declick, bool meter_inputs); + boost::shared_ptr _solo_control; + boost::shared_ptr _mute_control; - virtual void process_output_buffers (BufferSet& bufs, - nframes_t start_frame, nframes_t end_frame, - nframes_t nframes, nframes_t offset, bool with_processors, int declick, - bool meter); + /* tight cache-line access here is more important than sheer speed of access. + keep these after things that should be aligned + */ + + bool _muted : 1; + bool _soloed : 1; + bool _solo_safe : 1; + bool _recordable : 1; + bool _mute_affects_pre_fader : 1; + bool _mute_affects_post_fader : 1; + bool _mute_affects_control_outs : 1; + bool _mute_affects_main_outs : 1; + bool _silent : 1; + bool _declickable : 1; protected: @@ -348,10 +345,8 @@ class Route : public IO static uint32_t order_key_cnt; - struct ltstr - { - bool operator()(const char* s1, const char* s2) const - { + struct ltstr { + bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } }; @@ -365,8 +360,7 @@ class Route : public IO int reset_processor_counts (ProcessorStreams*); /* locked */ int _reset_processor_counts (ProcessorStreams*); /* unlocked */ - /* processor I/O channels and plugin count handling */ - + /** processor I/O channels and plugin count handling */ struct ProcessorCount { boost::shared_ptr processor; ChanCount in; @@ -376,7 +370,8 @@ class Route : public IO }; int32_t apply_some_processor_counts (std::list& iclist); - bool check_some_processor_counts (std::list& iclist, ChanCount required_inputs, ProcessorStreams* err_streams); + bool check_some_processor_counts (std::list& iclist, + ChanCount required_inputs, ProcessorStreams* err_streams); void set_deferred_state (); void add_processor_from_xml (const XMLNode&); diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index ef67d0cc79..2e56e99722 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -150,9 +150,7 @@ class Session : public PBD::StatefulDestructible SetAudioRange, SetPlayRange, - /* only one of each of these events - can be queued at any one time - */ + /* only one of each of these events can be queued at any one time */ StopOnce, AutoLoop @@ -165,32 +163,33 @@ class Session : public PBD::StatefulDestructible Clear }; - Type type; - Action action; - nframes_t action_frame; - nframes_t target_frame; - double speed; + Type type; + Action action; + nframes_t action_frame; + nframes_t target_frame; + double speed; union { - void* ptr; - bool yes_or_no; - nframes_t target2_frame; - SlaveSource slave; - Route* route; + void* ptr; + bool yes_or_no; + nframes_t target2_frame; + SlaveSource slave; + Route* route; }; - boost::shared_ptr region; - - list audio_range; - list music_range; + list audio_range; + list music_range; + + boost::shared_ptr region; Event(Type t, Action a, nframes_t when, nframes_t where, double spd, bool yn = false) - : type (t), - action (a), - action_frame (when), - target_frame (where), - speed (spd), - yes_or_no (yn) {} + : type (t) + , action (a) + , action_frame (when) + , target_frame (where) + , speed (spd) + , yes_or_no (yn) + {} void set_ptr (void* p) { ptr = p; @@ -275,12 +274,12 @@ class Session : public PBD::StatefulDestructible Glib::ustring peak_path (Glib::ustring) const; - static string change_audio_path_by_name (string oldpath, string oldname, string newname, bool destructive); - static string change_midi_path_by_name (string oldpath, string oldname, string newname, bool destructive); + static string change_source_path_by_name (string oldpath, string oldname, string newname, bool destructive); string peak_path_from_audio_path (string) const; - string audio_path_from_name (string, uint32_t nchans, uint32_t chan, bool destructive); - string midi_path_from_name (string); + string new_audio_source_name (const string&, uint32_t nchans, uint32_t chan, bool destructive); + string new_midi_source_name (const string&); + string new_source_path_from_name (DataType type, const string&); void process (nframes_t nframes); @@ -400,16 +399,15 @@ class Session : public PBD::StatefulDestructible bool transport_locked () const; int wipe (); - //int wipe_diskstream (AudioDiskstream *); int remove_region_from_region_list (boost::shared_ptr); nframes_t get_maximum_extent () const; nframes_t current_end_frame() const { return end_location->start(); } nframes_t current_start_frame() const { return start_location->start(); } - // "actual" sample rate of session, set by current audioengine rate, pullup/down etc. + /// "actual" sample rate of session, set by current audioengine rate, pullup/down etc. nframes_t frame_rate() const { return _current_frame_rate; } - // "native" sample rate of session, regardless of current audioengine rate, pullup/down etc + /// "native" sample rate of session, regardless of current audioengine rate, pullup/down etc nframes_t nominal_frame_rate() const { return _nominal_frame_rate; } nframes_t frames_per_hour() const { return _frames_per_hour; } @@ -441,10 +439,10 @@ class Session : public PBD::StatefulDestructible void remove_event (nframes_t frame, Event::Type type); void clear_events (Event::Type type); - nframes_t get_block_size() const { return current_block_size; } + nframes_t get_block_size() const { return current_block_size; } nframes_t worst_output_latency () const { return _worst_output_latency; } - nframes_t worst_input_latency () const { return _worst_input_latency; } - nframes_t worst_track_latency () const { return _worst_track_latency; } + nframes_t worst_input_latency () const { return _worst_input_latency; } + nframes_t worst_track_latency () const { return _worst_track_latency; } int save_state (std::string snapshot_name, bool pending = false); int restore_state (std::string snapshot_name); @@ -470,7 +468,7 @@ class Session : public PBD::StatefulDestructible /// The instant xml file is written to the session directory void add_instant_xml (XMLNode&, bool write_to_config = true); - XMLNode * instant_xml (const std::string& str); + XMLNode* instant_xml (const std::string& str); enum StateOfTheState { Clean = 0x0, @@ -495,8 +493,8 @@ class Session : public PBD::StatefulDestructible sigc::signal edit_group_added; sigc::signal mix_group_added; - sigc::signal edit_group_removed; - sigc::signal mix_group_removed; + sigc::signal edit_group_removed; + sigc::signal mix_group_removed; void foreach_edit_group (sigc::slot sl) { for (list::iterator i = edit_groups.begin(); i != edit_groups.end(); i++) { @@ -512,11 +510,13 @@ class Session : public PBD::StatefulDestructible /* fundamental operations. duh. */ - std::list > new_audio_track (int input_channels, int output_channels, TrackMode mode = Normal, uint32_t how_many = 1); + std::list > new_audio_track ( + int input_channels, int output_channels, TrackMode mode = Normal, uint32_t how_many = 1); + RouteList new_audio_route (int input_channels, int output_channels, uint32_t how_many); - std::list > new_midi_track (TrackMode mode = Normal, uint32_t how_many = 1); - //boost::shared_ptr new_midi_route (uint32_t how_many = 1); + std::list > new_midi_track ( + TrackMode mode = Normal, uint32_t how_many = 1); void remove_route (boost::shared_ptr); void resort_routes (); @@ -552,8 +552,8 @@ class Session : public PBD::StatefulDestructible void sync_time_vars(); void bbt_time (nframes_t when, BBT_Time&); - void smpte_to_sample( SMPTE::Time& smpte, nframes_t& sample, bool use_offset, bool use_subframes ) const; - void sample_to_smpte( nframes_t sample, SMPTE::Time& smpte, bool use_offset, bool use_subframes ) const; + void smpte_to_sample(SMPTE::Time& smpte, nframes_t& sample, bool use_offset, bool use_subframes) const; + void sample_to_smpte(nframes_t sample, SMPTE::Time& smpte, bool use_offset, bool use_subframes) const; void smpte_time (SMPTE::Time &); void smpte_time (nframes_t when, SMPTE::Time&); void smpte_time_subframes (nframes_t when, SMPTE::Time&); @@ -656,23 +656,19 @@ class Session : public PBD::StatefulDestructible int remove_last_capture (); - /* handlers should return -1 for "stop cleanup", 0 for - "yes, delete this playlist" and 1 for "no, don't delete - this playlist. + /** handlers should return -1 for "stop cleanup", + 0 for "yes, delete this playlist", + 1 for "no, don't delete this playlist". */ - sigc::signal > AskAboutPlaylistDeletion; - /* handlers should return 0 for "ignore the rate mismatch" - and !0 for "do not use this session" + /** handlers should return 0 for "ignore the rate mismatch", + !0 for "do not use this session" */ - static sigc::signal AskAboutSampleRateMismatch; - /* handlers should return !0 for use pending state, 0 for - ignore it. + /** handlers should return !0 for use pending state, 0 for ignore it. */ - static sigc::signal AskAboutPendingState; boost::shared_ptr create_audio_source_for_session (ARDOUR::AudioDiskstream&, uint32_t which_channel, bool destructive); @@ -780,7 +776,7 @@ class Session : public PBD::StatefulDestructible sigc::signal > BundleAdded; sigc::signal > BundleRemoved; - /* MIDI */ + /* MIDI control */ void midi_panic(void); int set_mtc_port (string port_tag); @@ -917,7 +913,7 @@ class Session : public PBD::StatefulDestructible /* clicking */ - boost::shared_ptr click_io() { return _click_io; } + boost::shared_ptr click_io() { return _click_io; } /* disk, buffer loads */ @@ -1078,10 +1074,10 @@ class Session : public PBD::StatefulDestructible bool follow_slave (nframes_t, nframes_t); void calculate_moving_average_of_slave_delta(int dir, nframes_t this_delta); void track_slave_state( - float slave_speed, + float slave_speed, nframes_t slave_transport_frame, nframes_t this_delta, - bool starting); + bool starting); void follow_slave_silently(nframes_t nframes, nframes_t offset, float slave_speed); void set_slave_source (SlaveSource); @@ -1119,7 +1115,6 @@ class Session : public PBD::StatefulDestructible } int get_transport_declick_required () { - if (transport_sub_state & PendingDeclickIn) { transport_sub_state &= ~PendingDeclickIn; return 1; @@ -1131,7 +1126,8 @@ class Session : public PBD::StatefulDestructible } bool maybe_stop (nframes_t limit) { - if ((_transport_speed > 0.0f && _transport_frame >= limit) || (_transport_speed < 0.0f && _transport_frame == 0)) { + if ( (_transport_speed > 0.0f && _transport_frame >= limit) + || (_transport_speed < 0.0f && _transport_frame == 0) ) { stop_transport (); return true; } @@ -1194,7 +1190,9 @@ class Session : public PBD::StatefulDestructible mutable gint butler_should_do_transport_work; int butler_request_pipe[2]; - inline bool transport_work_requested() const { return g_atomic_int_get(&butler_should_do_transport_work); } + inline bool transport_work_requested() const { + return g_atomic_int_get(&butler_should_do_transport_work); + } struct ButlerRequest { enum Type { @@ -1498,8 +1496,6 @@ class Session : public PBD::StatefulDestructible SourceMap get_sources() { return sources; } private: - - int load_sources (const XMLNode& node); XMLNode& get_sources_as_xml (); diff --git a/libs/ardour/ardour/silentfilesource.h b/libs/ardour/ardour/silentfilesource.h index cbb123139a..ad433e5f94 100644 --- a/libs/ardour/ardour/silentfilesource.h +++ b/libs/ardour/ardour/silentfilesource.h @@ -26,26 +26,27 @@ namespace ARDOUR { class SilentFileSource : public AudioFileSource { - public: - virtual ~SilentFileSource (); - +public: int update_header (nframes_t when, struct tm&, time_t) { return 0; } int flush_header () { return 0; } float sample_rate () const { return _sample_rate; } - void set_length (nframes_t len); + void set_length (nframes_t len) { _length = len; } bool destructive() const { return false; } bool can_be_analysed() const { return false; } - protected: - - float _sample_rate; - - SilentFileSource (Session&, const XMLNode&, nframes_t nframes, float sample_rate); - +protected: friend class SourceFactory; + SilentFileSource (Session& s, const XMLNode& x, nframes_t len, float srate) + : Source (s, x) + , AudioFileSource (s, x, false) + , _sample_rate(srate) + { + _length = len; + } + nframes_t read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const { memset (dst, 0, sizeof (Sample) * cnt); return cnt; @@ -55,11 +56,13 @@ class SilentFileSource : public AudioFileSource { void set_header_timeline_position () {} - int read_peaks_with_fpp (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, double samples_per_unit, nframes_t fpp) const { + int read_peaks_with_fpp (PeakData *peaks, nframes_t npeaks, nframes_t start, nframes_t cnt, + double samples_per_unit, nframes_t fpp) const { memset (peaks, 0, sizeof (PeakData) * npeaks); return 0; } - + + float _sample_rate; }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h index 4855cb6e31..259328c5fa 100644 --- a/libs/ardour/ardour/smf_source.h +++ b/libs/ardour/ardour/smf_source.h @@ -18,14 +18,14 @@ */ -#ifndef __ardour_smf_filesource_h__ -#define __ardour_smf_filesource_h__ +#ifndef __ardour_smf_source_h__ +#define __ardour_smf_source_h__ #include #include - -#include #include +#include +#include namespace Evoral { template class Event; } @@ -34,51 +34,42 @@ namespace ARDOUR { template class MidiRingBuffer; /** Standard Midi File (Type 0) Source */ -class SMFSource : public MidiSource, public Evoral::SMF { - public: +class SMFSource : public MidiSource, public FileSource, public Evoral::SMF { +public: /** Constructor for existing external-to-session files */ - SMFSource (Session& session, std::string path, Source::Flag flags = Source::Flag(0)); + SMFSource (Session& session, const Glib::ustring& path, bool embedded, + Source::Flag flags = Source::Flag(0)); - /* Constructor for existing in-session files */ - SMFSource (Session& session, const XMLNode&); + /** Constructor for existing in-session files */ + SMFSource (Session& session, const XMLNode&, bool must_exist = false); virtual ~SMFSource (); - - bool set_name (const std::string& newname) { return (set_source_name(newname, false) == 0); } - int set_source_name (string newname, bool destructive); - - static bool safe_file_extension (const Glib::ustring& path); - Glib::ustring path() const { return _path; } + bool safe_file_extension (const Glib::ustring& path) const { + return safe_midi_file_extension(path); + } - void set_allow_remove_if_empty (bool yn); - void mark_for_remove(); + bool set_name (const std::string& newname) { return (set_source_name(newname, false) == 0); } - void append_event_unlocked_beats(const Evoral::Event& ev); - void append_event_unlocked_frames(const Evoral::Event& ev); - - int move_to_trash (const string trash_dir_name); + void append_event_unlocked_beats (const Evoral::Event& ev); + void append_event_unlocked_frames (const Evoral::Event& ev); void mark_streaming_midi_write_started (NoteMode mode, nframes_t start_time); void mark_streaming_write_completed (); - void mark_take (string); - string take_id() const { return _take_id; } - - static void set_search_path (string); - static void set_header_position_offset (nframes_t offset, bool negative); - XMLNode& get_state (); int set_state (const XMLNode&); - void load_model(bool lock=true, bool force_reload=false); - void destroy_model(); + void load_model (bool lock=true, bool force_reload=false); + void destroy_model (); - void flush_midi(); + void flush_midi (); + + static void set_header_position_offset (nframes_t offset, bool negative); - private: - int init (string idstr, bool must_exist); + static bool safe_midi_file_extension (const Glib::ustring& path); +private: nframes_t read_unlocked ( MidiRingBuffer& dst, nframes_t start, @@ -90,22 +81,13 @@ class SMFSource : public MidiSource, public Evoral::SMF { MidiRingBuffer& src, nframes_t cnt); - bool find (std::string path, bool must_exist, bool& is_new); - bool removable() const; - bool writable() const { return _flags & Writable; } - - void set_default_controls_interpolation(); - - Glib::ustring _path; - string _take_id; - bool _allow_remove_if_empty; - double _last_ev_time_beats; - nframes_t _last_ev_time_frames; + void set_default_controls_interpolation (); - static string _search_path; + double _last_ev_time_beats; + nframes_t _last_ev_time_frames; }; }; /* namespace ARDOUR */ -#endif /* __ardour_smf_filesource_h__ */ +#endif /* __ardour_smf_source_h__ */ diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h index acb03391a4..5154a7a80c 100644 --- a/libs/ardour/ardour/sndfilesource.h +++ b/libs/ardour/ardour/sndfilesource.h @@ -29,17 +29,15 @@ namespace ARDOUR { class SndFileSource : public AudioFileSource { public: - /* constructor to be called for existing external-to-session files */ + /** Constructor to be called for existing external-to-session files */ + SndFileSource (Session&, const Glib::ustring& path, bool embedded, int chn, Flag flags); - SndFileSource (Session&, Glib::ustring path, int chn, Flag flags); - - /* constructor to be called for new in-session files */ - - SndFileSource (Session&, Glib::ustring path, SampleFormat samp_format, HeaderFormat hdr_format, nframes_t rate, - Flag flags = SndFileSource::default_writable_flags); + /* Constructor to be called for new in-session files */ + SndFileSource (Session&, const Glib::ustring& path, bool embedded, + SampleFormat samp_format, HeaderFormat hdr_format, nframes_t rate, + Flag flags = SndFileSource::default_writable_flags); - /* constructor to be called for existing in-session files */ - + /** Constructor to be called for existing in-session files */ SndFileSource (Session&, const XMLNode&); ~SndFileSource (); @@ -77,7 +75,7 @@ class SndFileSource : public AudioFileSource { SF_INFO _info; BroadcastInfo *_broadcast_info; - void init (); + void init_sndfile (); int open(); int setup_broadcast_info (nframes_t when, struct tm&, time_t); diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h index 137aad5fbe..7b5fc43659 100644 --- a/libs/ardour/ardour/source.h +++ b/libs/ardour/ardour/source.h @@ -51,7 +51,7 @@ class Source : public SessionObject, public ARDOUR::Readable Destructive = 0x80 }; - Source (Session&, const std::string& name, DataType type, Flag flags=Flag(0)); + Source (Session&, DataType type, const std::string& name, Flag flags=Flag(0)); Source (Session&, const XMLNode&); virtual ~Source (); @@ -63,11 +63,12 @@ class Source : public SessionObject, public ARDOUR::Readable nframes_t length() const { return _length; } - virtual Glib::ustring path() const = 0; + virtual const Glib::ustring& path() const = 0; virtual nframes_t natural_position() const { return 0; } - virtual void mark_for_remove() = 0; + void mark_for_remove(); + virtual void mark_streaming_write_started () {} virtual void mark_streaming_write_completed () = 0; @@ -76,8 +77,10 @@ class Source : public SessionObject, public ARDOUR::Readable XMLNode& get_state (); int set_state (const XMLNode&); - virtual bool destructive() const { return false; } - virtual bool length_mutable() const { return false; } + bool destructive() const { return (_flags & Destructive); } + bool writable () const { return _flags & Writable; } + virtual bool set_destructive (bool yn) { return false; } + virtual bool length_mutable() const { return false; } void use () { _in_use++; } void disuse () { if (_in_use) { _in_use--; } } @@ -103,6 +106,11 @@ class Source : public SessionObject, public ARDOUR::Readable void update_length (nframes_t pos, nframes_t cnt); + int64_t timeline_position() const { return _timeline_position; } + virtual void set_timeline_position (int64_t pos); + + void set_allow_remove_if_empty (bool yn); + virtual const Evoral::TimeConverter& time_converter() const { return Evoral::IdentityConverter(); } @@ -114,7 +122,9 @@ class Source : public SessionObject, public ARDOUR::Readable Flag _flags; time_t _timestamp; nframes_t _length; + int64_t _timeline_position; bool _analysed; + mutable Glib::Mutex _lock; mutable Glib::Mutex _analysis_lock; Glib::Mutex _playlist_lock; diff --git a/libs/ardour/ardour/source_factory.h b/libs/ardour/ardour/source_factory.h index 5370ad845d..69aa641657 100644 --- a/libs/ardour/ardour/source_factory.h +++ b/libs/ardour/ardour/source_factory.h @@ -44,10 +44,12 @@ class SourceFactory { static boost::shared_ptr createSilent (Session&, const XMLNode& node, nframes_t nframes, float sample_rate); - static boost::shared_ptr createReadable (DataType type, Session&, std::string path, + static boost::shared_ptr createReadable (DataType type, Session&, + const std::string& path, bool embedded, int chn, Source::Flag flags, bool announce = true, bool async = false); - static boost::shared_ptr createWritable (DataType type, Session&, std::string name, + static boost::shared_ptr createWritable (DataType type, Session&, + const std::string& path, bool embedded, bool destructive, nframes_t rate, bool announce = true, bool async = false); static Glib::Cond* PeaksToBuild; diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index 78f5ee29e2..ed8027ec59 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -2336,7 +2336,9 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node) try { fs = boost::dynamic_pointer_cast ( - SourceFactory::createWritable (DataType::AUDIO, _session, prop->value(), false, _session.frame_rate())); + SourceFactory::createWritable (DataType::AUDIO, _session, + prop->value(), true, + false, _session.frame_rate())); } catch (failed_constructor& err) { @@ -2370,22 +2372,25 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node) boost::shared_ptr region; try { - region = boost::dynamic_pointer_cast (RegionFactory::create (pending_sources, 0, first_fs->length(), - region_name_from_path (first_fs->name(), true), - 0, AudioRegion::Flag (AudioRegion::DefaultFlags|AudioRegion::Automatic|AudioRegion::WholeFile))); + region = boost::dynamic_pointer_cast (RegionFactory::create ( + pending_sources, 0, first_fs->length(), + region_name_from_path (first_fs->name(), true), 0, + Region::Flag (Region::DefaultFlags|Region::Automatic|Region::WholeFile))); region->special_set_position (0); } catch (failed_constructor& err) { - error << string_compose (_("%1: cannot create whole-file region from pending capture sources"), - _name) - << endmsg; + error << string_compose ( + _("%1: cannot create whole-file region from pending capture sources"), + _name) << endmsg; return -1; } try { - region = boost::dynamic_pointer_cast (RegionFactory::create (pending_sources, 0, first_fs->length(), region_name_from_path (first_fs->name(), true))); + region = boost::dynamic_pointer_cast (RegionFactory::create ( + pending_sources, 0, first_fs->length(), + region_name_from_path (first_fs->name(), true))); } catch (failed_constructor& err) { diff --git a/libs/ardour/audio_library.cc b/libs/ardour/audio_library.cc index cd473d933f..42ec537830 100644 --- a/libs/ardour/audio_library.cc +++ b/libs/ardour/audio_library.cc @@ -136,7 +136,6 @@ AudioLibrary::search_members_and (vector& members, const vector if (*head != 0) { lrdf_uris* ulist = lrdf_match_multi(*head); for (uint32_t j = 0; ulist && j < ulist->count; ++j) { -// cerr << "AND: " << Glib::filename_from_uri(ulist->items[j]) << endl; members.push_back(Glib::filename_from_uri(ulist->items[j])); } lrdf_free_uris(ulist); diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc index 434b64e88d..d1371ad0fb 100644 --- a/libs/ardour/audiofilesource.cc +++ b/libs/ardour/audiofilesource.cc @@ -63,13 +63,12 @@ using namespace PBD; using namespace Glib; ustring AudioFileSource::peak_dir = ""; -ustring AudioFileSource::search_path; sigc::signal AudioFileSource::HeaderPositionOffsetChanged; uint64_t AudioFileSource::header_position_offset = 0; /* XXX maybe this too */ -char AudioFileSource::bwf_serial_number[13] = "000000000000"; +char AudioFileSource::bwf_serial_number[13] = "000000000000"; struct SizedSampleBuffer { nframes_t size; @@ -86,24 +85,23 @@ struct SizedSampleBuffer { Glib::StaticPrivate thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT; -/** Constructor used for existing internal-to-session files. File must exist. */ -AudioFileSource::AudioFileSource (Session& s, ustring path, Source::Flag flags) - : AudioSource (s, path) - , _channel (0) +/** Constructor used for existing internal-to-session files. */ +AudioFileSource::AudioFileSource (Session& s, const ustring& path, bool embedded, Source::Flag flags) + : Source (s, DataType::AUDIO, path, flags) + , AudioSource (s, path) + , FileSource (s, DataType::AUDIO, path, embedded, flags) { - _is_embedded = AudioFileSource::determine_embeddedness (path); - if (init (path, true)) { throw failed_constructor (); } - } -/** Constructor used for new internal-to-session files. File cannot exist. */ -AudioFileSource::AudioFileSource (Session& s, ustring path, Source::Flag flags, +/** Constructor used for new internal-to-session files. */ +AudioFileSource::AudioFileSource (Session& s, const ustring& path, bool embedded, Source::Flag flags, SampleFormat samp_format, HeaderFormat hdr_format) - : AudioSource (s, path) - , _channel (0) + : Source (s, DataType::AUDIO, path, flags) + , AudioSource (s, path) + , FileSource (s, DataType::AUDIO, path, embedded, flags) { _is_embedded = false; @@ -114,16 +112,15 @@ AudioFileSource::AudioFileSource (Session& s, ustring path, Source::Flag flags, /** Constructor used for existing internal-to-session files. File must exist. */ AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist) - : AudioSource (s, node) - /* _channel is set in set_state() or init() */ + : Source (s, node) + , AudioSource (s, node) + , FileSource (s, node, must_exist) { if (set_state (node)) { throw failed_constructor (); } - string foo = _name; - - if (init (foo, must_exist)) { + if (init (_name, must_exist)) { throw failed_constructor (); } } @@ -136,37 +133,13 @@ AudioFileSource::~AudioFileSource () } } -bool -AudioFileSource::determine_embeddedness (ustring path) -{ - return (path.find("/") == 0); -} - -bool -AudioFileSource::removable () const -{ - return (_flags & Removable) && ((_flags & RemoveAtDestroy) || ((_flags & RemovableIfEmpty) && length() == 0)); -} - int -AudioFileSource::init (ustring pathstr, bool must_exist) +AudioFileSource::init (const ustring& pathstr, bool must_exist) { - _length = 0; - _timeline_position = 0; _peaks_built = false; - - if (!find (pathstr, must_exist, _file_is_new, _channel)) { - throw non_existent_source (); - } - - if (_file_is_new && must_exist) { - return -1; - } - - return 0; + return FileSource::init (pathstr, must_exist); } - ustring AudioFileSource::peak_path (ustring audio_path) { @@ -282,45 +255,21 @@ AudioFileSource::get_state () int AudioFileSource::set_state (const XMLNode& node) { - const XMLProperty* prop; - - if (AudioSource::set_state (node)) { + if (Source::set_state (node)) { return -1; } - if ((prop = node.property (X_("channel"))) != 0) { - _channel = atoi (prop->value()); - } else { - _channel = 0; - } - - if ((prop = node.property (X_("name"))) != 0) { - _is_embedded = AudioFileSource::determine_embeddedness (prop->value()); - } else { - _is_embedded = false; + if (AudioSource::set_state (node)) { + return -1; } - - if ((prop = node.property (X_("destructive"))) != 0) { - /* old style, from the period when we had DestructiveFileSource */ - _flags = Flag (_flags | Destructive); + + if (FileSource::set_state (node)) { + return -1; } return 0; } -void -AudioFileSource::mark_for_remove () -{ - // This operation is not allowed for sources for destructive tracks or embedded files. - // Fortunately mark_for_remove() is never called for embedded files. This function - // must be fixed if that ever happens. - if (_flags & Destructive) { - return; - } - - _flags = Flag (_flags | Removable | RemoveAtDestroy); -} - void AudioFileSource::mark_streaming_write_completed () { @@ -339,262 +288,10 @@ AudioFileSource::mark_streaming_write_completed () } } -void -AudioFileSource::mark_take (ustring id) -{ - if (writable()) { - _take_id = id; - } -} - int -AudioFileSource::move_to_trash (const ustring& trash_dir_name) +AudioFileSource::move_dependents_to_trash() { - if (is_embedded()) { - cerr << "tried to move an embedded region to trash" << endl; - return -1; - } - - if (!writable()) { - return -1; - } - - /* don't move the file across filesystems, just stick it in the - trash_dir_name directory on whichever filesystem it was already on - */ - - ustring newpath; - newpath = Glib::path_get_dirname (_path); - newpath = Glib::path_get_dirname (newpath); - - newpath += string("/") + trash_dir_name + "/"; - newpath += Glib::path_get_basename (_path); - - /* the new path already exists, try versioning */ - if (access (newpath.c_str(), F_OK) == 0) { - char buf[PATH_MAX+1]; - int version = 1; - ustring newpath_v; - - snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version); - newpath_v = buf; - - while (access (newpath_v.c_str(), F_OK) == 0 && version < 999) { - snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version); - newpath_v = buf; - } - - if (version == 999) { - PBD::error << string_compose ( - _("there are already 1000 files with names like %1; versioning discontinued"), - newpath) - << endmsg; - } else { - newpath = newpath_v; - } - } - - if (::rename (_path.c_str(), newpath.c_str()) != 0) { - PBD::error << string_compose ( - _("cannot rename audio file source from %1 to %2 (%3)"), - _path, newpath, strerror (errno)) << endmsg; - return -1; - } - - if (::unlink (peakpath.c_str()) != 0) { - error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), - peakpath, _path, strerror (errno)) - << endmsg; - /* try to back out */ - rename (newpath.c_str(), _path.c_str()); - return -1; - } - - _path = newpath; - peakpath = ""; - - /* file can not be removed twice, since the operation is not idempotent */ - _flags = Flag (_flags & ~(RemoveAtDestroy|Removable|RemovableIfEmpty)); - - return 0; -} - -bool -AudioFileSource::find (ustring& pathstr, bool must_exist, bool& isnew, uint16_t& chan) -{ - ustring::size_type pos; - bool ret = false; - - isnew = false; - - if (pathstr[0] != '/') { - - /* non-absolute pathname: find pathstr in search path */ - - vector dirs; - int cnt; - ustring fullpath; - ustring keeppath; - - if (search_path.length() == 0) { - error << _("FileSource: search path not set") << endmsg; - goto out; - } - - split (search_path, dirs, ':'); - - cnt = 0; - - for (vector::iterator i = dirs.begin(); i != dirs.end(); ++i) { - fullpath = *i; - if (fullpath[fullpath.length()-1] != '/') { - fullpath += '/'; - } - - fullpath += pathstr; - - /* i (paul) made a nasty design error by using ':' as a special character in - Ardour 0.99 .. this hack tries to make things sort of work. - */ - - if ((pos = pathstr.find_last_of (':')) != ustring::npos) { - - if (Glib::file_test (fullpath, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { - - /* its a real file, no problem */ - - keeppath = fullpath; - ++cnt; - - } else { - - if (must_exist) { - - /* might be an older session using file:channel syntax. see if the version - without the :suffix exists - */ - - ustring shorter = pathstr.substr (0, pos); - fullpath = *i; - - if (fullpath[fullpath.length()-1] != '/') { - fullpath += '/'; - } - - fullpath += shorter; - - if (Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { - chan = atoi (pathstr.substr (pos+1)); - pathstr = shorter; - keeppath = fullpath; - ++cnt; - } - - } else { - - /* new derived file (e.g. for timefx) being created in a newer session */ - - } - } - - } else { - - if (Glib::file_test (fullpath, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { - keeppath = fullpath; - ++cnt; - } - } - } - - if (cnt > 1) { - - error << string_compose (_("FileSource: \"%1\" is ambigous when searching %2\n\t"), pathstr, search_path) << endmsg; - goto out; - - } else if (cnt == 0) { - - if (must_exist) { - error << string_compose(_("Filesource: cannot find required file (%1): while searching %2"), pathstr, search_path) << endmsg; - goto out; - } else { - isnew = true; - } - } - - /* Current find() is unable to parse relative path names to yet non-existant - sources. QuickFix(tm) */ - if (keeppath == "") { - if (must_exist) { - error << "AudioFileSource::find(), keeppath = \"\", but the file must exist" << endl; - } else { - keeppath = pathstr; - } - } - - _name = pathstr; - _path = keeppath; - ret = true; - - } else { - - /* external files and/or very very old style sessions include full paths */ - - /* ugh, handle ':' situation */ - - if ((pos = pathstr.find_last_of (':')) != ustring::npos) { - - ustring shorter = pathstr.substr (0, pos); - - if (Glib::file_test (shorter, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { - chan = atoi (pathstr.substr (pos+1)); - pathstr = shorter; - } - } - - _path = pathstr; - - if (is_embedded()) { - _name = pathstr; - } else { - _name = pathstr.substr (pathstr.find_last_of ('/') + 1); - } - - if (!Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { - - /* file does not exist or we cannot read it */ - - if (must_exist) { - error << string_compose(_("Filesource: cannot find required file (%1): %2"), _path, strerror (errno)) << endmsg; - goto out; - } - - if (errno != ENOENT) { - error << string_compose(_("Filesource: cannot check for existing file (%1): %2"), _path, strerror (errno)) << endmsg; - goto out; - } - - /* a new file */ - - isnew = true; - ret = true; - - } else { - - /* already exists */ - - ret = true; - - } - } - - out: - return ret; -} - -void -AudioFileSource::set_search_path (ustring p) -{ - search_path = p; + return ::unlink (peakpath.c_str()); } void @@ -604,55 +301,6 @@ AudioFileSource::set_header_position_offset (nframes_t offset) HeaderPositionOffsetChanged (); } -void -AudioFileSource::set_timeline_position (int64_t pos) -{ - _timeline_position = pos; -} - -void -AudioFileSource::set_allow_remove_if_empty (bool yn) -{ - if (!writable()) { - return; - } - - if (yn) { - _flags = Flag (_flags | RemovableIfEmpty); - } else { - _flags = Flag (_flags & ~RemovableIfEmpty); - } -} - -int -AudioFileSource::set_source_name (ustring newname, bool destructive) -{ - Glib::Mutex::Lock lm (_lock); - ustring oldpath = _path; - ustring newpath = Session::change_audio_path_by_name (oldpath, _name, newname, destructive); - - if (newpath.empty()) { - error << string_compose (_("programming error: %1"), "cannot generate a changed audio path") << endmsg; - return -1; - } - - // Test whether newpath exists, if yes notify the user but continue. - if (access(newpath.c_str(),F_OK) == 0) { - error << _("Programming error! Ardour tried to rename a file over another file! It's safe to continue working, but please report this to the developers.") << endmsg; - return -1; - } - - if (rename (oldpath.c_str(), newpath.c_str()) != 0) { - error << string_compose (_("cannot rename audio file %1 to %2"), _name, newpath) << endmsg; - return -1; - } - - _name = Glib::path_get_basename (newpath); - _path = newpath; - - return rename_peakfile (peak_path (_path)); -} - bool AudioFileSource::is_empty (Session& s, ustring path) { @@ -678,7 +326,7 @@ AudioFileSource::setup_peakfile () } bool -AudioFileSource::safe_file_extension(ustring file) +AudioFileSource::safe_audio_file_extension(const ustring& file) { const char* suffixes[] = { ".wav", ".WAV", @@ -715,19 +363,6 @@ AudioFileSource::safe_file_extension(ustring file) return false; } -void -AudioFileSource::mark_immutable () -{ - /* destructive sources stay writable, and their other flags don't - change. - */ - - if (!(_flags & Destructive)) { - _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename)); - } -} - - Sample* AudioFileSource::get_interleave_buffer (nframes_t size) { diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc index 8d710b247a..7b56d1891e 100644 --- a/libs/ardour/audiosource.cc +++ b/libs/ardour/audiosource.cc @@ -56,7 +56,7 @@ bool AudioSource::_build_peakfiles = false; #define _FPP 256 AudioSource::AudioSource (Session& s, ustring name) - : Source (s, name, DataType::AUDIO) + : Source (s, DataType::AUDIO, name) { _peaks_built = false; _peak_byte_max = 0; @@ -118,8 +118,6 @@ AudioSource::set_state (const XMLNode& node) { const XMLProperty* prop; - Source::set_state (node); - if ((prop = node.property ("captured-for")) != 0) { _captured_for = prop->value(); } @@ -913,11 +911,3 @@ AudioSource::available_peaks (double zoom_factor) const return (end/sizeof(PeakData)) * _FPP; } -void -AudioSource::update_length (nframes_t pos, nframes_t cnt) -{ - if (pos + cnt > _length) { - _length = pos+cnt; - } -} - diff --git a/libs/ardour/configuration.cc b/libs/ardour/configuration.cc index 1a78848a34..d322ab4e49 100644 --- a/libs/ardour/configuration.cc +++ b/libs/ardour/configuration.cc @@ -88,7 +88,7 @@ Configuration::load_state () /* load system configuration first */ - if ( find_file_in_search_path (ardour_search_path() + system_config_search_path(), + if (find_file_in_search_path (ardour_search_path() + system_config_search_path(), "ardour_system.rc", system_rc_file) ) { XMLTree tree; diff --git a/libs/ardour/file_source.cc b/libs/ardour/file_source.cc new file mode 100644 index 0000000000..ed9c80338a --- /dev/null +++ b/libs/ardour/file_source.cc @@ -0,0 +1,419 @@ +/* + Copyright (C) 2006-2009 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include + +#include +#include +#include // for rename(), sigh +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "i18n.h" + +using namespace ARDOUR; +using namespace PBD; +using namespace Glib; + +static const std::string PATH_SEP = "/"; // I don't do windows + +map FileSource::search_paths; + +FileSource::FileSource (Session& session, DataType type, + const ustring& path, bool embedded, Source::Flag flag) + : Source(session, type, path, flag) + , _path(path) + , _file_is_new(true) + , _channel (0) + , _is_embedded(embedded) +{ +} + +FileSource::FileSource (Session& session, const XMLNode& node, bool must_exist) + : Source(session, node) + , _file_is_new(false) +{ + _path = _name; + _is_embedded = (_path.find(PATH_SEP) != string::npos); +} + +bool +FileSource::removable () const +{ + return (_flags & Removable) + && ( (_flags & RemoveAtDestroy) + || ((_flags & RemovableIfEmpty) && length() == 0)); +} + +int +FileSource::init (const ustring& pathstr, bool must_exist) +{ + _length = 0; + _timeline_position = 0; + + if (!find (_type, pathstr, must_exist, _file_is_new, _channel)) { + throw MissingSource (); + } + + if (_file_is_new && must_exist) { + return -1; + } + + return 0; +} + +int +FileSource::set_state (const XMLNode& node) +{ + const XMLProperty* prop; + + if ((prop = node.property (X_("channel"))) != 0) { + _channel = atoi (prop->value()); + } else { + _channel = 0; + } + + _is_embedded = (_name.find(PATH_SEP) == string::npos); + + return 0; +} + +void +FileSource::mark_take (const ustring& id) +{ + if (writable ()) { + _take_id = id; + } +} + +int +FileSource::move_to_trash (const ustring& trash_dir_name) +{ + if (is_embedded()) { + cerr << "tried to move an embedded region to trash" << endl; + return -1; + } + + if (!writable()) { + return -1; + } + + /* don't move the file across filesystems, just stick it in the + trash_dir_name directory on whichever filesystem it was already on + */ + + ustring newpath; + newpath = Glib::path_get_dirname (_path); + newpath = Glib::path_get_dirname (newpath); + + newpath += string(PATH_SEP) + trash_dir_name + PATH_SEP; + newpath += Glib::path_get_basename (_path); + + /* the new path already exists, try versioning */ + if (access (newpath.c_str(), F_OK) == 0) { + char buf[PATH_MAX+1]; + int version = 1; + ustring newpath_v; + + snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version); + newpath_v = buf; + + while (access (newpath_v.c_str(), F_OK) == 0 && version < 999) { + snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version); + newpath_v = buf; + } + + if (version == 999) { + PBD::error << string_compose ( + _("there are already 1000 files with names like %1; versioning discontinued"), + newpath) << endmsg; + } else { + newpath = newpath_v; + } + } + + if (::rename (_path.c_str(), newpath.c_str()) != 0) { + PBD::error << string_compose ( + _("cannot rename file source from %1 to %2 (%3)"), + _path, newpath, strerror (errno)) << endmsg; + return -1; + } + + if (move_dependents_to_trash() != 0) { + /* try to back out */ + rename (newpath.c_str(), _path.c_str()); + return -1; + } + + _path = newpath; + + /* file can not be removed twice, since the operation is not idempotent */ + _flags = Flag (_flags & ~(RemoveAtDestroy|Removable|RemovableIfEmpty)); + + return 0; +} + +/** Find the actual source file based on \a path. + * + * If the source is embedded, \a path should be a filename (no slashes). + * If the source is external, \a path should be a full path. + * In either case, _path is set to the complete absolute path of the source file. + * \return true iff the file was found. + */ +bool +FileSource::find (DataType type, const ustring& path, bool must_exist, bool& isnew, uint16_t& chan) +{ + Glib::ustring search_path = search_paths[type]; + + ustring pathstr = path; + ustring::size_type pos; + bool ret = false; + + isnew = false; + + if (pathstr[0] != '/') { + + /* non-absolute pathname: find pathstr in search path */ + + vector dirs; + int cnt; + ustring fullpath; + ustring keeppath; + + if (search_path.length() == 0) { + error << _("FileSource: search path not set") << endmsg; + goto out; + } + + split (search_path, dirs, ':'); + + cnt = 0; + + for (vector::iterator i = dirs.begin(); i != dirs.end(); ++i) { + fullpath = *i; + if (fullpath[fullpath.length()-1] != '/') { + fullpath += '/'; + } + + fullpath += pathstr; + + /* i (paul) made a nasty design error by using ':' as a special character in + Ardour 0.99 .. this hack tries to make things sort of work. + */ + + if ((pos = pathstr.find_last_of (':')) != ustring::npos) { + + if (Glib::file_test (fullpath, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { + + /* its a real file, no problem */ + + keeppath = fullpath; + ++cnt; + + } else { + + if (must_exist) { + + /* might be an older session using file:channel syntax. see if the version + without the :suffix exists + */ + + ustring shorter = pathstr.substr (0, pos); + fullpath = *i; + + if (fullpath[fullpath.length()-1] != '/') { + fullpath += '/'; + } + + fullpath += shorter; + + if (Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { + chan = atoi (pathstr.substr (pos+1)); + pathstr = shorter; + keeppath = fullpath; + ++cnt; + } + + } else { + + /* new derived file (e.g. for timefx) being created in a newer session */ + + } + } + + } else { + + if (Glib::file_test (fullpath, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { + keeppath = fullpath; + ++cnt; + } + } + } + + if (cnt > 1) { + + error << string_compose ( + _("FileSource: \"%1\" is ambigous when searching %2\n\t"), + pathstr, search_path) << endmsg; + goto out; + + } else if (cnt == 0) { + + if (must_exist) { + error << string_compose( + _("Filesource: cannot find required file (%1): while searching %2"), + pathstr, search_path) << endmsg; + goto out; + } else { + isnew = true; + } + } + + /* Current find() is unable to parse relative path names to yet non-existant + sources. QuickFix(tm) */ + if (keeppath == "") { + if (must_exist) { + error << "FileSource::find(), keeppath = \"\", but the file must exist" << endl; + } else { + keeppath = pathstr; + } + } + + _path = keeppath; + + ret = true; + + } else { + + /* external files and/or very very old style sessions include full paths */ + + /* ugh, handle ':' situation */ + + if ((pos = pathstr.find_last_of (':')) != ustring::npos) { + + ustring shorter = pathstr.substr (0, pos); + + if (Glib::file_test (shorter, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { + chan = atoi (pathstr.substr (pos+1)); + pathstr = shorter; + } + } + + _path = pathstr; + + if (!Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { + + /* file does not exist or we cannot read it */ + + if (must_exist) { + error << string_compose( + _("Filesource: cannot find required file (%1): %2"), + _path, strerror (errno)) << endmsg; + goto out; + } + + if (errno != ENOENT) { + error << string_compose( + _("Filesource: cannot check for existing file (%1): %2"), + _path, strerror (errno)) << endmsg; + goto out; + } + + /* a new file */ + isnew = true; + ret = true; + + } else { + + /* already exists */ + ret = true; + } + } + + if (_is_embedded) { + _name = Glib::path_get_basename (_name); + } + +out: + return ret; +} + +int +FileSource::set_source_name (const ustring& newname, bool destructive) +{ + Glib::Mutex::Lock lm (_lock); + ustring oldpath = _path; + ustring newpath = Session::change_source_path_by_name (oldpath, _name, newname, destructive); + + if (newpath.empty()) { + error << string_compose (_("programming error: %1"), "cannot generate a changed file path") << endmsg; + return -1; + } + + // Test whether newpath exists, if yes notify the user but continue. + if (access(newpath.c_str(),F_OK) == 0) { + error << _("Programming error! Ardour tried to rename a file over another file! It's safe to continue working, but please report this to the developers.") << endmsg; + return -1; + } + + if (rename (oldpath.c_str(), newpath.c_str()) != 0) { + error << string_compose (_("cannot rename audio file %1 to %2"), _name, newpath) << endmsg; + return -1; + } + + _name = Glib::path_get_basename (newpath); + _path = newpath; + + return 0; +} + +void +FileSource::set_search_path (DataType type, const ustring& p) +{ + search_paths[type] = p; +} + +void +FileSource::mark_immutable () +{ + /* destructive sources stay writable, and their other flags don't change. */ + if (!(_flags & Destructive)) { + _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename)); + } +} + diff --git a/libs/ardour/filter.cc b/libs/ardour/filter.cc index 0075555773..30393a145d 100644 --- a/libs/ardour/filter.cc +++ b/libs/ardour/filter.cc @@ -66,7 +66,9 @@ Filter::make_new_sources (boost::shared_ptr region, SourceList& nsrcs, s try { nsrcs.push_back (boost::dynamic_pointer_cast ( - SourceFactory::createWritable (region->data_type(), session, path, false, session.frame_rate()))); + SourceFactory::createWritable (region->data_type(), session, + path, true, + false, session.frame_rate()))); } catch (failed_constructor& err) { diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc index f983352d58..92ecaec753 100644 --- a/libs/ardour/import.cc +++ b/libs/ardour/import.cc @@ -217,13 +217,10 @@ create_mono_sources_for_writing (const vector& new_paths, Session& sess, const DataType type = ((*i).rfind(".mid") != string::npos) ? DataType::MIDI : DataType::AUDIO; - source = SourceFactory::createWritable ( - type, - sess, - i->c_str(), + source = SourceFactory::createWritable (type, sess, + i->c_str(), true, false, // destructive - samplerate - ); + samplerate); } catch (const failed_constructor& err) { @@ -365,7 +362,7 @@ write_midi_data_to_new_files (Evoral::SMF* source, Session::ImportStatus& status } } catch (...) { - error << "Corrupt MIDI file " << source->path() << endl; + error << "Corrupt MIDI file " << source->file_path() << endl; } } diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index 03208eda02..b539d5b9d3 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -50,8 +50,7 @@ using namespace PBD; sigc::signal MidiSource::MidiSourceCreated; MidiSource::MidiSource (Session& s, string name, Source::Flag flags) - : Source (s, name, DataType::MIDI, flags) - , _timeline_position(0) + : Source (s, DataType::MIDI, name, flags) , _read_data_count(0) , _write_data_count(0) , _converter(s, _timeline_position) @@ -62,7 +61,6 @@ MidiSource::MidiSource (Session& s, string name, Source::Flag flags) MidiSource::MidiSource (Session& s, const XMLNode& node) : Source (s, node) - , _timeline_position(0) , _read_data_count(0) , _write_data_count(0) , _converter(s, _timeline_position) @@ -98,8 +96,6 @@ MidiSource::set_state (const XMLNode& node) { const XMLProperty* prop; - Source::set_state (node); - if ((prop = node.property ("captured-for")) != 0) { _captured_for = prop->value(); } @@ -161,10 +157,10 @@ MidiSource::file_changed (string path) } void -MidiSource::set_timeline_position (nframes_t when) +MidiSource::set_timeline_position (int64_t pos) { - _timeline_position = when; - _converter.set_origin(when); + Source::set_timeline_position(pos); + _converter.set_origin(pos); } void @@ -225,7 +221,8 @@ MidiSource::session_saved() string newpath = _session.session_directory().midi_path().to_string() +"/"+ newname + ".mid"; boost::shared_ptr newsrc = boost::dynamic_pointer_cast( - SourceFactory::createWritable(DataType::MIDI, _session, newpath, 1, 0, true)); + SourceFactory::createWritable(DataType::MIDI, _session, + newpath, true, false, _session.frame_rate())); newsrc->set_timeline_position(_timeline_position); _model->write_to(newsrc); diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index a0b61f3b97..e55167ff08 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -2534,7 +2534,9 @@ Session::region_name (string& result, string base, bool newlevel) char buf[16]; string subbase; - assert(base.find("/") == string::npos); + if (base.find("/") != string::npos) { + base = base.substr(base.find_last_of("/") + 1); + } if (base == "") { @@ -2842,6 +2844,7 @@ Session::remove_region_from_region_list (boost::shared_ptr r) } /* Source Management */ + void Session::add_source (boost::shared_ptr source) { @@ -2912,7 +2915,6 @@ Session::source_by_id (const PBD::ID& id) return source; } - boost::shared_ptr Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn) { @@ -2920,26 +2922,19 @@ Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn) for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) { cerr << "comparing " << path << " with " << i->second->name() << endl; - boost::shared_ptr afs = boost::dynamic_pointer_cast(i->second); + boost::shared_ptr afs + = boost::dynamic_pointer_cast(i->second); if (afs && afs->path() == path && chn == afs->channel()) { return afs; } - } return boost::shared_ptr(); } -Glib::ustring -Session::peak_path (Glib::ustring base) const -{ - sys::path peakfile_path(_session_dir->peak_path()); - peakfile_path /= basename_nosuffix (base) + peakfile_suffix; - return peakfile_path.to_string(); -} string -Session::change_audio_path_by_name (string path, string oldname, string newname, bool destructive) +Session::change_source_path_by_name (string path, string oldname, string newname, bool destructive) { string look_for; string old_basename = PBD::basename_nosuffix (oldname); @@ -2987,7 +2982,7 @@ Session::change_audio_path_by_name (string path, string oldname, string newname, /* non-destructive file sources have a name of the form: - /path/to/NAME-nnnnn(%[LR])?.wav + /path/to/NAME-nnnnn(%[LR])?.ext the task here is to replace NAME with the new name. */ @@ -3025,7 +3020,7 @@ Session::change_audio_path_by_name (string path, string oldname, string newname, if (postfix != string::npos) { suffix = suffix.substr (postfix); } else { - error << "Logic error in Session::change_audio_path_by_name(), please report to the developers" << endl; + error << "Logic error in Session::change_source_path_by_name(), please report" << endl; return ""; } @@ -3052,8 +3047,42 @@ Session::change_audio_path_by_name (string path, string oldname, string newname, return path; } +/** Return the full path (in some session directory) for a new embedded source. + * \a name must be a session-unique name that does not contain slashes + * (e.g. as returned by new_*_source_name) + */ string -Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool destructive) +Session::new_source_path_from_name (DataType type, const string& name) +{ + assert(name.find("/") == string::npos); + + SessionDirectory sdir(get_best_session_directory_for_new_source()); + + sys::path p; + if (type == DataType::AUDIO) { + p = sdir.sound_path(); + } else if (type == DataType::MIDI) { + p = sdir.midi_path(); + } else { + error << "Unknown source type, unable to create file path" << endmsg; + return ""; + } + + p /= name; + return p.to_string(); +} + +Glib::ustring +Session::peak_path (Glib::ustring base) const +{ + sys::path peakfile_path(_session_dir->peak_path()); + peakfile_path /= basename_nosuffix (base) + peakfile_suffix; + return peakfile_path.to_string(); +} + +/** Return a unique name based on \a base for a new internal audio source */ +string +Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t chan, bool destructive) { string spath; uint32_t cnt; @@ -3062,12 +3091,9 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool string legalized; buf[0] = '\0'; - legalized = legalize_for_path (name); - - /* find a "version" of the file name that doesn't exist in - any of the possible directories. - */ + legalized = legalize_for_path (base); + // Find a "version" of the base name that doesn't exist in any of the possible directories. for (cnt = (destructive ? ++destructive_index : 1); cnt <= limit; ++cnt) { vector::iterator i; @@ -3080,18 +3106,24 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool spath = sdir.sound_path().to_string(); if (destructive) { + if (nchan < 2) { - snprintf (buf, sizeof(buf), "%s/T%04d-%s.wav", spath.c_str(), cnt, legalized.c_str()); + snprintf (buf, sizeof(buf), "%s/T%04d-%s.wav", + spath.c_str(), cnt, legalized.c_str()); } else if (nchan == 2) { if (chan == 0) { - snprintf (buf, sizeof(buf), "%s/T%04d-%s%%L.wav", spath.c_str(), cnt, legalized.c_str()); + snprintf (buf, sizeof(buf), "%s/T%04d-%s%%L.wav", + spath.c_str(), cnt, legalized.c_str()); } else { - snprintf (buf, sizeof(buf), "%s/T%04d-%s%%R.wav", spath.c_str(), cnt, legalized.c_str()); + snprintf (buf, sizeof(buf), "%s/T%04d-%s%%R.wav", + spath.c_str(), cnt, legalized.c_str()); } } else if (nchan < 26) { - snprintf (buf, sizeof(buf), "%s/T%04d-%s%%%c.wav", spath.c_str(), cnt, legalized.c_str(), 'a' + chan); + snprintf (buf, sizeof(buf), "%s/T%04d-%s%%%c.wav", + spath.c_str(), cnt, legalized.c_str(), 'a' + chan); } else { - snprintf (buf, sizeof(buf), "%s/T%04d-%s.wav", spath.c_str(), cnt, legalized.c_str()); + snprintf (buf, sizeof(buf), "%s/T%04d-%s.wav", + spath.c_str(), cnt, legalized.c_str()); } } else { @@ -3125,173 +3157,42 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool } if (cnt > limit) { - error << string_compose(_("There are already %1 recordings for %2, which I consider too many."), limit, name) << endmsg; + error << string_compose( + _("There are already %1 recordings for %2, which I consider too many."), + limit, base) << endmsg; destroy (); throw failed_constructor(); } } - /* we now have a unique name for the file, but figure out where to - actually put it. - */ - - string foo = buf; - - SessionDirectory sdir(get_best_session_directory_for_new_source ()); - - spath = sdir.sound_path().to_string(); - spath += '/'; - - string::size_type pos = foo.find_last_of ('/'); - - if (pos == string::npos) { - spath += foo; - } else { - spath += foo.substr (pos + 1); - } - - return spath; + return Glib::path_get_basename(buf); } +/** Create a new embedded audio source */ boost::shared_ptr Session::create_audio_source_for_session (AudioDiskstream& ds, uint32_t chan, bool destructive) { - string spath = audio_path_from_name (ds.name(), ds.n_channels().n_audio(), chan, destructive); + const size_t n_chans = ds.n_channels().n_audio(); + const string name = new_audio_source_name (ds.name(), n_chans, chan, destructive); + const string path = new_source_path_from_name(DataType::AUDIO, name); return boost::dynamic_pointer_cast ( - SourceFactory::createWritable (DataType::AUDIO, *this, spath, destructive, frame_rate())); + SourceFactory::createWritable ( + DataType::AUDIO, *this, path, true, destructive, frame_rate())); } -// FIXME: _terrible_ code duplication +/** Return a unique name based on \a base for a new internal MIDI source */ string -Session::change_midi_path_by_name (string path, string oldname, string newname, bool destructive) +Session::new_midi_source_name (const string& base) { - string look_for; - string old_basename = PBD::basename_nosuffix (oldname); - string new_legalized = legalize_for_path (newname); - - /* note: we know (or assume) the old path is already valid */ - - if (destructive) { - - /* destructive file sources have a name of the form: - - /path/to/Tnnnn-NAME(%[LR])?.wav - - the task here is to replace NAME with the new name. - */ - - /* find last slash */ - - string dir; - string prefix; - string::size_type slash; - string::size_type dash; - - if ((slash = path.find_last_of ('/')) == string::npos) { - return ""; - } - - dir = path.substr (0, slash+1); - - /* '-' is not a legal character for the NAME part of the path */ - - if ((dash = path.find_last_of ('-')) == string::npos) { - return ""; - } - - prefix = path.substr (slash+1, dash-(slash+1)); - - path = dir; - path += prefix; - path += '-'; - path += new_legalized; - path += ".mid"; /* XXX gag me with a spoon */ - - } else { - - /* non-destructive file sources have a name of the form: - - /path/to/NAME-nnnnn(%[LR])?.wav - - the task here is to replace NAME with the new name. - */ - - string dir; - string suffix; - string::size_type slash; - string::size_type dash; - string::size_type postfix; - - /* find last slash */ - - if ((slash = path.find_last_of ('/')) == string::npos) { - return ""; - } - - dir = path.substr (0, slash+1); - - /* '-' is not a legal character for the NAME part of the path */ - - if ((dash = path.find_last_of ('-')) == string::npos) { - return ""; - } - - suffix = path.substr (dash+1); - - // Suffix is now everything after the dash. Now we need to eliminate - // the nnnnn part, which is done by either finding a '%' or a '.' - - postfix = suffix.find_last_of ("%"); - if (postfix == string::npos) { - postfix = suffix.find_last_of ('.'); - } - - if (postfix != string::npos) { - suffix = suffix.substr (postfix); - } else { - error << "Logic error in Session::change_midi_path_by_name(), please report to the developers" << endl; - return ""; - } - - const uint32_t limit = 10000; - char buf[PATH_MAX+1]; - - for (uint32_t cnt = 1; cnt <= limit; ++cnt) { - - snprintf (buf, sizeof(buf), "%s%s-%u%s", dir.c_str(), newname.c_str(), cnt, suffix.c_str()); - - if (access (buf, F_OK) != 0) { - path = buf; - break; - } - path = ""; - } - - if (path == "") { - error << "FATAL ERROR! Could not find a " << endl; - } - - } - - return path; -} - -string -Session::midi_path_from_name (string name) -{ - string spath; uint32_t cnt; char buf[PATH_MAX+1]; const uint32_t limit = 10000; string legalized; buf[0] = '\0'; - legalized = legalize_for_path (name); - - /* find a "version" of the file name that doesn't exist in - any of the possible directories. - */ + legalized = legalize_for_path (base); + // Find a "version" of the file name that doesn't exist in any of the possible directories. for (cnt = 1; cnt <= limit; ++cnt) { vector::iterator i; @@ -3302,12 +3203,9 @@ Session::midi_path_from_name (string name) SessionDirectory sdir((*i).path); sys::path p = sdir.midi_path(); - p /= legalized; - spath = p.to_string(); - - snprintf (buf, sizeof(buf), "%s-%u.mid", spath.c_str(), cnt); + snprintf (buf, sizeof(buf), "%s-%u.mid", p.to_string().c_str(), cnt); if (sys::exists (buf)) { existing++; @@ -3319,39 +3217,28 @@ Session::midi_path_from_name (string name) } if (cnt > limit) { - error << string_compose(_("There are already %1 recordings for %2, which I consider too many."), limit, name) << endmsg; + error << string_compose( + _("There are already %1 recordings for %2, which I consider too many."), + limit, base) << endmsg; + destroy (); throw failed_constructor(); } } - /* we now have a unique name for the file, but figure out where to - actually put it. - */ - - string foo = buf; - - SessionDirectory sdir(get_best_session_directory_for_new_source ()); - - spath = sdir.midi_path().to_string(); - spath += '/'; - - string::size_type pos = foo.find_last_of ('/'); - - if (pos == string::npos) { - spath += foo; - } else { - spath += foo.substr (pos + 1); - } - - return spath; + return Glib::path_get_basename(buf); } + +/** Create a new embedded MIDI source */ boost::shared_ptr Session::create_midi_source_for_session (MidiDiskstream& ds) { - string mpath = midi_path_from_name (ds.name()); + const string name = new_midi_source_name (ds.name()); + const string path = new_source_path_from_name (DataType::MIDI, name); - return boost::dynamic_pointer_cast (SourceFactory::createWritable (DataType::MIDI, *this, mpath, false, frame_rate())); + return boost::dynamic_pointer_cast ( + SourceFactory::createWritable ( + DataType::MIDI, *this, path, true, false, frame_rate())); } @@ -4130,7 +4017,7 @@ Session::write_one_track (AudioTrack& track, nframes_t start, nframes_t end, try { fsource = boost::dynamic_pointer_cast ( - SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate())); + SourceFactory::createWritable (DataType::AUDIO, *this, buf, true, false, frame_rate())); } catch (failed_constructor& err) { diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index ce6878b881..3f9a481340 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -414,12 +414,7 @@ Session::setup_raid_path (string path) SearchPath sound_search_path; SearchPath midi_search_path; - for ( - SearchPath::const_iterator i = search_path.begin(); - i != search_path.end(); - ++i - ) - { + for (SearchPath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) { sp.path = (*i).to_string (); sp.blocks = 0; // not needed session_dirs.push_back (sp); @@ -430,14 +425,11 @@ Session::setup_raid_path (string path) midi_search_path += sdir.midi_path (); } - // set the AudioFileSource and SMFSource search path - - AudioFileSource::set_search_path (sound_search_path.to_string ()); - SMFSource::set_search_path (midi_search_path.to_string ()); - + // set the search path for each data type + FileSource::set_search_path (DataType::AUDIO, sound_search_path.to_string ()); + SMFSource::set_search_path (DataType::MIDI, midi_search_path.to_string ()); // reset the round-robin soundfile path thingie - last_rr_session_dir = session_dirs.begin(); } @@ -997,16 +989,11 @@ Session::state(bool full_state) for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) { - /* Don't save information about AudioFileSources that are empty */ + /* Don't save information about non-destructive file sources that are empty */ + /* FIXME: MIDI breaks if this is made FileSource like it should be... */ boost::shared_ptr fs; - if ((fs = boost::dynamic_pointer_cast (siter->second)) != 0) { - - /* 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 (!fs->destructive()) { if (fs->length() == 0) { continue; @@ -1739,14 +1726,11 @@ Session::load_sources (const XMLNode& node) set_dirty(); for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - try { if ((source = XMLSourceFactory (**niter)) == 0) { error << _("Session: cannot create Source from XML description.") << endmsg; } - } - - catch (non_existent_source& err) { + } catch (MissingSource& err) { warning << _("A sound file is missing. It will be replaced by silence.") << endmsg; source = SourceFactory::createSilent (*this, **niter, max_frames, _current_frame_rate); } @@ -2622,9 +2606,9 @@ Session::cleanup_sources (Session::cleanup_report& rep) */ for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) { - boost::shared_ptr fs; + boost::shared_ptr fs; - if ((fs = boost::dynamic_pointer_cast (i->second)) != 0) { + if ((fs = boost::dynamic_pointer_cast (i->second)) != 0) { all_sources.insert (fs->path()); } } diff --git a/libs/ardour/silentfilesource.cc b/libs/ardour/silentfilesource.cc deleted file mode 100644 index b34944e342..0000000000 --- a/libs/ardour/silentfilesource.cc +++ /dev/null @@ -1,39 +0,0 @@ -/* - Copyright (C) 2007 Paul Davis - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include - -using namespace ARDOUR; - -SilentFileSource::SilentFileSource (Session& s, const XMLNode& node, nframes_t len, float sr) - : AudioFileSource (s, node, false) -{ - _length = len; - _sample_rate = sr; -} - -SilentFileSource::~SilentFileSource () -{ -} - -void -SilentFileSource::set_length (nframes_t len) -{ - _length = len; -} diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index d87293faed..be9b9dd3f1 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -45,32 +45,31 @@ #include "i18n.h" using namespace ARDOUR; - -string SMFSource::_search_path; +using namespace Glib; /** Constructor used for new internal-to-session files. File cannot exist. */ -SMFSource::SMFSource(Session& s, std::string path, Source::Flag flags) - : MidiSource(s, region_name_from_path(path, false)) +SMFSource::SMFSource (Session& s, const ustring& path, bool embedded, Source::Flag flags) + : Source(s, DataType::MIDI, path, flags) + , MidiSource(s, path) + , FileSource(s, DataType::MIDI, path, embedded, flags) , Evoral::SMF() - , _allow_remove_if_empty(true) , _last_ev_time_beats(0.0) , _last_ev_time_frames(0) { - if (init(path, false)) { + if (init(_name, false)) { throw failed_constructor (); } if (create(path)) { throw failed_constructor (); } - - assert(_name.find("/") == string::npos); } -/** Constructor used for existing internal-to-session files. File must exist. */ -SMFSource::SMFSource(Session& s, const XMLNode& node) - : MidiSource(s, node) - , _allow_remove_if_empty(true) +/** Constructor used for existing internal-to-session files. */ +SMFSource::SMFSource (Session& s, const XMLNode& node, bool must_exist) + : Source(s, node) + , MidiSource(s, node) + , FileSource(s, node, must_exist) , _last_ev_time_beats(0.0) , _last_ev_time_frames(0) { @@ -85,8 +84,6 @@ SMFSource::SMFSource(Session& s, const XMLNode& node) if (open(_path)) { throw failed_constructor (); } - - assert(_name.find("/") == string::npos); } SMFSource::~SMFSource () @@ -96,40 +93,12 @@ SMFSource::~SMFSource () } } -bool -SMFSource::removable () const -{ - return (_flags & Removable) && ((_flags & RemoveAtDestroy) || - ((_flags & RemovableIfEmpty) && is_empty())); -} - -int -SMFSource::init (string pathstr, bool must_exist) -{ - bool is_new = false; - - if (!find (pathstr, must_exist, is_new)) { - cerr << "cannot find " << pathstr << " with me = " << must_exist << endl; - return -1; - } - - if (is_new && must_exist) { - return -1; - } - - assert(_name.find("/") == string::npos); - return 0; -} - /** All stamps in audio frames */ nframes_t SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t dur, nframes_t stamp_offset, nframes_t negative_stamp_offset) const { - //cerr << "SMF read_unlocked " << name() << " read " - //<< start << ", count=" << dur << ", offset=" << stamp_offset << endl; - - int ret; + int ret = 0; uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn _read_data_count = 0; @@ -266,7 +235,7 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t dur) /** Append an event with a timestamp in beats (double) */ void -SMFSource::append_event_unlocked_beats(const Evoral::Event& ev) +SMFSource::append_event_unlocked_beats (const Evoral::Event& ev) { if (ev.size() == 0) { return; @@ -297,7 +266,7 @@ SMFSource::append_event_unlocked_beats(const Evoral::Event& ev) /** Append an event with a timestamp in frames (nframes_t) */ void -SMFSource::append_event_unlocked_frames(const Evoral::Event& ev) +SMFSource::append_event_unlocked_frames (const Evoral::Event& ev) { if (ev.size() == 0) { return; @@ -330,48 +299,30 @@ SMFSource::append_event_unlocked_frames(const Evoral::Event& ev) } } - XMLNode& SMFSource::get_state () { - XMLNode& root (MidiSource::get_state()); - char buf[16]; - snprintf (buf, sizeof (buf), "0x%x", (int)_flags); - root.add_property ("flags", buf); - return root; + return MidiSource::get_state(); } int SMFSource::set_state (const XMLNode& node) { - const XMLProperty* prop; + if (Source::set_state (node)) { + return -1; + } if (MidiSource::set_state (node)) { return -1; } - - if ((prop = node.property (X_("flags"))) != 0) { - int ival; - sscanf (prop->value().c_str(), "0x%x", &ival); - _flags = Flag (ival); - } else { - _flags = Flag (0); + + if (FileSource::set_state (node)) { + return -1; } - assert(_name.find("/") == string::npos); - return 0; } -void -SMFSource::mark_for_remove () -{ - if (!writable()) { - return; - } - _flags = Flag (_flags | RemoveAtDestroy); -} - void SMFSource::mark_streaming_midi_write_started (NoteMode mode, nframes_t start_frame) { @@ -394,212 +345,14 @@ SMFSource::mark_streaming_write_completed () Evoral::SMF::end_write (); } -void -SMFSource::mark_take (string id) -{ - if (writable()) { - _take_id = id; - } -} - -int -SMFSource::move_to_trash (const string trash_dir_name) -{ - if (!writable()) { - return -1; - } - - /* don't move the file across filesystems, just stick it in the - trash_dir_name directory on whichever filesystem it was already on - */ - - Glib::ustring newpath; - newpath = Glib::path_get_dirname (_path); - newpath = Glib::path_get_dirname (newpath); - - newpath += string("/") + trash_dir_name + "/"; - newpath += Glib::path_get_basename (_path); - - /* the new path already exists, try versioning */ - if (access (newpath.c_str(), F_OK) == 0) { - char buf[PATH_MAX+1]; - int version = 1; - string newpath_v; - - snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version); - newpath_v = buf; - - while (access (newpath_v.c_str(), F_OK) == 0 && version < 999) { - snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version); - newpath_v = buf; - } - - if (version == 999) { - PBD::error << string_compose ( - _("there are already 1000 files with names like %1; versioning discontinued"), - newpath) << endmsg; - } else { - newpath = newpath_v; - } - } - - if (::rename (_path.c_str(), newpath.c_str()) != 0) { - PBD::error << string_compose ( - _("cannot rename midi file source from %1 to %2 (%3)"), - _path, newpath, strerror (errno)) << endmsg; - return -1; - } - - _path = newpath; - - /* file can not be removed twice, since the operation is not idempotent */ - _flags = Flag (_flags & ~(RemoveAtDestroy|Removable|RemovableIfEmpty)); - - return 0; -} - bool -SMFSource::safe_file_extension(const Glib::ustring& file) +SMFSource::safe_midi_file_extension (const Glib::ustring& file) { return (file.rfind(".mid") != Glib::ustring::npos); } -// FIXME: Merge this with audiofilesource somehow (make a generic filesource?) -bool -SMFSource::find (string pathstr, bool must_exist, bool& isnew) -{ - bool ret = false; - - isnew = false; - - if (pathstr[0] != '/') { - - /* non-absolute pathname: find pathstr in search path */ - - vector dirs; - int cnt; - string fullpath; - string keeppath; - - if (_search_path.length() == 0) { - PBD::error << _("FileSource: search path not set") << endmsg; - goto out; - } - - split (_search_path, dirs, ':'); - - cnt = 0; - - for (vector::iterator i = dirs.begin(); i != dirs.end(); ++i) { - fullpath = *i; - if (fullpath[fullpath.length()-1] != '/') { - fullpath += '/'; - } - fullpath += pathstr; - - if (access (fullpath.c_str(), R_OK) == 0) { - keeppath = fullpath; - ++cnt; - } - } - - if (cnt > 1) { - - PBD::error << string_compose (_("FileSource: \"%1\" is ambigous when searching %2\n\t"), pathstr, _search_path) << endmsg; - goto out; - - } else if (cnt == 0) { - - if (must_exist) { - PBD::error << string_compose(_("Filesource: cannot find required file (%1): while searching %2"), pathstr, _search_path) << endmsg; - goto out; - } else { - isnew = true; - } - } - - _name = pathstr; - _path = keeppath; - ret = true; - - } else { - - /* external files and/or very very old style sessions include full paths */ - - _path = pathstr; - _name = pathstr.substr (pathstr.find_last_of ('/') + 1); - - if (access (_path.c_str(), R_OK) != 0) { - - /* file does not exist or we cannot read it */ - - if (must_exist) { - PBD::error << string_compose(_("Filesource: cannot find required file (%1): %2"), _path, strerror (errno)) << endmsg; - goto out; - } - - if (errno != ENOENT) { - PBD::error << string_compose(_("Filesource: cannot check for existing file (%1): %2"), _path, strerror (errno)) << endmsg; - goto out; - } - - /* a new file */ - - isnew = true; - ret = true; - - } else { - - /* already exists */ - - ret = true; - } - } - - out: - return ret; -} - -void -SMFSource::set_search_path (string p) -{ - _search_path = p; -} - - -void -SMFSource::set_allow_remove_if_empty (bool yn) -{ - if (writable()) { - _allow_remove_if_empty = yn; - } -} - -int -SMFSource::set_source_name (string newname, bool destructive) -{ - //Glib::Mutex::Lock lm (_lock); FIXME - string oldpath = _path; - string newpath = Session::change_midi_path_by_name (oldpath, _name, newname, destructive); - - if (newpath.empty()) { - PBD::error << string_compose (_("programming error: %1"), "cannot generate a changed midi path") << endmsg; - return -1; - } - - if (rename (oldpath.c_str(), newpath.c_str()) != 0) { - PBD::error << string_compose (_("cannot rename midi file for %1 to %2"), _name, newpath) << endmsg; - return -1; - } - - _name = Glib::path_get_basename (newpath); - _path = newpath; - - return 0; -} - void -SMFSource::load_model(bool lock, bool force_reload) +SMFSource::load_model (bool lock, bool force_reload) { if (_writing) { return; @@ -662,7 +415,7 @@ SMFSource::load_model(bool lock, bool force_reload) #define LINEAR_INTERPOLATION_MODE_WORKS_PROPERLY 0 void -SMFSource::set_default_controls_interpolation() +SMFSource::set_default_controls_interpolation () { // set interpolation style to defaults, can be changed by the GUI later Evoral::ControlSet::Controls controls = _model->controls(); @@ -679,14 +432,14 @@ SMFSource::set_default_controls_interpolation() void -SMFSource::destroy_model() +SMFSource::destroy_model () { //cerr << _name << " destroying model " << _model.get() << endl; _model.reset(); } void -SMFSource::flush_midi() +SMFSource::flush_midi () { Evoral::SMF::end_write(); } diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc index 8d89f2aa92..d651d40970 100644 --- a/libs/ardour/sndfilesource.cc +++ b/libs/ardour/sndfilesource.cc @@ -50,38 +50,40 @@ const Source::Flag SndFileSource::default_writable_flags = Source::Flag ( Source::CanRename ); SndFileSource::SndFileSource (Session& s, const XMLNode& node) - : AudioFileSource (s, node) + : Source(s, node) + , AudioFileSource (s, node) { - init (); + init_sndfile (); if (open()) { throw failed_constructor (); } } -SndFileSource::SndFileSource (Session& s, ustring path, int chn, Flag flags) - /* files created this way are never writable or removable */ - : AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy))) +/** Files created this way are never writable or removable */ +SndFileSource::SndFileSource (Session& s, const ustring& path, bool embedded, int chn, Flag flags) + : Source(s, DataType::AUDIO, path, flags) + , AudioFileSource (s, path, embedded, + Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy))) { _channel = chn; - init (); + init_sndfile (); if (open()) { throw failed_constructor (); } } -SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags) - : AudioFileSource (s, path, flags, sfmt, hf) +/** This constructor is used to construct new files, not open existing ones. */ +SndFileSource::SndFileSource (Session& s, const ustring& path, bool embedded, + SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags) + : Source(s, DataType::AUDIO, path, flags) + , AudioFileSource (s, path, embedded, flags, sfmt, hf) { int fmt = 0; - init (); - - /* this constructor is used to construct new files, not open - existing ones. - */ + init_sndfile (); _file_is_new = true; @@ -161,7 +163,7 @@ SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, Heade } void -SndFileSource::init () +SndFileSource::init_sndfile () { ustring file; @@ -191,7 +193,8 @@ SndFileSource::init () _timeline_position = header_position_offset; } - AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change)); + AudioFileSource::HeaderPositionOffsetChanged.connect ( + mem_fun (*this, &SndFileSource::handle_header_position_change)); } int diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc index aaae432570..a0ee2ac706 100644 --- a/libs/ardour/source.cc +++ b/libs/ardour/source.cc @@ -46,10 +46,11 @@ using namespace std; using namespace ARDOUR; -Source::Source (Session& s, const string& name, DataType type, Flag flags) +Source::Source (Session& s, DataType type, const string& name, Flag flags) : SessionObject(s, name) , _type(type) , _flags(flags) + , _timeline_position(0) { _analysed = false; _timestamp = 0; @@ -61,6 +62,7 @@ Source::Source (Session& s, const XMLNode& node) : SessionObject(s, "unnamed source") , _type(DataType::AUDIO) , _flags (Flag (Writable|CanRename)) + , _timeline_position(0) { _timestamp = 0; _length = 0; @@ -83,7 +85,7 @@ Source::get_state () XMLNode *node = new XMLNode ("Source"); char buf[64]; - node->add_property ("name", _name); + node->add_property ("name", name()); node->add_property ("type", _type.to_string()); node->add_property (X_("flags"), enum_2_string (_flags)); _id.print (buf, sizeof (buf)); @@ -128,6 +130,11 @@ Source::set_state (const XMLNode& node) _flags = Flag (0); } + + /* old style, from the period when we had DestructiveFileSource */ + if ((prop = node.property (X_("destructive"))) != 0) { + _flags = Flag (_flags | Destructive); + } return 0; } @@ -136,7 +143,7 @@ void Source::update_length (nframes_t pos, nframes_t cnt) { if (pos + cnt > _length) { - _length = pos+cnt; + _length = pos + cnt; } } @@ -272,3 +279,36 @@ Source::check_for_analysis_data_on_disk () return ok; } +void +Source::mark_for_remove () +{ + // This operation is not allowed for sources for destructive tracks or embedded files. + // Fortunately mark_for_remove() is never called for embedded files. This function + // must be fixed if that ever happens. + if (_flags & Destructive) { + return; + } + + _flags = Flag (_flags | Removable | RemoveAtDestroy); +} + +void +Source::set_timeline_position (int64_t pos) +{ + _timeline_position = pos; +} + +void +Source::set_allow_remove_if_empty (bool yn) +{ + if (!writable()) { + return; + } + + if (yn) { + _flags = Flag (_flags | RemovableIfEmpty); + } else { + _flags = Flag (_flags & ~RemovableIfEmpty); + } +} + diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc index 2d2d6917bd..db5e7d313b 100644 --- a/libs/ardour/source_factory.cc +++ b/libs/ardour/source_factory.cc @@ -179,7 +179,8 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks) } boost::shared_ptr -SourceFactory::createReadable (DataType type, Session& s, string path, int chn, Source::Flag flags, bool announce, bool defer_peaks) +SourceFactory::createReadable (DataType type, Session& s, const string& path, bool embedded, + int chn, Source::Flag flags, bool announce, bool defer_peaks) { if (type == DataType::AUDIO) { @@ -187,7 +188,7 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn, try { - boost::shared_ptr ret (new SndFileSource (s, path, chn, flags)); + boost::shared_ptr ret (new SndFileSource (s, path, embedded, chn, flags)); if (setup_peakfile (ret, defer_peaks)) { return boost::shared_ptr(); @@ -203,7 +204,7 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn, catch (failed_constructor& err) { #ifdef USE_COREAUDIO_FOR_FILES - boost::shared_ptr ret (new CoreAudioSource (s, path, chn, flags)); + boost::shared_ptr ret (new CoreAudioSource (s, path, embedded, chn, flags)); if (setup_peakfile (ret, defer_peaks)) { return boost::shared_ptr(); } @@ -224,8 +225,7 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn, } else if (type == DataType::MIDI) { - // FIXME: flags? - boost::shared_ptr ret (new SMFSource (s, path, SMFSource::Flag(0))); + boost::shared_ptr ret (new SMFSource (s, path, embedded, SMFSource::Flag(0))); if (announce) { SourceCreated (ret); @@ -239,12 +239,13 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn, } boost::shared_ptr -SourceFactory::createWritable (DataType type, Session& s, std::string path, bool destructive, nframes_t rate, bool announce, bool defer_peaks) +SourceFactory::createWritable (DataType type, Session& s, const std::string& path, bool embedded, + bool destructive, nframes_t rate, bool announce, bool defer_peaks) { /* this might throw failed_constructor(), which is OK */ if (type == DataType::AUDIO) { - boost::shared_ptr ret (new SndFileSource (s, path, + boost::shared_ptr ret (new SndFileSource (s, path, embedded, Config->get_native_file_data_format(), Config->get_native_file_header_format(), rate, @@ -265,7 +266,7 @@ SourceFactory::createWritable (DataType type, Session& s, std::string path, bool } else if (type == DataType::MIDI) { - boost::shared_ptr ret (new SMFSource (s, path)); + boost::shared_ptr ret (new SMFSource (s, path, embedded, Source::Flag(0))); // no analysis data - this is a new file @@ -278,3 +279,4 @@ SourceFactory::createWritable (DataType type, Session& s, std::string path, bool return boost::shared_ptr (); } + diff --git a/libs/evoral/evoral/SMF.hpp b/libs/evoral/evoral/SMF.hpp index 0be2a4b8a7..4a6b21870b 100644 --- a/libs/evoral/evoral/SMF.hpp +++ b/libs/evoral/evoral/SMF.hpp @@ -47,7 +47,7 @@ public: int create(const std::string& path, int track=1, uint16_t ppqn=19200) THROW_FILE_ERROR; void close() THROW_FILE_ERROR; - const std::string& path() const { return _path; }; + const std::string& file_path() const { return _file_path; }; void seek_to_start() const; int seek_to_track(int track); @@ -65,7 +65,7 @@ public: void flush() {}; private: - std::string _path; + std::string _file_path; smf_t* _smf; smf_track_t* _smf_track; bool _empty; ///< true iff file contains(non-empty) events diff --git a/libs/evoral/src/SMF.cpp b/libs/evoral/src/SMF.cpp index d7d052e3f0..372c37c0bb 100644 --- a/libs/evoral/src/SMF.cpp +++ b/libs/evoral/src/SMF.cpp @@ -80,8 +80,8 @@ SMF::open(const std::string& path, int track) THROW_FILE_ERROR smf_delete(_smf); } - _path = path; - _smf = smf_load(_path.c_str()); + _file_path = path; + _smf = smf_load(_file_path.c_str()); if (_smf == NULL) { return -1; } @@ -117,7 +117,7 @@ SMF::create(const std::string& path, int track, uint16_t ppqn) THROW_FILE_ERROR smf_delete(_smf); } - _path = path; + _file_path = path; _smf = smf_new(); if (smf_set_ppqn(_smf, ppqn) != 0) { @@ -148,7 +148,7 @@ void SMF::close() THROW_FILE_ERROR { if (_smf) { - if (smf_save(_smf, _path.c_str()) != 0) { + if (smf_save(_smf, _file_path.c_str()) != 0) { throw FileError(); } smf_delete(_smf); @@ -258,7 +258,7 @@ SMF::begin_write() void SMF::end_write() THROW_FILE_ERROR { - if (smf_save(_smf, _path.c_str()) != 0) + if (smf_save(_smf, _file_path.c_str()) != 0) throw FileError(); } -- cgit v1.2.3