diff options
Diffstat (limited to 'libs/ardour')
36 files changed, 865 insertions, 552 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index 3892af6e9b..465138d90d 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -12,7 +12,7 @@ ardour = env.Copy() # this defines the version number of libardour # -domain = 'libardour' +domain = 'libardour2' ardour.Append(DOMAIN = domain, MAJOR = 2, MINOR = 0, MICRO = 0) ardour.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"") @@ -101,6 +101,7 @@ recent_sessions.cc region.cc region_factory.cc reverse.cc +resampled_source.cc quantize.cc route.cc route_group.cc diff --git a/libs/ardour/ardour/ardour.h b/libs/ardour/ardour/ardour.h index 1b9725a04c..6e7b494441 100644 --- a/libs/ardour/ardour/ardour.h +++ b/libs/ardour/ardour/ardour.h @@ -47,8 +47,6 @@ namespace ARDOUR { int init (bool with_vst, bool try_optimization); int cleanup (); - int setup_midi(AudioEngine& engine); - std::string get_ardour_revision (); microseconds_t get_microseconds (); diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h index 78d10f9d64..4d80c8ddf5 100644 --- a/libs/ardour/ardour/audiofilesource.h +++ b/libs/ardour/ardour/audiofilesource.h @@ -61,7 +61,8 @@ class AudioFileSource : public AudioSource { Glib::ustring path() const { return _path; } Glib::ustring peak_path (Glib::ustring audio_path); - Glib::ustring old_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; } @@ -122,7 +123,7 @@ class AudioFileSource : public AudioSource { to cause issues. */ - virtual void handle_header_position_change (); + virtual void handle_header_position_change () {} protected: @@ -166,6 +167,10 @@ class AudioFileSource : public AudioSource { bool find (Glib::ustring& path, bool must_exist, bool& is_new, uint16_t& chan); bool removable() const; bool writable() const { return _flags & Writable; } + + private: + Glib::ustring old_peak_path (Glib::ustring audio_path); + Glib::ustring broken_peak_path (Glib::ustring audio_path); }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h index 812c30e8c2..7b22528bd1 100644 --- a/libs/ardour/ardour/audiosource.h +++ b/libs/ardour/ardour/audiosource.h @@ -40,7 +40,6 @@ using std::list; using std::vector; -using Glib::ustring; namespace ARDOUR { @@ -49,10 +48,23 @@ const nframes_t frames_per_peak = 256; class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR::AudioSource> { public: - AudioSource (Session&, ustring name); + AudioSource (Session&, Glib::ustring name); AudioSource (Session&, const XMLNode&); virtual ~AudioSource (); + + /* one could argue that this should belong to Source, but other data types + generally do not come with a model of "offset along an audio timeline" + so its here in AudioSource for now. + */ + + virtual nframes_t natural_position() const { return 0; } + /* returns the number of items in this `audio_source' */ + + virtual nframes_t length() const { + return _length; + } + virtual nframes_t available_peaks (double zoom) const; virtual nframes_t read (Sample *dst, nframes_t start, nframes_t cnt) const; @@ -65,8 +77,8 @@ const nframes_t frames_per_peak = 256; virtual bool can_truncate_peaks() const { return true; } - void set_captured_for (ustring str) { _captured_for = str; } - ustring captured_for() const { return _captured_for; } + void set_captured_for (Glib::ustring str) { _captured_for = str; } + Glib::ustring captured_for() const { return _captured_for; } uint32_t read_data_count() const { return _read_data_count; } uint32_t write_data_count() const { return _write_data_count; } @@ -81,7 +93,7 @@ const nframes_t frames_per_peak = 256; XMLNode& get_state (); int set_state (const XMLNode&); - int rename_peakfile (ustring newpath); + int rename_peakfile (Glib::ustring newpath); void touch_peakfile (); static void set_build_missing_peakfiles (bool yn) { @@ -92,35 +104,43 @@ const nframes_t frames_per_peak = 256; _build_peakfiles = yn; } + static bool get_build_peakfiles () { + return _build_peakfiles; + } + virtual int setup_peakfile () { return 0; } int prepare_for_peakfile_writes (); - void done_with_peakfile_writes (); + void done_with_peakfile_writes (bool done = true); protected: static bool _build_missing_peakfiles; static bool _build_peakfiles; - bool _peaks_built; - mutable Glib::Mutex _lock; - ustring peakpath; - ustring _captured_for; + bool _peaks_built; + mutable Glib::Mutex _lock; + mutable Glib::Mutex _peaks_ready_lock; + nframes_t _length; + Glib::ustring peakpath; + Glib::ustring _captured_for; mutable uint32_t _read_data_count; // modified in read() mutable uint32_t _write_data_count; // modified in write() - int initialize_peakfile (bool newfile, ustring path); + int initialize_peakfile (bool newfile, Glib::ustring path); int build_peaks_from_scratch (); - int compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force); + int compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force, bool intermediate_peaks_ready_signal); void truncate_peakfile(); mutable off_t _peak_byte_max; // modified in compute_and_write_peak() virtual nframes_t read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const = 0; virtual nframes_t write_unlocked (Sample *dst, nframes_t cnt) = 0; - virtual ustring peak_path(ustring audio_path) = 0; - virtual ustring old_peak_path(ustring audio_path) = 0; + virtual Glib::ustring peak_path(Glib::ustring audio_path) = 0; + 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); + private: int peakfile; nframes_t peak_leftover_cnt; @@ -128,7 +148,7 @@ const nframes_t frames_per_peak = 256; Sample* peak_leftovers; nframes_t peak_leftover_frame; - bool file_changed (ustring path); + bool file_changed (Glib::ustring path); }; } diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h index fe47614a1f..f96ecc0bd1 100644 --- a/libs/ardour/ardour/automatable.h +++ b/libs/ardour/ardour/automatable.h @@ -83,6 +83,14 @@ public: Glib::Mutex& automation_lock() const { return _automation_lock; } + static void set_automation_interval (jack_nframes_t frames) { + _automation_interval = frames; + } + + static jack_nframes_t automation_interval() { + return _automation_interval; + } + protected: void can_automate(Parameter); @@ -102,6 +110,7 @@ protected: std::set<Parameter> _can_automate_list; nframes_t _last_automation_snapshot; + static nframes_t _automation_interval; }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/configuration.h b/libs/ardour/ardour/configuration.h index 70b7e166c1..7b890500d8 100644 --- a/libs/ardour/ardour/configuration.h +++ b/libs/ardour/ardour/configuration.h @@ -42,17 +42,7 @@ class Configuration : public PBD::Stateful Configuration(); virtual ~Configuration(); - struct MidiPortDescriptor { - std::string tag; - std::string device; - std::string type; - std::string mode; - - MidiPortDescriptor (const XMLNode&); - XMLNode& get_state(); - }; - - std::map<std::string,MidiPortDescriptor *> midi_ports; + std::map<std::string,XMLNode> midi_ports; void map_parameters (sigc::slot<void,const char*> theSlot); diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h index 4d5579a9a0..b592a9f721 100644 --- a/libs/ardour/ardour/configuration_vars.h +++ b/libs/ardour/ardour/configuration_vars.h @@ -138,11 +138,15 @@ CONFIG_VARIABLE (bool, verify_remove_last_capture, "verify-remove-last-capture", CONFIG_VARIABLE (bool, no_new_session_dialog, "no-new-session-dialog", false) CONFIG_VARIABLE (bool, use_vst, "use-vst", true) CONFIG_VARIABLE (uint32_t, subframes_per_frame, "subframes-per-frame", 100) -CONFIG_VARIABLE (uint32_t, saved_history_depth, "save-history-depth", 100) +CONFIG_VARIABLE (bool, save_history, "save-history", true) +CONFIG_VARIABLE (int32_t, saved_history_depth, "save-history-depth", 20) +CONFIG_VARIABLE (int32_t, history_depth, "history-depth", 20) CONFIG_VARIABLE (bool, use_overlap_equivalency, "use-overlap-equivalency", false) CONFIG_VARIABLE (bool, periodic_safety_backups, "periodic-safety-backups", true) CONFIG_VARIABLE (uint32_t, periodic_safety_backup_interval, "periodic-safety-backup-interval", 120) -CONFIG_VARIABLE (string, possible_audio_file_regexp, "possible-audio-file-regexp", "\\.(wav|aiff|caf|w64|L|R)$") +CONFIG_VARIABLE (float, automation_interval, "automation-interval", 50) +CONFIG_VARIABLE (bool, sync_all_route_ordering, "sync-all-route-ordering", true) +CONFIG_VARIABLE (bool, only_copy_imported_files, "only-copy-imported-files", true) /* denormal management */ diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h index 6c040be63e..6e68c01d8c 100644 --- a/libs/ardour/ardour/io.h +++ b/libs/ardour/ardour/io.h @@ -219,7 +219,7 @@ class IO : public Automatable, public Latent public: /* automation */ - + struct GainControl : public AutomationControl { GainControl (std::string name, IO& i, boost::shared_ptr<AutomationList> al) : AutomationControl (i._session, al, name) diff --git a/libs/ardour/ardour/profile.h b/libs/ardour/ardour/profile.h index 3347447915..b016063c4d 100644 --- a/libs/ardour/ardour/profile.h +++ b/libs/ardour/ardour/profile.h @@ -29,6 +29,8 @@ class RuntimeProfile { public: enum Element { SmallScreen, + SAE, + SinglePackage, LastElement }; @@ -38,6 +40,12 @@ class RuntimeProfile { void set_small_screen() { bits[SmallScreen] = true; } bool get_small_screen() const { return bits[SmallScreen]; } + void set_sae () { bits[SAE] = true; } + bool get_sae () const { return bits[SAE]; } + + void set_single_package () { bits[SinglePackage] = true; } + bool get_single_package () const { return bits[SinglePackage]; } + private: boost::dynamic_bitset<uint64_t> bits; diff --git a/libs/ardour/ardour/resampled_source.h b/libs/ardour/ardour/resampled_source.h new file mode 100644 index 0000000000..9a88ca9644 --- /dev/null +++ b/libs/ardour/ardour/resampled_source.h @@ -0,0 +1,50 @@ +/* + 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. + +*/ + +#ifndef __ardour_resampled_source_h__ +#define __ardour_resampled_source_h__ + +#include <samplerate.h> + +#include <ardour/types.h> +#include <ardour/importable_source.h> + +namespace ARDOUR { + +class ResampledImportableSource : public ImportableSource +{ + public: + ResampledImportableSource (SNDFILE* sf, SF_INFO* info, nframes_t rate, SrcQuality); + ~ResampledImportableSource (); + + nframes_t read (Sample* buffer, nframes_t nframes); + + float ratio() const { return src_data.src_ratio; } + + static const uint32_t blocksize; + + private: + float* input; + SRC_STATE* src_state; + SRC_DATA src_data; +}; + +} + +#endif /* __ardour_resampled_source_h__ */ diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 1fd6eff0f8..fc17af06ee 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -258,6 +258,9 @@ class Route : public IO uint32_t remote_control_id () const; sigc::signal<void> RemoteControlIDChanged; + void sync_order_keys (); + static sigc::signal<void> SyncOrderKeys; + protected: friend class Session; diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 94caf8a242..bbcae6e91d 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -261,6 +261,8 @@ class Session : public PBD::StatefulDestructible std::string automation_dir () const; + 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); @@ -422,6 +424,7 @@ class Session : public PBD::StatefulDestructible int restore_history (string snapshot_name); void remove_state (string snapshot_name); void rename_state (string old_name, string new_name); + void remove_pending_capture_state (); sigc::signal<void,string> StateSaved; sigc::signal<void> StateReady; @@ -568,13 +571,14 @@ class Session : public PBD::StatefulDestructible string doing_what; /* control info */ - bool multichan; bool sample_convert; + SrcQuality quality; volatile bool freeze; std::vector<Glib::ustring> paths; /* result */ - std::vector<boost::shared_ptr<Region> > new_regions; + SourceList sources; + }; int import_audiofile (import_status&); @@ -650,8 +654,6 @@ class Session : public PBD::StatefulDestructible void add_curve(Curve*); void add_automation_list(AutomationList*); - nframes_t automation_interval () const { return _automation_interval; } - /* fade curves */ float get_default_fade_length () const { return default_fade_msecs; } @@ -1650,8 +1652,6 @@ class Session : public PBD::StatefulDestructible void allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, bool force); uint32_t _npan_buffers; - nframes_t _automation_interval; - /* VST support */ long _vst_callback (VSTPlugin*, @@ -1668,7 +1668,6 @@ class Session : public PBD::StatefulDestructible uint32_t n_physical_outputs; uint32_t n_physical_inputs; - void remove_pending_capture_state (); int find_all_sources (std::string path, std::set<std::string>& result); int find_all_sources_across_snapshots (std::set<std::string>& result, bool exclude_this_snapshot); @@ -1688,6 +1687,8 @@ class Session : public PBD::StatefulDestructible XMLNode& get_control_protocol_state (); + void set_history_depth (uint32_t depth); + void sync_order_keys (); }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h index 916e9da49e..4fd71a4c96 100644 --- a/libs/ardour/ardour/sndfilesource.h +++ b/libs/ardour/ardour/sndfilesource.h @@ -76,9 +76,6 @@ class SndFileSource : public AudioFileSource { SF_INFO _info; SF_BROADCAST_INFO *_broadcast_info; - mutable float *interleave_buf; - mutable nframes_t interleave_bufsize; - void init (); int open(); void close(); @@ -105,6 +102,7 @@ class SndFileSource : public AudioFileSource { void handle_header_position_change (); static int64_t get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists); + static Sample* get_interleave_buffer (nframes_t size); }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/source_factory.h b/libs/ardour/ardour/source_factory.h index fb591216bf..01f50126a4 100644 --- a/libs/ardour/ardour/source_factory.h +++ b/libs/ardour/ardour/source_factory.h @@ -36,16 +36,23 @@ class Session; class SourceFactory { public: + static void init (); + static sigc::signal<void,boost::shared_ptr<Source> > SourceCreated; - static boost::shared_ptr<Source> create (Session&, const XMLNode& node); + static boost::shared_ptr<Source> create (Session&, const XMLNode& node, bool async = false); 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, int chn, AudioFileSource::Flag flags, bool announce = true); - static boost::shared_ptr<Source> createWritable (DataType type, Session&, std::string name, bool destructive, nframes_t rate, bool announce = true); + static boost::shared_ptr<Source> createReadable (DataType type, Session&, std::string path, int chn, AudioFileSource::Flag flags, + bool announce = true, bool async = false); + static boost::shared_ptr<Source> createWritable (DataType type, Session&, std::string name, bool destructive, nframes_t rate, + bool announce = true, bool async = true); + + static Glib::Cond* PeaksToBuild; + static Glib::StaticMutex peak_building_lock; + static std::list<boost::weak_ptr<AudioSource> > files_with_peaks; - private: - static int setup_peakfile (boost::shared_ptr<Source>); + static int setup_peakfile (boost::shared_ptr<Source>, bool async); }; } diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index e13bd09d83..5b50713313 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -370,6 +370,15 @@ namespace ARDOUR { }; typedef std::vector<boost::shared_ptr<Source> > SourceList; + + enum SrcQuality { + SrcBest, + SrcGood, + SrcQuick, + SrcFast, + SrcFastest + }; + } // namespace ARDOUR std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf); diff --git a/libs/ardour/ardour/utils.h b/libs/ardour/ardour/utils.h index cde17d8b49..e52274eb1f 100644 --- a/libs/ardour/ardour/utils.h +++ b/libs/ardour/ardour/utils.h @@ -50,7 +50,7 @@ int cmp_nocase (const std::string& s, const std::string& s2); int touch_file(Glib::ustring path); Glib::ustring path_expand (Glib::ustring); -Glib::ustring region_name_from_path (Glib::ustring path, bool strip_channels); +Glib::ustring region_name_from_path (Glib::ustring path, bool strip_channels, bool add_channel_suffix = false, uint32_t total = 0, uint32_t this_one = 0); bool path_is_paired (Glib::ustring path, Glib::ustring& pair_base); void compute_equal_power_fades (nframes_t nframes, float* in, float* out); diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc index d28d88488e..d5c6120946 100644 --- a/libs/ardour/audio_playlist.cc +++ b/libs/ardour/audio_playlist.cc @@ -379,7 +379,9 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh) bottom = region; } - + if (!top->opaque()) { + continue; + } OverlapType c = top->coverage (bottom->position(), bottom->last_frame()); diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index a4ce5f291d..2a4b36f7d8 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -156,7 +156,7 @@ AudioEngine::start () _has_run = true; Running(); /* EMIT SIGNAL */ } else { - error << _("cannot activate JACK client") << endmsg; + // error << _("cannot activate JACK client") << endmsg; } } @@ -1078,7 +1078,7 @@ AudioEngine::connect_to_jack (string client_name) error << _("Unable to connect to JACK server") << endmsg; } - error << string_compose (_("Could not connect to JACK server as \"%1\""), jack_client_name) << endmsg; + // error message is not useful here return -1; } diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc index 1044dd10d2..1284dd343b 100644 --- a/libs/ardour/audiofilesource.cc +++ b/libs/ardour/audiofilesource.cc @@ -21,10 +21,13 @@ #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> @@ -40,6 +43,7 @@ #include <ardour/sndfile_helpers.h> #include <ardour/sndfilesource.h> #include <ardour/session.h> +#include <ardour/session_directory.h> #include <ardour/source_factory.h> #include <ardour/filename_extensions.h> @@ -153,7 +157,60 @@ AudioFileSource::init (ustring pathstr, bool must_exist) ustring AudioFileSource::peak_path (ustring audio_path) { - return _session.peak_path_from_audio_path (audio_path); + ustring base; + + base = PBD::basename_nosuffix (audio_path); + base += '%'; + base += (char) ('A' + _channel); + + return _session.peak_path (base); +} + +ustring +AudioFileSource::find_broken_peakfile (ustring peak_path, ustring audio_path) +{ + ustring str; + + /* check for the broken location in use by 2.0 for several months */ + + str = broken_peak_path (audio_path); + + if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) { + + if (is_embedded()) { + + /* it would be nice to rename it but the nature of + the bug means that we can't reliably use it. + */ + + peak_path = str; + + } else { + /* all native files are mono, so we can just rename + it. + */ + ::rename (str.c_str(), peak_path.c_str()); + } + + } else { + /* Nasty band-aid for older sessions that were created before we + used libsndfile for all audio files. + */ + + + str = old_peak_path (audio_path); + if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) { + peak_path = str; + } + } + + return peak_path; +} + +ustring +AudioFileSource::broken_peak_path (ustring audio_path) +{ + return _session.peak_path (audio_path); } ustring @@ -171,9 +228,9 @@ AudioFileSource::old_peak_path (ustring audio_path) char buf[32]; #ifdef __APPLE__ - snprintf (buf, sizeof (buf), "%u-%u-%d", stat_mount.st_ino, stat_file.st_ino, _channel); + snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel); #else - snprintf (buf, sizeof (buf), "%ld-%ld-%d", stat_mount.st_ino, stat_file.st_ino, _channel); + snprintf (buf, sizeof (buf), "%ld-%ld-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel); #endif ustring res = peak_dir; @@ -227,7 +284,7 @@ AudioFileSource::set_state (const XMLNode& node) } if ((prop = node.property (X_("channel"))) != 0) { - _channel = atoi (prop->value().c_str()); + _channel = atoi (prop->value()); } else { _channel = 0; } @@ -265,6 +322,10 @@ AudioFileSource::mark_streaming_write_completed () if (!writable()) { return; } + + /* XXX notice that we're readers of _peaks_built + but we must hold a solid lock on PeaksReady. + */ Glib::Mutex::Lock lm (_lock); @@ -432,7 +493,7 @@ AudioFileSource::find (ustring& pathstr, bool must_exist, bool& isnew, uint16_t& fullpath += shorter; if (Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { - chan = atoi (pathstr.substr (pos+1).c_str()); + chan = atoi (pathstr.substr (pos+1)); pathstr = shorter; keeppath = fullpath; ++cnt; @@ -484,7 +545,7 @@ AudioFileSource::find (ustring& pathstr, bool must_exist, bool& isnew, uint16_t& 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).c_str()); + chan = atoi (pathstr.substr (pos+1)); pathstr = shorter; } } @@ -542,15 +603,6 @@ AudioFileSource::set_header_position_offset (nframes_t offset) HeaderPositionOffsetChanged (); } -void -AudioFileSource::handle_header_position_change () -{ - if (writable()) { - set_header_timeline_position (); - flush_header (); - } -} - void AudioFileSource::set_timeline_position (int64_t pos) { @@ -603,15 +655,15 @@ AudioFileSource::set_source_name (ustring newname, bool destructive) bool AudioFileSource::is_empty (Session& s, ustring path) { - bool ret = false; + SoundFileInfo info; + string err; - boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, s, path, 0, NoPeakFile, false)); - - if (afs) { - ret = (afs->length() == 0); + if (!get_soundfile_info (path, info, err)) { + /* dangerous: we can't get info, so assume that its not empty */ + return false; } - return ret; + return info.length == 0; } int diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc index d09a9b29cd..a2ce7209f6 100644 --- a/libs/ardour/audiosource.cc +++ b/libs/ardour/audiosource.cc @@ -20,6 +20,7 @@ #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> +#include <poll.h> #include <float.h> #include <utime.h> #include <cerrno> @@ -29,18 +30,21 @@ #include <algorithm> #include <vector> +#include <glibmm/fileutils.h> + #include <pbd/xml++.h> #include <pbd/pthread_utils.h> #include <ardour/audiosource.h> #include <ardour/cycle_timer.h> -#include <ardour/runtime_functions.h> +#include <ardour/session.h> #include "i18n.h" using namespace std; using namespace ARDOUR; using namespace PBD; +using Glib::ustring; bool AudioSource::_build_missing_peakfiles = false; bool AudioSource::_build_peakfiles = false; @@ -126,12 +130,12 @@ bool AudioSource::peaks_ready (sigc::slot<void> the_slot, sigc::connection& conn) const { bool ret; - Glib::Mutex::Lock lm (_lock); + Glib::Mutex::Lock lm (_peaks_ready_lock); /* check to see if the peak data is ready. if not connect the slot while still holding the lock. */ - + if (!(ret = _peaks_built)) { conn = PeaksReady.connect (the_slot); } @@ -182,15 +186,10 @@ AudioSource::initialize_peakfile (bool newfile, ustring audio_path) peakpath = peak_path (audio_path); - /* Nasty band-aid for older sessions that were created before we - used libsndfile for all audio files. - */ + /* if the peak file should be there, but isn't .... */ - if (!newfile && access (peakpath.c_str(), R_OK) != 0) { - ustring str = old_peak_path (audio_path); - if (access (str.c_str(), R_OK) == 0) { - peakpath = str; - } + if (!newfile && !Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) { + peakpath = find_broken_peakfile (peakpath, audio_path); } if (newfile) { @@ -332,7 +331,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr /* open, read, close */ if ((_peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) { - error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg; + error << string_compose(_("AudioSource: cannot open peakpath (a) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg; return -1; } @@ -406,7 +405,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr /* open ... close during out: handling */ if ((_peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) { - error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg; + error << string_compose(_("AudioSource: cannot open peakpath (b) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg; return 0; } @@ -581,9 +580,11 @@ AudioSource::build_peaks_from_scratch () { nframes_t current_frame; nframes_t cnt; - Sample buf[frames_per_peak]; + Sample* buf = 0; nframes_t frames_read; nframes_t frames_to_read; + const nframes_t bufsize = 65536; // 256kB per disk read for mono data is about ideal + int ret = -1; { @@ -598,39 +599,41 @@ AudioSource::build_peaks_from_scratch () current_frame = 0; cnt = _length; _peaks_built = false; + buf = new Sample[bufsize]; while (cnt) { - frames_to_read = min (frames_per_peak, cnt); + frames_to_read = min (bufsize, cnt); if ((frames_read = read_unlocked (buf, current_frame, frames_to_read)) != frames_to_read) { error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg; - done_with_peakfile_writes (); + done_with_peakfile_writes (false); goto out; } - if (compute_and_write_peaks (buf, current_frame, frames_read, true)) { + if (compute_and_write_peaks (buf, current_frame, frames_read, true, false)) { break; } current_frame += frames_read; cnt -= frames_read; } - + if (cnt == 0) { /* success */ truncate_peakfile(); - _peaks_built = true; } - done_with_peakfile_writes (); + done_with_peakfile_writes ((cnt == 0)); } - - /* lock no longer held, safe to signal */ - - if (_peaks_built) { - PeaksReady (); /* EMIT SIGNAL */ - ret = 0; + + { + Glib::Mutex::Lock lm (_peaks_ready_lock); + + if (_peaks_built) { + PeaksReady (); /* EMIT SIGNAL */ + ret = 0; + } } out: @@ -638,6 +641,10 @@ AudioSource::build_peaks_from_scratch () unlink (peakpath.c_str()); } + if (buf) { + delete [] buf; + } + return ret; } @@ -645,17 +652,21 @@ int AudioSource::prepare_for_peakfile_writes () { if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) { - error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg; + error << string_compose(_("AudioSource: cannot open peakpath (c) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg; return -1; } return 0; } void -AudioSource::done_with_peakfile_writes () +AudioSource::done_with_peakfile_writes (bool done) { if (peak_leftover_cnt) { - compute_and_write_peaks (0, 0, 0, true); + compute_and_write_peaks (0, 0, 0, true, false); + } + + if (done) { + _peaks_built = true; } if (peakfile >= 0) { @@ -665,7 +676,7 @@ AudioSource::done_with_peakfile_writes () } int -AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force) +AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force, bool intermediate_peaks_ready) { Sample* buf2 = 0; nframes_t to_do; @@ -695,7 +706,8 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe x.min = peak_leftovers[0]; x.max = peak_leftovers[0]; - find_peaks (peak_leftovers + 1, peak_leftover_cnt - 1, &x.min, &x.max); + + ARDOUR::find_peaks (peak_leftovers + 1, peak_leftover_cnt - 1, &x.min, &x.max); off_t byte = (peak_leftover_frame / frames_per_peak) * sizeof (PeakData); @@ -706,8 +718,13 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe _peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData))); - PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */ - PeaksReady (); /* EMIT SIGNAL */ + { + Glib::Mutex::Lock lm (_peaks_ready_lock); + PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */ + if (intermediate_peaks_ready) { + PeaksReady (); /* EMIT SIGNAL */ + } + } /* left overs are done */ @@ -778,7 +795,7 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe peakbuf[peaks_computed].max = buf[0]; peakbuf[peaks_computed].min = buf[0]; - find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max); + ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max); peaks_computed++; buf += this_time; @@ -814,8 +831,11 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe _peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaks_computed)); if (frames_done) { + Glib::Mutex::Lock lm (_peaks_ready_lock); PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */ - PeaksReady (); /* EMIT SIGNAL */ + if (intermediate_peaks_ready) { + PeaksReady (); /* EMIT SIGNAL */ + } } ret = 0; @@ -882,3 +902,11 @@ AudioSource::available_peaks (double zoom_factor) const return (end/sizeof(PeakData)) * frames_per_peak; } +void +AudioSource::update_length (nframes_t pos, nframes_t cnt) +{ + if (pos + cnt > _length) { + _length = pos+cnt; + } +} + diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc index e344d5f2a6..c509997b2e 100644 --- a/libs/ardour/auditioner.cc +++ b/libs/ardour/auditioner.cc @@ -137,7 +137,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region) boost::shared_ptr<AudioRegion> the_region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region))); the_region->set_position (0, this); - _diskstream->playlist()->clear (); + _diskstream->playlist()->drop_regions (); _diskstream->playlist()->add_region (the_region, 0, 1); if (_diskstream->n_channels().n_audio() < the_region->n_channels()) { diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc index 0609b8d380..45b19d1997 100644 --- a/libs/ardour/automatable.cc +++ b/libs/ardour/automatable.cc @@ -34,6 +34,8 @@ using namespace std; using namespace ARDOUR; using namespace PBD; +nframes_t Automatable::_automation_interval = 0; + Automatable::Automatable(Session& _session, const string& name) : SessionObject(_session, name) , _last_automation_snapshot(0) @@ -422,7 +424,7 @@ Automatable::protect_automation () void Automatable::automation_snapshot (nframes_t now) { - if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) { + if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) { for (Controls::iterator i = _controls.begin(); i != _controls.end(); ++i) { if (i->second->list()->automation_write()) { diff --git a/libs/ardour/configuration.cc b/libs/ardour/configuration.cc index 5faab7c0ab..1460491180 100644 --- a/libs/ardour/configuration.cc +++ b/libs/ardour/configuration.cc @@ -25,6 +25,9 @@ #include <pbd/filesystem.h> #include <pbd/file_utils.h> +#include <midi++/manager.h> + +#include <ardour/ardour.h> #include <ardour/configuration.h> #include <ardour/audio_diskstream.h> #include <ardour/control_protocol_manager.h> @@ -195,9 +198,12 @@ Configuration::get_state () LocaleGuard lg (X_("POSIX")); root = new XMLNode("Ardour"); - typedef map<string, MidiPortDescriptor*>::const_iterator CI; - for(CI m = midi_ports.begin(); m != midi_ports.end(); ++m){ - root->add_child_nocopy(m->second->get_state()); + + MIDI::Manager::PortMap::const_iterator i; + const MIDI::Manager::PortMap& ports = MIDI::Manager::instance()->get_midi_ports(); + + for (i = ports.begin(); i != ports.end(); ++i) { + root->add_child_nocopy(i->second->get_state()); } root->add_child_nocopy (get_variables (sigc::mem_fun (*this, &Configuration::save_config_options_predicate), "Config")); @@ -250,10 +256,13 @@ Configuration::set_state (const XMLNode& root) if (node->name() == "MIDI-port") { try { - pair<string,MidiPortDescriptor*> newpair; - newpair.second = new MidiPortDescriptor (*node); - newpair.first = newpair.second->tag; - midi_ports.insert (newpair); + + MIDI::Port::Descriptor desc (*node); + map<string,XMLNode>::iterator x; + if ((x = midi_ports.find (desc.tag)) != midi_ports.end()) { + midi_ports.erase (x); + } + midi_ports.insert (pair<string,XMLNode>(desc.tag,*node)); } catch (failed_constructor& err) { @@ -296,53 +305,6 @@ Configuration::set_variables (const XMLNode& node, ConfigVariableBase::Owner own #undef CONFIG_VARIABLE_SPECIAL } - -Configuration::MidiPortDescriptor::MidiPortDescriptor (const XMLNode& node) -{ - const XMLProperty *prop; - bool have_tag = false; - bool have_device = false; - bool have_type = false; - bool have_mode = false; - - if ((prop = node.property ("tag")) != 0) { - tag = prop->value(); - have_tag = true; - } - - if ((prop = node.property ("device")) != 0) { - device = prop->value(); - have_device = true; - } - - if ((prop = node.property ("type")) != 0) { - type = prop->value(); - have_type = true; - } - - if ((prop = node.property ("mode")) != 0) { - mode = prop->value(); - have_mode = true; - } - - if (!have_tag || !have_device || !have_type || !have_mode) { - throw failed_constructor(); - } -} - -XMLNode& -Configuration::MidiPortDescriptor::get_state() -{ - XMLNode* root = new XMLNode("MIDI-port"); - - root->add_property("tag", tag); - root->add_property("device", device); - root->add_property("type", type); - root->add_property("mode", mode); - - return *root; -} - void Configuration::map_parameters (sigc::slot<void,const char*> theSlot) { diff --git a/libs/ardour/crossfade.cc b/libs/ardour/crossfade.cc index 556f11125e..d45d5efa9f 100644 --- a/libs/ardour/crossfade.cc +++ b/libs/ardour/crossfade.cc @@ -294,6 +294,13 @@ Crossfade::read_at (Sample *buf, Sample *mixdown_buffer, offset = start - _position; + /* Prevent data from piling up inthe crossfade buffers when reading a transparent region */ + if (!(_out->opaque())) { + memset (crossfade_buffer_out, 0, sizeof (Sample) * to_write); + } else if (!(_in->opaque())) { + memset (crossfade_buffer_in, 0, sizeof (Sample) * to_write); + } + _out->read_at (crossfade_buffer_out, mixdown_buffer, gain_buffer, start, to_write, chan_n); _in->read_at (crossfade_buffer_in, mixdown_buffer, gain_buffer, start, to_write, chan_n); @@ -358,6 +365,13 @@ Crossfade::refresh () return false; } + /* Top layer shouldn't be transparent */ + + if (!((layer_relation > 0 ? _in : _out)->opaque())) { + Invalidated (shared_from_this()); + return false; + } + /* layer ordering cannot change */ int32_t new_layer_relation = (int32_t) (_in->layer() - _out->layer()); diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 52be946f1e..c3eae5ad86 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -39,7 +39,6 @@ #include <pbd/fpu.h> #include <midi++/port.h> -#include <midi++/port_request.h> #include <midi++/manager.h> #include <midi++/mmc.h> @@ -51,6 +50,7 @@ #include <ardour/audiosource.h> #include <ardour/utils.h> #include <ardour/session.h> +#include <ardour/source_factory.h> #include <ardour/control_protocol_manager.h> #include <ardour/audioengine.h> @@ -114,47 +114,25 @@ setup_osc () #endif int -ARDOUR::setup_midi (AudioEngine& engine) +setup_midi () { - std::map<string,Configuration::MidiPortDescriptor*>::iterator i; - int nports; - - if ((nports = Config->midi_ports.size()) == 0) { + if (Config->midi_ports.size() == 0) { warning << _("no MIDI ports specified: no MMC or MTC control possible") << endmsg; return 0; } - MIDI::Manager::instance()->set_api_data(engine.jack()); - - for (i = Config->midi_ports.begin(); i != Config->midi_ports.end(); ++i) { - Configuration::MidiPortDescriptor* port_descriptor; - - port_descriptor = (*i).second; - - MIDI::PortRequest request (port_descriptor->device, - port_descriptor->tag, - port_descriptor->mode, - port_descriptor->type); - - if (request.status != MIDI::PortRequest::OK) { - error << string_compose(_("MIDI port specifications for \"%1\" are not understandable."), port_descriptor->tag) << endmsg; - continue; - } - - MIDI::Manager::instance()->add_port (request); - - nports++; + for (std::map<string,XMLNode>::iterator i = Config->midi_ports.begin(); i != Config->midi_ports.end(); ++i) { + MIDI::Manager::instance()->add_port (i->second); } MIDI::Port* first; const MIDI::Manager::PortMap& ports = MIDI::Manager::instance()->get_midi_ports(); - first = ports.begin()->second; - if (nports > 1) { + if (ports.size() > 1) { - /* More than one port, so try using specific names for each port */ + first = ports.begin()->second; - map<string,Configuration::MidiPortDescriptor *>::iterator i; + /* More than one port, so try using specific names for each port */ if (Config->get_mmc_port_name() != N_("default")) { default_mmc_port = MIDI::Manager::instance()->port (Config->get_mmc_port_name()); @@ -182,11 +160,13 @@ ARDOUR::setup_midi (AudioEngine& engine) default_midi_port = first; } - } else { + } else if (ports.size() == 1) { + + first = ports.begin()->second; /* Only one port described, so use it for both MTC and MMC */ - default_mmc_port = MIDI::Manager::instance()->port (""); + default_mmc_port = first; default_mtc_port = default_mmc_port; default_midi_port = default_mmc_port; } @@ -209,15 +189,16 @@ ARDOUR::setup_midi (AudioEngine& engine) return 0; } - + void setup_hardware_optimization (bool try_optimization) { bool generic_mix_functions = true; - FPU fpu; if (try_optimization) { + FPU fpu; + #if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS) if (fpu.has_sse()) { @@ -253,6 +234,10 @@ setup_hardware_optimization (bool try_optimization) info << "Apple VecLib H/W specific optimizations in use" << endmsg; } #endif + + /* consider FPU denormal handling to be "h/w optimization" */ + + setup_fpu (); } if (generic_mix_functions) { @@ -265,9 +250,6 @@ setup_hardware_optimization (bool try_optimization) info << "No H/W specific optimizations in use" << endmsg; } - - setup_fpu (); - } int @@ -306,6 +288,8 @@ ARDOUR::init (bool use_vst, bool try_optimization) setup_hardware_optimization (try_optimization); + SourceFactory::init (); + /* singleton - first object is "it" */ new PluginManager (); @@ -387,6 +371,13 @@ ARDOUR::LocaleGuard::~LocaleGuard () void ARDOUR::setup_fpu () { + + if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) { + // valgrind doesn't understand this assembler stuff + // September 10th, 2007 + return; + } + #if defined(ARCH_X86) && defined(USE_XMMINTRIN) int MXCSR; diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc index bc16cde156..bd6351cf05 100644 --- a/libs/ardour/import.cc +++ b/libs/ardour/import.cc @@ -32,9 +32,9 @@ #include <glibmm.h> #include <pbd/basename.h> +#include <pbd/convert.h> #include <ardour/ardour.h> -#include <ardour/types.h> #include <ardour/session.h> #include <ardour/session_directory.h> #include <ardour/audio_diskstream.h> @@ -43,82 +43,22 @@ #include <ardour/audioregion.h> #include <ardour/region_factory.h> #include <ardour/source_factory.h> - +#include <ardour/resampled_source.h> #include "i18n.h" using namespace ARDOUR; using namespace PBD; -#define BLOCKSIZE 4096U - -class ImportableSource { - public: - ImportableSource (SNDFILE* sf, SF_INFO* info) : in (sf), sf_info (info) {} - virtual ~ImportableSource() {} - - virtual nframes_t read (Sample* buffer, nframes_t nframes) { - nframes_t per_channel = nframes / sf_info->channels; - per_channel = sf_readf_float (in, buffer, per_channel); - return per_channel * sf_info->channels; - } - - virtual float ratio() const { return 1.0f; } - -protected: - SNDFILE* in; - SF_INFO* sf_info; -}; - -class ResampledImportableSource : public ImportableSource { - public: - ResampledImportableSource (SNDFILE* sf, SF_INFO* info, nframes_t rate) : ImportableSource (sf, info) { - int err; - - sf_seek (in, 0, SEEK_SET) ; - - /* Initialize the sample rate converter. */ - - if ((src_state = src_new (SRC_SINC_BEST_QUALITY, sf_info->channels, &err)) == 0) { - error << string_compose(_("Import: src_new() failed : %1"), src_strerror (err)) << endmsg ; - throw failed_constructor (); - } - - src_data.end_of_input = 0 ; /* Set this later. */ - - /* Start with zero to force load in while loop. */ - - src_data.input_frames = 0 ; - src_data.data_in = input ; - - src_data.src_ratio = ((float) rate) / sf_info->samplerate ; - - } - - ~ResampledImportableSource () { - src_state = src_delete (src_state) ; - } - - nframes_t read (Sample* buffer, nframes_t nframes); - - float ratio() const { return src_data.src_ratio; } - - private: - float input[BLOCKSIZE]; - SRC_STATE* src_state; - SRC_DATA src_data; -}; - int Session::import_audiofile (import_status& status) { SNDFILE *in; vector<boost::shared_ptr<AudioFileSource> > newfiles; - SourceList sources; SF_INFO info; float *data = 0; Sample **channel_data = 0; - long nfiles = 0; + int nfiles = 0; string basepath; string sounds_dir; nframes_t so_far; @@ -127,178 +67,166 @@ Session::import_audiofile (import_status& status) vector<string> new_paths; struct tm* now; ImportableSource* importable = 0; - const nframes_t nframes = BLOCKSIZE; - - status.new_regions.clear (); - - if ((in = sf_open (status.paths.front().c_str(), SFM_READ, &info)) == 0) { - error << string_compose(_("Import: cannot open input sound file \"%1\""), status.paths.front()) << endmsg; - status.done = 1; - status.cancel = 1; - return -1; - } - - if ((nframes_t) info.samplerate != frame_rate()) { - importable = new ResampledImportableSource (in, &info, frame_rate()); - } else { - importable = new ImportableSource (in, &info); - } - - for (int n = 0; n < info.channels; ++n) { - newfiles.push_back (boost::shared_ptr<AudioFileSource>()); - } + const nframes_t nframes = ResampledImportableSource::blocksize; + uint32_t cnt = 1; - SessionDirectory sdir(get_best_session_directory_for_new_source ()); - sounds_dir = sdir.sound_path().to_string(); - - basepath = PBD::basename_nosuffix (status.paths.front()); + status.sources.clear (); + + for (vector<Glib::ustring>::iterator p = status.paths.begin(); p != status.paths.end(); ++p, ++cnt) { - for (int n = 0; n < info.channels; ++n) { + if ((in = sf_open ((*p).c_str(), SFM_READ, &info)) == 0) { + error << string_compose(_("Import: cannot open input sound file \"%1\""), (*p)) << endmsg; + status.done = 1; + status.cancel = 1; + return -1; + } + + if ((nframes_t) info.samplerate != frame_rate()) { + importable = new ResampledImportableSource (in, &info, frame_rate(), status.quality); + } else { + importable = new ImportableSource (in, &info); + } + + newfiles.clear (); - bool goodfile = false; + for (int n = 0; n < info.channels; ++n) { + newfiles.push_back (boost::shared_ptr<AudioFileSource>()); + } + + SessionDirectory sdir(get_best_session_directory_for_new_source ()); + sounds_dir = sdir.sound_path().to_string(); - do { - if (info.channels == 2) { - if (n == 0) { - snprintf (buf, sizeof(buf), "%s/%s-L.wav", sounds_dir.c_str(), basepath.c_str()); + basepath = PBD::basename_nosuffix ((*p)); + + for (int n = 0; n < info.channels; ++n) { + + bool goodfile = false; + + do { + if (info.channels == 2) { + if (n == 0) { + snprintf (buf, sizeof(buf), "%s/%s-L.wav", sounds_dir.c_str(), basepath.c_str()); + } else { + snprintf (buf, sizeof(buf), "%s/%s-R.wav", sounds_dir.c_str(), basepath.c_str()); + } + } else if (info.channels > 1) { + snprintf (buf, sizeof(buf), "%s/%s-c%d.wav", sounds_dir.c_str(), basepath.c_str(), n+1); } else { - snprintf (buf, sizeof(buf), "%s/%s-R.wav", sounds_dir.c_str(), basepath.c_str()); + snprintf (buf, sizeof(buf), "%s/%s.wav", sounds_dir.c_str(), basepath.c_str()); } - } else if (info.channels > 1) { - snprintf (buf, sizeof(buf), "%s/%s-c%d.wav", sounds_dir.c_str(), basepath.c_str(), n+1); - } else { - snprintf (buf, sizeof(buf), "%s/%s.wav", sounds_dir.c_str(), basepath.c_str()); - } - if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) { + if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) { - /* if the file already exists, we must come up with - * a new name for it. for now we just keep appending - * _ to basepath - */ + /* if the file already exists, we must come up with + * a new name for it. for now we just keep appending + * _ to basepath + */ - basepath += "_"; + basepath += "_"; - } else { + } else { - goodfile = true; - } + goodfile = true; + } - } while ( !goodfile); + } while ( !goodfile); - try { - newfiles[n] = boost::dynamic_pointer_cast<AudioFileSource> ( - SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate())); - } + try { + newfiles[n] = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate())); + } - catch (failed_constructor& err) { - error << string_compose(_("Session::import_audiofile: cannot open new file source for channel %1"), n+1) << endmsg; - goto out; - } + catch (failed_constructor& err) { + error << string_compose(_("Session::import_audiofile: cannot open new file source for channel %1"), n+1) << endmsg; + goto out; + } - new_paths.push_back (buf); - nfiles++; - } + new_paths.push_back (buf); + newfiles[n]->prepare_for_peakfile_writes (); + nfiles++; + } - data = new float[nframes * info.channels]; - channel_data = new Sample * [ info.channels ]; + data = new float[nframes * info.channels]; + channel_data = new Sample * [ info.channels ]; - for (int n = 0; n < info.channels; ++n) { - channel_data[n] = new Sample[nframes]; - } + for (int n = 0; n < info.channels; ++n) { + channel_data[n] = new Sample[nframes]; + } - so_far = 0; + so_far = 0; - status.doing_what = _("converting audio"); - status.progress = 0.0; + if ((nframes_t) info.samplerate != frame_rate()) { + status.doing_what = string_compose (_("converting %1\n(resample from %2KHz to %3KHz)\n(%4 of %5)"), + basepath, + info.samplerate/1000.0f, + frame_rate()/1000.0f, + cnt, status.paths.size()); + + } else { + status.doing_what = string_compose (_("converting %1\n(%2 of %3)"), + basepath, + cnt, status.paths.size()); - while (!status.cancel) { + } + + status.progress = 0.0; + + while (!status.cancel) { - nframes_t nread, nfread; - long x; - long chn; + nframes_t nread, nfread; + long x; + long chn; - if ((nread = importable->read (data, nframes)) == 0) { - break; - } - nfread = nread / info.channels; + if ((nread = importable->read (data, nframes)) == 0) { + break; + } + nfread = nread / info.channels; - /* de-interleave */ + /* de-interleave */ - for (chn = 0; chn < info.channels; ++chn) { + for (chn = 0; chn < info.channels; ++chn) { - nframes_t n; - for (x = chn, n = 0; n < nfread; x += info.channels, ++n) { - channel_data[chn][n] = (Sample) data[x]; + nframes_t n; + for (x = chn, n = 0; n < nfread; x += info.channels, ++n) { + channel_data[chn][n] = (Sample) data[x]; + } } - } - /* flush to disk */ + /* flush to disk */ - for (chn = 0; chn < info.channels; ++chn) { - newfiles[chn]->write (channel_data[chn], nfread); - } + for (chn = 0; chn < info.channels; ++chn) { + newfiles[chn]->write (channel_data[chn], nfread); + } - so_far += nread; - status.progress = so_far / (importable->ratio () * info.frames * info.channels); - } + so_far += nread; + status.progress = so_far / (importable->ratio () * info.frames * info.channels); + } - if (status.cancel) { - goto out; - } + if (status.cancel) { + goto out; + } + + for (int n = 0; n < info.channels; ++n) { + status.sources.push_back (newfiles[n]); + } - if (status.multichan) { - status.doing_what = _("building region"); - } else { - status.doing_what = _("building regions"); + if (status.cancel) { + goto out; + } } - + status.freeze = true; time_t xnow; time (&xnow); now = localtime (&xnow); - if (status.multichan) { - /* all sources are used in a single multichannel region */ + /* flush the final length(s) to the header(s) */ - for (int n = 0; n < nfiles && !status.cancel; ++n) { - /* flush the final length to the header */ - newfiles[n]->update_header(0, *now, xnow); - sources.push_back(newfiles[n]); - } - - bool strip_paired_suffixes = (newfiles.size() > 1); - - boost::shared_ptr<AudioRegion> r (boost::dynamic_pointer_cast<AudioRegion> - (RegionFactory::create (sources, 0, - newfiles[0]->length(), - region_name_from_path (basepath, strip_paired_suffixes), - 0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile)))); - - status.new_regions.push_back (r); - - } else { - for (int n = 0; n < nfiles && !status.cancel; ++n) { - - /* flush the final length to the header */ - - newfiles[n]->update_header(0, *now, xnow); - - /* The sources had zero-length when created, which means that the Session - did not bother to create whole-file AudioRegions for them. Do it now. - - Note: leave any trailing paired indicators from the file names as part - of the region name. - */ - - status.new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> - (RegionFactory::create (boost::static_pointer_cast<Source> (newfiles[n]), 0, newfiles[n]->length(), - region_name_from_path (newfiles[n]->name(), false), - 0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile | AudioRegion::Import)))); - } + for (SourceList::iterator x = status.sources.begin(); x != status.sources.end() && !status.cancel; ++x) { + boost::dynamic_pointer_cast<AudioFileSource>(*x)->update_header(0, *now, xnow); + boost::dynamic_pointer_cast<AudioSource>(*x)->done_with_peakfile_writes (); } - + /* save state so that we don't lose these new Sources */ if (!status.cancel) { @@ -321,7 +249,8 @@ Session::import_audiofile (import_status& status) } if (status.cancel) { - status.new_regions.clear (); + + status.sources.clear (); for (vector<string>::iterator i = new_paths.begin(); i != new_paths.end(); ++i) { unlink ((*i).c_str()); @@ -337,50 +266,3 @@ Session::import_audiofile (import_status& status) return ret; } - -nframes_t -ResampledImportableSource::read (Sample* output, nframes_t nframes) -{ - int err; - - /* If the input buffer is empty, refill it. */ - - if (src_data.input_frames == 0) { - - src_data.input_frames = ImportableSource::read (input, BLOCKSIZE); - - /* The last read will not be a full buffer, so set end_of_input. */ - - if ((nframes_t) src_data.input_frames < BLOCKSIZE) { - src_data.end_of_input = SF_TRUE ; - } - - src_data.input_frames /= sf_info->channels; - src_data.data_in = input ; - } - - src_data.data_out = output; - - if (!src_data.end_of_input) { - src_data.output_frames = nframes / sf_info->channels ; - } else { - src_data.output_frames = src_data.input_frames; - } - - if ((err = src_process (src_state, &src_data))) { - error << string_compose(_("Import: %1"), src_strerror (err)) << endmsg ; - return 0 ; - } - - /* Terminate if at end */ - - if (src_data.end_of_input && src_data.output_frames_gen == 0) { - return 0; - } - - src_data.data_in += src_data.input_frames_used * sf_info->channels ; - src_data.input_frames -= src_data.input_frames_used ; - - return src_data.output_frames_gen * sf_info->channels; -} - diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index a708821c20..bff8c18bc9 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -1307,7 +1307,7 @@ IO::state (bool full_state) int const in_max = _input_maximum == ChanCount::INFINITE ? -1 : _input_maximum.get(_default_type); int const out_max = _output_maximum == ChanCount::INFINITE ? -1 : _output_maximum.get(_default_type); - snprintf (buf, sizeof(buf)-1, "%zd,%d,%zd,%d", _input_minimum.get(_default_type), in_max, _output_minimum.get(_default_type), out_max); + snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", _input_minimum.get(_default_type), in_max, _output_minimum.get(_default_type), out_max); node->add_property ("iolimits", buf); @@ -2335,7 +2335,7 @@ IO::automation_snapshot (nframes_t now) { Automatable::automation_snapshot (now); - if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) { + if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) { _panner->snapshot (now); } } diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index 4af7e2b907..09b54000d8 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -1176,8 +1176,8 @@ Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region) save = !(_splicing || _nudging); } - if ((what_changed & Region::MuteChanged) && - !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) { + if ((what_changed & our_interests) && + !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) { check_dependents (region, false); } diff --git a/libs/ardour/resampled_source.cc b/libs/ardour/resampled_source.cc new file mode 100644 index 0000000000..38aa3832b9 --- /dev/null +++ b/libs/ardour/resampled_source.cc @@ -0,0 +1,128 @@ +/* + 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 <pbd/error.h> +#include <ardour/resampled_source.h> +#include <pbd/failed_constructor.h> + +#include "i18n.h" + +using namespace ARDOUR; +using namespace PBD; + +const uint32_t ResampledImportableSource::blocksize = 4096U; + +ResampledImportableSource::ResampledImportableSource (SNDFILE* sf, SF_INFO* info, nframes_t rate, SrcQuality srcq) + : ImportableSource (sf, info) +{ + int err; + + sf_seek (in, 0, SEEK_SET) ; + + /* Initialize the sample rate converter. */ + + int src_type; + + switch (srcq) { + case SrcBest: + src_type = SRC_SINC_BEST_QUALITY; + break; + case SrcGood: + src_type = SRC_SINC_MEDIUM_QUALITY; + break; + case SrcQuick: + src_type = SRC_SINC_FASTEST; + break; + case SrcFast: + src_type = SRC_ZERO_ORDER_HOLD; + break; + case SrcFastest: + src_type = SRC_LINEAR; + break; + } + + if ((src_state = src_new (src_type, sf_info->channels, &err)) == 0) { + error << string_compose(_("Import: src_new() failed : %1"), src_strerror (err)) << endmsg ; + throw failed_constructor (); + } + + src_data.end_of_input = 0 ; /* Set this later. */ + + /* Start with zero to force load in while loop. */ + + src_data.input_frames = 0 ; + src_data.data_in = input ; + + src_data.src_ratio = ((float) rate) / sf_info->samplerate ; + + input = new float[blocksize]; +} + +ResampledImportableSource::~ResampledImportableSource () +{ + src_state = src_delete (src_state) ; + delete [] input; +} + +nframes_t +ResampledImportableSource::read (Sample* output, nframes_t nframes) +{ + int err; + + /* If the input buffer is empty, refill it. */ + + if (src_data.input_frames == 0) { + + src_data.input_frames = ImportableSource::read (input, blocksize); + + /* The last read will not be a full buffer, so set end_of_input. */ + + if ((nframes_t) src_data.input_frames < blocksize) { + src_data.end_of_input = SF_TRUE ; + } + + src_data.input_frames /= sf_info->channels; + src_data.data_in = input ; + } + + src_data.data_out = output; + + if (!src_data.end_of_input) { + src_data.output_frames = nframes / sf_info->channels ; + } else { + src_data.output_frames = src_data.input_frames; + } + + if ((err = src_process (src_state, &src_data))) { + error << string_compose(_("Import: %1"), src_strerror (err)) << endmsg ; + return 0 ; + } + + /* Terminate if at end */ + + if (src_data.end_of_input && src_data.output_frames_gen == 0) { + return 0; + } + + src_data.data_in += src_data.input_frames_used * sf_info->channels ; + src_data.input_frames -= src_data.input_frames_used ; + + return src_data.output_frames_gen * sf_info->channels; +} + diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 19095425f2..be7dfb8469 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -53,7 +53,7 @@ using namespace ARDOUR; using namespace PBD; uint32_t Route::order_key_cnt = 0; - +sigc::signal<void> Route::SyncOrderKeys; Route::Route (Session& sess, string name, int input_min, int input_max, int output_min, int output_max, Flag flg, DataType default_type) : IO (sess, name, input_min, input_max, output_min, output_max, default_type), @@ -161,10 +161,35 @@ void Route::set_order_key (const char* name, long n) { order_keys[strdup(name)] = n; + + if (Config->get_sync_all_route_ordering()) { + for (OrderKeys::iterator x = order_keys.begin(); x != order_keys.end(); ++x) { + x->second = n; + } + } + _session.set_dirty (); } void +Route::sync_order_keys () +{ + uint32_t key; + + if (order_keys.empty()) { + return; + } + + OrderKeys::iterator x = order_keys.begin(); + key = x->second; + ++x; + + for (; x != order_keys.end(); ++x) { + x->second = key; + } +} + +void Route::inc_gain (gain_t fraction, void *src) { IO::inc_gain (fraction, src); @@ -460,13 +485,9 @@ Route::process_output_buffers (BufferSet& bufs, // OR recording - // h/w monitoring not in use - - (!Config->get_monitoring_model() == HardwareMonitoring && - // AND software monitoring required - Config->get_monitoring_model() == SoftwareMonitoring)) { + Config->get_monitoring_model() == SoftwareMonitoring) { if (apply_gain_automation) { diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 742b17af2c..e7f2c542e6 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -124,8 +124,7 @@ Session::Session (AudioEngine &eng, routes (new RouteList), auditioner ((Auditioner*) 0), _click_io ((IO*) 0), - main_outs (0), - _automation_interval (0) + main_outs (0) { if (!eng.connected()) { throw failed_constructor(); @@ -224,8 +223,7 @@ Session::Session (AudioEngine &eng, _send_smpte_update (false), diskstreams (new DiskstreamList), routes (new RouteList), - main_outs (0), - _automation_interval (0) + main_outs (0) { if (!eng.connected()) { @@ -1257,8 +1255,10 @@ Session::set_frame_rate (nframes_t frames_per_second) sync_time_vars(); - _automation_interval = ((nframes_t) ceil ((double) frames_per_second * 0.25)); + Automatable::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * (0.001 * Config->get_automation_interval()))); + clear_clicks (); + // XXX we need some equivalent to this, somehow // SndFileSource::setup_standard_crossfades (frames_per_second); @@ -2755,13 +2755,11 @@ Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn) return boost::shared_ptr<Source>(); } -string -Session::peak_path_from_audio_path (string audio_path) const +Glib::ustring +Session::peak_path (Glib::ustring base) const { sys::path peakfile_path(_session_dir->peak_path()); - - peakfile_path /= basename_nosuffix (audio_path) + peakfile_suffix; - + peakfile_path /= basename_nosuffix (base) + peakfile_suffix; return peakfile_path.to_string(); } @@ -3387,8 +3385,8 @@ Session::remove_empty_sounds () try { sys::remove (audio_file_path); - const string peak_path = peak_path_from_audio_path (audio_file_path.to_string()); - sys::remove (peak_path); + const string peakfile = peak_path (audio_file_path.to_string()); + sys::remove (peakfile); } catch (const sys::filesystem_error& err) { @@ -4124,6 +4122,23 @@ Session::compute_initial_length () } void +Session::sync_order_keys () +{ + if (!Config->get_sync_all_route_ordering()) { + /* leave order keys as they are */ + return; + } + + boost::shared_ptr<RouteList> r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + (*i)->sync_order_keys (); + } + + Route::SyncOrderKeys (); // EMIT SIGNAL +} + +void Session::foreach_bundle (sigc::slot<void, boost::shared_ptr<Bundle> > sl) { Glib::Mutex::Lock lm (bundle_lock); diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc index 35c1019c0e..aa5a1b87d4 100644 --- a/libs/ardour/session_events.cc +++ b/libs/ardour/session_events.cc @@ -410,6 +410,8 @@ Session::process_event (Event* ev) case Event::Audition: set_audition (ev->region); + // drop reference to region + ev->region.reset (); break; case Event::InputConfigurationChange: diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index f2f396cbee..0534da6c89 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -138,10 +138,14 @@ Session::first_stage_init (string fullpath, string snapshot_name) _name = _current_snapshot_name = snapshot_name; + set_history_depth (Config->get_history_depth()); + _current_frame_rate = _engine.frame_rate (); _tempo_map = new TempoMap (_current_frame_rate); _tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed)); + + g_atomic_int_set (&processing_prohibited, 0); insert_cnt = 0; _transport_speed = 0; @@ -501,7 +505,7 @@ void Session::remove_pending_capture_state () { sys::path pending_state_file_path(_session_dir->root_path()); - + pending_state_file_path /= _current_snapshot_name + pending_suffix; try @@ -2668,8 +2672,6 @@ Session::save_history (string snapshot_name) { XMLTree tree; - tree.set_root (&_history.get_state (Config->get_saved_history_depth())); - if (snapshot_name.empty()) { snapshot_name = _current_snapshot_name; } @@ -2691,6 +2693,13 @@ Session::save_history (string snapshot_name) } } + + if (!Config->get_save_history() || Config->get_saved_history_depth() < 0) { + return 0; + } + + tree.set_root (&_history.get_state (Config->get_saved_history_depth())); + if (!tree.write (xml_path.to_string())) { error << string_compose (_("history could not be saved to %1"), xml_path.to_string()) << endmsg; @@ -2977,6 +2986,10 @@ Session::config_changed (const char* parameter_name) set_remote_control_ids (); } else if (PARAM_IS ("denormal-model")) { setup_fpu (); + } else if (PARAM_IS ("history-depth")) { + set_history_depth (Config->get_history_depth()); + } else if (PARAM_IS ("sync-all-route-ordering")) { + sync_order_keys (); } set_dirty (); @@ -2984,3 +2997,9 @@ Session::config_changed (const char* parameter_name) #undef PARAM_IS } + +void +Session::set_history_depth (uint32_t d) +{ + _history.set_depth (d); +} diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc index 6977eef6bd..7c4859aa55 100644 --- a/libs/ardour/sndfilesource.cc +++ b/libs/ardour/sndfilesource.cc @@ -25,7 +25,7 @@ #include <sys/stat.h> #include <glibmm/miscutils.h> - +#include <glibmm/thread.h> #include <ardour/sndfilesource.h> #include <ardour/sndfile_helpers.h> #include <ardour/utils.h> @@ -45,6 +45,21 @@ const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSou AudioFileSource::RemovableIfEmpty| AudioFileSource::CanRename); +struct SizedSampleBuffer { + nframes_t size; + Sample* buf; + + SizedSampleBuffer (nframes_t sz) : size (sz) { + buf = new Sample[size]; + } + + ~SizedSampleBuffer() { + delete [] buf; + } +}; + +Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT; + SndFileSource::SndFileSource (Session& s, const XMLNode& node) : AudioFileSource (s, node) { @@ -186,8 +201,6 @@ SndFileSource::init () // lets try to keep the object initalizations here at the top xfade_buf = 0; - interleave_buf = 0; - interleave_bufsize = 0; sf = 0; _broadcast_info = 0; @@ -272,10 +285,6 @@ SndFileSource::~SndFileSource () touch_peakfile (); } - if (interleave_buf) { - delete [] interleave_buf; - } - if (_broadcast_info) { delete _broadcast_info; } @@ -341,14 +350,7 @@ SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const real_cnt = cnt * _info.channels; - if (interleave_bufsize < real_cnt) { - - if (interleave_buf) { - delete [] interleave_buf; - } - interleave_bufsize = real_cnt; - interleave_buf = new float[interleave_bufsize]; - } + Sample* interleave_buf = get_interleave_buffer (real_cnt); nread = sf_read_float (sf, interleave_buf, real_cnt); ptr = interleave_buf + _channel; @@ -401,7 +403,7 @@ SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt) update_length (oldlen, cnt); if (_build_peakfiles) { - compute_and_write_peaks (data, frame_pos, cnt, false); + compute_and_write_peaks (data, frame_pos, cnt, false, true); } _write_data_count = cnt; @@ -493,7 +495,7 @@ SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt) update_length (file_pos, cnt); if (_build_peakfiles) { - compute_and_write_peaks (data, file_pos, cnt, false); + compute_and_write_peaks (data, file_pos, cnt, false, true); } file_pos += cnt; @@ -904,3 +906,21 @@ SndFileSource::one_of_several_channels () const { return _info.channels > 1; } + +Sample* +SndFileSource::get_interleave_buffer (nframes_t size) +{ + SizedSampleBuffer* ssb; + + if ((ssb = thread_interleave_buffer.get()) == 0) { + ssb = new SizedSampleBuffer (size); + thread_interleave_buffer.set (ssb); + } + + if (ssb->size < size) { + ssb = new SizedSampleBuffer (size); + thread_interleave_buffer.set (ssb); + } + + return ssb->buf; +} diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc index 148f737551..c6b19c8600 100644 --- a/libs/ardour/source_factory.cc +++ b/libs/ardour/source_factory.cc @@ -19,6 +19,8 @@ */ #include <pbd/error.h> +#include <pbd/convert.h> +#include <pbd/pthread_utils.h> #include <ardour/source_factory.h> #include <ardour/sndfilesource.h> @@ -37,15 +39,69 @@ using namespace std; using namespace PBD; sigc::signal<void,boost::shared_ptr<Source> > SourceFactory::SourceCreated; +Glib::Cond* SourceFactory::PeaksToBuild; +Glib::StaticMutex SourceFactory::peak_building_lock; +std::list<boost::weak_ptr<AudioSource> > SourceFactory::files_with_peaks; + +static void +peak_thread_work () +{ + PBD::ThreadCreated (pthread_self(), string ("peakbuilder-") + to_string (pthread_self(), std::dec)); + + while (true) { + + SourceFactory::peak_building_lock.lock (); + + wait: + if (SourceFactory::files_with_peaks.empty()) { + SourceFactory::PeaksToBuild->wait (SourceFactory::peak_building_lock); + } + + if (SourceFactory::files_with_peaks.empty()) { + goto wait; + } + + boost::shared_ptr<AudioSource> as (SourceFactory::files_with_peaks.front().lock()); + SourceFactory::files_with_peaks.pop_front (); + SourceFactory::peak_building_lock.unlock (); + + if (!as) { + continue; + } + + as->setup_peakfile (); + } +} + +void +SourceFactory::init () +{ + PeaksToBuild = new Glib::Cond(); + + for (int n = 0; n < 2; ++n) { + Glib::Thread::create (sigc::ptr_fun (::peak_thread_work), false); + } +} int -SourceFactory::setup_peakfile (boost::shared_ptr<Source> s) +SourceFactory::setup_peakfile (boost::shared_ptr<Source> s, bool async) { boost::shared_ptr<AudioSource> as (boost::dynamic_pointer_cast<AudioSource> (s)); + if (as) { - if (as->setup_peakfile ()) { - error << string_compose("SourceFactory: could not set up peakfile for %1", as->name()) << endmsg; - return -1; + + if (async) { + + Glib::Mutex::Lock lm (peak_building_lock); + files_with_peaks.push_back (boost::weak_ptr<AudioSource> (as)); + PeaksToBuild->broadcast (); + + } else { + + if (as->setup_peakfile ()) { + error << string_compose("SourceFactory: could not set up peakfile for %1", as->name()) << endmsg; + return -1; + } } } @@ -60,84 +116,85 @@ SourceFactory::createSilent (Session& s, const XMLNode& node, nframes_t nframes, return ret; } +#ifdef USE_COREAUDIO_FOR_FILES boost::shared_ptr<Source> -SourceFactory::create (Session& s, const XMLNode& node) +SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks) { - /* this is allowed to throw */ - - DataType type = DataType::AUDIO; - const XMLProperty* prop = node.property("type"); - if (prop) { - type = DataType(prop->value()); - } - - if (type == DataType::AUDIO) { - -#ifdef HAVE_COREAUDIO - try { - boost::shared_ptr<Source> ret (new CoreAudioSource (s, node)); - if (setup_peakfile (ret)) { + try { + boost::shared_ptr<Source> ret (new CoreAudioSource (s, node)); + if (!defer_peaks) { + if (setup_peakfile (ret, false)) { return boost::shared_ptr<Source>(); } - SourceCreated (ret); - return ret; - } + } + SourceCreated (ret); + return ret; + } - catch (failed_constructor& err) { - - /* this is allowed to throw */ - - boost::shared_ptr<Source> ret (new SndFileSource (s, node)); - if (setup_peakfile (ret)) { + + catch (failed_constructor& err) { + + /* this is allowed to throw */ + + boost::shared_ptr<Source> ret (new SndFileSource (s, node)); + if (!defer_peaks) { + if (setup_peakfile (ret, false)) { return boost::shared_ptr<Source>(); } - SourceCreated (ret); - return ret; } -#else - boost::shared_ptr<Source> ret (new SndFileSource (s, node)); - - if (setup_peakfile (ret)) { - return boost::shared_ptr<Source>(); - } - SourceCreated (ret); return ret; -#endif + } - } else if (type == DataType::MIDI) { + return boost::shared_ptr<Source>(); +} - boost::shared_ptr<Source> ret (new SMFSource (s, node)); - - SourceCreated (ret); - return ret; +#else + +boost::shared_ptr<Source> +SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks) +{ + /* this is allowed to throw */ + boost::shared_ptr<Source> ret (new SndFileSource (s, node)); + + if (!defer_peaks) { + if (setup_peakfile (ret, false)) { + return boost::shared_ptr<Source>(); + } } - return boost::shared_ptr<Source> (); + SourceCreated (ret); + return ret; } +#endif // USE_COREAUDIO_FOR_FILES + boost::shared_ptr<Source> -SourceFactory::createReadable (DataType type, Session& s, string path, int chn, AudioFileSource::Flag flags, bool announce) +SourceFactory::createReadable (DataType type, Session& s, string path, int chn, AudioFileSource::Flag flags, bool announce, bool defer_peaks) { if (type == DataType::AUDIO) { #ifdef HAVE_COREAUDIO try { boost::shared_ptr<Source> ret (new CoreAudioSource (s, path, chn, flags)); - if (setup_peakfile (ret)) { - return boost::shared_ptr<Source>(); + if (!defer_peaks) { + if (setup_peakfile (ret, false)) { + return boost::shared_ptr<Source>(); + } } if (announce) { SourceCreated (ret); } return ret; } - + catch (failed_constructor& err) { boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags)); - if (setup_peakfile (ret)) { - return boost::shared_ptr<Source>(); + if (!defer_peaks) { + if (setup_peakfile (ret, false)) { + return boost::shared_ptr<Source>(); + } } if (announce) { SourceCreated (ret); @@ -147,8 +204,10 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn, #else boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags)); - if (setup_peakfile (ret)) { - return boost::shared_ptr<Source>(); + if (!defer_peaks) { + if (setup_peakfile (ret, false)) { + return boost::shared_ptr<Source>(); + } } if (announce) { @@ -157,7 +216,7 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn, return ret; #endif - + } else if (type == DataType::MIDI) { // FIXME: flags? @@ -174,21 +233,23 @@ 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) +SourceFactory::createWritable (DataType type, Session& s, std::string path, 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, - Config->get_native_file_data_format(), - Config->get_native_file_header_format(), - rate, - (destructive ? AudioFileSource::Flag (SndFileSource::default_writable_flags | AudioFileSource::Destructive) : - SndFileSource::default_writable_flags))); - - if (setup_peakfile (ret)) { - return boost::shared_ptr<Source>(); + (s, path, + Config->get_native_file_data_format(), + Config->get_native_file_header_format(), + rate, + (destructive ? AudioFileSource::Flag (SndFileSource::default_writable_flags | AudioFileSource::Destructive) : + SndFileSource::default_writable_flags))); + + if (!defer_peaks) { + if (setup_peakfile (ret, false)) { + return boost::shared_ptr<Source>(); + } } if (announce) { SourceCreated (ret); diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc index 01e070e920..cfd38c5099 100644 --- a/libs/ardour/utils.cc +++ b/libs/ardour/utils.cc @@ -143,7 +143,7 @@ touch_file (ustring path) } ustring -region_name_from_path (ustring path, bool strip_channels) +region_name_from_path (ustring path, bool strip_channels, bool add_channel_suffix, uint32_t total, uint32_t this_one) { path = PBD::basename_nosuffix (path); @@ -160,6 +160,17 @@ region_name_from_path (ustring path, bool strip_channels) } } + if (add_channel_suffix) { + + path += '%'; + + if (total > 2) { + path += (char) ('a' + this_one); + } else { + path += (char) (this_one == 0 ? 'L' : 'R'); + } + } + return path; } |