2 * Copyright (C) 2017-2018 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2017-2019 Robin Gareus <robin@gareus.org>
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.
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.
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.
20 #include "pbd/debug.h"
21 #include "pbd/error.h"
22 #include "pbd/playback_buffer.h"
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 #include "ardour/track.h"
42 using namespace ARDOUR;
46 const string DiskIOProcessor::state_node_name = X_("DiskIOProcessor");
48 // PBD::Signal0<void> DiskIOProcessor::DiskOverrun;
49 // PBD::Signal0<void> DiskIOProcessor::DiskUnderrun;
51 DiskIOProcessor::DiskIOProcessor (Session& s, string const & str, Flag f)
55 , in_set_state (false)
57 , _need_butler (false)
58 , channels (new ChannelList)
60 , _samples_written_to_ringbuffer (0)
61 , _samples_read_from_ringbuffer (0)
63 set_display_to_user (false);
66 DiskIOProcessor::~DiskIOProcessor ()
69 RCUWriter<ChannelList> writer (channels);
70 boost::shared_ptr<ChannelList> c = writer.get_copy();
72 for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
82 for (uint32_t n = 0; n < DataType::num_types; ++n) {
84 _playlists[n]->release ();
91 DiskIOProcessor::init ()
93 set_block_size (_session.get_block_size());
97 DiskIOProcessor::set_buffering_parameters (BufferingPreset bp)
99 samplecnt_t read_chunk_size;
100 samplecnt_t read_buffer_size;
101 samplecnt_t write_chunk_size;
102 samplecnt_t write_buffer_size;
104 if (!get_buffering_presets (bp, read_chunk_size, read_buffer_size, write_chunk_size, write_buffer_size)) {
108 DiskReader::set_chunk_samples (read_chunk_size);
109 DiskWriter::set_chunk_samples (write_chunk_size);
111 Config->set_audio_capture_buffer_seconds (write_buffer_size);
112 Config->set_audio_playback_buffer_seconds (read_buffer_size);
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)
124 read_chunk_size = 65536; /* samples */
125 write_chunk_size = 65536; /* samples */
126 read_buffer_size = 5; /* seconds */
127 write_buffer_size = 5; /* seconds */
131 read_chunk_size = 262144; /* samples */
132 write_chunk_size = 131072; /* samples */
133 read_buffer_size = 10; /* seconds */
134 write_buffer_size = 10; /* seconds */
138 read_chunk_size = 524288; /* samples */
139 write_chunk_size = 131072; /* samples */
140 read_buffer_size = 20; /* seconds */
141 write_buffer_size = 20; /* seconds */
152 DiskIOProcessor::can_support_io_configuration (const ChanCount& in, ChanCount& out)
154 if (in.n_midi() != 0 && in.n_midi() != 1) {
155 /* we only support zero or 1 MIDI stream */
159 /* currently no way to deliver different channels that we receive */
166 DiskIOProcessor::configure_io (ChanCount in, ChanCount out)
168 DEBUG_TRACE (DEBUG::DiskIO, string_compose ("Configuring %1 for in:%2 out:%3\n", name(), in, out));
170 bool changed = false;
173 RCUWriter<ChannelList> writer (channels);
174 boost::shared_ptr<ChannelList> c = writer.get_copy();
176 uint32_t n_audio = in.n_audio();
178 if (n_audio > c->size()) {
179 add_channel_to (c, n_audio - c->size());
181 } else if (n_audio < c->size()) {
182 remove_channel_from (c, c->size() - n_audio);
186 /* writer leaves scope, actual channel list is updated */
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);
196 seek (_session.transport_sample());
199 return Processor::configure_io (in, out);
203 DiskIOProcessor::set_block_size (pframes_t nframes)
209 DiskIOProcessor::non_realtime_locate (samplepos_t location)
211 /* now refill channel buffers */
213 seek (location, true);
217 DiskIOProcessor::set_state (const XMLNode& node, int version)
219 XMLProperty const * prop;
221 Processor::set_state (node, version);
223 if ((prop = node.property ("flags")) != 0) {
224 _flags = Flag (string_2_enum (prop->value(), _flags));
231 DiskIOProcessor::add_channel (uint32_t how_many)
233 RCUWriter<ChannelList> writer (channels);
234 boost::shared_ptr<ChannelList> c = writer.get_copy();
236 return add_channel_to (c, how_many);
240 DiskIOProcessor::remove_channel_from (boost::shared_ptr<ChannelList> c, uint32_t how_many)
242 while (how_many-- && !c->empty()) {
251 DiskIOProcessor::remove_channel (uint32_t how_many)
253 RCUWriter<ChannelList> writer (channels);
254 boost::shared_ptr<ChannelList> c = writer.get_copy();
256 return remove_channel_from (c, how_many);
260 DiskIOProcessor::playlist_deleted (boost::weak_ptr<Playlist> wpl)
262 boost::shared_ptr<Playlist> pl (wpl.lock());
268 for (uint32_t n = 0; n < DataType::num_types; ++n) {
269 if (pl == _playlists[n]) {
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.
275 _playlists[n].reset ();
281 boost::shared_ptr<AudioPlaylist>
282 DiskIOProcessor::audio_playlist () const
284 return boost::dynamic_pointer_cast<AudioPlaylist> (_playlists[DataType::AUDIO]);
287 boost::shared_ptr<MidiPlaylist>
288 DiskIOProcessor::midi_playlist () const
290 return boost::dynamic_pointer_cast<MidiPlaylist> (_playlists[DataType::MIDI]);
294 DiskIOProcessor::use_playlist (DataType dt, boost::shared_ptr<Playlist> playlist)
300 DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: set to use playlist %2 (%3)\n", name(), playlist->name(), dt.to_string()));
302 if (playlist == _playlists[dt]) {
303 DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: already using that playlist\n", name()));
307 playlist_connections.drop_connections ();
309 if (_playlists[dt]) {
310 _playlists[dt]->release();
313 _playlists[dt] = playlist;
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));
321 DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1 now using playlist %1 (%2)\n", name(), playlist->name(), playlist->id()));
326 DiskIOProcessor::ChannelInfo::ChannelInfo (samplecnt_t bufsize)
329 , capture_transition_buf (0)
330 , curr_capture_cnt (0)
334 DiskIOProcessor::ChannelInfo::~ChannelInfo ()
338 delete capture_transition_buf;
341 capture_transition_buf = 0;
345 DiskIOProcessor::drop_track ()
351 DiskIOProcessor::set_track (boost::shared_ptr<Track> t)
356 _track->DropReferences.connect_same_thread (*this, boost::bind (&DiskIOProcessor::drop_track, this));
360 /** Get the start, end, and length of a location "atomically".
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.
368 DiskIOProcessor::get_location_times(const Location* location,
374 *start = location->start();
375 *end = location->end();
376 *length = *end - *start;