r269@gandalf: fugalh | 2006-08-03 20:18:05 -0600
[ardour.git] / libs / ardour / diskstream.cc
1 /*
2     Copyright (C) 2000-2006 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id: diskstream.cc 567 2006-06-07 14:54:12Z trutkin $
19 */
20
21 #include <fstream>
22 #include <cstdio>
23 #include <unistd.h>
24 #include <cmath>
25 #include <cerrno>
26 #include <string>
27 #include <climits>
28 #include <fcntl.h>
29 #include <cstdlib>
30 #include <ctime>
31 #include <sys/stat.h>
32 #include <sys/mman.h>
33
34 #include <pbd/error.h>
35 #include <pbd/basename.h>
36 #include <glibmm/thread.h>
37 #include <pbd/xml++.h>
38
39 #include <ardour/ardour.h>
40 #include <ardour/audioengine.h>
41 #include <ardour/diskstream.h>
42 #include <ardour/utils.h>
43 #include <ardour/configuration.h>
44 #include <ardour/audiofilesource.h>
45 #include <ardour/destructive_filesource.h>
46 #include <ardour/send.h>
47 #include <ardour/playlist.h>
48 #include <ardour/cycle_timer.h>
49 #include <ardour/region.h>
50
51 #include "i18n.h"
52 #include <locale.h>
53
54 using namespace std;
55 using namespace ARDOUR;
56 using namespace PBD;
57
58 jack_nframes_t Diskstream::disk_io_chunk_frames = 0;
59
60 sigc::signal<void,Diskstream*>    Diskstream::DiskstreamCreated;
61 sigc::signal<void,list<Source*>*> Diskstream::DeleteSources;
62 sigc::signal<void>                Diskstream::DiskOverrun;
63 sigc::signal<void>                Diskstream::DiskUnderrun;
64
65 Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
66         : _name (name)
67         , _session (sess)
68         , _playlist(NULL)
69 {
70         init (flag);
71 }
72         
73 Diskstream::Diskstream (Session& sess, const XMLNode& node)
74         : _session (sess)
75         , _playlist(NULL)
76 {
77         init (Recordable);
78 }
79
80 void
81 Diskstream::init (Flag f)
82 {
83         _refcnt = 0;
84         _flags = f;
85         _io = 0;
86         _alignment_style = ExistingMaterial;
87         _persistent_alignment_style = ExistingMaterial;
88         first_input_change = true;
89         i_am_the_modifier = 0;
90         g_atomic_int_set (&_record_enabled, 0);
91         was_recording = false;
92         capture_start_frame = 0;
93         capture_captured = 0;
94         _visible_speed = 1.0f;
95         _actual_speed = 1.0f;
96         _buffer_reallocation_required = false;
97         _seek_required = false;
98         first_recordable_frame = max_frames;
99         last_recordable_frame = max_frames;
100         _roll_delay = 0;
101         _capture_offset = 0;
102         _processed = false;
103         _slaved = false;
104         adjust_capture_position = 0;
105         last_possibly_recording = 0;
106         loop_location = 0;
107         wrap_buffer_size = 0;
108         speed_buffer_size = 0;
109         last_phase = 0;
110         phi = (uint64_t) (0x1000000);
111         file_frame = 0;
112         playback_sample = 0;
113         playback_distance = 0;
114         _read_data_count = 0;
115         _write_data_count = 0;
116
117         pending_overwrite = false;
118         overwrite_frame = 0;
119         overwrite_queued = false;
120         input_change_pending = NoChange;
121
122         _n_channels = 0;
123 }
124
125 Diskstream::~Diskstream ()
126 {
127         // Taken by derived class destrctors.. should assure locked here somehow?
128         //Glib::Mutex::Lock lm (state_lock);
129
130         if (_playlist)
131                 _playlist->unref ();
132 }
133
134 void
135 Diskstream::set_io (IO& io)
136 {
137         _io = &io;
138         set_align_style_from_io ();
139 }
140
141 void
142 Diskstream::handle_input_change (IOChange change, void *src)
143 {
144         Glib::Mutex::Lock lm (state_lock);
145
146         if (!(input_change_pending & change)) {
147                 input_change_pending = IOChange (input_change_pending|change);
148                 _session.request_input_change_handling ();
149         }
150 }
151
152 void
153 Diskstream::non_realtime_set_speed ()
154 {
155         if (_buffer_reallocation_required)
156         {
157                 Glib::Mutex::Lock lm (state_lock);
158                 allocate_temporary_buffers ();
159
160                 _buffer_reallocation_required = false;
161         }
162
163         if (_seek_required) {
164                 if (speed() != 1.0f || speed() != -1.0f) {
165                         seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()), true);
166                 }
167                 else {
168                         seek (_session.transport_frame(), true);
169                 }
170
171                 _seek_required = false;
172         }
173 }
174
175 bool
176 Diskstream::realtime_set_speed (double sp, bool global)
177 {
178         bool changed = false;
179         double new_speed = sp * _session.transport_speed();
180         
181         if (_visible_speed != sp) {
182                 _visible_speed = sp;
183                 changed = true;
184         }
185         
186         if (new_speed != _actual_speed) {
187                 
188                 jack_nframes_t required_wrap_size = (jack_nframes_t) floor (_session.get_block_size() * 
189                                                                             fabs (new_speed)) + 1;
190                 
191                 if (required_wrap_size > wrap_buffer_size) {
192                         _buffer_reallocation_required = true;
193                 }
194                 
195                 _actual_speed = new_speed;
196                 phi = (uint64_t) (0x1000000 * fabs(_actual_speed));
197         }
198
199         if (changed) {
200                 if (!global) {
201                         _seek_required = true;
202                 }
203                 SpeedChanged (); /* EMIT SIGNAL */
204         }
205
206         return _buffer_reallocation_required || _seek_required;
207 }
208
209 void
210 Diskstream::prepare ()
211 {
212         _processed = false;
213         playback_distance = 0;
214 }
215
216 void
217 Diskstream::recover ()
218 {
219         state_lock.unlock();
220         _processed = false;
221 }
222
223 void
224 Diskstream::set_capture_offset ()
225 {
226         if (_io == 0) {
227                 /* can't capture, so forget it */
228                 return;
229         }
230
231         _capture_offset = _io->input_latency();
232 }
233
234 void
235 Diskstream::set_align_style (AlignStyle a)
236 {
237         if (record_enabled() && _session.actively_recording()) {
238                 return;
239         }
240
241         if (a != _alignment_style) {
242                 _alignment_style = a;
243                 AlignmentStyleChanged ();
244         }
245 }
246
247 int
248 Diskstream::set_loop (Location *location)
249 {
250         if (location) {
251                 if (location->start() >= location->end()) {
252                         error << string_compose(_("Location \"%1\" not valid for track loop (start >= end)"), location->name()) << endl;
253                         return -1;
254                 }
255         }
256
257         loop_location = location;
258
259          LoopSet (location); /* EMIT SIGNAL */
260         return 0;
261 }
262
263 jack_nframes_t
264 Diskstream::get_capture_start_frame (uint32_t n)
265 {
266         Glib::Mutex::Lock lm (capture_info_lock);
267
268         if (capture_info.size() > n) {
269                 return capture_info[n]->start;
270         }
271         else {
272                 return capture_start_frame;
273         }
274 }
275
276 jack_nframes_t
277 Diskstream::get_captured_frames (uint32_t n)
278 {
279         Glib::Mutex::Lock lm (capture_info_lock);
280
281         if (capture_info.size() > n) {
282                 return capture_info[n]->frames;
283         }
284         else {
285                 return capture_captured;
286         }
287 }
288
289 void
290 Diskstream::set_roll_delay (jack_nframes_t nframes)
291 {
292         _roll_delay = nframes;
293 }
294
295 void
296 Diskstream::set_speed (double sp)
297 {
298         _session.request_diskstream_speed (*this, sp);
299
300         /* to force a rebuffering at the right place */
301         playlist_modified();
302 }
303
304 int
305 Diskstream::use_playlist (Playlist* playlist)
306 {
307         {
308                 Glib::Mutex::Lock lm (state_lock);
309
310                 if (playlist == _playlist) {
311                         return 0;
312                 }
313
314                 plstate_connection.disconnect();
315                 plmod_connection.disconnect ();
316                 plgone_connection.disconnect ();
317
318                 if (_playlist) {
319                         _playlist->unref();
320                 }
321                         
322                 _playlist = playlist;
323                 _playlist->ref();
324
325                 if (!in_set_state && recordable()) {
326                         reset_write_sources (false);
327                 }
328                 
329                 plstate_connection = _playlist->StateChanged.connect (mem_fun (*this, &Diskstream::playlist_changed));
330                 plmod_connection = _playlist->Modified.connect (mem_fun (*this, &Diskstream::playlist_modified));
331                 plgone_connection = _playlist->GoingAway.connect (mem_fun (*this, &Diskstream::playlist_deleted));
332         }
333
334         if (!overwrite_queued) {
335                 _session.request_overwrite_buffer (this);
336                 overwrite_queued = true;
337         }
338         
339         PlaylistChanged (); /* EMIT SIGNAL */
340         _session.set_dirty ();
341
342         return 0;
343 }
344
345 void
346 Diskstream::playlist_changed (Change ignored)
347 {
348         playlist_modified ();
349 }
350
351 void
352 Diskstream::playlist_modified ()
353 {
354         if (!i_am_the_modifier && !overwrite_queued) {
355                 _session.request_overwrite_buffer (this);
356                 overwrite_queued = true;
357         } 
358 }
359
360 void
361 Diskstream::playlist_deleted (Playlist* pl)
362 {
363         /* this catches an ordering issue with session destruction. playlists 
364            are destroyed before diskstreams. we have to invalidate any handles
365            we have to the playlist.
366         */
367
368         _playlist = 0;
369 }
370
371 int
372 Diskstream::set_name (string str)
373 {
374         if (str != _name) {
375                 assert(playlist());
376                 playlist()->set_name (str);
377                 _name = str;
378                 
379                 if (!in_set_state && recordable()) {
380                         /* rename existing capture files so that they have the correct name */
381                         return rename_write_sources ();
382                 } else {
383                         return -1;
384                 }
385         }
386
387         return 0;
388 }
389
390 void
391 Diskstream::set_destructive (bool yn)
392 {
393         if (yn != destructive()) {
394                 reset_write_sources (true, true);
395                 if (yn) {
396                         _flags |= Destructive;
397                 } else {
398                         _flags &= ~Destructive;
399                 }
400         }
401 }