diff options
Diffstat (limited to 'libs/audiographer/audiographer/sndfile/tmp_file_rt.h')
-rw-r--r-- | libs/audiographer/audiographer/sndfile/tmp_file_rt.h | 84 |
1 files changed, 42 insertions, 42 deletions
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: |