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 #include "ardour/track.h"
39 
40 #include "pbd/i18n.h"
41 
42 using namespace ARDOUR;
43 using namespace PBD;
44 using namespace std;
45 
46 const string DiskIOProcessor::state_node_name = X_("DiskIOProcessor");
47 
48 // PBD::Signal0<void> DiskIOProcessor::DiskOverrun;
49 // PBD::Signal0<void>  DiskIOProcessor::DiskUnderrun;
50 
DiskIOProcessor(Session & s,Track & t,string const & str,Flag f)51 DiskIOProcessor::DiskIOProcessor (Session& s, Track& t, string const & str, Flag f)
52 	: Processor (s, str)
53 	, _flags (f)
54 	, _slaved (false)
55 	, in_set_state (false)
56 	, playback_sample (0)
57 	, _need_butler (false)
58 	, _track (t)
59 	, channels (new ChannelList)
60 	, _midi_buf (0)
61 	, _samples_written_to_ringbuffer (0)
62 	, _samples_read_from_ringbuffer (0)
63 {
64 	set_display_to_user (false);
65 }
66 
~DiskIOProcessor()67 DiskIOProcessor::~DiskIOProcessor ()
68 {
69 	{
70 		RCUWriter<ChannelList> writer (channels);
71 		boost::shared_ptr<ChannelList> c = writer.get_copy();
72 
73 		for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
74 			delete *chan;
75 		}
76 
77 		c->clear();
78 	}
79 
80 	channels.flush ();
81 	delete _midi_buf;
82 
83 	for (uint32_t n = 0; n < DataType::num_types; ++n) {
84 		if (_playlists[n]) {
85 			_playlists[n]->release ();
86 		}
87 	}
88 }
89 
90 
91 void
init()92 DiskIOProcessor::init ()
93 {
94 	set_block_size (_session.get_block_size());
95 }
96 
97 void
set_buffering_parameters(BufferingPreset bp)98 DiskIOProcessor::set_buffering_parameters (BufferingPreset bp)
99 {
100 	samplecnt_t read_chunk_size;
101 	samplecnt_t read_buffer_size;
102 	samplecnt_t write_chunk_size;
103 	samplecnt_t write_buffer_size;
104 
105 	if (!get_buffering_presets (bp, read_chunk_size, read_buffer_size, write_chunk_size, write_buffer_size)) {
106 		return;
107 	}
108 
109 	DiskReader::set_chunk_samples (read_chunk_size);
110 	DiskWriter::set_chunk_samples (write_chunk_size);
111 
112 	Config->set_audio_capture_buffer_seconds (write_buffer_size);
113 	Config->set_audio_playback_buffer_seconds (read_buffer_size);
114 }
115 
116 bool
get_buffering_presets(BufferingPreset bp,samplecnt_t & read_chunk_size,samplecnt_t & read_buffer_size,samplecnt_t & write_chunk_size,samplecnt_t & write_buffer_size)117 DiskIOProcessor::get_buffering_presets (BufferingPreset bp,
118                                         samplecnt_t& read_chunk_size,
119                                         samplecnt_t& read_buffer_size,
120                                         samplecnt_t& write_chunk_size,
121                                         samplecnt_t& write_buffer_size)
122 {
123 	switch (bp) {
124 	case Small:
125 		read_chunk_size = 65536;  /* samples */
126 		write_chunk_size = 65536; /* samples */
127 		read_buffer_size = 5;  /* seconds */
128 		write_buffer_size = 5; /* seconds */
129 		break;
130 
131 	case Medium:
132 		read_chunk_size = 262144;  /* samples */
133 		write_chunk_size = 131072; /* samples */
134 		read_buffer_size = 10;  /* seconds */
135 		write_buffer_size = 10; /* seconds */
136 		break;
137 
138 	case Large:
139 		read_chunk_size = 524288; /* samples */
140 		write_chunk_size = 131072; /* samples */
141 		read_buffer_size = 20; /* seconds */
142 		write_buffer_size = 20; /* seconds */
143 		break;
144 
145 	default:
146 		return false;
147 	}
148 
149 	return true;
150 }
151 
152 bool
can_support_io_configuration(const ChanCount & in,ChanCount & out)153 DiskIOProcessor::can_support_io_configuration (const ChanCount& in, ChanCount& out)
154 {
155 	if (in.n_midi() != 0 && in.n_midi() != 1) {
156 		/* we only support zero or 1 MIDI stream */
157 		return false;
158 	}
159 
160 	/* currently no way to deliver different channels that we receive */
161 	out = in;
162 
163 	return true;
164 }
165 
166 bool
configure_io(ChanCount in,ChanCount out)167 DiskIOProcessor::configure_io (ChanCount in, ChanCount out)
168 {
169 	DEBUG_TRACE (DEBUG::DiskIO, string_compose ("Configuring %1 for in:%2 out:%3\n", name(), in, out));
170 
171 	bool changed = false;
172 
173 	{
174 		RCUWriter<ChannelList> writer (channels);
175 		boost::shared_ptr<ChannelList> c = writer.get_copy();
176 
177 		uint32_t n_audio = in.n_audio();
178 
179 		if (n_audio > c->size()) {
180 			add_channel_to (c, n_audio - c->size());
181 			changed = true;
182 		} else if (n_audio < c->size()) {
183 			remove_channel_from (c, c->size() - n_audio);
184 			changed = true;
185 		}
186 
187 		/* writer leaves scope, actual channel list is updated */
188 	}
189 
190 	if (in.n_midi() > 0 && !_midi_buf) {
191 		const size_t size = _session.butler()->midi_buffer_size();
192 		_midi_buf = new MidiRingBuffer<samplepos_t>(size);
193 		changed = true;
194 	}
195 
196 	if (changed) {
197 		configuration_changed ();
198 	}
199 
200 	return Processor::configure_io (in, out);
201 }
202 
203 int
set_block_size(pframes_t nframes)204 DiskIOProcessor::set_block_size (pframes_t nframes)
205 {
206 	return 0;
207 }
208 
209 void
non_realtime_locate(samplepos_t location)210 DiskIOProcessor::non_realtime_locate (samplepos_t location)
211 {
212 	/* now refill channel buffers */
213 
214 	seek (location, true);
215 }
216 
217 int
set_state(const XMLNode & node,int version)218 DiskIOProcessor::set_state (const XMLNode& node, int version)
219 {
220 	XMLProperty const * prop;
221 
222 	Processor::set_state (node, version);
223 
224 	if ((prop = node.property ("flags")) != 0) {
225 		_flags = Flag (string_2_enum (prop->value(), _flags));
226 	}
227 
228 	return 0;
229 }
230 
231 int
add_channel(uint32_t how_many)232 DiskIOProcessor::add_channel (uint32_t how_many)
233 {
234 	RCUWriter<ChannelList> writer (channels);
235 	boost::shared_ptr<ChannelList> c = writer.get_copy();
236 
237 	return add_channel_to (c, how_many);
238 }
239 
240 int
remove_channel_from(boost::shared_ptr<ChannelList> c,uint32_t how_many)241 DiskIOProcessor::remove_channel_from (boost::shared_ptr<ChannelList> c, uint32_t how_many)
242 {
243 	while (how_many-- && !c->empty()) {
244 		delete c->back();
245 		c->pop_back();
246 	}
247 
248 	return 0;
249 }
250 
251 int
remove_channel(uint32_t how_many)252 DiskIOProcessor::remove_channel (uint32_t how_many)
253 {
254 	RCUWriter<ChannelList> writer (channels);
255 	boost::shared_ptr<ChannelList> c = writer.get_copy();
256 
257 	return remove_channel_from (c, how_many);
258 }
259 
260 void
playlist_deleted(boost::weak_ptr<Playlist> wpl)261 DiskIOProcessor::playlist_deleted (boost::weak_ptr<Playlist> wpl)
262 {
263 	boost::shared_ptr<Playlist> pl (wpl.lock());
264 
265 	if (!pl) {
266 		return;
267 	}
268 
269 	for (uint32_t n = 0; n < DataType::num_types; ++n) {
270 		if (pl == _playlists[n]) {
271 
272 			/* this catches an ordering issue with session destruction. playlists
273 			   are destroyed before disk readers. we have to invalidate any handles
274 			   we have to the playlist.
275 			*/
276 			_playlists[n].reset ();
277 			break;
278 		}
279 	}
280 }
281 
282 boost::shared_ptr<AudioPlaylist>
audio_playlist() const283 DiskIOProcessor::audio_playlist () const
284 {
285 	return boost::dynamic_pointer_cast<AudioPlaylist> (_playlists[DataType::AUDIO]);
286 }
287 
288 boost::shared_ptr<MidiPlaylist>
midi_playlist() const289 DiskIOProcessor::midi_playlist () const
290 {
291 	return boost::dynamic_pointer_cast<MidiPlaylist> (_playlists[DataType::MIDI]);
292 }
293 
294 int
use_playlist(DataType dt,boost::shared_ptr<Playlist> playlist)295 DiskIOProcessor::use_playlist (DataType dt, boost::shared_ptr<Playlist> playlist)
296 {
297 	if (!playlist) {
298 		return 0;
299 	}
300 
301 	DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: set to use playlist %2 (%3)\n", name(), playlist->name(), dt.to_string()));
302 
303 	if (playlist == _playlists[dt]) {
304 		DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: already using that playlist\n", name()));
305 		return 0;
306 	}
307 
308 	playlist_connections.drop_connections ();
309 
310 	if (_playlists[dt]) {
311 		_playlists[dt]->release();
312 	}
313 
314 	_playlists[dt] = playlist;
315 	playlist->use();
316 
317 	playlist->ContentsChanged.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_modified, this));
318 	playlist->LayeringChanged.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_modified, this));
319 	playlist->DropReferences.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_deleted, this, boost::weak_ptr<Playlist>(playlist)));
320 	playlist->RangesMoved.connect_same_thread (playlist_connections, boost::bind (&DiskIOProcessor::playlist_ranges_moved, this, _1, _2));
321 
322 	DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1 now using playlist %1 (%2)\n", name(), playlist->name(), playlist->id()));
323 
324 	return 0;
325 }
326 
ChannelInfo(samplecnt_t bufsize)327 DiskIOProcessor::ChannelInfo::ChannelInfo (samplecnt_t bufsize)
328 	: rbuf (0)
329 	, wbuf (0)
330 	, capture_transition_buf (0)
331 	, curr_capture_cnt (0)
332 {
333 }
334 
~ChannelInfo()335 DiskIOProcessor::ChannelInfo::~ChannelInfo ()
336 {
337 	delete rbuf;
338 	delete wbuf;
339 	delete capture_transition_buf;
340 	rbuf = 0;
341 	wbuf = 0;
342 	capture_transition_buf = 0;
343 }
344 
345 /** Get the start, end, and length of a location "atomically".
346  *
347  * Note: Locations don't get deleted, so all we care about when I say "atomic"
348  * is that we are always pointing to the same one and using start/length values
349  * obtained just once.  Use this function to achieve this since location being
350  * a parameter achieves this.
351  */
352 void
get_location_times(const Location * location,samplepos_t * start,samplepos_t * end,samplepos_t * length)353 DiskIOProcessor::get_location_times(const Location* location,
354                    samplepos_t*     start,
355                    samplepos_t*     end,
356                    samplepos_t*     length)
357 {
358 	if (location) {
359 		*start  = location->start();
360 		*end    = location->end();
361 		*length = *end - *start;
362 	}
363 }
364 
365