dynamic playback & capture buffer resizing (though transport is stopped first)
[ardour.git] / libs / ardour / audio_track.cc
1 /*
2     Copyright (C) 2002 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 */
19
20 #include <boost/scoped_array.hpp>
21
22 #include "pbd/error.h"
23 #include "pbd/enumwriter.h"
24 #include "pbd/boost_debug.h"
25
26 #include "evoral/Curve.hpp"
27
28 #include "ardour/amp.h"
29 #include "ardour/audio_buffer.h"
30 #include "ardour/audio_diskstream.h"
31 #include "ardour/audio_track.h"
32 #include "ardour/audioplaylist.h"
33 #include "ardour/audioregion.h"
34 #include "ardour/audiosource.h"
35 #include "ardour/buffer_set.h"
36 #include "ardour/io_processor.h"
37 #include "ardour/panner.h"
38 #include "ardour/meter.h"
39 #include "ardour/playlist_factory.h"
40 #include "ardour/plugin_insert.h"
41 #include "ardour/processor.h"
42 #include "ardour/region_factory.h"
43 #include "ardour/route_group_specialized.h"
44 #include "ardour/session.h"
45 #include "ardour/utils.h"
46 #include "ardour/session_playlists.h"
47 #include "ardour/delivery.h"
48 #include "ardour/meter.h"
49 #include "i18n.h"
50
51 using namespace std;
52 using namespace ARDOUR;
53 using namespace PBD;
54
55 AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode mode)
56         : Track (sess, name, flag, mode)
57 {
58 }
59
60 AudioTrack::~AudioTrack ()
61 {
62 }
63
64 void
65 AudioTrack::use_new_diskstream ()
66 {
67         AudioDiskstream::Flag dflags = AudioDiskstream::Flag (0);
68
69         if (_flags & Hidden) {
70                 dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Hidden);
71         } else {
72                 dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Recordable);
73         }
74
75         if (_mode == Destructive) {
76                 dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Destructive);
77         } else if (_mode == NonLayered){
78                 dflags = AudioDiskstream::Flag(dflags | AudioDiskstream::NonLayered);
79         }
80
81         AudioDiskstream* dsp (new AudioDiskstream (_session, name(), dflags));
82         boost::shared_ptr<AudioDiskstream> ds (dsp);
83
84         ds->do_refill_with_alloc ();
85         ds->set_block_size (_session.get_block_size ());
86
87         set_diskstream (ds);
88 }
89
90 void
91 AudioTrack::set_diskstream (boost::shared_ptr<Diskstream> ds)
92 {
93         Track::set_diskstream (ds);
94
95         _diskstream->set_track (this);
96         _diskstream->set_destructive (_mode == Destructive);
97         _diskstream->set_non_layered (_mode == NonLayered);
98
99         if (audio_diskstream()->deprecated_io_node) {
100
101                 if (!IO::connecting_legal) {
102                         IO::ConnectingLegal.connect_same_thread (*this, boost::bind (&AudioTrack::deprecated_use_diskstream_connections, this));
103                 } else {
104                         deprecated_use_diskstream_connections ();
105                 }
106         }
107
108         _diskstream->set_record_enabled (false);
109         _diskstream->monitor_input (false);
110
111         DiskstreamChanged (); /* EMIT SIGNAL */
112 }
113
114 boost::shared_ptr<AudioDiskstream>
115 AudioTrack::audio_diskstream() const
116 {
117         return boost::dynamic_pointer_cast<AudioDiskstream>(_diskstream);
118 }
119
120 int
121 AudioTrack::set_mode (TrackMode m)
122 {
123         if (m != _mode) {
124
125                 if (_diskstream->set_destructive (m == Destructive)) {
126                         return -1;
127                 }
128
129                 _diskstream->set_non_layered (m == NonLayered);
130                 _mode = m;
131
132                 TrackModeChanged (); /* EMIT SIGNAL */
133         }
134
135         return 0;
136 }
137
138 bool
139 AudioTrack::can_use_mode (TrackMode m, bool& bounce_required)
140 {
141         switch (m) {
142         case NonLayered:
143         case Normal:
144                 bounce_required = false;
145                 return true;
146
147         case Destructive:
148         default:
149                 return _diskstream->can_become_destructive (bounce_required);
150         }
151 }
152
153 int
154 AudioTrack::deprecated_use_diskstream_connections ()
155 {
156         boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
157
158         if (diskstream->deprecated_io_node == 0) {
159                 return 0;
160         }
161
162         const XMLProperty* prop;
163         XMLNode& node (*diskstream->deprecated_io_node);
164
165         /* don't do this more than once. */
166
167         diskstream->deprecated_io_node = 0;
168
169         if ((prop = node.property ("gain")) != 0) {
170                 _amp->set_gain (atof (prop->value().c_str()), this);
171         }
172
173         if ((prop = node.property ("input-connection")) != 0) {
174                 boost::shared_ptr<Bundle> c = _session.bundle_by_name (prop->value());
175
176                 if (c == 0) {
177                         error << string_compose(_("Unknown bundle \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
178
179                         if ((c = _session.bundle_by_name (_("in 1"))) == 0) {
180                                 error << _("No input bundles available as a replacement")
181                                 << endmsg;
182                                 return -1;
183                         } else {
184                                 info << string_compose (_("Bundle %1 was not available - \"in 1\" used instead"), prop->value())
185                                << endmsg;
186                         }
187                 }
188
189                 _input->connect_ports_to_bundle (c, this);
190
191         } else if ((prop = node.property ("inputs")) != 0) {
192                 if (_input->set_ports (prop->value())) {
193                         error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
194                         return -1;
195                 }
196         }
197
198         return 0;
199 }
200
201 int
202 AudioTrack::set_state (const XMLNode& node, int version)
203 {
204         return _set_state (node, version, true);
205 }
206
207 int
208 AudioTrack::_set_state (const XMLNode& node, int version, bool call_base)
209 {
210         const XMLProperty *prop;
211         XMLNodeConstIterator iter;
212
213         if (call_base) {
214                 if (Route::_set_state (node, version, call_base)) {
215                         return -1;
216                 }
217         }
218
219         if ((prop = node.property (X_("mode"))) != 0) {
220                 _mode = TrackMode (string_2_enum (prop->value(), _mode));
221         } else {
222                 _mode = Normal;
223         }
224
225         XMLNodeList nlist;
226         XMLNodeConstIterator niter;
227         XMLNode *child;
228
229         nlist = node.children();
230         for (niter = nlist.begin(); niter != nlist.end(); ++niter){
231                 child = *niter;
232
233                 if (child->name() == X_("recenable")) {
234                         _rec_enable_control->set_state (*child, version);
235                         _session.add_controllable (_rec_enable_control);
236                 }
237         }
238
239         if (version >= 3000) {
240                 if ((child = find_named_node (node, X_("Diskstream"))) != 0) {
241                         boost::shared_ptr<AudioDiskstream> ds (new AudioDiskstream (_session, *child));
242                         ds->do_refill_with_alloc ();
243                         set_diskstream (ds);
244                 }
245         }
246
247         pending_state = const_cast<XMLNode*> (&node);
248
249         if (_session.state_of_the_state() & Session::Loading) {
250                 _session.StateReady.connect_same_thread (*this, boost::bind (&AudioTrack::set_state_part_two, this));
251         } else {
252                 set_state_part_two ();
253         }
254
255         return 0;
256 }
257
258 XMLNode&
259 AudioTrack::state (bool full_state)
260 {
261         XMLNode& root (Route::state(full_state));
262         XMLNode* freeze_node;
263         char buf[64];
264
265         if (_freeze_record.playlist) {
266                 XMLNode* inode;
267
268                 freeze_node = new XMLNode (X_("freeze-info"));
269                 freeze_node->add_property ("playlist", _freeze_record.playlist->name());
270                 freeze_node->add_property ("state", enum_2_string (_freeze_record.state));
271
272                 for (vector<FreezeRecordProcessorInfo*>::iterator i = _freeze_record.processor_info.begin(); i != _freeze_record.processor_info.end(); ++i) {
273                         inode = new XMLNode (X_("processor"));
274                         (*i)->id.print (buf, sizeof (buf));
275                         inode->add_property (X_("id"), buf);
276                         inode->add_child_copy ((*i)->state);
277
278                         freeze_node->add_child_nocopy (*inode);
279                 }
280
281                 root.add_child_nocopy (*freeze_node);
282         }
283
284         root.add_property (X_("mode"), enum_2_string (_mode));
285         root.add_child_nocopy (_rec_enable_control->get_state());
286         root.add_child_nocopy (_diskstream->get_state ());
287
288         return root;
289 }
290
291 void
292 AudioTrack::set_state_part_two ()
293 {
294         XMLNode* fnode;
295         XMLProperty* prop;
296         LocaleGuard lg (X_("POSIX"));
297
298         /* This is called after all session state has been restored but before
299            have been made ports and connections are established.
300         */
301
302         if (pending_state == 0) {
303                 return;
304         }
305
306         if ((fnode = find_named_node (*pending_state, X_("freeze-info"))) != 0) {
307
308                 _freeze_record.state = Frozen;
309
310                 for (vector<FreezeRecordProcessorInfo*>::iterator i = _freeze_record.processor_info.begin(); i != _freeze_record.processor_info.end(); ++i) {
311                         delete *i;
312                 }
313                 _freeze_record.processor_info.clear ();
314
315                 if ((prop = fnode->property (X_("playlist"))) != 0) {
316                         boost::shared_ptr<Playlist> pl = _session.playlists->by_name (prop->value());
317                         if (pl) {
318                                 _freeze_record.playlist = boost::dynamic_pointer_cast<AudioPlaylist> (pl);
319                         } else {
320                                 _freeze_record.playlist.reset ();
321                                 _freeze_record.state = NoFreeze;
322                         return;
323                         }
324                 }
325
326                 if ((prop = fnode->property (X_("state"))) != 0) {
327                         _freeze_record.state = FreezeState (string_2_enum (prop->value(), _freeze_record.state));
328                 }
329
330                 XMLNodeConstIterator citer;
331                 XMLNodeList clist = fnode->children();
332
333                 for (citer = clist.begin(); citer != clist.end(); ++citer) {
334                         if ((*citer)->name() != X_("processor")) {
335                                 continue;
336                         }
337
338                         if ((prop = (*citer)->property (X_("id"))) == 0) {
339                                 continue;
340                         }
341
342                         FreezeRecordProcessorInfo* frii = new FreezeRecordProcessorInfo (*((*citer)->children().front()),
343                                                                                    boost::shared_ptr<Processor>());
344                         frii->id = prop->value ();
345                         _freeze_record.processor_info.push_back (frii);
346                 }
347         }
348 }
349
350 int
351 AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick,
352                   bool can_record, bool rec_monitors_input, bool& need_butler)
353 {
354         Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
355         if (!lm.locked()) {
356                 return 0;
357         }
358
359         int dret;
360         Sample* b;
361         Sample* tmpb;
362         nframes_t transport_frame;
363         boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
364         
365         automation_snapshot (start_frame, false);
366
367         if (n_outputs().n_total() == 0 && _processors.empty()) {
368                 return 0;
369         }
370
371         if (!_active) {
372                 silence (nframes);
373                 return 0;
374         }
375
376         transport_frame = _session.transport_frame();
377
378         if ((nframes = check_initial_delay (nframes, transport_frame)) == 0) {
379
380                 /* need to do this so that the diskstream sets its
381                    playback distance to zero, thus causing diskstream::commit
382                    to do nothing.
383                 */
384                 return diskstream->process (transport_frame, 0, can_record, rec_monitors_input, need_butler);
385         }
386
387         _silent = false;
388         _amp->apply_gain_automation(false);
389
390         if ((dret = diskstream->process (transport_frame, nframes, can_record, rec_monitors_input, need_butler)) != 0) {
391                 silence (nframes);
392                 return dret;
393         }
394
395         /* special condition applies */
396
397         if (_meter_point == MeterInput) {
398                 _input->process_input (_meter, start_frame, end_frame, nframes);
399         }
400
401         if (diskstream->record_enabled() && !can_record && !_session.config.get_auto_input()) {
402
403                 /* not actually recording, but we want to hear the input material anyway,
404                    at least potentially (depending on monitoring options)
405                  */
406
407                 passthru (start_frame, end_frame, nframes, false);
408
409         } else if ((b = diskstream->playback_buffer(0)) != 0) {
410
411                 /*
412                   XXX is it true that the earlier test on n_outputs()
413                   means that we can avoid checking it again here? i think
414                   so, because changing the i/o configuration of an IO
415                   requires holding the AudioEngine lock, which we hold
416                   while in the process() tree.
417                 */
418
419
420                 /* copy the diskstream data to all output buffers */
421
422                 size_t limit = input_streams ().n_audio();
423                 BufferSet& bufs = _session.get_scratch_buffers ();
424                 const size_t blimit = bufs.count().n_audio();
425
426                 uint32_t n;
427                 uint32_t i;
428
429                 if (limit > blimit) {
430
431                         /* example case: auditioner configured for stereo output,
432                            but loaded with an 8 channel file. there are only
433                            2 passthrough buffers, but n_process_buffers() will
434                            return 8.
435
436                            arbitrary decision: map all channels in the diskstream
437                            to the outputs available.
438                         */
439
440                         float scaling = limit/blimit;
441
442                         for (i = 0, n = 1; i < blimit; ++i, ++n) {
443
444                                 /* first time through just copy a channel into
445                                    the output buffer.
446                                 */
447
448                                 Sample* bb = bufs.get_audio (i).data();
449
450                                 for (nframes_t xx = 0; xx < nframes; ++xx) {
451                                         bb[xx] = b[xx] * scaling;
452                                 }
453
454                                 if (n < diskstream->n_channels().n_audio()) {
455                                         tmpb = diskstream->playback_buffer(n);
456                                         if (tmpb!=0) {
457                                                 b = tmpb;
458                                         }
459                                 }
460                         }
461
462                         for (;i < limit; ++i, ++n) {
463
464                                 /* for all remaining channels, sum with existing
465                                    data in the output buffers
466                                 */
467
468                                 bufs.get_audio (i%blimit).accumulate_with_gain_from (b, nframes, 0, scaling);
469
470                                 if (n < diskstream->n_channels().n_audio()) {
471                                         tmpb = diskstream->playback_buffer(n);
472                                         if (tmpb!=0) {
473                                                 b = tmpb;
474                                         }
475                                 }
476
477                         }
478
479                         limit = blimit;
480
481                 } else {
482                         for (i = 0, n = 1; i < limit; ++i, ++n) {
483                                 memcpy (bufs.get_audio (i).data(), b, sizeof (Sample) * nframes);
484                                 if (n < diskstream->n_channels().n_audio()) {
485                                         tmpb = diskstream->playback_buffer(n);
486                                         if (tmpb!=0) {
487                                                 b = tmpb;
488                                         }
489                                 }
490                         }
491
492                         /* try to leave any MIDI buffers alone */
493
494                         ChanCount chn;
495                         chn.set_audio (limit);
496                         chn.set_midi (_input->n_ports().n_midi());
497                         bufs.set_count (chn);
498                 }
499
500                 /* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
501
502                 if (!diskstream->record_enabled() && _session.transport_rolling()) {
503 #ifdef XXX_MOVE_THIS_TO_AMP
504                         Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
505
506                         if (am.locked() && gain_control()->automation_playback()) {
507                                 _amp->apply_gain_automation(
508                                                 gain_control()->list()->curve().rt_safe_get_vector (
509                                                         start_frame, end_frame, _session.gain_automation_buffer(), nframes));
510                         }
511 #endif
512                 }
513
514                 process_output_buffers (bufs, start_frame, end_frame, nframes, (!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick);
515
516         } else {
517                 /* problem with the diskstream; just be quiet for a bit */
518                 silence (nframes);
519         }
520
521         return 0;
522 }
523
524 int
525 AudioTrack::export_stuff (BufferSet& buffers, sframes_t start, nframes_t nframes, bool enable_processing)
526 {
527         boost::scoped_array<gain_t> gain_buffer (new gain_t[nframes]);
528         boost::scoped_array<Sample> mix_buffer (new Sample[nframes]);
529         boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
530
531         Glib::RWLock::ReaderLock rlock (_processor_lock);
532
533         boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist>(diskstream->playlist());
534         assert(apl);
535
536         assert(buffers.get_audio(0).capacity() >= nframes);
537
538         if (apl->read (buffers.get_audio(0).data(), mix_buffer.get(), gain_buffer.get(), start, nframes) != nframes) {
539                 return -1;
540         }
541
542         assert(buffers.count().n_audio() >= 1);
543         uint32_t n=1;
544         Sample* b = buffers.get_audio(0).data();
545         BufferSet::audio_iterator bi = buffers.audio_begin();
546         ++bi;
547         for ( ; bi != buffers.audio_end(); ++bi, ++n) {
548                 if (n < diskstream->n_channels().n_audio()) {
549                         if (apl->read (bi->data(), mix_buffer.get(), gain_buffer.get(), start, nframes, n) != nframes) {
550                                 return -1;
551                         }
552                         b = bi->data();
553                 }
554                 else {
555                         /* duplicate last across remaining buffers */
556                         memcpy (bi->data(), b, sizeof (Sample) * nframes);
557                 }
558         }
559
560         // If no processing is required, there's no need to go any further.
561         if (!enable_processing) {
562                 return 0;
563         }
564
565         /* note: only run processors during export. other layers in the machinery
566            will already have checked that there are no external port processors.
567            Also, don't run deliveries that write to real output ports, and don't
568            run meters.
569         */
570
571         for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
572                 boost::shared_ptr<Processor> processor = boost::dynamic_pointer_cast<Processor> (*i);
573                 boost::shared_ptr<Delivery> delivery = boost::dynamic_pointer_cast<Delivery> (*i);
574                 boost::shared_ptr<PeakMeter> meter = boost::dynamic_pointer_cast<PeakMeter> (*i);
575                 
576                 if (processor && (!delivery || !Delivery::role_requires_output_ports (delivery->role())) && !meter) {
577                         processor->run (buffers, start, start+nframes, nframes, true);
578                 }
579         }
580
581         return 0;
582 }
583
584 boost::shared_ptr<Region>
585 AudioTrack::bounce (InterThreadInfo& itt)
586 {
587         vector<boost::shared_ptr<Source> > srcs;
588         return _session.write_one_track (*this, _session.current_start_frame(), _session.current_end_frame(), false, srcs, itt);
589 }
590
591 boost::shared_ptr<Region>
592 AudioTrack::bounce_range (nframes_t start, nframes_t end, InterThreadInfo& itt, bool enable_processing)
593 {
594         vector<boost::shared_ptr<Source> > srcs;
595         return _session.write_one_track (*this, start, end, false, srcs, itt, enable_processing);
596 }
597
598 void
599 AudioTrack::freeze_me (InterThreadInfo& itt)
600 {
601         vector<boost::shared_ptr<Source> > srcs;
602         string new_playlist_name;
603         boost::shared_ptr<Playlist> new_playlist;
604         string dir;
605         string region_name;
606         boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
607
608         if ((_freeze_record.playlist = boost::dynamic_pointer_cast<AudioPlaylist>(diskstream->playlist())) == 0) {
609                 return;
610         }
611
612         uint32_t n = 1;
613
614         while (n < (UINT_MAX-1)) {
615
616                 string candidate;
617
618                 candidate = string_compose ("<F%2>%1", _freeze_record.playlist->name(), n);
619
620                 if (_session.playlists->by_name (candidate) == 0) {
621                         new_playlist_name = candidate;
622                         break;
623                 }
624
625                 ++n;
626
627         }
628
629         if (n == (UINT_MAX-1)) {
630           error << string_compose (X_("There are too many frozen versions of playlist \"%1\""
631                             " to create another one"), _freeze_record.playlist->name())
632                << endmsg;
633                 return;
634         }
635
636         boost::shared_ptr<Region> res;
637
638         if ((res = _session.write_one_track (*this, _session.current_start_frame(), _session.current_end_frame(), true, srcs, itt)) == 0) {
639                 return;
640         }
641
642         _freeze_record.processor_info.clear ();
643
644         {
645                 Glib::RWLock::ReaderLock lm (_processor_lock);
646
647                 for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); ++r) {
648
649                         boost::shared_ptr<Processor> processor;
650
651                         if ((processor = boost::dynamic_pointer_cast<Processor>(*r)) != 0) {
652
653                                 FreezeRecordProcessorInfo* frii  = new FreezeRecordProcessorInfo ((*r)->get_state(), processor);
654
655                                 frii->id = processor->id();
656
657                                 _freeze_record.processor_info.push_back (frii);
658
659                                 /* now deactivate the processor */
660
661                                 processor->deactivate ();
662                                 _session.set_dirty ();
663                         }
664                 }
665         }
666
667         new_playlist = PlaylistFactory::create (DataType::AUDIO, _session, new_playlist_name, false);
668
669         /* XXX need main outs automation state _freeze_record.pan_automation_state = _mainpanner->automation_state(); */
670
671         region_name = new_playlist_name;
672
673         /* create a new region from all filesources, keep it private */
674
675         PropertyList plist;
676         
677         plist.add (Properties::start, 0);
678         plist.add (Properties::length, srcs[0]->length(srcs[0]->timeline_position()));
679         plist.add (Properties::name, region_name);
680         plist.add (Properties::whole_file, true);
681
682         boost::shared_ptr<Region> region (RegionFactory::create (srcs, plist, false));
683
684         new_playlist->set_orig_diskstream_id (_diskstream->id());
685         new_playlist->add_region (region, _session.current_start_frame());
686         new_playlist->set_frozen (true);
687         region->set_locked (true);
688
689         diskstream->use_playlist (boost::dynamic_pointer_cast<AudioPlaylist>(new_playlist));
690         diskstream->set_record_enabled (false);
691
692         /* reset stuff that has already been accounted for in the freeze process */
693
694         set_gain (1.0, this);
695         _amp->gain_control()->set_automation_state (Off);
696         /* XXX need to use _main_outs _panner->set_automation_state (Off); */
697
698         _freeze_record.state = Frozen;
699         FreezeChange(); /* EMIT SIGNAL */
700 }
701
702 void
703 AudioTrack::unfreeze ()
704 {
705         if (_freeze_record.playlist) {
706                 audio_diskstream()->use_playlist (_freeze_record.playlist);
707
708                 {
709                         Glib::RWLock::ReaderLock lm (_processor_lock); // should this be a write lock? jlc
710                         for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
711                                 for (vector<FreezeRecordProcessorInfo*>::iterator ii = _freeze_record.processor_info.begin(); ii != _freeze_record.processor_info.end(); ++ii) {
712                                         if ((*ii)->id == (*i)->id()) {
713                                                 (*i)->set_state (((*ii)->state), Stateful::current_state_version);
714                                                 break;
715                                         }
716                                 }
717                         }
718                 }
719
720                 _freeze_record.playlist.reset ();
721                 /* XXX need to use _main_outs _panner->set_automation_state (_freeze_record.pan_automation_state); */
722         }
723
724         _freeze_record.state = UnFrozen;
725         FreezeChange (); /* EMIT SIGNAL */
726 }
727
728 boost::shared_ptr<AudioFileSource>
729 AudioTrack::write_source (uint32_t n)
730 {
731         boost::shared_ptr<AudioDiskstream> ds = boost::dynamic_pointer_cast<AudioDiskstream> (_diskstream);
732         assert (ds);
733         return ds->write_source (n);
734 }
735