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
This commit is contained in:
David Robillard 2009-02-17 02:11:49 +00:00
parent 4565b73a39
commit 022818b4a7
33 changed files with 983 additions and 1276 deletions

View File

@ -672,9 +672,10 @@ Editor::embed_sndfiles (vector<Glib::ustring> paths, bool multifile,
if ((s = session->source_by_path_and_channel (path, n)) == 0) {
source = boost::dynamic_pointer_cast<AudioFileSource> (
SourceFactory::createReadable (DataType::AUDIO, *session, path, n,
SourceFactory::createReadable (DataType::AUDIO, *session,
path, false, n,
(mode == ImportAsTapeTrack
? Source::Destructive
? Source::Destructive
: Source::Flag (0)),
true, true));
} else {

View File

@ -204,7 +204,10 @@ Editor::write_region (string path, boost::shared_ptr<AudioRegion> region)
try {
fs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createWritable (DataType::AUDIO, *session, path, false, session->frame_rate()));
fs = boost::dynamic_pointer_cast<AudioFileSource> (
SourceFactory::createWritable (DataType::AUDIO, *session,
path, true,
false, session->frame_rate()));
}
catch (failed_constructor& err) {
@ -340,7 +343,10 @@ Editor::write_audio_range (AudioPlaylist& playlist, const ChanCount& count, list
path = s;
try {
fs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createWritable (DataType::AUDIO, *session, path, false, session->frame_rate()));
fs = boost::dynamic_pointer_cast<AudioFileSource> (
SourceFactory::createWritable (DataType::AUDIO, *session,
path, true,
false, session->frame_rate()));
}
catch (failed_constructor& err) {

View File

@ -332,8 +332,8 @@ SoundFileBox::audition ()
for (int n = 0; n < sf_info.channels; ++n) {
try {
afs = boost::dynamic_pointer_cast<AudioFileSource> (
SourceFactory::createReadable (DataType::AUDIO, *_session, path,
n, Source::Flag (0), false));
SourceFactory::createReadable (DataType::AUDIO, *_session,
path, false, n, Source::Flag (0), false));
srclist.push_back(afs);
@ -639,13 +639,13 @@ SoundFileBrowser::meter ()
bool
SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
{
return AudioFileSource::safe_file_extension (filter_info.filename);
return AudioFileSource::safe_audio_file_extension (filter_info.filename);
}
bool
SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
{
return SMFSource::safe_file_extension (filter_info.filename);
return SMFSource::safe_midi_file_extension (filter_info.filename);
}
void
@ -1096,7 +1096,7 @@ SoundFileOmega::check_info (const vector<ustring>& paths, bool& same_size, bool&
src_needed = true;
}
} else if (SMFSource::safe_file_extension (*i)) {
} else if (SMFSource::safe_midi_file_extension (*i)) {
Evoral::SMFReader reader(*i);
if (reader.num_tracks() > 1) {

View File

@ -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

View File

@ -21,18 +21,12 @@
#define __ardour_audiofilesource_h__
#include <exception>
#include <time.h>
#include <ardour/audiosource.h>
#include <ardour/file_source.h>
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<void> 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);
int init (const Glib::ustring& idstr, bool must_exist);
static bool determine_embeddedness (Glib::ustring path);
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];

View File

@ -43,7 +43,7 @@ using std::vector;
namespace ARDOUR {
class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR::AudioSource>
class AudioSource : virtual public Source, public boost::enable_shared_from_this<ARDOUR::AudioSource>
{
public:
AudioSource (Session&, Glib::ustring name);
@ -68,7 +68,6 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
virtual float sample_rate () const = 0;
virtual void mark_for_remove() = 0;
virtual void mark_streaming_write_completed () {}
virtual bool can_truncate_peaks() const { return true; }
@ -116,7 +115,6 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
static bool _build_peakfiles;
bool _peaks_built;
mutable Glib::Mutex _lock;
mutable Glib::Mutex _peaks_ready_lock;
Glib::ustring peakpath;
Glib::ustring _captured_for;
@ -138,8 +136,6 @@ class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR:
virtual Glib::ustring find_broken_peakfile (Glib::ustring missing_peak_path,
Glib::ustring audio_path) = 0;
void update_length (nframes_t pos, nframes_t cnt);
virtual int read_peaks_with_fpp (PeakData *peaks,
nframes_t npeaks, nframes_t start, nframes_t cnt,
double samples_per_visual_peak, nframes_t fpp) const;

View File

@ -0,0 +1,83 @@
/*
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.
*/
#ifndef __ardour_filesource_h__
#define __ardour_filesource_h__
#include <exception>
#include <time.h>
#include <ardour/source.h>
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<DataType, Glib::ustring> search_paths;
};
} // namespace ARDOUR
#endif /* __ardour_filesource_h__ */

View File

@ -38,7 +38,7 @@ class MidiModel;
template<typename T> 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<double>& ev) = 0;
virtual void append_event_unlocked_frames(const Evoral::Event<nframes_t>& 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<MidiModel> model() { return _model; }
void set_model(boost::shared_ptr<MidiModel> 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<nframes_t>& 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()

View File

@ -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;
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;
boost::shared_ptr<ToggleControllable> _solo_control;
boost::shared_ptr<ToggleControllable> _mute_control;
nframes_t check_initial_delay (nframes_t, nframes_t&, nframes_t&);
void passthru (nframes_t start_frame, nframes_t end_frame,
nframes_t nframes, nframes_t offset, int declick, bool meter_inputs);
void passthru (nframes_t start_frame, nframes_t end_frame,
nframes_t nframes, nframes_t offset, int declick, bool meter_inputs);
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);
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 _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;
boost::shared_ptr<ToggleControllable> _solo_control;
boost::shared_ptr<ToggleControllable> _mute_control;
/* 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<ARDOUR::Processor> processor;
ChanCount in;
@ -376,7 +370,8 @@ class Route : public IO
};
int32_t apply_some_processor_counts (std::list<ProcessorCount>& iclist);
bool check_some_processor_counts (std::list<ProcessorCount>& iclist, ChanCount required_inputs, ProcessorStreams* err_streams);
bool check_some_processor_counts (std::list<ProcessorCount>& iclist,
ChanCount required_inputs, ProcessorStreams* err_streams);
void set_deferred_state ();
void add_processor_from_xml (const XMLNode&);

View File

@ -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> region;
list<AudioRange> audio_range;
list<MusicRange> music_range;
list<AudioRange> audio_range;
list<MusicRange> music_range;
boost::shared_ptr<Region> 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<Region>);
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<void,RouteGroup*> edit_group_added;
sigc::signal<void,RouteGroup*> mix_group_added;
sigc::signal<void> edit_group_removed;
sigc::signal<void> mix_group_removed;
sigc::signal<void> edit_group_removed;
sigc::signal<void> mix_group_removed;
void foreach_edit_group (sigc::slot<void,RouteGroup*> sl) {
for (list<RouteGroup *>::iterator i = edit_groups.begin(); i != edit_groups.end(); i++) {
@ -512,11 +510,13 @@ class Session : public PBD::StatefulDestructible
/* fundamental operations. duh. */
std::list<boost::shared_ptr<AudioTrack> > new_audio_track (int input_channels, int output_channels, TrackMode mode = Normal, uint32_t how_many = 1);
std::list<boost::shared_ptr<AudioTrack> > new_audio_track (
int input_channels, int output_channels, TrackMode mode = Normal, uint32_t how_many = 1);
RouteList new_audio_route (int input_channels, int output_channels, uint32_t how_many);
std::list<boost::shared_ptr<MidiTrack> > new_midi_track (TrackMode mode = Normal, uint32_t how_many = 1);
//boost::shared_ptr<Route> new_midi_route (uint32_t how_many = 1);
std::list<boost::shared_ptr<MidiTrack> > new_midi_track (
TrackMode mode = Normal, uint32_t how_many = 1);
void remove_route (boost::shared_ptr<Route>);
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<int,boost::shared_ptr<ARDOUR::Playlist> > 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<int,nframes_t, nframes_t> 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<int> AskAboutPendingState;
boost::shared_ptr<AudioFileSource> create_audio_source_for_session (ARDOUR::AudioDiskstream&, uint32_t which_channel, bool destructive);
@ -780,7 +776,7 @@ class Session : public PBD::StatefulDestructible
sigc::signal<void,boost::shared_ptr<Bundle> > BundleAdded;
sigc::signal<void,boost::shared_ptr<Bundle> > 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<IO> click_io() { return _click_io; }
boost::shared_ptr<IO> 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 ();

View File

@ -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

View File

@ -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 <cstdio>
#include <time.h>
#include <ardour/midi_source.h>
#include <evoral/SMF.hpp>
#include <ardour/midi_source.h>
#include <ardour/file_source.h>
namespace Evoral { template<typename T> class Event; }
@ -34,51 +34,42 @@ namespace ARDOUR {
template<typename T> 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 safe_file_extension (const Glib::ustring& path) const {
return safe_midi_file_extension(path);
}
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; }
void set_allow_remove_if_empty (bool yn);
void mark_for_remove();
void append_event_unlocked_beats(const Evoral::Event<double>& ev);
void append_event_unlocked_frames(const Evoral::Event<nframes_t>& ev);
int move_to_trash (const string trash_dir_name);
void append_event_unlocked_beats (const Evoral::Event<double>& ev);
void append_event_unlocked_frames (const Evoral::Event<nframes_t>& 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<nframes_t>& dst,
nframes_t start,
@ -90,22 +81,13 @@ class SMFSource : public MidiSource, public Evoral::SMF {
MidiRingBuffer<nframes_t>& 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();
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;
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__ */

View File

@ -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);

View File

@ -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<double, nframes_t>& time_converter() const {
return Evoral::IdentityConverter<double, nframes_t>();
}
@ -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;

View File

@ -44,10 +44,12 @@ class SourceFactory {
static boost::shared_ptr<Source> createSilent (Session&, const XMLNode& node,
nframes_t nframes, float sample_rate);
static boost::shared_ptr<Source> createReadable (DataType type, Session&, std::string path,
static boost::shared_ptr<Source> 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<Source> createWritable (DataType type, Session&, std::string name,
static boost::shared_ptr<Source> 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;

View File

@ -2336,7 +2336,9 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
try {
fs = boost::dynamic_pointer_cast<AudioFileSource> (
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<AudioRegion> region;
try {
region = boost::dynamic_pointer_cast<AudioRegion> (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<AudioRegion> (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<AudioRegion> (RegionFactory::create (pending_sources, 0, first_fs->length(), region_name_from_path (first_fs->name(), true)));
region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (
pending_sources, 0, first_fs->length(),
region_name_from_path (first_fs->name(), true)));
}
catch (failed_constructor& err) {

View File

@ -136,7 +136,6 @@ AudioLibrary::search_members_and (vector<string>& members, const vector<string>
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);

View File

@ -63,13 +63,12 @@ using namespace PBD;
using namespace Glib;
ustring AudioFileSource::peak_dir = "";
ustring AudioFileSource::search_path;
sigc::signal<void> 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<SizedSampleBuffer> 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 (Source::set_state (node)) {
return -1;
}
if (AudioSource::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 ((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<ustring> 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<ustring>::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)
{

View File

@ -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;
}
}

View File

@ -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;

419
libs/ardour/file_source.cc Normal file
View File

@ -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 <vector>
#include <sys/time.h>
#include <sys/stat.h>
#include <stdio.h> // for rename(), sigh
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <pbd/convert.h>
#include <pbd/basename.h>
#include <pbd/mountpoint.h>
#include <pbd/stl_delete.h>
#include <pbd/strsplit.h>
#include <pbd/shortpath.h>
#include <pbd/enumwriter.h>
#include <glibmm/miscutils.h>
#include <glibmm/fileutils.h>
#include <glibmm/thread.h>
#include <ardour/file_source.h>
#include <ardour/session.h>
#include <ardour/session_directory.h>
#include <ardour/source_factory.h>
#include <ardour/filename_extensions.h>
#include "i18n.h"
using namespace ARDOUR;
using namespace PBD;
using namespace Glib;
static const std::string PATH_SEP = "/"; // I don't do windows
map<DataType, ustring> 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<ustring> 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<ustring>::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));
}
}

View File

@ -66,7 +66,9 @@ Filter::make_new_sources (boost::shared_ptr<Region> region, SourceList& nsrcs, s
try {
nsrcs.push_back (boost::dynamic_pointer_cast<Source> (
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) {

View File

@ -217,13 +217,10 @@ create_mono_sources_for_writing (const vector<string>& 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;
}
}

View File

@ -50,8 +50,7 @@ using namespace PBD;
sigc::signal<void,MidiSource *> 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<MidiSource> newsrc = boost::dynamic_pointer_cast<MidiSource>(
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);

View File

@ -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<Region> r)
}
/* Source Management */
void
Session::add_source (boost::shared_ptr<Source> source)
{
@ -2912,7 +2915,6 @@ Session::source_by_id (const PBD::ID& id)
return source;
}
boost::shared_ptr<Source>
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<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(i->second);
boost::shared_ptr<AudioFileSource> afs
= boost::dynamic_pointer_cast<AudioFileSource>(i->second);
if (afs && afs->path() == path && chn == afs->channel()) {
return afs;
}
}
return boost::shared_ptr<Source>();
}
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<space_and_path>::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<AudioFileSource>
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<AudioFileSource> (
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<space_and_path>::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<MidiSource>
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<SMFSource> (SourceFactory::createWritable (DataType::MIDI, *this, mpath, false, frame_rate()));
return boost::dynamic_pointer_cast<SMFSource> (
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<AudioFileSource> (
SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate()));
SourceFactory::createWritable (DataType::AUDIO, *this, buf, true, false, frame_rate()));
}
catch (failed_constructor& err) {

View File

@ -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<AudioFileSource> fs;
if ((fs = boost::dynamic_pointer_cast<AudioFileSource> (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<AudioFileSource> fs;
boost::shared_ptr<FileSource> fs;
if ((fs = boost::dynamic_pointer_cast<AudioFileSource> (i->second)) != 0) {
if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
all_sources.insert (fs->path());
}
}

View File

@ -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 <ardour/silentfilesource.h>
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;
}

View File

@ -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<nframes_t>& 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<nframes_t>& src, nframes_t dur)
/** Append an event with a timestamp in beats (double) */
void
SMFSource::append_event_unlocked_beats(const Evoral::Event<double>& ev)
SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev)
{
if (ev.size() == 0) {
return;
@ -297,7 +266,7 @@ SMFSource::append_event_unlocked_beats(const Evoral::Event<double>& ev)
/** Append an event with a timestamp in frames (nframes_t) */
void
SMFSource::append_event_unlocked_frames(const Evoral::Event<nframes_t>& ev)
SMFSource::append_event_unlocked_frames (const Evoral::Event<nframes_t>& ev)
{
if (ev.size() == 0) {
return;
@ -330,48 +299,30 @@ SMFSource::append_event_unlocked_frames(const Evoral::Event<nframes_t>& 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<string> 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<string>::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();
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -179,7 +179,8 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
}
boost::shared_ptr<Source>
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<Source> ret (new SndFileSource (s, path, chn, flags));
boost::shared_ptr<Source> ret (new SndFileSource (s, path, embedded, chn, flags));
if (setup_peakfile (ret, defer_peaks)) {
return boost::shared_ptr<Source>();
@ -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<Source> ret (new CoreAudioSource (s, path, chn, flags));
boost::shared_ptr<Source> ret (new CoreAudioSource (s, path, embedded, chn, flags));
if (setup_peakfile (ret, defer_peaks)) {
return boost::shared_ptr<Source>();
}
@ -224,8 +225,7 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn,
} else if (type == DataType::MIDI) {
// FIXME: flags?
boost::shared_ptr<Source> ret (new SMFSource (s, path, SMFSource::Flag(0)));
boost::shared_ptr<Source> 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<Source>
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<Source> ret (new SndFileSource (s, path,
boost::shared_ptr<Source> 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<Source> ret (new SMFSource (s, path));
boost::shared_ptr<Source> 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<Source> ();
}

View File

@ -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

View File

@ -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();
}