if a complete refill is called for, DiskReader cannot internal seek
[ardour.git] / libs / ardour / disk_io.cc
1 /*
2  * Copyright (C) 2017-2018 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2017-2019 Robin Gareus <robin@gareus.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #include "pbd/debug.h"
21 #include "pbd/error.h"
22 #include "pbd/playback_buffer.h"
23
24 #include "ardour/audioplaylist.h"
25 #include "ardour/butler.h"
26 #include "ardour/debug.h"
27 #include "ardour/disk_io.h"
28 #include "ardour/disk_reader.h"
29 #include "ardour/disk_writer.h"
30 #include "ardour/location.h"
31 #include "ardour/midi_ring_buffer.h"
32 #include "ardour/midi_playlist.h"
33 #include "ardour/playlist.h"
34 #include "ardour/playlist_factory.h"
35 #include "ardour/rc_configuration.h"
36 #include "ardour/session.h"
37 #include "ardour/session_playlists.h"
38
39 #include "pbd/i18n.h"
40
41 using namespace ARDOUR;
42 using namespace PBD;
43 using namespace std;
44
45 const string DiskIOProcessor::state_node_name = X_("DiskIOProcessor");
46
47 // PBD::Signal0<void> DiskIOProcessor::DiskOverrun;
48 // PBD::Signal0<void>  DiskIOProcessor::DiskUnderrun;
49
50 DiskIOProcessor::DiskIOProcessor (Session& s, string const & str, Flag f)
51         : Processor (s, str)
52         , _flags (f)
53         , i_am_the_modifier (false)
54         , _slaved (false)
55         , in_set_state (false)
56         , playback_sample (0)
57         , _need_butler (false)
58         , channels (new ChannelList)
59         , _midi_buf (0)
60         , _samples_written_to_ringbuffer (0)
61         , _samples_read_from_ringbuffer (0)
62 {
63         set_display_to_user (false);
64 }
65
66 DiskIOProcessor::~DiskIOProcessor ()
67 {
68         {
69                 RCUWriter<ChannelList> writer (channels);
70                 boost::shared_ptr<ChannelList> c = writer.get_copy();
71
72                 for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
73                         delete *chan;
74                 }
75
76                 c->clear();
77         }
78
79         channels.flush ();
80         delete _midi_buf;
81
82         for (uint32_t n = 0; n < DataType::num_types; ++n) {
83                 if (_playlists[n]) {
84                         _playlists[n]->release ();
85                 }
86         }
87 }
88
89
90 void
91 DiskIOProcessor::init ()
92 {
93         set_block_size (_session.get_block_size());
94 }
95
96 void
97 DiskIOProcessor::set_buffering_parameters (BufferingPreset bp)
98 {
99         samplecnt_t read_chunk_size;
100         samplecnt_t read_buffer_size;
101         samplecnt_t write_chunk_size;
102         samplecnt_t write_buffer_size;
103
104         if (!get_buffering_presets (bp, read_chunk_size, read_buffer_size, write_chunk_size, write_buffer_size)) {
105                 return;
106         }
107
108         DiskReader::set_chunk_samples (read_chunk_size);
109         DiskWriter::set_chunk_samples (write_chunk_size);
110
111         Config->set_audio_capture_buffer_seconds (write_buffer_size);
112         Config->set_audio_playback_buffer_seconds (read_buffer_size);
113 }
114
115 bool
116 DiskIOProcessor::get_buffering_presets (BufferingPreset bp,
117                                         samplecnt_t& read_chunk_size,
118                                         samplecnt_t& read_buffer_size,
119                                         samplecnt_t& write_chunk_size,
120                                         samplecnt_t& write_buffer_size)
121 {
122         switch (bp) {
123         case Small:
124                 read_chunk_size = 65536;  /* samples */
125                 write_chunk_size = 65536; /* samples */
126                 read_buffer_size = 5;  /* seconds */
127                 write_buffer_size = 5; /* seconds */
128                 break;
129
130         case Medium:
131                 read_chunk_size = 262144;  /* samples */
132                 write_chunk_size = 131072; /* samples */
133                 read_buffer_size = 10;  /* seconds */
134                 write_buffer_size = 10; /* seconds */
135                 break;
136
137         case Large:
138                 read_chunk_size = 524288; /* samples */
139                 write_chunk_size = 131072; /* samples */
140                 read_buffer_size = 20; /* seconds */
141                 write_buffer_size = 20; /* seconds */
142                 break;
143
144         default:
145                 return false;
146         }
147
148         return true;
149 }
150
151 bool
152 DiskIOProcessor::can_support_io_configuration (const ChanCount& in, ChanCount& out)
153 {
154         if (in.n_midi() != 0 && in.n_midi() != 1) {
155                 /* we only support zero or 1 MIDI stream */
156                 return false;
157         }
158
159         /* currently no way to deliver different channels that we receive */
160         out = in;
161
162         return true;
163 }
164
165 bool
166 DiskIOProcessor::configure_io (ChanCount in, ChanCount out)
167 {
168         DEBUG_TRACE (DEBUG::DiskIO, string_compose ("Configuring %1 for in:%2 out:%3\n", name(), in, out));
169
170         bool changed = false;
171
172         {
173                 RCUWriter<ChannelList> writer (channels);
174                 boost::shared_ptr<ChannelList> c = writer.get_copy();
175
176                 uint32_t n_audio = in.n_audio();
177
178                 if (n_audio > c->size()) {
179                         add_channel_to (c, n_audio - c->size());
180                         changed = true;
181                 } else if (n_audio < c->size()) {
182                         remove_channel_from (c, c->size() - n_audio);
183                         changed = true;
184                 }
185
186                 /* writer leaves scope, actual channel list is updated */
187         }
188
189         if (in.n_midi() > 0 && !_midi_buf) {
190                 const size_t size = _session.butler()->midi_diskstream_buffer_size();
191                 _midi_buf = new MidiRingBuffer<samplepos_t>(size);
192                 changed = true;
193         }
194
195         if (changed) {
196                 seek (_session.transport_sample());
197         }
198
199         return Processor::configure_io (in, out);
200 }
201
202 int
203 DiskIOProcessor::set_block_size (pframes_t nframes)
204 {
205         return 0;
206 }
207
208 void
209 DiskIOProcessor::non_realtime_locate (samplepos_t location)
210 {
211         /* now refill channel buffers */
212
213         seek (location, true);
214 }
215
216 int
217 DiskIOProcessor::set_state (const XMLNode& node, int version)
218 {
219         XMLProperty const * prop;
220
221         Processor::set_state (node, version);
222
223         if ((prop = node.property ("flags")) != 0) {
224                 _flags = Flag (string_2_enum (prop->value(), _flags));
225         }
226
227         return 0;
228 }
229
230 int
231 DiskIOProcessor::add_channel (uint32_t how_many)
232 {
233         RCUWriter<ChannelList> writer (channels);
234         boost::shared_ptr<ChannelList> c = writer.get_copy();
235
236         return add_channel_to (c, how_many);
237 }
238
239 int
240 DiskIOProcessor::remove_channel_from (boost::shared_ptr<ChannelList> c, uint32_t how_many)
241 {
242         while (how_many-- && !c->empty()) {
243                 delete c->back();
244                 c->pop_back();
245         }
246
247         return 0;
248 }
249
250 int
251 DiskIOProcessor::remove_channel (uint32_t how_many)
252 {
253         RCUWriter<ChannelList> writer (channels);
254         boost::shared_ptr<ChannelList> c = writer.get_copy();
255
256         return remove_channel_from (c, how_many);
257 }
258
259 void
260 DiskIOProcessor::playlist_deleted (boost::weak_ptr<Playlist> wpl)
261 {
262         boost::shared_ptr<Playlist> pl (wpl.lock());
263
264         if (!pl) {
265                 return;
266         }
267
268         for (uint32_t n = 0; n < DataType::num_types; ++n) {
269                 if (pl == _playlists[n]) {
270
271                         /* this catches an ordering issue with session destruction. playlists
272                            are destroyed before disk readers. we have to invalidate any handles
273                            we have to the playlist.
274                         */
275                         _playlists[n].reset ();
276                         break;
277                 }
278         }
279 }
280
281 boost::shared_ptr<AudioPlaylist>
282 DiskIOProcessor::audio_playlist () const
283 {
284         return boost::dynamic_pointer_cast<AudioPlaylist> (_playlists[DataType::AUDIO]);
285 }
286
287 boost::shared_ptr<MidiPlaylist>
288 DiskIOProcessor::midi_playlist () const
289 {
290         return boost::dynamic_pointer_cast<MidiPlaylist> (_playlists[DataType::MIDI]);
291 }
292
293 int
294 DiskIOProcessor::use_playlist (DataType dt, boost::shared_ptr<Playlist> playlist)
295 {
296         if (!playlist) {
297                 return 0;
298         }
299
300         DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: set to use playlist %2 (%3)\n", name(), playlist->name(), dt.to_string()));
301
302         if (playlist == _playlists[dt]) {
303                 DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: already using that playlist\n", name()));
304                 return 0;
305         }
306
307         playlist_connections.drop_connections ();
308
309         if (_playlists[dt]) {
310                 _playlists[dt]->release();
311         }
312
313         _playlists[dt] = playlist;
314         playlist->use();
315
316         playlist->ContentsChanged.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_modified, this));
317         playlist->LayeringChanged.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_modified, this));
318         playlist->DropReferences.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_deleted, this, boost::weak_ptr<Playlist>(playlist)));
319         playlist->RangesMoved.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_ranges_moved, this, _1, _2));
320
321         DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1 now using playlist %1 (%2)\n", name(), playlist->name(), playlist->id()));
322
323         return 0;
324 }
325
326 DiskIOProcessor::ChannelInfo::ChannelInfo (samplecnt_t bufsize)
327         : rbuf (0)
328         , wbuf (0)
329         , capture_transition_buf (0)
330         , curr_capture_cnt (0)
331 {
332 }
333
334 DiskIOProcessor::ChannelInfo::~ChannelInfo ()
335 {
336         delete rbuf;
337         delete wbuf;
338         delete capture_transition_buf;
339         rbuf = 0;
340         wbuf = 0;
341         capture_transition_buf = 0;
342 }
343
344 void
345 DiskIOProcessor::drop_route ()
346 {
347         _route.reset ();
348 }
349
350 void
351 DiskIOProcessor::set_route (boost::shared_ptr<Route> r)
352 {
353         _route = r;
354
355         if (_route) {
356                 _route->DropReferences.connect_same_thread (*this, boost::bind (&DiskIOProcessor::drop_route, this));
357         }
358 }
359
360 /** Get the start, end, and length of a location "atomically".
361  *
362  * Note: Locations don't get deleted, so all we care about when I say "atomic"
363  * is that we are always pointing to the same one and using start/length values
364  * obtained just once.  Use this function to achieve this since location being
365  * a parameter achieves this.
366  */
367 void
368 DiskIOProcessor::get_location_times(const Location* location,
369                    samplepos_t*     start,
370                    samplepos_t*     end,
371                    samplepos_t*     length)
372 {
373         if (location) {
374                 *start  = location->start();
375                 *end    = location->end();
376                 *length = *end - *start;
377         }
378 }
379