Ardour  9.0-pre0-582-g084a23a80d
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/compose.h"
10 #include "pbd/gstdio_compat.h"
11 #include "pbd/pthread_utils.h"
12 #include "pbd/ringbuffer.h"
13 
15 #include "audiographer/sink.h"
16 #include "sndfile_writer.h"
17 #include "sndfile_reader.h"
18 
19 #include "tmp_file.h"
20 
21 namespace AudioGrapher
22 {
23 
24  static const samplecnt_t rb_chunksize = 8192; // samples
25 
29 template<typename T = DefaultSampleType>
30 class TmpFileRt
31  : public TmpFile<T>
32 {
33  public:
34 
36  TmpFileRt (char * filename_template, int format, ChannelCount channels, samplecnt_t samplerate)
37  : SndfileHandle (g_mkstemp(filename_template), true, SndfileBase::ReadWrite, format, channels, samplerate)
38  , filename (filename_template)
40  , _rb (std::max (_chunksize * 16, 5 * samplerate * channels))
41  {
42  init ();
43  }
44 
45  using SndfileHandle::operator=;
46 
48  {
49  end_write ();
50  /* explicitly close first, some OS (yes I'm looking at you windows)
51  * cannot delete files that are still open
52  */
53  if (!filename.empty()) {
55  std::remove(filename.c_str());
56  }
57  pthread_mutex_destroy (&_disk_thread_lock);
58  pthread_cond_destroy (&_data_ready);
59  }
60 
62  void process (ProcessContext<T> const & c)
63  {
65 
67  throw Exception (*this, string_compose
68  ("Wrong number of channels given to process(), %1 instead of %2",
70  }
71 
72  if (SndfileWriter<T>::throw_level (ThrowProcess) && _rb.write_space() < (size_t) c.samples()) {
73  throw Exception (*this, string_compose
74  ("Could not write data to ringbuffer/output file (%1)",
76 
77  }
78 
79  _rb.write (c.data(), c.samples());
80 
82  _capture = false;
84  }
85 
86  if (pthread_mutex_trylock (&_disk_thread_lock) == 0) {
87  pthread_cond_signal (&_data_ready);
88  pthread_mutex_unlock (&_disk_thread_lock);
89  }
90  }
91 
92  using Sink<T>::process;
93 
94  void disk_thread ()
95  {
96  T *framebuf = (T*) malloc (_chunksize * sizeof (T));
97 
98  pthread_mutex_lock (&_disk_thread_lock);
99 
100  while (_capture) {
101  if ((samplecnt_t)_rb.read_space () >= _chunksize) {
102  _rb.read (framebuf, _chunksize);
103  samplecnt_t const written = SndfileBase::write (framebuf, _chunksize);
104  assert (written == _chunksize);
106  }
107  if (!_capture) {
108  break;
109  }
110  pthread_cond_wait (&_data_ready, &_disk_thread_lock);
111  }
112 
113  // flush ringbuffer
114  while (_rb.read_space () > 0) {
115  size_t remain = std::min ((samplecnt_t)_rb.read_space (), _chunksize);
116  _rb.read (framebuf, remain);
117  samplecnt_t const written = SndfileBase::write (framebuf, remain);
119  }
120 
122  pthread_mutex_unlock (&_disk_thread_lock);
123  free (framebuf);
125  }
126 
127  protected:
128  std::string filename;
129 
130  bool _capture;
133 
134  pthread_mutex_t _disk_thread_lock;
135  pthread_cond_t _data_ready;
136  pthread_t _thread_id;
137 
138  static void * _disk_thread (void *arg)
139  {
140  TmpFileRt *d = static_cast<TmpFileRt *>(arg);
141  d->disk_thread ();
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_and_store ("ExportDiskIO", &_thread_id, _disk_thread, this, 0)) {
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::Signal< void(std::string)> FileWritten
void process(ProcessContext< T > const &c)
Writes data to file.
Definition: tmp_file_rt.h:62
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:36
TmpFileRt(TmpFileRt const &other)
Definition: tmp_file_rt.h:170
PBD::RingBuffer< T > _rb
Definition: tmp_file_rt.h:132
static void * _disk_thread(void *arg)
Definition: tmp_file_rt.h:138
pthread_cond_t _data_ready
Definition: tmp_file_rt.h:135
pthread_mutex_t _disk_thread_lock
Definition: tmp_file_rt.h:134
A temporary file deleted after this class is destructed.
Definition: tmp_file.h:21
PBD::Signal< void()> FileFlushed
Definition: tmp_file.h:24
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:246
@ 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:24
int pthread_create_and_store(std::string name, pthread_t *thread, void *(*start_routine)(void *), void *arg, uint32_t stacklimit=0x80000)