diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2006-06-14 21:17:32 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2006-06-14 21:17:32 +0000 |
commit | b09ab546542040b1d468c9925c60bda2dfd80da8 (patch) | |
tree | a64fdab212cbcc61fe0e2cf9d20dbc363141cf2a /libs | |
parent | 2387ef8bfb49e60b233244580fd132d25c6dc3e3 (diff) |
use libsndfile for all audio file i/o, and rename DiskStream AudioDiskStream
git-svn-id: svn://localhost/ardour2/trunk@589 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
39 files changed, 939 insertions, 1365 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index 0fb5cfc788..a015bfb313 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -27,12 +27,15 @@ ardour.Append(POTFILE = domain + '.pot') ardour.Append(CPPPATH = '#libs/surfaces/control_protocol') ardour_files=Split(""" +audio_diskstream.cc audio_library.cc audio_playlist.cc audio_track.cc audioengine.cc +audiofilesource.cc audiofilter.cc audioregion.cc +audiosource.cc auditioner.cc automation.cc automation_event.cc @@ -44,9 +47,6 @@ curve.cc cycle_timer.cc default_click.cc destructive_filesource.cc -diskstream.cc -externalsource.cc -filesource.cc gain.cc gdither.cc globals.cc diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h index c7af9fc5d8..1c17cbc859 100644 --- a/libs/ardour/ardour/audio_track.h +++ b/libs/ardour/ardour/audio_track.h @@ -26,7 +26,7 @@ namespace ARDOUR { class Session; -class DiskStream; +class AudioDiskstream; class AudioPlaylist; class RouteGroup; @@ -52,8 +52,8 @@ class AudioTrack : public Route bool can_record() const { return true; } void set_record_enable (bool yn, void *src); - DiskStream& disk_stream() const { return *diskstream; } - int set_diskstream (DiskStream&, void *); + AudioDiskstream& disk_stream() const { return *diskstream; } + int set_diskstream (AudioDiskstream&, void *); int use_diskstream (string name); int use_diskstream (id_t id); @@ -99,7 +99,7 @@ class AudioTrack : public Route void set_meter_point (MeterPoint, void* src); protected: - DiskStream *diskstream; + AudioDiskstream *diskstream; MeterPoint _saved_meter_point; TrackMode _mode; diff --git a/libs/ardour/ardour/audiofilter.h b/libs/ardour/ardour/audiofilter.h index d0fc275cf6..02e5e6f061 100644 --- a/libs/ardour/ardour/audiofilter.h +++ b/libs/ardour/ardour/audiofilter.h @@ -28,7 +28,6 @@ namespace ARDOUR { class AudioRegion; class Session; -class FileSource; class AudioFilter { @@ -37,7 +36,6 @@ class AudioFilter { : session (s){} virtual ~AudioFilter() {} - virtual int run (ARDOUR::AudioRegion&) = 0; std::vector<ARDOUR::AudioRegion*> results; diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index f210fa595b..009aa4b5b0 100644 --- a/libs/ardour/ardour/audioregion.h +++ b/libs/ardour/ardour/audioregion.h @@ -27,7 +27,6 @@ #include <pbd/undo.h> #include <ardour/ardour.h> -#include <ardour/source.h> #include <ardour/gain.h> #include <ardour/region.h> #include <ardour/export.h> @@ -40,6 +39,7 @@ class Route; class Playlist; class Session; class AudioFilter; +class AudioSource; struct AudioRegionState : public RegionState { @@ -56,7 +56,7 @@ struct AudioRegionState : public RegionState class AudioRegion : public Region { public: - typedef vector<Source *> SourceList; + typedef vector<AudioSource *> SourceList; static Change FadeInChanged; static Change FadeOutChanged; @@ -66,12 +66,12 @@ class AudioRegion : public Region static Change ScaleAmplitudeChanged; static Change EnvelopeChanged; - AudioRegion (Source&, jack_nframes_t start, jack_nframes_t length, bool announce = true); - AudioRegion (Source&, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true); + AudioRegion (AudioSource&, jack_nframes_t start, jack_nframes_t length, bool announce = true); + AudioRegion (AudioSource&, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true); AudioRegion (SourceList &, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true); AudioRegion (const AudioRegion&, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true); AudioRegion (const AudioRegion&); - AudioRegion (Source&, const XMLNode&); + AudioRegion (AudioSource&, const XMLNode&); AudioRegion (SourceList &, const XMLNode&); ~AudioRegion(); @@ -85,7 +85,7 @@ class AudioRegion : public Region void lock_sources (); void unlock_sources (); - Source& source (uint32_t n=0) const { if (n < sources.size()) return *sources[n]; else return *sources[0]; } + AudioSource& source (uint32_t n=0) const { if (n < sources.size()) return *sources[n]; else return *sources[0]; } void set_scale_amplitude (gain_t); gain_t scale_amplitude() const { return _scale_amplitude; } diff --git a/libs/ardour/ardour/coreaudio_source.h b/libs/ardour/ardour/coreaudio_source.h index 736ea32df7..82533de950 100644 --- a/libs/ardour/ardour/coreaudio_source.h +++ b/libs/ardour/ardour/coreaudio_source.h @@ -31,8 +31,11 @@ class CoreAudioSource : public ExternalSource { CoreAudioSource (const XMLNode&); ~CoreAudioSource (); - jack_nframes_t read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const; float sample_rate() const; + int update_header (jack_nframes_t when, struct tm&, time_t); + + protected: + jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const; private: ExtAudioFileRef af; diff --git a/libs/ardour/ardour/cycle_timer.h b/libs/ardour/ardour/cycle_timer.h index 1ec7c74903..b9cbbbf0a8 100644 --- a/libs/ardour/ardour/cycle_timer.h +++ b/libs/ardour/ardour/cycle_timer.h @@ -22,29 +22,27 @@ #define __ardour_cycle_timer_h__ #include <string> -#include <cstdio> +#include <iostream> #include <ardour/cycles.h> -using std::string; - class CycleTimer { private: static float cycles_per_usec; - uint32_t long entry; - uint32_t long exit; - string _name; + cycles_t _entry; + cycles_t _exit; + std::string _name; public: - CycleTimer(string name) : _name (name){ + CycleTimer(std::string name) : _name (name){ if (cycles_per_usec == 0) { cycles_per_usec = get_mhz (); } - entry = get_cycles(); + _entry = get_cycles(); } ~CycleTimer() { - exit = get_cycles(); - printf ("%s: %.9f usecs (%lu-%lu)\n", _name.c_str(), (float) (exit - entry) / cycles_per_usec, entry, exit); + _exit = get_cycles(); + std::cerr << _name << ": " << (float) (_exit - _entry) / cycles_per_usec << " (" << _entry << ", " << _exit << ')' << endl; } static float get_mhz (); diff --git a/libs/ardour/ardour/destructive_filesource.h b/libs/ardour/ardour/destructive_filesource.h index dbaf379257..49a1e3b48a 100644 --- a/libs/ardour/ardour/destructive_filesource.h +++ b/libs/ardour/ardour/destructive_filesource.h @@ -23,30 +23,33 @@ #include <string> -#include <ardour/filesource.h> +#include <ardour/sndfilesource.h> struct tm; namespace ARDOUR { -class DestructiveFileSource : public FileSource { +class DestructiveFileSource : public SndFileSource { public: - DestructiveFileSource (std::string path, jack_nframes_t rate, bool repair_first = false, SampleFormat samp_format=FormatInt24); - DestructiveFileSource (const XMLNode&, jack_nframes_t rate); + DestructiveFileSource (std::string path, SampleFormat samp_format, HeaderFormat hdr_format, jack_nframes_t rate, + Flag flags = AudioFileSource::Flag (AudioFileSource::Writable| + AudioFileSource::BuildPeaks)); + + DestructiveFileSource (const XMLNode&); ~DestructiveFileSource (); - int seek (jack_nframes_t frame); jack_nframes_t last_capture_start_frame() const; void mark_capture_start (jack_nframes_t); void mark_capture_end (); void clear_capture_marks(); - jack_nframes_t write (Sample *src, jack_nframes_t cnt, char * workbuf); - XMLNode& get_state (); static void setup_standard_crossfades (jack_nframes_t sample_rate); + protected: + jack_nframes_t write_unlocked (Sample *src, jack_nframes_t start, jack_nframes_t cnt, char * workbuf); + private: static jack_nframes_t xfade_frames; static gain_t* out_coefficient; @@ -59,7 +62,7 @@ class DestructiveFileSource : public FileSource { Sample* xfade_buf; jack_nframes_t crossfade (Sample* data, jack_nframes_t cnt, int dir, char * workbuf); - + void set_timeline_position (jack_nframes_t); }; } diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h index d322f564ee..c653c8502e 100644 --- a/libs/ardour/ardour/playlist.h +++ b/libs/ardour/ardour/playlist.h @@ -37,7 +37,6 @@ #include <ardour/crossfade_compare.h> #include <ardour/location.h> #include <ardour/stateful.h> -#include <ardour/source.h> #include <ardour/state_manager.h> namespace ARDOUR { diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 83acb3f82a..902510436a 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -60,11 +60,12 @@ namespace ARDOUR { class Port; class AudioEngine; class Slave; -class DiskStream; +class AudioDiskstream; class Route; class AuxInput; class Source; -class FileSource; +class AudioSource; +class AudioFileSource; class Auditioner; class Insert; class Send; @@ -261,25 +262,30 @@ class Session : public sigc::trackable, public Stateful vector<Sample*>& get_silent_buffers (uint32_t howmany); vector<Sample*>& get_send_buffers () { return _send_buffers; } - DiskStream *diskstream_by_id (id_t id); - DiskStream *diskstream_by_name (string name); + AudioDiskstream *diskstream_by_id (id_t id); + AudioDiskstream *diskstream_by_name (string name); bool have_captured() const { return _have_captured; } void refill_all_diskstream_buffers (); uint32_t diskstream_buffer_size() const { return dstream_buffer_size; } - uint32_t get_next_diskstream_id() const { return n_diskstreams(); } - uint32_t n_diskstreams() const; - typedef list<DiskStream *> DiskStreamList; + /* XXX fix required here when we get new diskstream types *, but + not sure of the direction to take this in until then. + */ + + uint32_t get_next_diskstream_id() const { return n_audio_diskstreams(); } + uint32_t n_audio_diskstreams() const; + + typedef list<AudioDiskstream *> AudioDiskstreamList; - Session::DiskStreamList disk_streams() const { + Session::AudioDiskstreamList audio_disk_streams() const { Glib::RWLock::ReaderLock lm (diskstream_lock); - return diskstreams; /* XXX yes, force a copy */ + return audio_diskstreams; /* XXX yes, force a copy */ } - void foreach_diskstream (void (DiskStream::*func)(void)); - template<class T> void foreach_diskstream (T *obj, void (T::*func)(DiskStream&)); + void foreach_audio_diskstream (void (AudioDiskstream::*func)(void)); + template<class T> void foreach_audio_diskstream (T *obj, void (T::*func)(AudioDiskstream&)); typedef list<Route *> RouteList; @@ -344,7 +350,7 @@ class Session : public sigc::trackable, public Stateful sigc::signal<void> HaltOnXrun; sigc::signal<void,Route*> RouteAdded; - sigc::signal<void,DiskStream*> DiskStreamAdded; + sigc::signal<void,AudioDiskstream*> AudioDiskstreamAdded; void request_roll (); void request_bounded_roll (jack_nframes_t start, jack_nframes_t end); @@ -356,15 +362,15 @@ class Session : public sigc::trackable, public Stateful void goto_start () { request_locate (start_location->start(), false); } void use_rf_shuttle_speed (); void request_transport_speed (float speed); - void request_overwrite_buffer (DiskStream*); - void request_diskstream_speed (DiskStream&, float speed); + void request_overwrite_buffer (AudioDiskstream*); + void request_diskstream_speed (AudioDiskstream&, float speed); void request_input_change_handling (); bool locate_pending() const { return static_cast<bool>(post_transport_work&PostTransportLocate); } bool transport_locked () const; int wipe (); - int wipe_diskstream (DiskStream *); + int wipe_diskstream (AudioDiskstream *); int remove_region_from_region_list (Region&); @@ -612,7 +618,7 @@ class Session : public sigc::trackable, public Stateful jack_nframes_t convert_to_frames_at (jack_nframes_t position, AnyTime&); - sigc::signal<void> SMPTEOffsetChanged; + static sigc::signal<void> SMPTEOffsetChanged; sigc::signal<void> SMPTETypeChanged; void request_slave_source (SlaveSource, jack_nframes_t pos = 0); @@ -668,8 +674,9 @@ class Session : public sigc::trackable, public Stateful int start_audio_export (ARDOUR::AudioExportSpecification&); int stop_audio_export (ARDOUR::AudioExportSpecification&); - void add_source (Source *); - int remove_file_source (FileSource&); + void add_audio_source (AudioSource *); + void remove_source (Source *); + int cleanup_audio_file_source (AudioFileSource&); struct cleanup_report { vector<string> paths; @@ -701,7 +708,8 @@ class Session : public sigc::trackable, public Stateful sigc::signal<void,Source *> SourceAdded; sigc::signal<void,Source *> SourceRemoved; - FileSource *create_file_source (ARDOUR::DiskStream&, int32_t chan, bool destructive); + AudioFileSource *create_audio_source_for_session (ARDOUR::AudioDiskstream&, uint32_t which_channel, bool destructive); + Source *get_source (ARDOUR::id_t); /* playlist management */ @@ -745,8 +753,8 @@ class Session : public sigc::trackable, public Stateful /* flattening stuff */ - int write_one_track (AudioTrack&, jack_nframes_t start, jack_nframes_t cnt, bool overwrite, vector<Source*>&, - InterThreadInfo& wot); + int write_one_audio_track (AudioTrack&, jack_nframes_t start, jack_nframes_t cnt, bool overwrite, vector<AudioSource*>&, + InterThreadInfo& wot); int freeze (InterThreadInfo&); /* session-wide solo/mute/rec-enable */ @@ -972,7 +980,7 @@ class Session : public sigc::trackable, public Stateful void set_frame_rate (jack_nframes_t nframes); protected: - friend class DiskStream; + friend class AudioDiskstream; void stop_butler (); void wait_till_butler_finished(); @@ -1434,12 +1442,12 @@ class Session : public sigc::trackable, public Stateful bool waiting_to_start; void set_auto_loop (bool yn); - void overwrite_some_buffers (DiskStream*); + void overwrite_some_buffers (AudioDiskstream*); void flush_all_redirects (); void locate (jack_nframes_t, bool with_roll, bool with_flush, bool with_loop=false); void start_locate (jack_nframes_t, bool with_roll, bool with_flush, bool with_loop=false); void force_locate (jack_nframes_t frame, bool with_roll = false); - void set_diskstream_speed (DiskStream*, float speed); + void set_diskstream_speed (AudioDiskstream*, float speed); void set_transport_speed (float speed, bool abort = false); void stop_transport (bool abort = false); void start_transport (); @@ -1470,10 +1478,10 @@ class Session : public sigc::trackable, public Stateful /* disk-streams */ - DiskStreamList diskstreams; + AudioDiskstreamList audio_diskstreams; mutable Glib::RWLock diskstream_lock; uint32_t dstream_buffer_size; - void add_diskstream (DiskStream*); + void add_diskstream (AudioDiskstream*); int load_diskstreams (const XMLNode&); /* routes stuff */ @@ -1515,16 +1523,14 @@ class Session : public sigc::trackable, public Stateful /* SOURCES */ - mutable Glib::Mutex source_lock; - typedef std::map<id_t, Source *> SourceList; + mutable Glib::Mutex audio_source_lock; + typedef std::map<id_t, AudioSource *> AudioSourceList; - SourceList sources; + AudioSourceList audio_sources; int load_sources (const XMLNode& node); XMLNode& get_sources_as_xml (); - void remove_source (Source *); - Source *XMLSourceFactory (const XMLNode&); /* PLAYLISTS */ @@ -1543,7 +1549,7 @@ class Session : public sigc::trackable, public Stateful Playlist *XMLPlaylistFactory (const XMLNode&); void playlist_length_changed (Playlist *); - void diskstream_playlist_changed (DiskStream *); + void diskstream_playlist_changed (AudioDiskstream *); /* NAMED SELECTIONS */ diff --git a/libs/ardour/ardour/session_diskstream.h b/libs/ardour/ardour/session_diskstream.h index 3c888c92c3..33fc5419ba 100644 --- a/libs/ardour/ardour/session_diskstream.h +++ b/libs/ardour/ardour/session_diskstream.h @@ -22,15 +22,15 @@ #define __ardour_session_diskstream_h__ #include <ardour/session.h> -#include <ardour/diskstream.h> +#include <ardour/audio_diskstream.h> namespace ARDOUR { template<class T> void -Session::foreach_diskstream (T *obj, void (T::*func)(DiskStream&)) +Session::foreach_audio_diskstream (T *obj, void (T::*func)(AudioDiskstream&)) { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); i++) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); i++) { if (!(*i)->hidden()) { (obj->*func) (**i); } diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h index 5d11c9ef09..b9ea308b34 100644 --- a/libs/ardour/ardour/sndfilesource.h +++ b/libs/ardour/ardour/sndfilesource.h @@ -23,29 +23,57 @@ #include <sndfile.h> -#include <ardour/externalsource.h> +#include <ardour/audiofilesource.h> namespace ARDOUR { -class SndFileSource : public ExternalSource { +class SndFileSource : public AudioFileSource { public: - SndFileSource (const string& path_plus_channel, bool build_peak = true); + /* constructor to be called for existing external-to-session files */ + + SndFileSource (std::string path, Flag flags); + + /* constructor to be called for new in-session files */ + + SndFileSource (std::string path, SampleFormat samp_format, HeaderFormat hdr_format, jack_nframes_t rate, + Flag flags = AudioFileSource::Flag (AudioFileSource::Writable| + AudioFileSource::Removable| + AudioFileSource::RemovableIfEmpty| + AudioFileSource::CanRename| + AudioFileSource::BuildPeaks)); + + /* constructor to be called for existing in-session files */ + SndFileSource (const XMLNode&); + ~SndFileSource (); - jack_nframes_t length() const { return _info.frames; } - jack_nframes_t read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const; float sample_rate () const; + int update_header (jack_nframes_t when, struct tm&, time_t); + int flush_header (); + + static Flag default_in_session_flags(); + + protected: + void set_header_timeline_position (); + + jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const; + jack_nframes_t write_unlocked (Sample *dst, jack_nframes_t cnt, char * workbuf); + + jack_nframes_t write_float (Sample* data, jack_nframes_t pos, jack_nframes_t cnt); private: SNDFILE *sf; SF_INFO _info; + SF_BROADCAST_INFO* _broadcast_info; - mutable float *tmpbuf; - mutable jack_nframes_t tmpbufsize; - mutable Glib::Mutex _tmpbuf_lock; + mutable float *interleave_buf; + mutable jack_nframes_t interleave_bufsize; - void init (const string &str, bool build_peak); + void init (const string &str); + int open(); + void close(); + int setup_broadcast_info (jack_nframes_t when, struct tm&, time_t); }; }; /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h index 3781950fbf..f3133c71cd 100644 --- a/libs/ardour/ardour/source.h +++ b/libs/ardour/ardour/source.h @@ -21,166 +21,46 @@ #ifndef __ardour_source_h__ #define __ardour_source_h__ -#include <list> -#include <vector> #include <string> -#include <ctime> - #include <sigc++/signal.h> -#include <glibmm/thread.h> - #include <ardour/ardour.h> #include <ardour/stateful.h> -#include <pbd/xml++.h> - -using std::list; -using std::vector; -using std::string; namespace ARDOUR { -struct PeakData { - typedef Sample PeakDatum; - - PeakDatum min; - PeakDatum max; -}; - -const jack_nframes_t frames_per_peak = 256; - class Source : public Stateful, public sigc::trackable { public: - Source (bool announce=true); + Source (std::string name); Source (const XMLNode&); virtual ~Source (); - const string& name() const { return _name; } + std::string name() const { return _name; } + int set_name (std::string str, bool destructive); ARDOUR::id_t id() const { return _id; } - /* returns the number of items in this `source' */ - - virtual jack_nframes_t length() const { - return _length; - } - - virtual jack_nframes_t available_peaks (double zoom) const; - - virtual jack_nframes_t read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const { - return 0; - } - - virtual jack_nframes_t write (Sample *src, jack_nframes_t cnt, char * workbuf) { - return 0; - } - - virtual float sample_rate () const { return 0; } - uint32_t use_cnt() const { return _use_cnt; } void use (); void release (); - virtual void mark_for_remove() = 0; - virtual void mark_streaming_write_completed () {} - time_t timestamp() const { return _timestamp; } void stamp (time_t when) { _timestamp = when; } - void set_captured_for (string str) { _captured_for = str; } - string 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; } - - int read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start, jack_nframes_t cnt, double samples_per_unit) const; - int build_peaks (); - bool peaks_ready (sigc::slot<void>, sigc::connection&) const; - - static sigc::signal<void,Source*> SourceCreated; - - sigc::signal<void,Source *> GoingAway; - mutable sigc::signal<void> PeaksReady; - mutable sigc::signal<void,jack_nframes_t,jack_nframes_t> PeakRangeReady; - XMLNode& get_state (); int set_state (const XMLNode&); - static int start_peak_thread (); - static void stop_peak_thread (); - - int rename_peakfile (std::string newpath); - - static void set_build_missing_peakfiles (bool yn) { - _build_missing_peakfiles = yn; - } - static void set_build_peakfiles (bool yn) { - _build_peakfiles = yn; - } + sigc::signal<void,Source *> GoingAway; protected: - static bool _build_missing_peakfiles; - static bool _build_peakfiles; - string _name; - uint32_t _use_cnt; - bool _peaks_built; - mutable Glib::Mutex _lock; - jack_nframes_t _length; - bool next_peak_clear_should_notify; - string peakpath; + uint32_t _use_cnt; time_t _timestamp; - string _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, string path); - void build_peaks_from_scratch (); - - int do_build_peak (jack_nframes_t, jack_nframes_t); - virtual jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const = 0; - virtual string peak_path(string audio_path) = 0; - - static pthread_t peak_thread; - static bool have_peak_thread; - static void* peak_thread_work(void*); - - static int peak_request_pipe[2]; - - struct PeakRequest { - enum Type { - Build, - Quit - }; - }; - - static vector<Source*> pending_peak_sources; - static Glib::StaticMutex pending_peak_sources_lock; - - static void queue_for_peaks (Source&); - static void clear_queue_for_peaks (); - - struct PeakBuildRecord { - jack_nframes_t frame; - jack_nframes_t cnt; - - PeakBuildRecord (jack_nframes_t f, jack_nframes_t c) - : frame (f), cnt (c) {} - PeakBuildRecord (const PeakBuildRecord& other) { - frame = other.frame; - cnt = other.cnt; - } - }; - - list<Source::PeakBuildRecord *> pending_peak_builds; private: ARDOUR::id_t _id; - - bool file_changed (string path); }; } diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 3d7ab4b59a..cdf71b8cc6 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -255,10 +255,18 @@ namespace ARDOUR { BWF, WAVE, WAVE64, + CAF, + AIFF, iXML, RF64 }; + struct PeakData { + typedef Sample PeakDatum; + + PeakDatum min; + PeakDatum max; + }; }; std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf); diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc index 30adc54d1a..d146b92a4b 100644 --- a/libs/ardour/audio_track.cc +++ b/libs/ardour/audio_track.cc @@ -23,10 +23,11 @@ #include <sigc++/bind.h> #include <ardour/audio_track.h> -#include <ardour/diskstream.h> +#include <ardour/audio_diskstream.h> #include <ardour/session.h> #include <ardour/redirect.h> #include <ardour/audioregion.h> +#include <ardour/audiosource.h> #include <ardour/route_group_specialized.h> #include <ardour/insert.h> #include <ardour/audioplaylist.h> @@ -43,19 +44,19 @@ AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode diskstream (0), _midi_rec_enable_control (*this, _session.midi_port()) { - DiskStream::Flag dflags = DiskStream::Flag (0); + AudioDiskstream::Flag dflags = AudioDiskstream::Flag (0); if (_flags & Hidden) { - dflags = DiskStream::Flag (dflags | DiskStream::Hidden); + dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Hidden); } else { - dflags = DiskStream::Flag (dflags | DiskStream::Recordable); + dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Recordable); } if (mode == Destructive) { - dflags = DiskStream::Flag (dflags | DiskStream::Destructive); + dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Destructive); } - DiskStream* ds = new DiskStream (_session, name, dflags); + AudioDiskstream* ds = new AudioDiskstream (_session, name, dflags); _declickable = true; _freeze_record.state = NoFreeze; @@ -64,6 +65,8 @@ AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode set_diskstream (*ds, this); + // session.SMPTEOffsetChanged.connect (mem_fun (*this, &AudioTrack::handle_smpte_offset_change)); + // we do this even though Route already did it in it's init reset_midi_control (_session.midi_port(), _session.get_midi_control()); @@ -90,6 +93,14 @@ AudioTrack::~AudioTrack () } } +#if 0 +void +AudioTrack::handle_smpte_offset_change () +{ + diskstream +} +#endif + int AudioTrack::deprecated_use_diskstream_connections () { @@ -143,7 +154,7 @@ AudioTrack::deprecated_use_diskstream_connections () } int -AudioTrack::set_diskstream (DiskStream& ds, void *src) +AudioTrack::set_diskstream (AudioDiskstream& ds, void *src) { if (diskstream) { diskstream->unref(); @@ -166,7 +177,7 @@ AudioTrack::set_diskstream (DiskStream& ds, void *src) diskstream->monitor_input (false); ic_connection.disconnect(); - ic_connection = input_changed.connect (mem_fun (*diskstream, &DiskStream::handle_input_change)); + ic_connection = input_changed.connect (mem_fun (*diskstream, &AudioDiskstream::handle_input_change)); diskstream_changed (src); /* EMIT SIGNAL */ @@ -176,7 +187,7 @@ AudioTrack::set_diskstream (DiskStream& ds, void *src) int AudioTrack::use_diskstream (string name) { - DiskStream *dstream; + AudioDiskstream *dstream; if ((dstream = _session.diskstream_by_name (name)) == 0) { error << string_compose(_("AudioTrack: diskstream \"%1\" not known by session"), name) << endmsg; @@ -189,7 +200,7 @@ AudioTrack::use_diskstream (string name) int AudioTrack::use_diskstream (id_t id) { - DiskStream *dstream; + AudioDiskstream *dstream; if ((dstream = _session.diskstream_by_id (id)) == 0) { error << string_compose(_("AudioTrack: diskstream \"%1\" not known by session"), id) << endmsg; @@ -899,23 +910,23 @@ AudioTrack::update_total_latency () void AudioTrack::bounce (InterThreadInfo& itt) { - vector<Source*> srcs; - _session.write_one_track (*this, 0, _session.current_end_frame(), false, srcs, itt); + vector<AudioSource*> srcs; + _session.write_one_audio_track (*this, 0, _session.current_end_frame(), false, srcs, itt); } void AudioTrack::bounce_range (jack_nframes_t start, jack_nframes_t end, InterThreadInfo& itt) { - vector<Source*> srcs; - _session.write_one_track (*this, start, end, false, srcs, itt); + vector<AudioSource*> srcs; + _session.write_one_audio_track (*this, start, end, false, srcs, itt); } void AudioTrack::freeze (InterThreadInfo& itt) { Insert* insert; - vector<Source*> srcs; + vector<AudioSource*> srcs; string new_playlist_name; Playlist* new_playlist; string dir; @@ -950,7 +961,7 @@ AudioTrack::freeze (InterThreadInfo& itt) return; } - if (_session.write_one_track (*this, 0, _session.current_end_frame(), true, srcs, itt)) { + if (_session.write_one_audio_track (*this, 0, _session.current_end_frame(), true, srcs, itt)) { return; } diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 87866e7b31..c4f90efd49 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -229,9 +229,10 @@ AudioEngine::_freewheel_callback (int onoff, void *arg) int AudioEngine::process_callback (jack_nframes_t nframes) { + // CycleTimer ct ("AudioEngine::process"); Glib::Mutex::Lock tm (_process_lock, Glib::TRY_LOCK); jack_nframes_t next_processed_frames; - + /* handle wrap around of total frames counter */ if (max_frames - _processed_frames < nframes) { diff --git a/libs/ardour/audiofilter.cc b/libs/ardour/audiofilter.cc index c340bccb2c..843a3a7d34 100644 --- a/libs/ardour/audiofilter.cc +++ b/libs/ardour/audiofilter.cc @@ -22,7 +22,7 @@ #include <cerrno> #include <pbd/basename.h> -#include <ardour/filesource.h> +#include <ardour/sndfilesource.h> #include <ardour/session.h> #include <ardour/audioregion.h> #include <ardour/audiofilter.h> @@ -47,7 +47,10 @@ AudioFilter::make_new_sources (AudioRegion& region, AudioRegion::SourceList& nsr } try { - nsrcs.push_back (new FileSource (path, session.frame_rate(), false, Config->get_native_file_data_format())); + nsrcs.push_back (new SndFileSource (path, + Config->get_native_file_data_format(), + Config->get_native_file_header_format(), + session.frame_rate())); } catch (failed_constructor& err) { @@ -73,7 +76,10 @@ AudioFilter::finish (AudioRegion& region, AudioRegion::SourceList& nsrcs) now = localtime (&xnow); for (AudioRegion::SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) { - dynamic_cast<FileSource*>((*si))->update_header (region.position(), *now, xnow); + AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*si); + if (afs) { + afs->update_header (region.position(), *now, xnow); + } } /* create a new region */ diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 21773d9222..6b118faa51 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -38,6 +38,7 @@ #include <ardour/dB.h> #include <ardour/playlist.h> #include <ardour/audiofilter.h> +#include <ardour/audiosource.h> #include "i18n.h" #include <locale.h> @@ -63,7 +64,7 @@ AudioRegionState::AudioRegionState (string why) { } -AudioRegion::AudioRegion (Source& src, jack_nframes_t start, jack_nframes_t length, bool announce) +AudioRegion::AudioRegion (AudioSource& src, jack_nframes_t start, jack_nframes_t length, bool announce) : Region (start, length, PBD::basename_nosuffix(src.name()), 0, Region::Flag(Region::DefaultFlags|Region::External)), _fade_in (0.0, 2.0, 1.0, false), _fade_out (0.0, 2.0, 1.0, false), @@ -89,7 +90,7 @@ AudioRegion::AudioRegion (Source& src, jack_nframes_t start, jack_nframes_t leng } } -AudioRegion::AudioRegion (Source& src, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce) +AudioRegion::AudioRegion (AudioSource& src, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce) : Region (start, length, name, layer, flags), _fade_in (0.0, 2.0, 1.0, false), _fade_out (0.0, 2.0, 1.0, false), @@ -150,7 +151,7 @@ AudioRegion::AudioRegion (const AudioRegion& other, jack_nframes_t offset, jack_ { /* create a new AudioRegion, that is part of an existing one */ - set<Source*> unique_srcs; + set<AudioSource*> unique_srcs; for (SourceList::const_iterator i= other.sources.begin(); i != other.sources.end(); ++i) { sources.push_back (*i); @@ -209,7 +210,7 @@ AudioRegion::AudioRegion (const AudioRegion &other) { /* Pure copy constructor */ - set<Source*> unique_srcs; + set<AudioSource*> unique_srcs; for (SourceList::const_iterator i = other.sources.begin(); i != other.sources.end(); ++i) { sources.push_back (*i); @@ -237,7 +238,7 @@ AudioRegion::AudioRegion (const AudioRegion &other) /* NOTE: no CheckNewRegion signal emitted here. This is the copy constructor */ } -AudioRegion::AudioRegion (Source& src, const XMLNode& node) +AudioRegion::AudioRegion (AudioSource& src, const XMLNode& node) : Region (node), _fade_in (0.0, 2.0, 1.0, false), _fade_out (0.0, 2.0, 1.0, false), @@ -268,7 +269,7 @@ AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node) { /* basic AudioRegion constructor */ - set<Source*> unique_srcs; + set<AudioSource*> unique_srcs; for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) { sources.push_back (*i); @@ -1094,7 +1095,7 @@ void AudioRegion::lock_sources () { SourceList::iterator i; - set<Source*> unique_srcs; + set<AudioSource*> unique_srcs; for (i = sources.begin(); i != sources.end(); ++i) { unique_srcs.insert (*i); @@ -1112,7 +1113,7 @@ void AudioRegion::unlock_sources () { SourceList::iterator i; - set<Source*> unique_srcs; + set<AudioSource*> unique_srcs; for (i = sources.begin(); i != sources.end(); ++i) { unique_srcs.insert (*i); diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc index ce7b9a3e6f..2f0b943c0e 100644 --- a/libs/ardour/auditioner.cc +++ b/libs/ardour/auditioner.cc @@ -20,7 +20,7 @@ #include <glibmm/thread.h> -#include <ardour/diskstream.h> +#include <ardour/audio_diskstream.h> #include <ardour/audioregion.h> #include <ardour/route.h> #include <ardour/session.h> diff --git a/libs/ardour/configuration.cc b/libs/ardour/configuration.cc index b7b1d65815..e73208b872 100644 --- a/libs/ardour/configuration.cc +++ b/libs/ardour/configuration.cc @@ -26,7 +26,7 @@ #include <ardour/ardour.h> #include <ardour/configuration.h> -#include <ardour/diskstream.h> +#include <ardour/audio_diskstream.h> #include <ardour/destructive_filesource.h> #include <ardour/control_protocol_manager.h> @@ -231,7 +231,7 @@ Configuration::set_state (const XMLNode& root) } } - DiskStream::set_disk_io_chunk_frames (minimum_disk_io_bytes.get() / sizeof (Sample)); + AudioDiskstream::set_disk_io_chunk_frames (minimum_disk_io_bytes.get() / sizeof (Sample)); return 0; } diff --git a/libs/ardour/destructive_filesource.cc b/libs/ardour/destructive_filesource.cc index 9a4c2425e9..00fabba445 100644 --- a/libs/ardour/destructive_filesource.cc +++ b/libs/ardour/destructive_filesource.cc @@ -66,13 +66,9 @@ gain_t* DestructiveFileSource::out_coefficient = 0; gain_t* DestructiveFileSource::in_coefficient = 0; jack_nframes_t DestructiveFileSource::xfade_frames = 64; -DestructiveFileSource::DestructiveFileSource (string path, jack_nframes_t rate, bool repair_first, SampleFormat samp_format) - : FileSource (path, rate, repair_first, samp_format) +DestructiveFileSource::DestructiveFileSource (string path, SampleFormat samp_format, HeaderFormat hdr_format, jack_nframes_t rate, Flag flags) + : SndFileSource (path, samp_format, hdr_format, rate, flags) { - if (out_coefficient == 0) { - setup_standard_crossfades (rate); - } - xfade_buf = new Sample[xfade_frames]; _capture_start = false; @@ -80,13 +76,9 @@ DestructiveFileSource::DestructiveFileSource (string path, jack_nframes_t rate, file_pos = 0; } -DestructiveFileSource::DestructiveFileSource (const XMLNode& node, jack_nframes_t rate) - : FileSource (node, rate) +DestructiveFileSource::DestructiveFileSource (const XMLNode& node) + : SndFileSource (node) { - if (out_coefficient == 0) { - setup_standard_crossfades (rate); - } - xfade_buf = new Sample[xfade_frames]; _capture_start = false; @@ -102,6 +94,10 @@ DestructiveFileSource::~DestructiveFileSource() void DestructiveFileSource::setup_standard_crossfades (jack_nframes_t rate) { + /* This static method is assumed to have been called by the Session + before any DFS's are created. + */ + xfade_frames = (jack_nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate); if (out_coefficient) { @@ -124,12 +120,6 @@ DestructiveFileSource::setup_standard_crossfades (jack_nframes_t rate) } } -int -DestructiveFileSource::seek (jack_nframes_t frame) -{ - return 0; -} - void DestructiveFileSource::mark_capture_start (jack_nframes_t pos) { @@ -188,7 +178,7 @@ DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in, } if (file_cnt) { - if ((retval = file_read (xfade_buf, fade_position, file_cnt, workbuf)) != (ssize_t) file_cnt) { + if ((retval = write_float (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) { if (retval >= 0 && errno == EAGAIN) { /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you. * short or no data there */ @@ -206,7 +196,7 @@ DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in, } if (nofade && !fade_in) { - if (file_write (data, file_pos, nofade, workbuf) != (ssize_t) nofade) { + if (write_float (data, file_pos, nofade) != nofade) { error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; return 0; } @@ -248,14 +238,14 @@ DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in, } if (xfade) { - if (file_write (xfade_buf, fade_position, xfade, workbuf) != (ssize_t) xfade) { + if (write_float (xfade_buf, fade_position, xfade) != xfade) { error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; return 0; } } if (fade_in && nofade) { - if (file_write (data + xfade, file_pos + xfade, nofade, workbuf) != (ssize_t) nofade) { + if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) { error << string_compose(_("DestructiveFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg; return 0; } @@ -265,96 +255,100 @@ DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in, } jack_nframes_t -DestructiveFileSource::write (Sample* data, jack_nframes_t cnt, char * workbuf) +DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) { - { - Glib::Mutex::Lock lm (_lock); - - jack_nframes_t old_file_pos; + jack_nframes_t old_file_pos; - if (_capture_start && _capture_end) { - _capture_start = false; - _capture_end = false; - - /* move to the correct location place */ - file_pos = capture_start_frame; - - // split cnt in half - jack_nframes_t subcnt = cnt / 2; - jack_nframes_t ofilepos = file_pos; - - // fade in - if (crossfade (data, subcnt, 1, workbuf) != subcnt) { - return 0; - } + if (!writable()) { + return 0; + } - file_pos += subcnt; - Sample * tmpdata = data + subcnt; - - // fade out - subcnt = cnt - subcnt; - if (crossfade (tmpdata, subcnt, 0, workbuf) != subcnt) { - return 0; - } + if (_capture_start && _capture_end) { + _capture_start = false; + _capture_end = false; + + /* move to the correct location place */ + file_pos = capture_start_frame; + + // split cnt in half + jack_nframes_t subcnt = cnt / 2; + jack_nframes_t ofilepos = file_pos; + + // fade in + if (crossfade (data, subcnt, 1, workbuf) != subcnt) { + return 0; + } + + file_pos += subcnt; + Sample * tmpdata = data + subcnt; + + // fade out + subcnt = cnt - subcnt; + if (crossfade (tmpdata, subcnt, 0, workbuf) != subcnt) { + return 0; + } + + file_pos = ofilepos; // adjusted below + } + else if (_capture_start) { - file_pos = ofilepos; // adjusted below + _capture_start = false; + _capture_end = false; + + /* move to the correct location place */ + file_pos = capture_start_frame; + + if (crossfade (data, cnt, 1, workbuf) != cnt) { + return 0; } - else if (_capture_start) { - _capture_start = false; - _capture_end = false; + + } else if (_capture_end) { - /* move to the correct location place */ - file_pos = capture_start_frame; - - if (crossfade (data, cnt, 1, workbuf) != cnt) { - return 0; - } + _capture_start = false; + _capture_end = false; + + if (crossfade (data, cnt, 0, workbuf) != cnt) { + return 0; + } - } else if (_capture_end) { - _capture_start = false; - _capture_end = false; + } else { - if (crossfade (data, cnt, 0, workbuf) != cnt) { - return 0; - } - } else { - if (file_write(data, file_pos, cnt, workbuf) != (ssize_t) cnt) { - return 0; - } + if (write_float (data, file_pos, cnt) != cnt) { + return 0; } - - old_file_pos = file_pos; - if (file_pos + cnt > _length) { - _length = file_pos + cnt; + } + + old_file_pos = file_pos; + if (file_pos + cnt > _length) { + _length = file_pos + cnt; + } + file_pos += cnt; + + if (_build_peakfiles) { + PeakBuildRecord *pbr = 0; + + if (pending_peak_builds.size()) { + pbr = pending_peak_builds.back(); } - file_pos += cnt; - if (_build_peakfiles) { - PeakBuildRecord *pbr = 0; - - if (pending_peak_builds.size()) { - pbr = pending_peak_builds.back(); - } + if (pbr && pbr->frame + pbr->cnt == old_file_pos) { - if (pbr && pbr->frame + pbr->cnt == old_file_pos) { - - /* the last PBR extended to the start of the current write, - so just extend it again. - */ - - pbr->cnt += cnt; - } else { - pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt)); - } + /* the last PBR extended to the start of the current write, + so just extend it again. + */ - _peaks_built = false; + pbr->cnt += cnt; + } else { + pending_peak_builds.push_back (new PeakBuildRecord (old_file_pos, cnt)); } + + _peaks_built = false; } if (_build_peakfiles) { queue_for_peaks (*this); } - + return cnt; } @@ -367,7 +361,14 @@ DestructiveFileSource::last_capture_start_frame () const XMLNode& DestructiveFileSource::get_state () { - XMLNode& node = FileSource::get_state (); + XMLNode& node = AudioFileSource::get_state (); node.add_property (X_("destructive"), "true"); return node; } + +void +DestructiveFileSource::set_timeline_position (jack_nframes_t pos) +{ + /* destructive tracks always start at where our reference frame zero is */ + timeline_position = 0; +} diff --git a/libs/ardour/filesource.cc b/libs/ardour/filesource.cc index 63a9a3d014..0e0ef0bc1e 100644 --- a/libs/ardour/filesource.cc +++ b/libs/ardour/filesource.cc @@ -62,8 +62,7 @@ #include <ardour/ardour.h> #include <ardour/version.h> -#include <ardour/source.h> -#include <ardour/filesource.h> +#include <ardour/audiofilesource.h> #include <ardour/session.h> #include <ardour/cycle_timer.h> #include <ardour/pcm_utils.h> diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 762ee101f8..e1cae3be71 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -43,7 +43,7 @@ #include <ardour/audio_library.h> #include <ardour/configuration.h> #include <ardour/plugin_manager.h> -#include <ardour/source.h> +#include <ardour/audiosource.h> #include <ardour/utils.h> #include <ardour/session.h> #include <ardour/control_protocol_manager.h> diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc index c13816e648..410171a590 100644 --- a/libs/ardour/import.cc +++ b/libs/ardour/import.cc @@ -36,8 +36,8 @@ #include <ardour/ardour.h> #include <ardour/session.h> -#include <ardour/diskstream.h> -#include <ardour/filesource.h> +#include <ardour/audio_diskstream.h> +#include <ardour/sndfilesource.h> #include <ardour/sndfile_helpers.h> #include <ardour/audioregion.h> @@ -51,8 +51,8 @@ int Session::import_audiofile (import_status& status) { SNDFILE *in; - FileSource **newfiles = 0; - ARDOUR::AudioRegion::SourceList sources; + AudioFileSource **newfiles = 0; + AudioRegion::SourceList sources; SF_INFO info; float *data = 0; Sample **channel_data = 0; @@ -94,7 +94,7 @@ Session::import_audiofile (import_status& status) } } - newfiles = new FileSource *[info.channels]; + newfiles = new AudioFileSource *[info.channels]; for (n = 0; n < info.channels; ++n) { newfiles[n] = 0; } @@ -137,7 +137,10 @@ Session::import_audiofile (import_status& status) try { - newfiles[n] = new FileSource (buf, frame_rate(), false, Config->get_native_file_data_format()); + newfiles[n] = new SndFileSource (buf, + Config->get_native_file_data_format(), + Config->get_native_file_header_format(), + frame_rate ()); } catch (failed_constructor& err) { diff --git a/libs/ardour/osc.cc b/libs/ardour/osc.cc index 67b70fba0c..5aaf9d5591 100644 --- a/libs/ardour/osc.cc +++ b/libs/ardour/osc.cc @@ -309,7 +309,6 @@ OSC::osc_receiver() if ((ret = poll (pfd, nfds, timeout)) < 0) { if (errno == EINTR) { /* gdb at work, perhaps */ - cerr << "EINTR hit " << endl; goto again; } diff --git a/libs/ardour/reverse.cc b/libs/ardour/reverse.cc index 335dacad6e..13dd531bac 100644 --- a/libs/ardour/reverse.cc +++ b/libs/ardour/reverse.cc @@ -24,7 +24,7 @@ #include <ardour/types.h> #include <ardour/reverse.h> -#include <ardour/filesource.h> +#include <ardour/audiofilesource.h> #include <ardour/session.h> #include <ardour/audioregion.h> diff --git a/libs/ardour/route_group.cc b/libs/ardour/route_group.cc index ae807e66e1..5730623742 100644 --- a/libs/ardour/route_group.cc +++ b/libs/ardour/route_group.cc @@ -29,7 +29,7 @@ #include <ardour/route_group.h> #include <ardour/audio_track.h> -#include <ardour/diskstream.h> +#include <ardour/audio_diskstream.h> #include <ardour/configuration.h> using namespace ARDOUR; diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index d729b5d7f7..bd5741959c 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -32,7 +32,8 @@ #include <sigc++/bind.h> #include <sigc++/retype.h> -#include <glibmm.h> +#include <glibmm/thread.h> +#include <glibmm/miscutils.h> #include <pbd/error.h> #include <glibmm/thread.h> @@ -43,14 +44,12 @@ #include <ardour/audioengine.h> #include <ardour/configuration.h> #include <ardour/session.h> -#include <ardour/diskstream.h> +#include <ardour/audio_diskstream.h> #include <ardour/utils.h> #include <ardour/audioplaylist.h> #include <ardour/audioregion.h> -#include <ardour/source.h> -#include <ardour/filesource.h> +#include <ardour/audiofilesource.h> #include <ardour/destructive_filesource.h> -#include <ardour/sndfilesource.h> #include <ardour/auditioner.h> #include <ardour/recent_sessions.h> #include <ardour/redirect.h> @@ -90,6 +89,7 @@ Session::mix_buffers_with_gain_t Session::mix_buffers_with_gain = 0; Session::mix_buffers_no_gain_t Session::mix_buffers_no_gain = 0; sigc::signal<int> Session::AskAboutPendingState; +sigc::signal<void> Session::SMPTEOffsetChanged; int Session::find_session (string str, string& path, string& snapshot, bool& isnew) @@ -455,10 +455,10 @@ Session::~Session () } #ifdef TRACK_DESTRUCTION - cerr << "delete diskstreams\n"; + cerr << "delete audio_diskstreams\n"; #endif /* TRACK_DESTRUCTION */ - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ) { - DiskStreamList::iterator tmp; + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ) { + AudioDiskstreamList::iterator tmp; tmp = i; ++tmp; @@ -469,10 +469,10 @@ Session::~Session () } #ifdef TRACK_DESTRUCTION - cerr << "delete sources\n"; + cerr << "delete audio sources\n"; #endif /* TRACK_DESTRUCTION */ - for (SourceList::iterator i = sources.begin(); i != sources.end(); ) { - SourceList::iterator tmp; + for (AudioSourceList::iterator i = audio_sources.begin(); i != audio_sources.end(); ) { + AudioSourceList::iterator tmp; tmp = i; ++tmp; @@ -881,7 +881,7 @@ Session::playlist_length_changed (Playlist* pl) } void -Session::diskstream_playlist_changed (DiskStream* dstream) +Session::diskstream_playlist_changed (AudioDiskstream* dstream) { Playlist *playlist; @@ -961,7 +961,7 @@ Session::set_auto_input (bool yn) The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (!auto_input); @@ -979,7 +979,7 @@ Session::reset_input_monitor_state () { if (transport_rolling()) { Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (Config->get_use_hardware_monitoring() && !auto_input); @@ -987,7 +987,7 @@ Session::reset_input_monitor_state () } } else { Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (Config->get_use_hardware_monitoring()); @@ -1068,7 +1068,7 @@ Session::auto_loop_changed (Location* location) } else if (seamless_loop && !loop_changing) { - // schedule a locate-roll to refill the diskstreams at the + // schedule a locate-roll to refill the audio_diskstreams at the // previous loop end loop_changing = true; @@ -1265,7 +1265,7 @@ Session::enable_record () */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { (*i)->monitor_input (true); } @@ -1300,7 +1300,7 @@ Session::disable_record (bool rt_context, bool force) */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { (*i)->monitor_input (false); } @@ -1327,7 +1327,7 @@ Session::step_back_from_record () */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if (auto_input && (*i)->record_enabled ()) { //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (false); @@ -1432,6 +1432,9 @@ Session::set_frame_rate (jack_nframes_t frames_per_second) Route::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * 0.25)); + // XXX we need some equivalent to this, somehow + // DestructiveFileSource::setup_standard_crossfades (frames_per_second); + set_dirty(); /* XXX need to reset/reinstantiate all LADSPA plugins */ @@ -1493,7 +1496,7 @@ Session::set_block_size (jack_nframes_t nframes) (*i)->set_block_size (nframes); } - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { (*i)->set_block_size (nframes); } @@ -1900,14 +1903,14 @@ Session::add_route (Route* route) } void -Session::add_diskstream (DiskStream* dstream) +Session::add_diskstream (AudioDiskstream* dstream) { /* need to do this in case we're rolling at the time, to prevent false underruns */ dstream->do_refill(0, 0, 0); { Glib::RWLock::WriterLock lm (diskstream_lock); - diskstreams.push_back (dstream); + audio_diskstreams.push_back (dstream); } /* take a reference to the diskstream, preventing it from @@ -1927,7 +1930,7 @@ Session::add_diskstream (DiskStream* dstream) set_dirty(); save_state (_current_snapshot_name); - DiskStreamAdded (dstream); /* EMIT SIGNAL */ + AudioDiskstreamAdded (dstream); /* EMIT SIGNAL */ } void @@ -1961,18 +1964,24 @@ Session::remove_route (Route& route) update_route_solo_state (); } - { - Glib::RWLock::WriterLock lm (diskstream_lock); - - AudioTrack* at; + AudioTrack* at; + AudioDiskstream* ds = 0; + + if ((at = dynamic_cast<AudioTrack*>(&route)) != 0) { + ds = &at->disk_stream(); + } + + if (ds) { - if ((at = dynamic_cast<AudioTrack*>(&route)) != 0) { - diskstreams.remove (&at->disk_stream()); - at->disk_stream().unref (); + { + Glib::RWLock::WriterLock lm (diskstream_lock); + audio_diskstreams.remove (ds); } - find_current_end (); + ds->unref (); } + + find_current_end (); update_latency_compensation (false, false); set_dirty(); @@ -2255,7 +2264,7 @@ Session::get_maximum_extent () const ensure atomicity. */ - for (DiskStreamList::const_iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::const_iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { Playlist* pl = (*i)->playlist(); if ((me = pl->get_maximum_extent()) > max) { max = me; @@ -2265,12 +2274,12 @@ Session::get_maximum_extent () const return max; } -DiskStream * +AudioDiskstream * Session::diskstream_by_name (string name) { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)->name() == name) { return* i; } @@ -2279,12 +2288,12 @@ Session::diskstream_by_name (string name) return 0; } -DiskStream * +AudioDiskstream * Session::diskstream_by_id (id_t id) { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)->id() == id) { return *i; } @@ -2583,7 +2592,10 @@ Session::destroy_region (Region* region) for (vector<Source*>::iterator i = srcs.begin(); i != srcs.end(); ++i) { if ((*i)->use_cnt() == 0) { - (*i)->mark_for_remove (); + AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*i); + if (afs) { + (afs)->mark_for_remove (); + } delete *i; } } @@ -2607,7 +2619,7 @@ Session::remove_last_capture () Glib::RWLock::ReaderLock lm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { list<Region*>& l = (*i)->last_capture_regions(); if (!l.empty()) { @@ -2630,15 +2642,15 @@ Session::remove_region_from_region_list (Region& r) /* Source Management */ void -Session::add_source (Source* source) +Session::add_audio_source (AudioSource* source) { - pair<SourceList::key_type, SourceList::mapped_type> entry; + pair<AudioSourceList::key_type, AudioSourceList::mapped_type> entry; { - Glib::Mutex::Lock lm (source_lock); + Glib::Mutex::Lock lm (audio_source_lock); entry.first = source->id(); entry.second = source; - sources.insert (entry); + audio_sources.insert (entry); } source->GoingAway.connect (mem_fun (this, &Session::remove_source)); @@ -2650,13 +2662,13 @@ Session::add_source (Source* source) void Session::remove_source (Source* source) { - SourceList::iterator i; + AudioSourceList::iterator i; { - Glib::Mutex::Lock lm (source_lock); + Glib::Mutex::Lock lm (audio_source_lock); - if ((i = sources.find (source->id())) != sources.end()) { - sources.erase (i); + if ((i = audio_sources.find (source->id())) != audio_sources.end()) { + audio_sources.erase (i); } } @@ -2675,15 +2687,21 @@ Session::remove_source (Source* source) Source * Session::get_source (ARDOUR::id_t id) { - Glib::Mutex::Lock lm (source_lock); - SourceList::iterator i; + Glib::Mutex::Lock lm (audio_source_lock); + AudioSourceList::iterator i; Source* source = 0; - if ((i = sources.find (id)) != sources.end()) { + if ((i = audio_sources.find (id)) != audio_sources.end()) { source = (*i).second; } - return source; + if (source) { + return source; + } + + /* XXX search MIDI or other searches here */ + + return 0; } string @@ -2890,17 +2908,23 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool return spath; } -FileSource * -Session::create_file_source (DiskStream& ds, int32_t chan, bool destructive) +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(), chan, destructive); /* this might throw failed_constructor(), which is OK */ - + if (destructive) { - return new DestructiveFileSource (spath, frame_rate(), false, Config->get_native_file_data_format()); + return new DestructiveFileSource (spath, + Config->get_native_file_data_format(), + Config->get_native_file_header_format(), + frame_rate()); } else { - return new FileSource (spath, frame_rate(), false, Config->get_native_file_data_format()); + return new SndFileSource (spath, + Config->get_native_file_data_format(), + Config->get_native_file_header_format(), + frame_rate()); } } @@ -3082,7 +3106,7 @@ Session::remove_empty_sounds () for (vector<string *>::iterator i = possible_audiofiles->begin(); i != possible_audiofiles->end(); ++i) { - if (FileSource::is_empty (*(*i))) { + if (AudioFileSource::is_empty (*(*i))) { unlink ((*i)->c_str()); @@ -3140,12 +3164,12 @@ Session::set_all_mute (bool yn) } uint32_t -Session::n_diskstreams () const +Session::n_audio_diskstreams () const { Glib::RWLock::ReaderLock lm (diskstream_lock); uint32_t n = 0; - for (DiskStreamList::const_iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::const_iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if (!(*i)->hidden()) { n++; } @@ -3154,10 +3178,10 @@ Session::n_diskstreams () const } void -Session::foreach_diskstream (void (DiskStream::*func)(void)) +Session::foreach_audio_diskstream (void (AudioDiskstream::*func)(void)) { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if (!(*i)->hidden()) { ((*i)->*func)(); } @@ -3184,7 +3208,7 @@ Session::graph_reordered () reflect any changes in latencies within the graph. */ - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { (*i)->set_capture_offset (); } } @@ -3467,7 +3491,7 @@ Session::reset_native_file_format () //RWLockMonitor lm1 (route_lock, true, __LINE__, __FILE__); Glib::RWLock::ReaderLock lm2 (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { (*i)->reset_write_sources (false); } } @@ -3487,7 +3511,7 @@ Session::route_name_unique (string n) const } int -Session::remove_file_source (FileSource& fs) +Session::cleanup_audio_file_source (AudioFileSource& fs) { return fs.move_to_trash (dead_sound_dir_name); } @@ -3562,12 +3586,12 @@ Session::freeze (InterThreadInfo& itt) } int -Session::write_one_track (AudioTrack& track, jack_nframes_t start, jack_nframes_t len, bool overwrite, vector<Source*>& srcs, - InterThreadInfo& itt) +Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nframes_t len, + bool overwrite, vector<AudioSource*>& srcs, InterThreadInfo& itt) { int ret = -1; Playlist* playlist; - FileSource* fsource; + AudioFileSource* fsource; uint32_t x; char buf[PATH_MAX+1]; string dir; @@ -3612,7 +3636,11 @@ Session::write_one_track (AudioTrack& track, jack_nframes_t start, jack_nframes_ } try { - fsource = new FileSource (buf, frame_rate(), false, Config->get_native_file_data_format()); + fsource = new SndFileSource (buf, + Config->get_native_file_data_format(), + Config->get_native_file_header_format(), + frame_rate()); + } catch (failed_constructor& err) { @@ -3651,9 +3679,13 @@ Session::write_one_track (AudioTrack& track, jack_nframes_t start, jack_nframes_ } uint32_t n = 0; - for (vector<Source*>::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) { - if ((*src)->write (buffers[n], this_chunk, workbuf) != this_chunk) { - goto out; + for (vector<AudioSource*>::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) { + AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*src); + + if (afs) { + if (afs->write (buffers[n], this_chunk, workbuf) != this_chunk) { + goto out; + } } } @@ -3671,14 +3703,20 @@ Session::write_one_track (AudioTrack& track, jack_nframes_t start, jack_nframes_ time (&now); xnow = localtime (&now); - for (vector<Source*>::iterator src=srcs.begin(); src != srcs.end(); ++src) { - dynamic_cast<FileSource*>((*src))->update_header (position, *xnow, now); + for (vector<AudioSource*>::iterator src=srcs.begin(); src != srcs.end(); ++src) { + AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*src); + if (afs) { + afs->update_header (position, *xnow, now); + } } /* build peakfile for new source */ - for (vector<Source*>::iterator src=srcs.begin(); src != srcs.end(); ++src) { - dynamic_cast<FileSource*>(*src)->build_peaks (); + for (vector<AudioSource*>::iterator src=srcs.begin(); src != srcs.end(); ++src) { + AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*src); + if (afs) { + afs->build_peaks (); + } } ret = 0; @@ -3686,8 +3724,11 @@ Session::write_one_track (AudioTrack& track, jack_nframes_t start, jack_nframes_ out: if (ret) { - for (vector<Source*>::iterator src=srcs.begin(); src != srcs.end(); ++src) { - dynamic_cast<FileSource*>(*src)->mark_for_remove (); + for (vector<AudioSource*>::iterator src=srcs.begin(); src != srcs.end(); ++src) { + AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*src); + if (afs) { + afs->mark_for_remove (); + } delete *src; } } diff --git a/libs/ardour/session_butler.cc b/libs/ardour/session_butler.cc index ebe0d64548..d29bf3937b 100644 --- a/libs/ardour/session_butler.cc +++ b/libs/ardour/session_butler.cc @@ -34,7 +34,7 @@ #include <ardour/configuration.h> #include <ardour/audioengine.h> #include <ardour/session.h> -#include <ardour/diskstream.h> +#include <ardour/audio_diskstream.h> #include <ardour/crossfade.h> #include <ardour/timestamps.h> @@ -168,10 +168,10 @@ Session::butler_thread_work () struct timeval begin, end; struct pollfd pfd[1]; bool disk_work_outstanding = false; - DiskStreamList::iterator i; + AudioDiskstreamList::iterator i; - butler_mixdown_buffer = new Sample[DiskStream::disk_io_frames()]; - butler_gain_buffer = new gain_t[DiskStream::disk_io_frames()]; + butler_mixdown_buffer = new Sample[AudioDiskstream::disk_io_frames()]; + butler_gain_buffer = new gain_t[AudioDiskstream::disk_io_frames()]; // this buffer is used for temp conversion purposes in filesources char * conv_buffer = conversion_buffer(ButlerContext); @@ -241,7 +241,7 @@ Session::butler_thread_work () } } - for (i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { // cerr << "BEFORE " << (*i)->name() << ": pb = " << (*i)->playback_buffer_load() << " cp = " << (*i)->capture_buffer_load() << endl; } @@ -257,7 +257,7 @@ Session::butler_thread_work () Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (i = diskstreams.begin(); !transport_work_requested() && butler_should_run && i != diskstreams.end(); ++i) { + for (i = audio_diskstreams.begin(); !transport_work_requested() && butler_should_run && i != audio_diskstreams.end(); ++i) { // cerr << "rah fondr " << (*i)->io()->name () << endl; @@ -278,7 +278,7 @@ Session::butler_thread_work () } - if (i != diskstreams.end()) { + if (i != audio_diskstreams.end()) { /* we didn't get to all the streams */ disk_work_outstanding = true; } @@ -300,7 +300,7 @@ Session::butler_thread_work () compute_io = true; gettimeofday (&begin, 0); - for (i = diskstreams.begin(); !transport_work_requested() && butler_should_run && i != diskstreams.end(); ++i) { + for (i = audio_diskstreams.begin(); !transport_work_requested() && butler_should_run && i != audio_diskstreams.end(); ++i) { // cerr << "write behind for " << (*i)->name () << endl; @@ -330,7 +330,7 @@ Session::butler_thread_work () request_stop (); } - if (i != diskstreams.end()) { + if (i != audio_diskstreams.end()) { /* we didn't get to all the streams */ disk_work_outstanding = true; } @@ -357,7 +357,7 @@ Session::butler_thread_work () Glib::Mutex::Lock lm (butler_request_lock); if (butler_should_run && (disk_work_outstanding || transport_work_requested())) { -// for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { +// for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { // cerr << "AFTER " << (*i)->name() << ": pb = " << (*i)->playback_buffer_load() << " cp = " << (*i)->capture_buffer_load() << endl; // } @@ -375,7 +375,7 @@ Session::butler_thread_work () void -Session::request_overwrite_buffer (DiskStream* stream) +Session::request_overwrite_buffer (AudioDiskstream* stream) { Event *ev = new Event (Event::Overwrite, Event::Add, Event::Immediate, 0, 0, 0.0); ev->set_ptr (stream); @@ -383,7 +383,7 @@ Session::request_overwrite_buffer (DiskStream* stream) } void -Session::overwrite_some_buffers (DiskStream* ds) +Session::overwrite_some_buffers (AudioDiskstream* ds) { /* executed by the audio thread */ @@ -398,7 +398,7 @@ Session::overwrite_some_buffers (DiskStream* ds) } else { Glib::RWLock::ReaderLock dm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { (*i)->set_pending_overwrite (true); } } diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc index d48bbe3053..74735d6ae8 100644 --- a/libs/ardour/session_events.cc +++ b/libs/ardour/session_events.cc @@ -28,7 +28,7 @@ #include <ardour/ardour.h> #include <ardour/session.h> -#include <ardour/diskstream.h> +#include <ardour/audio_diskstream.h> #include "i18n.h" @@ -389,11 +389,11 @@ Session::process_event (Event* ev) break; case Event::Overwrite: - overwrite_some_buffers (static_cast<DiskStream*>(ev->ptr)); + overwrite_some_buffers (static_cast<AudioDiskstream*>(ev->ptr)); break; case Event::SetDiskstreamSpeed: - set_diskstream_speed (static_cast<DiskStream*> (ev->ptr), ev->speed); + set_diskstream_speed (static_cast<AudioDiskstream*> (ev->ptr), ev->speed); break; case Event::SetSlaveSource: diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index 183b6df237..f6ea0c9f3f 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -47,7 +47,7 @@ #include <ardour/sndfile_helpers.h> #include <ardour/port.h> #include <ardour/audioengine.h> -#include <ardour/diskstream.h> +#include <ardour/audio_diskstream.h> #include <ardour/panner.h> #include "i18n.h" @@ -495,7 +495,7 @@ Session::prepare_to_export (AudioExportSpecification& spec) { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)-> seek (spec.start_frame, true)) { error << string_compose (_("%1: cannot seek to %2 for export"), (*i)->name(), spec.start_frame) diff --git a/libs/ardour/session_feedback.cc b/libs/ardour/session_feedback.cc index ea8580b3c2..b409686ce7 100644 --- a/libs/ardour/session_feedback.cc +++ b/libs/ardour/session_feedback.cc @@ -38,7 +38,7 @@ #include <ardour/audioengine.h> #include <ardour/session.h> #include <ardour/audio_track.h> -#include <ardour/diskstream.h> +#include <ardour/audio_diskstream.h> #include <ardour/control_protocol.h> #include "i18n.h" diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index d8382c69a4..fa9fa4a2a3 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -37,7 +37,7 @@ #include <ardour/audioengine.h> #include <ardour/session.h> #include <ardour/audio_track.h> -#include <ardour/diskstream.h> +#include <ardour/audio_diskstream.h> #include <ardour/slave.h> #include <ardour/cycles.h> diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index 2f098a384f..e218bd2458 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -30,7 +30,7 @@ #include <ardour/ardour.h> #include <ardour/session.h> #include <ardour/timestamps.h> -#include <ardour/diskstream.h> +#include <ardour/audio_diskstream.h> #include <ardour/audioengine.h> #include <ardour/slave.h> #include <ardour/auditioner.h> @@ -64,7 +64,7 @@ Session::process (jack_nframes_t nframes) void Session::prepare_diskstreams () { - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { (*i)->prepare (); } } @@ -136,12 +136,12 @@ Session::process_routes (jack_nframes_t nframes, jack_nframes_t offset) if ((ret = (*i)->roll (nframes, _transport_frame, _transport_frame + nframes, offset, declick, record_active, rec_monitors)) < 0) { - /* we have to do this here. Route::roll() for an AudioTrack will have called DiskStream::process(), - and the DS will expect DiskStream::commit() to be called. but we're aborting from that + /* we have to do this here. Route::roll() for an AudioTrack will have called AudioDiskstream::process(), + and the DS will expect AudioDiskstream::commit() to be called. but we're aborting from that call path, so make sure we release any outstanding locks here before we return failure. */ - for (DiskStreamList::iterator ids = diskstreams.begin(); ids != diskstreams.end(); ++ids) { + for (AudioDiskstreamList::iterator ids = audio_diskstreams.begin(); ids != audio_diskstreams.end(); ++ids) { (*ids)->recover (); } @@ -175,12 +175,12 @@ Session::silent_process_routes (jack_nframes_t nframes, jack_nframes_t offset) if ((ret = (*i)->silent_roll (nframes, _transport_frame, _transport_frame + nframes, offset, record_active, rec_monitors)) < 0) { - /* we have to do this here. Route::roll() for an AudioTrack will have called DiskStream::process(), - and the DS will expect DiskStream::commit() to be called. but we're aborting from that + /* we have to do this here. Route::roll() for an AudioTrack will have called AudioDiskstream::process(), + and the DS will expect AudioDiskstream::commit() to be called. but we're aborting from that call path, so make sure we release any outstanding locks here before we return failure. */ - for (DiskStreamList::iterator ids = diskstreams.begin(); ids != diskstreams.end(); ++ids) { + for (AudioDiskstreamList::iterator ids = audio_diskstreams.begin(); ids != audio_diskstreams.end(); ++ids) { (*ids)->recover (); } @@ -199,7 +199,7 @@ Session::commit_diskstreams (jack_nframes_t nframes, bool &needs_butler) float pworst = 1.0f; float cworst = 1.0f; - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)->hidden()) { continue; @@ -566,7 +566,7 @@ Session::follow_slave (jack_nframes_t nframes, jack_nframes_t offset) bool ok = true; jack_nframes_t frame_delta = slave_transport_frame - _transport_frame; - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if (!(*i)->can_internal_playback_seek (frame_delta)) { ok = false; break; @@ -574,7 +574,7 @@ Session::follow_slave (jack_nframes_t nframes, jack_nframes_t offset) } if (ok) { - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { (*i)->internal_playback_seek (frame_delta); } _transport_frame += frame_delta; diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index cf510e9881..7a42a537f5 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -58,13 +58,11 @@ #include <ardour/audioengine.h> #include <ardour/configuration.h> #include <ardour/session.h> -#include <ardour/diskstream.h> +#include <ardour/audio_diskstream.h> #include <ardour/utils.h> #include <ardour/audioplaylist.h> -#include <ardour/source.h> -#include <ardour/filesource.h> +#include <ardour/audiofilesource.h> #include <ardour/destructive_filesource.h> -#include <ardour/sndfilesource.h> #include <ardour/sndfile_helpers.h> #include <ardour/auditioner.h> #include <ardour/export.h> @@ -196,12 +194,13 @@ Session::first_stage_init (string fullpath, string snapshot_name) destructive_index = 0; /* allocate conversion buffers */ - _conversion_buffers[ButlerContext] = new char[DiskStream::disk_io_frames() * 4]; - _conversion_buffers[TransportContext] = new char[DiskStream::disk_io_frames() * 4]; + _conversion_buffers[ButlerContext] = new char[AudioDiskstream::disk_io_frames() * 4]; + _conversion_buffers[TransportContext] = new char[AudioDiskstream::disk_io_frames() * 4]; /* default short fade = 15ms */ Crossfade::set_short_xfade_length ((jack_nframes_t) floor ((15.0 * frame_rate()) / 1000.0)); + DestructiveFileSource::setup_standard_crossfades (frame_rate()); last_mmc_step.tv_sec = 0; last_mmc_step.tv_usec = 0; @@ -267,10 +266,10 @@ Session::first_stage_init (string fullpath, string snapshot_name) /* These are all static "per-class" signals */ Region::CheckNewRegion.connect (mem_fun (*this, &Session::add_region)); - Source::SourceCreated.connect (mem_fun (*this, &Session::add_source)); + AudioSource::AudioSourceCreated.connect (mem_fun (*this, &Session::add_audio_source)); Playlist::PlaylistCreated.connect (mem_fun (*this, &Session::add_playlist)); Redirect::RedirectCreated.connect (mem_fun (*this, &Session::add_redirect)); - DiskStream::DiskStreamCreated.connect (mem_fun (*this, &Session::add_diskstream)); + AudioDiskstream::AudioDiskstreamCreated.connect (mem_fun (*this, &Session::add_diskstream)); NamedSelection::NamedSelectionCreated.connect (mem_fun (*this, &Session::add_named_selection)); IO::MoreOutputs.connect (mem_fun (*this, &Session::ensure_passthru_buffers)); @@ -285,7 +284,7 @@ Session::first_stage_init (string fullpath, string snapshot_name) int Session::second_stage_init (bool new_session) { - ExternalSource::set_peak_dir (peak_dir()); + AudioFileSource::set_peak_dir (peak_dir()); if (!new_session) { if (load_state (_current_snapshot_name)) { @@ -425,7 +424,7 @@ Session::setup_raid_path (string path) } fspath += tape_dir_name; - FileSource::set_search_path (fspath); + AudioFileSource::set_search_path (fspath); return; } @@ -481,9 +480,9 @@ Session::setup_raid_path (string path) session_dirs.push_back (sp); } - /* set the FileSource search path */ + /* set the AudioFileSource search path */ - FileSource::set_search_path (fspath); + AudioFileSource::set_search_path (fspath); /* reset the round-robin soundfile path thingie */ @@ -625,11 +624,11 @@ Session::load_diskstreams (const XMLNode& node) for (citer = clist.begin(); citer != clist.end(); ++citer) { - DiskStream* dstream; + AudioDiskstream* dstream; try { - dstream = new DiskStream (*this, **citer); - /* added automatically by DiskStreamCreated handler */ + dstream = new AudioDiskstream (*this, **citer); + /* added automatically by AudioDiskstreamCreated handler */ } catch (failed_constructor& err) { @@ -1335,15 +1334,15 @@ Session::state(bool full_state) child = node->add_child ("Sources"); if (full_state) { - Glib::Mutex::Lock sl (source_lock); + Glib::Mutex::Lock sl (audio_source_lock); - for (SourceList::iterator siter = sources.begin(); siter != sources.end(); ++siter) { + for (AudioSourceList::iterator siter = audio_sources.begin(); siter != audio_sources.end(); ++siter) { - /* Don't save information about FileSources that are empty */ + /* Don't save information about AudioFileSources that are empty */ - FileSource* fs; + AudioFileSource* fs; - if ((fs = dynamic_cast<FileSource*> ((*siter).second)) != 0) { + if ((fs = dynamic_cast<AudioFileSource*> ((*siter).second)) != 0) { DestructiveFileSource* dfs = dynamic_cast<DestructiveFileSource*> (fs); /* destructive file sources are OK if they are empty, because @@ -1380,7 +1379,7 @@ Session::state(bool full_state) { Glib::RWLock::ReaderLock dl (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if (!(*i)->hidden()) { child->add_child_nocopy ((*i)->get_state()); } @@ -1511,7 +1510,7 @@ Session::set_state (const XMLNode& node) Options Sources AudioRegions - DiskStreams + AudioDiskstreams Connections Locations Routes @@ -1745,6 +1744,7 @@ Session::XMLRegionFactory (const XMLNode& node, bool full) const XMLProperty* prop; id_t s_id; Source* source; + AudioSource* as; AudioRegion::SourceList sources; uint32_t nchans = 1; char buf[128]; @@ -1772,7 +1772,13 @@ Session::XMLRegionFactory (const XMLNode& node, bool full) return 0; } - sources.push_back(source); + as = dynamic_cast<AudioSource*>(source); + if (!as) { + error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg; + return 0; + } + + sources.push_back (as); /* pickup other channels */ @@ -1785,7 +1791,13 @@ Session::XMLRegionFactory (const XMLNode& node, bool full) error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg; return 0; } - sources.push_back(source); + + as = dynamic_cast<AudioSource*>(source); + if (!as) { + error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg; + return 0; + } + sources.push_back (as); } } @@ -1804,12 +1816,14 @@ Session::get_sources_as_xml () { XMLNode* node = new XMLNode (X_("Sources")); - Glib::Mutex::Lock lm (source_lock); + Glib::Mutex::Lock lm (audio_source_lock); - for (SourceList::iterator i = sources.begin(); i != sources.end(); ++i) { + for (AudioSourceList::iterator i = audio_sources.begin(); i != audio_sources.end(); ++i) { node->add_child_nocopy ((*i).second->get_state()); } + /* XXX get MIDI and other sources here */ + return *node; } @@ -1867,23 +1881,12 @@ Session::XMLSourceFactory (const XMLNode& node) } try { - if (node.property (X_("destructive")) != 0) { - src = new DestructiveFileSource (node, frame_rate()); - } else { - src = new FileSource (node, frame_rate()); - } + src = AudioFileSource::create (node); } catch (failed_constructor& err) { - - try { - src = ExternalSource::create (node); - } - - catch (failed_constructor& err) { - error << _("Found a sound file that cannot be used by Ardour. See the progammers.") << endmsg; - return 0; - } + error << _("Found a sound file that cannot be used by Ardour. Talk to the progammers.") << endmsg; + return 0; } return src; @@ -2930,9 +2933,9 @@ Session::cleanup_sources (Session::cleanup_report& rep) rep.paths.clear (); rep.space = 0; - for (SourceList::iterator i = sources.begin(); i != sources.end(); ) { + for (AudioSourceList::iterator i = audio_sources.begin(); i != audio_sources.end(); ) { - SourceList::iterator tmp; + AudioSourceList::iterator tmp; tmp = i; ++tmp; @@ -2949,7 +2952,7 @@ Session::cleanup_sources (Session::cleanup_report& rep) adding it to the list of all sources below */ - sources.erase (i); + audio_sources.erase (i); } i = tmp; @@ -3013,20 +3016,17 @@ Session::cleanup_sources (Session::cleanup_report& rep) state file on disk still references sources we may have already dropped. */ - + find_all_sources_across_snapshots (all_sources, true); - /* add our current source list + /* add our current source list */ - - for (SourceList::iterator i = sources.begin(); i != sources.end(); ++i) { - FileSource* fs; - ExternalSource* sfs; + + for (AudioSourceList::iterator i = audio_sources.begin(); i != audio_sources.end(); ++i) { + AudioFileSource* fs; - if ((fs = dynamic_cast<FileSource*> ((*i).second)) != 0) { + if ((fs = dynamic_cast<AudioFileSource*> ((*i).second)) != 0) { all_sources.insert (fs->path()); - } else if ((sfs = dynamic_cast<ExternalSource*> ((*i).second)) != 0) { - all_sources.insert (sfs->path()); } } diff --git a/libs/ardour/session_time.cc b/libs/ardour/session_time.cc index e3badc5b11..a272f55737 100644 --- a/libs/ardour/session_time.cc +++ b/libs/ardour/session_time.cc @@ -32,6 +32,7 @@ #include <ardour/audioengine.h> #include <ardour/session.h> #include <ardour/tempo.h> +#include <ardour/audiofilesource.h> #include "i18n.h" @@ -91,6 +92,9 @@ Session::set_smpte_offset (jack_nframes_t off) { _smpte_offset = off; last_smpte_valid = false; + + AudioFileSource::set_header_position_offset (_smpte_offset, _smpte_offset_negative); + SMPTEOffsetChanged (); /* EMIT SIGNAL */ } @@ -99,6 +103,9 @@ Session::set_smpte_offset_negative (bool neg) { _smpte_offset_negative = neg; last_smpte_valid = false; + + AudioFileSource::set_header_position_offset (_smpte_offset, _smpte_offset_negative); + SMPTEOffsetChanged (); /* EMIT SIGNAL */ } @@ -558,7 +565,7 @@ void Session::sample_to_smpte( jack_nframes_t sample, SMPTE_Time& smpte, bool use_offset, bool use_subframes ) const { jack_nframes_t offset_sample; - + if (!use_offset) { offset_sample = sample; smpte.negative = false; @@ -690,7 +697,7 @@ Session::smpte_duration_string (char* buf, jack_nframes_t when) const SMPTE_Time smpte; smpte_duration (when, smpte); - snprintf (buf, sizeof (buf), "%02ld:%02ld:%02ld:%02ld", smpte.hours, smpte.minutes, smpte.seconds, smpte.frames); + snprintf (buf, sizeof (buf), "%02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 ":%02" PRIu32, smpte.hours, smpte.minutes, smpte.seconds, smpte.frames); } void diff --git a/libs/ardour/session_timefx.cc b/libs/ardour/session_timefx.cc index 6351aa9825..ee751b9af7 100644 --- a/libs/ardour/session_timefx.cc +++ b/libs/ardour/session_timefx.cc @@ -27,7 +27,6 @@ #include <ardour/session.h> #include <ardour/audioregion.h> -#include <ardour/filesource.h> #include <ardour/sndfilesource.h> #include "i18n.h" @@ -80,7 +79,10 @@ Session::tempoize_region (TimeStretchRequest& tsr) } try { - sources.push_back(new FileSource (path, frame_rate(), false, Config->get_native_file_data_format())); + sources.push_back (new SndFileSource (path, + Config->get_native_file_data_format(), + Config->get_native_file_header_format(), + frame_rate())); } catch (failed_constructor& err) { error << string_compose (_("tempoize: error creating new audio file %1 (%2)"), path, strerror (errno)) << endmsg; goto out; @@ -150,13 +152,16 @@ Session::tempoize_region (TimeStretchRequest& tsr) xnow = localtime (&now); for (it = sources.begin(); it != sources.end(); ++it) { - dynamic_cast<FileSource*>(*it)->update_header (tsr.region->position(), *xnow, now); + AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*it); + if (afs) { + afs->update_header (tsr.region->position(), *xnow, now); + } } region_name = tsr.region->name() + X_(".t"); r = new AudioRegion (sources, 0, sources.front()->length(), region_name, - 0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile)); + 0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile)); out: diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index db15b64c32..4a1f7a182b 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -36,7 +36,7 @@ #include <ardour/ardour.h> #include <ardour/audioengine.h> #include <ardour/session.h> -#include <ardour/diskstream.h> +#include <ardour/audio_diskstream.h> #include <ardour/auditioner.h> #include <ardour/slave.h> #include <ardour/location.h> @@ -78,7 +78,7 @@ Session::request_transport_speed (float speed) } void -Session::request_diskstream_speed (DiskStream& ds, float speed) +Session::request_diskstream_speed (AudioDiskstream& ds, float speed) { Event* ev = new Event (Event::SetDiskstreamSpeed, Event::Add, Event::Immediate, 0, speed); ev->set_ptr (&ds); @@ -200,7 +200,7 @@ Session::butler_transport_work () } if (post_transport_work & PostTransportInputChange) { - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { (*i)->non_realtime_input_change (); } } @@ -216,7 +216,7 @@ Session::butler_transport_work () cumulative_rf_motion = 0; reset_rf_scale (0); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if (!(*i)->hidden()) { if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) { (*i)->seek ((jack_nframes_t) (_transport_frame * (double) (*i)->speed())); @@ -248,7 +248,7 @@ Session::non_realtime_set_speed () { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { (*i)->non_realtime_set_speed (); } } @@ -258,7 +258,7 @@ Session::non_realtime_overwrite () { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)->pending_overwrite) { (*i)->overwrite_existing_buffers (); } @@ -274,7 +274,7 @@ Session::non_realtime_stop (bool abort) did_record = false; - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)->get_captured_frames () != 0) { did_record = true; break; @@ -327,7 +327,7 @@ Session::non_realtime_stop (bool abort) _have_captured = true; } - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { (*i)->transport_stopped (*now, xnow, abort); } @@ -364,7 +364,7 @@ Session::non_realtime_stop (bool abort) } #endif - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if (!(*i)->hidden()) { if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) { (*i)->seek ((jack_nframes_t) (_transport_frame * (double) (*i)->speed())); @@ -491,7 +491,7 @@ Session::set_auto_loop (bool yn) if (seamless_loop) { // set all diskstreams to use internal looping - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if (!(*i)->hidden()) { (*i)->set_loop (loc); } @@ -499,7 +499,7 @@ Session::set_auto_loop (bool yn) } else { // set all diskstreams to NOT use internal looping - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if (!(*i)->hidden()) { (*i)->set_loop (0); } @@ -529,7 +529,7 @@ Session::set_auto_loop (bool yn) clear_events (Event::AutoLoop); // set all diskstreams to NOT use internal looping - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if (!(*i)->hidden()) { (*i)->set_loop (0); } @@ -645,7 +645,7 @@ Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, b The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (!auto_input); @@ -660,7 +660,7 @@ Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, b The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (true); @@ -704,7 +704,7 @@ Session::set_transport_speed (float speed, bool abort) The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (true); @@ -730,7 +730,7 @@ Session::set_transport_speed (float speed, bool abort) The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if (auto_input && (*i)->record_enabled ()) { //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (false); @@ -781,7 +781,7 @@ Session::set_transport_speed (float speed, bool abort) _last_transport_speed = _transport_speed; _transport_speed = speed; - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if ((*i)->realtime_set_speed ((*i)->speed(), true)) { post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); } @@ -871,7 +871,7 @@ Session::actually_start_transport () transport_sub_state |= PendingDeclickIn; _transport_speed = 1.0; - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { (*i)->realtime_set_speed ((*i)->speed(), true); } @@ -1001,7 +1001,7 @@ Session::set_slave_source (SlaveSource src, jack_nframes_t frame) _slave_type = src; - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { if (!(*i)->hidden()) { if ((*i)->realtime_set_speed ((*i)->speed(), true)) { non_rt_required = true; @@ -1033,7 +1033,7 @@ Session::reverse_diskstream_buffers () } void -Session::set_diskstream_speed (DiskStream* stream, float speed) +Session::set_diskstream_speed (AudioDiskstream* stream, float speed) { if (stream->realtime_set_speed (speed, false)) { post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); @@ -1229,7 +1229,7 @@ Session::update_latency_compensation (bool with_stop, bool abort) /* reflect any changes in latencies into capture offsets */ - for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { + for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { (*i)->set_capture_offset (); } } diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc index 87f7faf423..6929385141 100644 --- a/libs/ardour/sndfilesource.cc +++ b/libs/ardour/sndfilesource.cc @@ -18,47 +18,203 @@ $Id$ */ +#include <cerrno> +#include <climits> + +#include <pwd.h> +#include <sys/utsname.h> + +#include <glibmm/miscutils.h> + #include <ardour/sndfilesource.h> #include "i18n.h" +using namespace std; using namespace ARDOUR; SndFileSource::SndFileSource (const XMLNode& node) - : ExternalSource (node) + : AudioFileSource (node) { - init (_name, true); - SourceCreated (this); /* EMIT SIGNAL */ + init (_name); + + if (open()) { + throw failed_constructor (); + } + + if (_build_peakfiles) { + if (initialize_peakfile (false, _path)) { + sf_close (sf); + sf = 0; + throw failed_constructor (); + } + } + + AudioSourceCreated (this); /* EMIT SIGNAL */ } -SndFileSource::SndFileSource (const string& idstr, bool build_peak) - : ExternalSource(idstr, build_peak) +SndFileSource::SndFileSource (string idstr, Flag flags) + : AudioFileSource (idstr, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy))) { - init (idstr, build_peak); + init (idstr); - if (build_peak) { - SourceCreated (this); /* EMIT SIGNAL */ + if (open()) { + throw failed_constructor (); } + + if (_build_peakfiles) { + if (initialize_peakfile (false, _path)) { + sf_close (sf); + sf = 0; + throw failed_constructor (); + } + } + + + AudioSourceCreated (this); /* EMIT SIGNAL */ +} + +SndFileSource::SndFileSource (string idstr, SampleFormat sfmt, HeaderFormat hf, jack_nframes_t rate, Flag flags) + : AudioFileSource(idstr, flags, sfmt, hf) +{ + int fmt = 0; + + init (idstr); + + cerr << "creating " << idstr << " hf = " << hf << endl; + + switch (hf) { + case CAF: + fmt = SF_FORMAT_CAF; + _flags = Flag (_flags & ~Broadcast); + break; + + case AIFF: + fmt = SF_FORMAT_AIFF; + _flags = Flag (_flags & ~Broadcast); + break; + + case BWF: + fmt = SF_FORMAT_WAV; + _flags = Flag (_flags | Broadcast); + break; + + case WAVE: + fmt = SF_FORMAT_WAV; + _flags = Flag (_flags & ~Broadcast); + break; + + case WAVE64: + fmt = SF_FORMAT_W64; + _flags = Flag (_flags & ~Broadcast); + break; + + default: + fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg; + /*NOTREACHED*/ + break; + + } + + switch (sfmt) { + case FormatFloat: + fmt |= SF_FORMAT_FLOAT; + break; + + case FormatInt24: + fmt |= SF_FORMAT_PCM_24; + break; + } + + _info.channels = 1; + _info.samplerate = rate; + _info.format = fmt; + + if (open()) { + throw failed_constructor(); + } + + if (writable() && (_flags & Broadcast)) { + + _broadcast_info = new SF_BROADCAST_INFO; + memset (_broadcast_info, 0, sizeof (*_broadcast_info)); + + snprintf (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str()); + + struct utsname utsinfo; + + if (uname (&utsinfo)) { + error << string_compose(_("FileSource: cannot get host information for BWF header (%1)"), strerror(errno)) << endmsg; + return; + } + + snprintf (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour:%s:%s:%s:%s:%s)", + Glib::get_real_name().c_str(), + utsinfo.nodename, + utsinfo.sysname, + utsinfo.release, + utsinfo.version); + + _broadcast_info->version = 1; + + /* XXX do something about this field */ + + snprintf (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord"); + + /* coding history is added by libsndfile */ + + if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (_broadcast_info)) != SF_TRUE) { + char errbuf[256]; + sf_error_str (0, errbuf, sizeof (errbuf) - 1); + error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"), _path, errbuf) << endmsg; + _flags = Flag (_flags & ~Broadcast); + delete _broadcast_info; + _broadcast_info = 0; + } + } + + if (_build_peakfiles) { + if (initialize_peakfile (false, _path)) { + sf_close (sf); + sf = 0; + throw failed_constructor (); + } + } + + /* since SndFileSource's constructed with this constructor can be writable, make sure we update if the header info changes */ + + if (writable()) { + HeaderPositionOffsetChanged.connect (mem_fun (*this, &AudioFileSource::handle_header_position_change)); + } + + if (_build_peakfiles) { + if (initialize_peakfile (false, _path)) { + sf_close (sf); + sf = 0; + throw failed_constructor (); + } + } + + AudioSourceCreated (this); /* EMIT SIGNAL */ } void -SndFileSource::init (const string& idstr, bool build_peak) +SndFileSource::init (const string& idstr) { string::size_type pos; string file; - tmpbuf = 0; - tmpbufsize = 0; + interleave_buf = 0; + interleave_bufsize = 0; sf = 0; - - _name = idstr; + _broadcast_info = 0; if ((pos = idstr.find_last_of (':')) == string::npos) { channel = 0; - file = idstr; + _name = Glib::path_get_basename (idstr); } else { channel = atoi (idstr.substr (pos+1).c_str()); - file = idstr.substr (0, pos); + _name = Glib::path_get_basename (idstr.substr (0, pos)); } /* although libsndfile says we don't need to set this, @@ -66,46 +222,56 @@ SndFileSource::init (const string& idstr, bool build_peak) */ memset (&_info, 0, sizeof(_info)); +} - /* note that we temporarily truncated _id at the colon */ - - if ((sf = sf_open (file.c_str(), SFM_READ, &_info)) == 0) { +int +SndFileSource::open () +{ + if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) { char errbuf[256]; sf_error_str (0, errbuf, sizeof (errbuf) - 1); - error << string_compose(_("SndFileSource: cannot open file \"%1\" (%2)"), file, errbuf) << endmsg; - throw failed_constructor(); + error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"), + _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg; + return -1; } if (channel >= _info.channels) { error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, channel) << endmsg; sf_close (sf); sf = 0; - throw failed_constructor(); + return -1; } _length = _info.frames; - _path = file; - if (build_peak) { - if (initialize_peakfile (false, _path)) { - sf_close (sf); - sf = 0; - throw failed_constructor (); - } + if (writable()) { + sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE); + } + + return 0; +} + +void +SndFileSource::close () +{ + if (sf) { + sf_close (sf); + sf = 0; } } SndFileSource::~SndFileSource () - { GoingAway (this); /* EMIT SIGNAL */ - if (sf) { - sf_close (sf); + close (); + + if (interleave_buf) { + delete [] interleave_buf; } - if (tmpbuf) { - delete [] tmpbuf; + if (_broadcast_info) { + delete [] _broadcast_info; } } @@ -116,49 +282,73 @@ SndFileSource::sample_rate () const } jack_nframes_t -SndFileSource::read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const +SndFileSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const { int32_t nread; float *ptr; uint32_t real_cnt; + jack_nframes_t file_cnt; - if (sf_seek (sf, (off_t) start, SEEK_SET) < 0) { - char errbuf[256]; - sf_error_str (0, errbuf, sizeof (errbuf) - 1); - error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg; - return 0; - } + if (start > _length) { - if (_info.channels == 1) { - jack_nframes_t ret = sf_read_float (sf, dst, cnt); - _read_data_count = cnt * sizeof(float); - return ret; - } + /* read starts beyond end of data, just memset to zero */ + + file_cnt = 0; - real_cnt = cnt * _info.channels; + } else if (start + cnt > _length) { + + /* read ends beyond end of data, read some, memset the rest */ + + file_cnt = _length - start; - { - Glib::Mutex::Lock lm (_tmpbuf_lock); + } else { - if (tmpbufsize < real_cnt) { - - if (tmpbuf) { - delete [] tmpbuf; - } - tmpbufsize = real_cnt; - tmpbuf = new float[tmpbufsize]; + /* read is entirely within data */ + + file_cnt = cnt; + } + + if (file_cnt) { + + if (sf_seek (sf, (off_t) start, SEEK_SET) < 0) { + char errbuf[256]; + sf_error_str (0, errbuf, sizeof (errbuf) - 1); + error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg; + return 0; } - nread = sf_read_float (sf, tmpbuf, real_cnt); - ptr = tmpbuf + channel; - nread /= _info.channels; - - /* stride through the interleaved data */ + if (_info.channels == 1) { + jack_nframes_t ret = sf_read_float (sf, dst, file_cnt); + _read_data_count = cnt * sizeof(float); + return ret; + } + } + + if (file_cnt != cnt) { + jack_nframes_t delta = cnt - file_cnt; + memset (dst+file_cnt, 0, sizeof (Sample) * delta); + } + + real_cnt = cnt * _info.channels; + + if (interleave_bufsize < real_cnt) { - for (int32_t n = 0; n < nread; ++n) { - dst[n] = *ptr; - ptr += _info.channels; + if (interleave_buf) { + delete [] interleave_buf; } + interleave_bufsize = real_cnt; + interleave_buf = new float[interleave_bufsize]; + } + + nread = sf_read_float (sf, interleave_buf, real_cnt); + ptr = interleave_buf + channel; + nread /= _info.channels; + + /* stride through the interleaved data */ + + for (int32_t n = 0; n < nread; ++n) { + dst[n] = *ptr; + ptr += _info.channels; } _read_data_count = cnt * sizeof(float); @@ -166,3 +356,163 @@ SndFileSource::read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char return nread; } +jack_nframes_t +SndFileSource::write_unlocked (Sample *data, jack_nframes_t cnt, char * workbuf) +{ + if (!writable()) { + return 0; + } + + if (_info.channels != 1) { + fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg; + /*NOTREACHED*/ + return 0; + } + + jack_nframes_t oldlen; + int32_t frame_pos = _length; + + if (write_float (data, frame_pos, cnt) != cnt) { + return 0; + } + + oldlen = _length; + update_length (oldlen, cnt); + + if (_build_peakfiles) { + PeakBuildRecord *pbr = 0; + + if (pending_peak_builds.size()) { + pbr = pending_peak_builds.back(); + } + + if (pbr && pbr->frame + pbr->cnt == oldlen) { + + /* the last PBR extended to the start of the current write, + so just extend it again. + */ + + pbr->cnt += cnt; + } else { + pending_peak_builds.push_back (new PeakBuildRecord (oldlen, cnt)); + } + + _peaks_built = false; + } + + + if (_build_peakfiles) { + queue_for_peaks (*this); + } + + _write_data_count = cnt; + + return cnt; +} + +int +SndFileSource::update_header (jack_nframes_t when, struct tm& now, time_t tnow) +{ + /* allow derived classes to override how this is done */ + + set_timeline_position (when); + + if (_flags & Broadcast) { + /* this will flush the header implicitly */ + return setup_broadcast_info (when, now, tnow); + } else { + return flush_header (); + } +} + +int +SndFileSource::flush_header () +{ + return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE); +} + +int +SndFileSource::setup_broadcast_info (jack_nframes_t when, struct tm& now, time_t tnow) +{ + /* random code is 9 digits */ + + int random_code = random() % 999999999; + + snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d", + bwf_country_code, + bwf_organization_code, + bwf_serial_number, + now.tm_hour, + now.tm_min, + now.tm_sec, + random_code); + + snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d", + 1900 + now.tm_year, + now.tm_mon, + now.tm_mday); + + snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d-%02d-%02d", + now.tm_hour, + now.tm_min, + now.tm_sec); + + /* now update header position taking header offset into account */ + + set_header_timeline_position (); + + /* note that libsndfile flushes the header to disk when resetting the broadcast info */ + + if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) { + error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg; + _flags = Flag (_flags & ~Broadcast); + delete _broadcast_info; + _broadcast_info = 0; + return -1; + } + + return 0; +} + +void +SndFileSource::set_header_timeline_position () +{ + uint64_t pos; + + _broadcast_info->time_reference_high = 0; + + if (header_position_negative) { + + if (ULONG_LONG_MAX - header_position_offset < timeline_position) { + pos = ULONG_LONG_MAX; // impossible + } else { + pos = timeline_position + header_position_offset; + } + + } else { + + if (timeline_position < header_position_offset) { + pos = 0; + } else { + pos = timeline_position - header_position_offset; + } + } + + _broadcast_info->time_reference_high = (pos >> 32); + _broadcast_info->time_reference_low = (pos & 0xffffffff); +} + +jack_nframes_t +SndFileSource::write_float (Sample* data, jack_nframes_t frame_pos, jack_nframes_t cnt) +{ + if (sf_seek (sf, frame_pos, SEEK_SET) != frame_pos) { + error << string_compose (_("%1: cannot seek to %2"), _path, frame_pos) << endmsg; + return 0; + } + + if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) { + return 0; + } + + return cnt; +} diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc index 7d790a036d..0d32ea4a21 100644 --- a/libs/ardour/source.cc +++ b/libs/ardour/source.cc @@ -42,35 +42,18 @@ using std::max; using namespace ARDOUR; -sigc::signal<void,Source *> Source::SourceCreated; -pthread_t Source::peak_thread; -bool Source::have_peak_thread = false; -vector<Source*> Source::pending_peak_sources; -Glib::StaticMutex Source::pending_peak_sources_lock = GLIBMM_STATIC_MUTEX_INIT; -int Source::peak_request_pipe[2]; - -bool Source::_build_missing_peakfiles = false; -bool Source::_build_peakfiles = false; - -Source::Source (bool announce) +Source::Source (string name) { + _name = name; _id = ARDOUR::new_id(); _use_cnt = 0; - _peaks_built = false; - next_peak_clear_should_notify = true; _timestamp = 0; - _read_data_count = 0; - _write_data_count = 0; } Source::Source (const XMLNode& node) { _use_cnt = 0; - _peaks_built = false; - next_peak_clear_should_notify = true; _timestamp = 0; - _read_data_count = 0; - _write_data_count = 0; if (set_state (node)) { throw failed_constructor(); @@ -96,10 +79,6 @@ Source::get_state () node->add_property ("timestamp", buf); } - if (_captured_for.length()) { - node->add_property ("captured-for", _captured_for); - } - return *node; } @@ -124,735 +103,10 @@ Source::set_state (const XMLNode& node) sscanf (prop->value().c_str(), "%ld", &_timestamp); } - if ((prop = node.property ("captured-for")) != 0) { - _captured_for = prop->value(); - } - - return 0; -} - -/*********************************************************************** - PEAK FILE STUFF - ***********************************************************************/ - -void* -Source::peak_thread_work (void* arg) -{ - PBD::ThreadCreated (pthread_self(), X_("Peak")); - struct pollfd pfd[1]; - - Glib::Mutex::Lock lm (pending_peak_sources_lock); - - while (true) { - - pfd[0].fd = peak_request_pipe[0]; - pfd[0].events = POLLIN|POLLERR|POLLHUP; - - pending_peak_sources_lock.unlock(); - - if (poll (pfd, 1, -1) < 0) { - - if (errno == EINTR) { - pending_peak_sources_lock.lock(); - continue; - } - - error << string_compose (_("poll on peak request pipe failed (%1)"), - strerror (errno)) - << endmsg; - break; - } - - if (pfd[0].revents & ~POLLIN) { - error << _("Error on peak thread request pipe") << endmsg; - break; - } - - if (pfd[0].revents & POLLIN) { - - char req; - - /* empty the pipe of all current requests */ - - while (1) { - size_t nread = ::read (peak_request_pipe[0], &req, sizeof (req)); - - if (nread == 1) { - switch ((PeakRequest::Type) req) { - - case PeakRequest::Build: - break; - - case PeakRequest::Quit: - pthread_exit_pbd (0); - /*NOTREACHED*/ - break; - - default: - break; - } - - } else if (nread == 0) { - break; - } else if (errno == EAGAIN) { - break; - } else { - fatal << _("Error reading from peak request pipe") << endmsg; - /*NOTREACHED*/ - } - } - } - - pending_peak_sources_lock.lock(); - - while (!pending_peak_sources.empty()) { - - Source* s = pending_peak_sources.front(); - pending_peak_sources.erase (pending_peak_sources.begin()); - - pending_peak_sources_lock.unlock(); - s->build_peaks(); - pending_peak_sources_lock.lock(); - } - } - - pthread_exit_pbd (0); - /*NOTREACHED*/ - return 0; -} - -int -Source::start_peak_thread () -{ - if (!_build_peakfiles) { - return 0; - } - - if (pipe (peak_request_pipe)) { - error << string_compose(_("Cannot create transport request signal pipe (%1)"), strerror (errno)) << endmsg; - return -1; - } - - if (fcntl (peak_request_pipe[0], F_SETFL, O_NONBLOCK)) { - error << string_compose(_("UI: cannot set O_NONBLOCK on peak request pipe (%1)"), strerror (errno)) << endmsg; - return -1; - } - - if (fcntl (peak_request_pipe[1], F_SETFL, O_NONBLOCK)) { - error << string_compose(_("UI: cannot set O_NONBLOCK on peak request pipe (%1)"), strerror (errno)) << endmsg; - return -1; - } - - if (pthread_create_and_store ("peak file builder", &peak_thread, 0, peak_thread_work, 0)) { - error << _("Source: could not create peak thread") << endmsg; - return -1; - } - - have_peak_thread = true; return 0; } void -Source::stop_peak_thread () -{ - if (!have_peak_thread) { - return; - } - - void* status; - - char c = (char) PeakRequest::Quit; - ::write (peak_request_pipe[1], &c, 1); - pthread_join (peak_thread, &status); -} - -void -Source::queue_for_peaks (Source& source) -{ - if (have_peak_thread) { - - Glib::Mutex::Lock lm (pending_peak_sources_lock); - - source.next_peak_clear_should_notify = true; - - if (find (pending_peak_sources.begin(), - pending_peak_sources.end(), - &source) == pending_peak_sources.end()) { - pending_peak_sources.push_back (&source); - } - - char c = (char) PeakRequest::Build; - ::write (peak_request_pipe[1], &c, 1); - } -} - -void Source::clear_queue_for_peaks () -{ - /* this is done to cancel a group of running peak builds */ - if (have_peak_thread) { - Glib::Mutex::Lock lm (pending_peak_sources_lock); - pending_peak_sources.clear (); - } -} - - -bool -Source::peaks_ready (sigc::slot<void> the_slot, sigc::connection& conn) const -{ - bool ret; - Glib::Mutex::Lock lm (_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); - } - - return ret; -} - -int -Source::rename_peakfile (string newpath) -{ - /* caller must hold _lock */ - - string oldpath = peakpath; - - if (access (oldpath.c_str(), F_OK) == 0) { - if (rename (oldpath.c_str(), newpath.c_str()) != 0) { - error << string_compose (_("cannot rename peakfile for %1 from %2 to %3 (%4)"), _name, oldpath, newpath, strerror (errno)) << endmsg; - return -1; - } - } - - peakpath = newpath; - - return 0; -} - -int -Source::initialize_peakfile (bool newfile, string audio_path) -{ - struct stat statbuf; - - peakpath = peak_path (audio_path); - - if (newfile) { - - if (!_build_peakfiles) { - return 0; - } - - _peaks_built = false; - - } else { - - if (stat (peakpath.c_str(), &statbuf)) { - if (errno != ENOENT) { - /* it exists in the peaks dir, but there is some kind of error */ - - error << string_compose(_("Source: cannot stat peakfile \"%1\""), peakpath) << endmsg; - return -1; - } - - } else { - - /* we found it in the peaks dir */ - } - - if (statbuf.st_size == 0) { - _peaks_built = false; - } else { - // Check if the audio file has changed since the peakfile was built. - struct stat stat_file; - int err = stat (audio_path.c_str(), &stat_file); - - if (!err && stat_file.st_mtime > statbuf.st_mtime){ - _peaks_built = false; - } else { - _peaks_built = true; - } - } - } - - if (!newfile && !_peaks_built && _build_missing_peakfiles && _build_peakfiles) { - build_peaks_from_scratch (); - } - - return 0; -} - -int -Source::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t start, jack_nframes_t cnt, double samples_per_visual_peak) const -{ - Glib::Mutex::Lock lm (_lock); - double scale; - double expected_peaks; - PeakData::PeakDatum xmax; - PeakData::PeakDatum xmin; - int32_t to_read; - uint32_t nread; - jack_nframes_t zero_fill = 0; - int ret = -1; - PeakData* staging = 0; - Sample* raw_staging = 0; - char * workbuf = 0; - int peakfile = -1; - - expected_peaks = (cnt / (double) frames_per_peak); - scale = npeaks/expected_peaks; - -#if 0 - cerr << "======>RP: npeaks = " << npeaks - << " start = " << start - << " cnt = " << cnt - << " len = " << _length - << " samples_per_visual_peak =" << samples_per_visual_peak - << " expected was " << expected_peaks << " ... scale = " << scale - << " PD ptr = " << peaks - <<endl; - -#endif - - /* fix for near-end-of-file conditions */ - - if (cnt > _length - start) { - // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << endl; - cnt = _length - start; - jack_nframes_t old = npeaks; - npeaks = min ((jack_nframes_t) floor (cnt / samples_per_visual_peak), npeaks); - zero_fill = old - npeaks; - } - - // cerr << "actual npeaks = " << npeaks << " zf = " << zero_fill << endl; - - if (npeaks == cnt) { - - // cerr << "RAW DATA\n"; - - /* no scaling at all, just get the sample data and duplicate it for - both max and min peak values. - */ - - Sample* raw_staging = new Sample[cnt]; - workbuf = new char[cnt*4]; - - if (read_unlocked (raw_staging, start, cnt, workbuf) != cnt) { - error << _("cannot read sample data for unscaled peak computation") << endmsg; - return -1; - } - - for (jack_nframes_t i = 0; i < npeaks; ++i) { - peaks[i].max = raw_staging[i]; - peaks[i].min = raw_staging[i]; - } - - delete [] raw_staging; - delete [] workbuf; - return 0; - } - - if (scale == 1.0) { - - off_t first_peak_byte = (start / frames_per_peak) * sizeof (PeakData); - - /* open, read, close */ - - if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) { - error << string_compose(_("Source: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg; - return -1; - } - - // cerr << "DIRECT PEAKS\n"; - - nread = ::pread (peakfile, peaks, sizeof (PeakData)* npeaks, first_peak_byte); - close (peakfile); - - if (nread != sizeof (PeakData) * npeaks) { - cerr << "Source[" - << _name - << "]: cannot read peaks from peakfile! (read only " - << nread - << " not " - << npeaks - << "at sample " - << start - << " = byte " - << first_peak_byte - << ')' - << endl; - return -1; - } - - if (zero_fill) { - memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill); - } - - return 0; - } - - - jack_nframes_t tnp; - - if (scale < 1.0) { - - // cerr << "DOWNSAMPLE\n"; - - /* the caller wants: - - - more frames-per-peak (lower resolution) than the peakfile, or to put it another way, - - less peaks than the peakfile holds for the same range - - So, read a block into a staging area, and then downsample from there. - - to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks - */ - - const uint32_t chunksize = (uint32_t) min (expected_peaks, 4096.0); - - staging = new PeakData[chunksize]; - - /* compute the rounded up frame position */ - - jack_nframes_t current_frame = start; - jack_nframes_t current_stored_peak = (jack_nframes_t) ceil (current_frame / (double) frames_per_peak); - uint32_t next_visual_peak = (uint32_t) ceil (current_frame / samples_per_visual_peak); - double next_visual_peak_frame = next_visual_peak * samples_per_visual_peak; - uint32_t stored_peak_before_next_visual_peak = (jack_nframes_t) next_visual_peak_frame / frames_per_peak; - uint32_t nvisual_peaks = 0; - uint32_t stored_peaks_read = 0; - uint32_t i = 0; - - /* handle the case where the initial visual peak is on a pixel boundary */ - - current_stored_peak = min (current_stored_peak, stored_peak_before_next_visual_peak); - - /* open ... close during out: handling */ - - if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) { - error << string_compose(_("Source: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg; - return 0; - } - - while (nvisual_peaks < npeaks) { - - if (i == stored_peaks_read) { - - uint32_t start_byte = current_stored_peak * sizeof(PeakData); - tnp = min ((_length/frames_per_peak - current_stored_peak), (jack_nframes_t) expected_peaks); - to_read = min (chunksize, tnp); - - off_t fend = lseek (peakfile, 0, SEEK_END); - - if ((nread = ::pread (peakfile, staging, sizeof (PeakData) * to_read, start_byte)) - != sizeof (PeakData) * to_read) { - cerr << "Source[" - << _name - << "]: cannot read peak data from peakfile (" - << (nread / sizeof(PeakData)) - << " peaks instead of " - << to_read - << ") (" - << strerror (errno) - << ')' - << " at start_byte = " << start_byte - << " _length = " << _length << " versus len = " << fend - << " expected maxpeaks = " << (_length - current_frame)/frames_per_peak - << " npeaks was " << npeaks - << endl; - goto out; - } - - i = 0; - stored_peaks_read = nread / sizeof(PeakData); - } - - xmax = -1.0; - xmin = 1.0; - - while ((i < stored_peaks_read) && (current_stored_peak <= stored_peak_before_next_visual_peak)) { - - xmax = max (xmax, staging[i].max); - xmin = min (xmin, staging[i].min); - ++i; - ++current_stored_peak; - --expected_peaks; - } - - peaks[nvisual_peaks].max = xmax; - peaks[nvisual_peaks].min = xmin; - ++nvisual_peaks; - ++next_visual_peak; - - //next_visual_peak_frame = min ((next_visual_peak * samples_per_visual_peak), (next_visual_peak_frame+samples_per_visual_peak) ); - next_visual_peak_frame = min ((double) start+cnt, (next_visual_peak_frame+samples_per_visual_peak) ); - stored_peak_before_next_visual_peak = (uint32_t) next_visual_peak_frame / frames_per_peak; - } - - if (zero_fill) { - memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill); - } - - ret = 0; - - } else { - - // cerr << "UPSAMPLE\n"; - - /* the caller wants - - - less frames-per-peak (more resolution) - - more peaks than stored in the Peakfile - - So, fetch data from the raw source, and generate peak - data on the fly. - */ - - jack_nframes_t frames_read = 0; - jack_nframes_t current_frame = start; - jack_nframes_t i = 0; - jack_nframes_t nvisual_peaks = 0; - jack_nframes_t chunksize = (jack_nframes_t) min (cnt, (jack_nframes_t) 4096); - raw_staging = new Sample[chunksize]; - workbuf = new char[chunksize *4]; - - jack_nframes_t frame_pos = start; - double pixel_pos = floor (frame_pos / samples_per_visual_peak); - double next_pixel_pos = ceil (frame_pos / samples_per_visual_peak); - double pixels_per_frame = 1.0 / samples_per_visual_peak; - - xmin = 1.0; - xmax = -1.0; - - while (nvisual_peaks < npeaks) { - - if (i == frames_read) { - - to_read = min (chunksize, (_length - current_frame)); - - if ((frames_read = read_unlocked (raw_staging, current_frame, to_read, workbuf)) < 0) { - error << string_compose(_("Source[%1]: peak read - cannot read %2 samples at offset %3") - , _name, to_read, current_frame) - << endmsg; - goto out; - } - - i = 0; - } - - xmax = max (xmax, raw_staging[i]); - xmin = min (xmin, raw_staging[i]); - ++i; - ++current_frame; - pixel_pos += pixels_per_frame; - - if (pixel_pos >= next_pixel_pos) { - - peaks[nvisual_peaks].max = xmax; - peaks[nvisual_peaks].min = xmin; - ++nvisual_peaks; - xmin = 1.0; - xmax = -1.0; - - next_pixel_pos = ceil (pixel_pos + 0.5); - } - } - - if (zero_fill) { - memset (&peaks[npeaks], 0, sizeof (PeakData) * zero_fill); - } - - ret = 0; - } - - out: - if (peakfile >= 0) { - close (peakfile); - } - - if (staging) { - delete [] staging; - } - - if (raw_staging) { - delete [] raw_staging; - } - - if (workbuf) { - delete [] workbuf; - } - - return ret; -} - -#undef DEBUG_PEAK_BUILD - -int -Source::build_peaks () -{ - vector<PeakBuildRecord*> built; - int status = -1; - bool pr_signal = false; - list<PeakBuildRecord*> copy; - - { - Glib::Mutex::Lock lm (_lock); - copy = pending_peak_builds; - pending_peak_builds.clear (); - } - -#ifdef DEBUG_PEAK_BUILD - cerr << "build peaks with " << copy.size() << " requests pending\n"; -#endif - - for (list<PeakBuildRecord *>::iterator i = copy.begin(); i != copy.end(); ++i) { - - if ((status = do_build_peak ((*i)->frame, (*i)->cnt)) != 0) { - unlink (peakpath.c_str()); - break; - } - built.push_back (new PeakBuildRecord (*(*i))); - delete *i; - } - - { - Glib::Mutex::Lock lm (_lock); - - if (status == 0) { - _peaks_built = true; - - if (next_peak_clear_should_notify) { - next_peak_clear_should_notify = false; - pr_signal = true; - } - } - } - - if (status == 0) { - for (vector<PeakBuildRecord *>::iterator i = built.begin(); i != built.end(); ++i) { - PeakRangeReady ((*i)->frame, (*i)->cnt); /* EMIT SIGNAL */ - delete *i; - } - - if (pr_signal) { - PeaksReady (); /* EMIT SIGNAL */ - } - } - - return status; -} - -int -Source::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt) -{ - jack_nframes_t current_frame; - Sample buf[frames_per_peak]; - Sample xmin, xmax; - uint32_t peaki; - PeakData* peakbuf; - char * workbuf = 0; - jack_nframes_t frames_read; - jack_nframes_t frames_to_read; - off_t first_peak_byte; - int peakfile = -1; - int ret = -1; - -#ifdef DEBUG_PEAK_BUILD - cerr << pthread_self() << ": " << _name << ": building peaks for " << first_frame << " to " << first_frame + cnt - 1 << endl; -#endif - - first_peak_byte = (first_frame / frames_per_peak) * sizeof (PeakData); - -#ifdef DEBUG_PEAK_BUILD - cerr << "seeking to " << first_peak_byte << " before writing new peak data\n"; -#endif - - current_frame = first_frame; - peakbuf = new PeakData[(cnt/frames_per_peak)+1]; - peaki = 0; - - workbuf = new char[max(frames_per_peak, cnt) * 4]; - - if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) { - error << string_compose(_("Source: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg; - return -1; - } - - while (cnt) { - - frames_to_read = min (frames_per_peak, cnt); - - if ((frames_read = read_unlocked (buf, current_frame, frames_to_read, workbuf)) != frames_to_read) { - error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg; - goto out; - } - - xmin = buf[0]; - xmax = buf[0]; - - for (jack_nframes_t n = 1; n < frames_read; ++n) { - xmax = max (xmax, buf[n]); - xmin = min (xmin, buf[n]); - -// if (current_frame < frames_read) { -// cerr << "sample = " << buf[n] << " max = " << xmax << " min = " << xmin << " max of 2 = " << max (xmax, buf[n]) << endl; -// } - } - - peakbuf[peaki].max = xmax; - peakbuf[peaki].min = xmin; - peaki++; - - current_frame += frames_read; - cnt -= frames_read; - } - - if (::pwrite (peakfile, peakbuf, sizeof (PeakData) * peaki, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaki)) { - error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg; - goto out; - } - - ret = 0; - - out: - delete [] peakbuf; - if (peakfile >= 0) { - close (peakfile); - } - if (workbuf) - delete [] workbuf; - return ret; -} - -void -Source::build_peaks_from_scratch () -{ - Glib::Mutex::Lock lp (_lock); - - next_peak_clear_should_notify = true; - pending_peak_builds.push_back (new PeakBuildRecord (0, _length)); - queue_for_peaks (*this); -} - -bool -Source::file_changed (string path) -{ - struct stat stat_file; - struct stat stat_peak; - - int e1 = stat (path.c_str(), &stat_file); - int e2 = stat (peak_path(path).c_str(), &stat_peak); - - if (!e1 && !e2 && stat_file.st_mtime > stat_peak.st_mtime){ - return true; - } else { - return false; - } -} - -void Source::use () { _use_cnt++; @@ -864,30 +118,3 @@ Source::release () if (_use_cnt) --_use_cnt; } -jack_nframes_t -Source::available_peaks (double zoom_factor) const -{ - int peakfile; - off_t end; - - if (zoom_factor < frames_per_peak) { - return length(); // peak data will come from the audio file - } - - /* peak data comes from peakfile */ - - if ((peakfile = ::open (peakpath.c_str(), O_RDONLY)) < 0) { - error << string_compose(_("Source: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg; - return 0; - } - - { - Glib::Mutex::Lock lm (_lock); - end = lseek (peakfile, 0, SEEK_END); - } - - close (peakfile); - - return (end/sizeof(PeakData)) * frames_per_peak; -} - |