diff options
Diffstat (limited to 'libs/audiographer')
4 files changed, 117 insertions, 77 deletions
diff --git a/libs/audiographer/audiographer/sndfile/sndfile_writer.h b/libs/audiographer/audiographer/sndfile/sndfile_writer.h index 57ad968dc5..81f0ddb497 100644 --- a/libs/audiographer/audiographer/sndfile/sndfile_writer.h +++ b/libs/audiographer/audiographer/sndfile/sndfile_writer.h @@ -40,19 +40,13 @@ class SndfileWriter virtual ~SndfileWriter () {} - SndfileWriter (SndfileWriter const & other) - : SndfileHandle (other) - { - init(); - } - using SndfileHandle::operator=; framecnt_t get_frames_written() const { return frames_written; } void reset_frames_written_count() { frames_written = 0; } /// Writes data to file - void process (ProcessContext<T> const & c) + virtual void process (ProcessContext<T> const & c) { check_flags (*this, c); @@ -88,7 +82,7 @@ class SndfileWriter init(); } - void init() + virtual void init() { frames_written = 0; add_supported_flag (ProcessContext<T>::EndOfInput); @@ -97,6 +91,9 @@ class SndfileWriter protected: std::string path; framecnt_t frames_written; + + private: + SndfileWriter (SndfileWriter const & other) {} }; } // namespace diff --git a/libs/audiographer/audiographer/sndfile/tmp_file.h b/libs/audiographer/audiographer/sndfile/tmp_file.h index c53557beda..d6bc5546a5 100644 --- a/libs/audiographer/audiographer/sndfile/tmp_file.h +++ b/libs/audiographer/audiographer/sndfile/tmp_file.h @@ -15,36 +15,14 @@ namespace AudioGrapher /// A temporary file deleted after this class is destructed template<typename T = DefaultSampleType> -class TmpFile : public SndfileWriter<T>, public SndfileReader<T> +class TmpFile + : public SndfileWriter<T> + , public SndfileReader<T> { public: + virtual ~TmpFile () {} + PBD::Signal0<void> FileFlushed; - /// \a filename_template must match the requirements for mkstemp, i.e. end in "XXXXXX" - TmpFile (char * filename_template, int format, ChannelCount channels, framecnt_t samplerate) - : SndfileHandle (g_mkstemp(filename_template), true, SndfileBase::ReadWrite, format, channels, samplerate) - , filename (filename_template) - {} - - TmpFile (int format, ChannelCount channels, framecnt_t samplerate) - : SndfileHandle (fileno (tmpfile()), true, SndfileBase::ReadWrite, format, channels, samplerate) - {} - - TmpFile (TmpFile const & other) : SndfileHandle (other) {} - using SndfileHandle::operator=; - - ~TmpFile() - { - /* explicitly close first, some OS (yes I'm looking at you windows) - * cannot delete files that are still open - */ - if (!filename.empty()) { - SndfileBase::close(); - std::remove(filename.c_str()); - } - } - - private: - std::string filename; }; } // namespace diff --git a/libs/audiographer/audiographer/sndfile/tmp_file_rt.h b/libs/audiographer/audiographer/sndfile/tmp_file_rt.h index ec1f85c773..86e363c266 100644 --- a/libs/audiographer/audiographer/sndfile/tmp_file_rt.h +++ b/libs/audiographer/audiographer/sndfile/tmp_file_rt.h @@ -10,18 +10,21 @@ #include "audiographer/flag_debuggable.h" #include "audiographer/sink.h" +#include "sndfile_writer.h" #include "sndfile_reader.h" +#include "tmp_file.h" namespace AudioGrapher { -/// A temporary file deleted after this class is destructed + static const framecnt_t rb_chunksize = 8192; // samples + +/** A temporary file deleted after this class is destructed + * with realtime safe background thread writer. + */ template<typename T = DefaultSampleType> class TmpFileRt - : public virtual SndfileReader<T> - , public virtual SndfileBase - , public Sink<T> - , public FlagDebuggable<> + : public TmpFile<T> { public: @@ -29,7 +32,8 @@ class TmpFileRt TmpFileRt (char * filename_template, int format, ChannelCount channels, framecnt_t samplerate) : SndfileHandle (g_mkstemp(filename_template), true, SndfileBase::ReadWrite, format, channels, samplerate) , filename (filename_template) - , _rb (samplerate * channels) + , _chunksize (rb_chunksize * channels) + , _rb (std::max (_chunksize * 16, 5 * samplerate * channels)) { init (); } @@ -50,81 +54,76 @@ class TmpFileRt pthread_cond_destroy (&_data_ready); } - framecnt_t get_frames_written() const { return frames_written; } - void reset_frames_written_count() { frames_written = 0; } - /// Writes data to file void process (ProcessContext<T> const & c) { - check_flags (*this, c); + SndfileWriter<T>::check_flags (*this, c); - if (SndfileReader<T>::throw_level (ThrowStrict) && c.channels() != channels()) { + if (SndfileWriter<T>::throw_level (ThrowStrict) && c.channels() != SndfileHandle::channels()) { throw Exception (*this, boost::str (boost::format ("Wrong number of channels given to process(), %1% instead of %2%") - % c.channels() % channels())); + % c.channels() % SndfileHandle::channels())); } - if (SndfileReader<T>::throw_level (ThrowProcess) && _rb.write_space() < c.frames()) { + if (SndfileWriter<T>::throw_level (ThrowProcess) && _rb.write_space() < c.frames()) { throw Exception (*this, boost::str (boost::format ("Could not write data to ringbuffer/output file (%1%)") - % strError())); + % SndfileHandle::strError())); } _rb.write (c.data(), c.frames()); + if (c.has_flag(ProcessContext<T>::EndOfInput)) { + _capture = false; + SndfileWriter<T>::FileWritten (filename); + } + if (pthread_mutex_trylock (&_disk_thread_lock) == 0) { pthread_cond_signal (&_data_ready); pthread_mutex_unlock (&_disk_thread_lock); } - - if (c.has_flag(ProcessContext<T>::EndOfInput)) { - end_write (); // XXX not rt-safe -- TODO add API call to flush - FileWritten (filename); - } } using Sink<T>::process; - PBD::Signal1<void, std::string> FileWritten; - void disk_thread () { - const size_t chunksize = 8192; // samples - T *framebuf = (T*) malloc (chunksize * sizeof (T)); + T *framebuf = (T*) malloc (_chunksize * sizeof (T)); pthread_mutex_lock (&_disk_thread_lock); - while (1) { + while (_capture) { + if ((framecnt_t)_rb.read_space () >= _chunksize) { + _rb.read (framebuf, _chunksize); + framecnt_t const written = SndfileBase::write (framebuf, _chunksize); + assert (written == _chunksize); + SndfileWriter<T>::frames_written += written; + } if (!_capture) { break; } - if (_rb.read_space () >= chunksize) { - _rb.read (framebuf, chunksize); - framecnt_t const written = write (framebuf, chunksize); - assert (written == chunksize); - frames_written += written; - } pthread_cond_wait (&_data_ready, &_disk_thread_lock); } // flush ringbuffer while (_rb.read_space () > 0) { - size_t remain = std::min ((size_t)_rb.read_space (), chunksize); + size_t remain = std::min ((framecnt_t)_rb.read_space (), _chunksize); _rb.read (framebuf, remain); - framecnt_t const written = write (framebuf, remain); - frames_written += written; + framecnt_t const written = SndfileBase::write (framebuf, remain); + SndfileWriter<T>::frames_written += written; } - writeSync(); + SndfileWriter<T>::writeSync(); pthread_mutex_unlock (&_disk_thread_lock); free (framebuf); + TmpFile<T>::FileFlushed (); } protected: std::string filename; - framecnt_t frames_written; bool _capture; + framecnt_t _chunksize; RingBuffer<T> _rb; pthread_mutex_t _disk_thread_lock; @@ -141,10 +140,6 @@ class TmpFileRt void end_write () { pthread_mutex_lock (&_disk_thread_lock); - if (!_capture) { - pthread_mutex_unlock (&_disk_thread_lock); - return; - } _capture = false; pthread_cond_signal (&_data_ready); pthread_mutex_unlock (&_disk_thread_lock); @@ -153,13 +148,18 @@ class TmpFileRt void init() { - frames_written = 0; + SndfileWriter<T>::frames_written = 0; _capture = true; - add_supported_flag (ProcessContext<T>::EndOfInput); + SndfileWriter<T>::add_supported_flag (ProcessContext<T>::EndOfInput); pthread_mutex_init (&_disk_thread_lock, 0); pthread_cond_init (&_data_ready, 0); - pthread_create (&_thread_id, NULL, _disk_thread, this); + if (pthread_create (&_thread_id, NULL, _disk_thread, this)) { + _capture = false; + if (SndfileWriter<T>::throw_level (ThrowStrict)) { + throw Exception (*this, "Cannot create export disk writer"); + } + } } private: diff --git a/libs/audiographer/audiographer/sndfile/tmp_file_sync.h b/libs/audiographer/audiographer/sndfile/tmp_file_sync.h new file mode 100644 index 0000000000..7807346935 --- /dev/null +++ b/libs/audiographer/audiographer/sndfile/tmp_file_sync.h @@ -0,0 +1,65 @@ +#ifndef AUDIOGRAPHER_TMP_FILE_SYNC_H +#define AUDIOGRAPHER_TMP_FILE_SYNC_H + +#include <cstdio> +#include <string> + +#include <glib.h> +#include "pbd/gstdio_compat.h" + +#include "sndfile_writer.h" +#include "sndfile_reader.h" +#include "tmp_file.h" + +namespace AudioGrapher +{ + +/// A temporary file deleted after this class is destructed +template<typename T = DefaultSampleType> +class TmpFileSync + : public TmpFile<T> +{ + public: + + /// \a filename_template must match the requirements for mkstemp, i.e. end in "XXXXXX" + TmpFileSync (char * filename_template, int format, ChannelCount channels, framecnt_t samplerate) + : SndfileHandle (g_mkstemp(filename_template), true, SndfileBase::ReadWrite, format, channels, samplerate) + , filename (filename_template) + {} + + TmpFileSync (int format, ChannelCount channels, framecnt_t samplerate) + : SndfileHandle (fileno (tmpfile()), true, SndfileBase::ReadWrite, format, channels, samplerate) + {} + + TmpFileSync (TmpFileSync const & other) : SndfileHandle (other) {} + using SndfileHandle::operator=; + + ~TmpFileSync() + { + /* explicitly close first, some OS (yes I'm looking at you windows) + * cannot delete files that are still open + */ + if (!filename.empty()) { + SndfileBase::close(); + std::remove(filename.c_str()); + } + } + + void process (ProcessContext<T> const & c) + { + SndfileWriter<T>::process (c); + + if (c.has_flag(ProcessContext<T>::EndOfInput)) { + TmpFile<T>::FileFlushed (); + } + } + + using Sink<T>::process; + + private: + std::string filename; +}; + +} // namespace + +#endif // AUDIOGRAPHER_TMP_FILE_SYNC_H |