Ardour  8.7-15-gadf511264b
tmp_file_rt.h
Go to the documentation of this file.
1 #ifndef AUDIOGRAPHER_TMP_FILE_RT_H
2 #define AUDIOGRAPHER_TMP_FILE_RT_H
3 
4 #include <cstdio>
5 #include <string>
6 
7 #include <glib.h>
8 
9 #include "pbd/gstdio_compat.h"
10 #include "pbd/pthread_utils.h"
11 #include "pbd/ringbuffer.h"
12 
14 #include "audiographer/sink.h"
15 #include "sndfile_writer.h"
16 #include "sndfile_reader.h"
17 
18 #include "tmp_file.h"
19 
20 namespace AudioGrapher
21 {
22 
23  static const samplecnt_t rb_chunksize = 8192; // samples
24 
28 template<typename T = DefaultSampleType>
29 class TmpFileRt
30  : public TmpFile<T>
31 {
32  public:
33 
35  TmpFileRt (char * filename_template, int format, ChannelCount channels, samplecnt_t samplerate)
36  : SndfileHandle (g_mkstemp(filename_template), true, SndfileBase::ReadWrite, format, channels, samplerate)
37  , filename (filename_template)
39  , _rb (std::max (_chunksize * 16, 5 * samplerate * channels))
40  {
41  init ();
42  }
43 
44  using SndfileHandle::operator=;
45 
47  {
48  end_write ();
49  /* explicitly close first, some OS (yes I'm looking at you windows)
50  * cannot delete files that are still open
51  */
52  if (!filename.empty()) {
54  std::remove(filename.c_str());
55  }
56  pthread_mutex_destroy (&_disk_thread_lock);
57  pthread_cond_destroy (&_data_ready);
58  }
59 
61  void process (ProcessContext<T> const & c)
62  {
64 
66  throw Exception (*this, boost::str (boost::format
67  ("Wrong number of channels given to process(), %1% instead of %2%")
69  }
70 
71  if (SndfileWriter<T>::throw_level (ThrowProcess) && _rb.write_space() < (size_t) c.samples()) {
72  throw Exception (*this, boost::str (boost::format
73  ("Could not write data to ringbuffer/output file (%1%)")
75  }
76 
77  _rb.write (c.data(), c.samples());
78 
80  _capture = false;
82  }
83 
84  if (pthread_mutex_trylock (&_disk_thread_lock) == 0) {
85  pthread_cond_signal (&_data_ready);
86  pthread_mutex_unlock (&_disk_thread_lock);
87  }
88  }
89 
90  using Sink<T>::process;
91 
92  void disk_thread ()
93  {
94  T *framebuf = (T*) malloc (_chunksize * sizeof (T));
95 
96  pthread_mutex_lock (&_disk_thread_lock);
97 
98  while (_capture) {
99  if ((samplecnt_t)_rb.read_space () >= _chunksize) {
100  _rb.read (framebuf, _chunksize);
101  samplecnt_t const written = SndfileBase::write (framebuf, _chunksize);
102  assert (written == _chunksize);
104  }
105  if (!_capture) {
106  break;
107  }
108  pthread_cond_wait (&_data_ready, &_disk_thread_lock);
109  }
110 
111  // flush ringbuffer
112  while (_rb.read_space () > 0) {
113  size_t remain = std::min ((samplecnt_t)_rb.read_space (), _chunksize);
114  _rb.read (framebuf, remain);
115  samplecnt_t const written = SndfileBase::write (framebuf, remain);
117  }
118 
120  pthread_mutex_unlock (&_disk_thread_lock);
121  free (framebuf);
123  }
124 
125  protected:
126  std::string filename;
127 
128  bool _capture;
131 
132  pthread_mutex_t _disk_thread_lock;
133  pthread_cond_t _data_ready;
134  pthread_t _thread_id;
135 
136  static void * _disk_thread (void *arg)
137  {
138  TmpFileRt *d = static_cast<TmpFileRt *>(arg);
139  pthread_set_name ("ExportDiskIO");
140  d->disk_thread ();
141  pthread_exit (0);
142  return 0;
143  }
144 
145  void end_write () {
146  pthread_mutex_lock (&_disk_thread_lock);
147  _capture = false;
148  pthread_cond_signal (&_data_ready);
149  pthread_mutex_unlock (&_disk_thread_lock);
150  pthread_join (_thread_id, NULL);
151  }
152 
153  void init()
154  {
156  _capture = true;
158  pthread_mutex_init (&_disk_thread_lock, 0);
159  pthread_cond_init (&_data_ready, 0);
160 
161  if (pthread_create (&_thread_id, NULL, _disk_thread, this)) {
162  _capture = false;
164  throw Exception (*this, "Cannot create export disk writer");
165  }
166  }
167  }
168 
169  private:
170  TmpFileRt (TmpFileRt const & other) : SndfileHandle (other) {}
171 };
172 
173 } // namespace
174 
175 #endif // AUDIOGRAPHER_TMP_FILE_RT_H
void check_flags(SelfType &self, ProcessContext< ContextType > context)
Prints debug output if context contains flags that are not supported by this class.
void add_supported_flag(Flag flag)
Adds a flag to the set of flags supported.
ChannelCount const & channels() const
bool has_flag(Flag flag) const
T const * data() const
data points to the array of data to process
samplecnt_t const & samples() const
samples tells how many samples the array pointed by data contains
Base class for all classes using libsndfile.
Definition: sndfile_base.h:13
int samplerate(void) const
Definition: sndfile.hh:103
const char * strError(void) const
sf_count_t write(const short *ptr, sf_count_t items)
int channels(void) const
Definition: sndfile.hh:102
int format(void) const
Definition: sndfile.hh:101
PBD::Signal1< void, std::string > FileWritten
void process(ProcessContext< T > const &c)
Writes data to file.
Definition: tmp_file_rt.h:61
TmpFileRt(char *filename_template, int format, ChannelCount channels, samplecnt_t samplerate)
filename_template must match the requirements for mkstemp, i.e. end in "XXXXXX"
Definition: tmp_file_rt.h:35
TmpFileRt(TmpFileRt const &other)
Definition: tmp_file_rt.h:170
PBD::RingBuffer< T > _rb
Definition: tmp_file_rt.h:130
static void * _disk_thread(void *arg)
Definition: tmp_file_rt.h:136
pthread_cond_t _data_ready
Definition: tmp_file_rt.h:133
pthread_mutex_t _disk_thread_lock
Definition: tmp_file_rt.h:132
A temporary file deleted after this class is destructed.
Definition: tmp_file.h:21
PBD::Signal0< void > FileFlushed
Definition: tmp_file.h:24
@ ThrowProcess
Process cycle level stuff.
Definition: throwing.h:23
@ ThrowStrict
Stricter checks than ThrowProcess, less than ThrowSample.
Definition: throwing.h:24
static const samplecnt_t rb_chunksize
Definition: tmp_file_rt.h:23
void pthread_set_name(const char *name)