changes associated with save/restore of AutomationControl id's
[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() == Controllable::xml_node_name && (prop = child->property ("name")) != 0) {
234                         if (prop->value() == X_("recenable")) {
235                                 _rec_enable_control->set_state (*child, version);
236                         }
237                 }
238         }
239
240         if (version >= 3000) {
241                 if ((child = find_named_node (node, X_("Diskstream"))) != 0) {
242                         boost::shared_ptr<AudioDiskstream> ds (new AudioDiskstream (_session, *child));
243                         ds->do_refill_with_alloc ();
244                         set_diskstream (ds);
245                 }
246         }
247
248         pending_state = const_cast<XMLNode*> (&node);
249
250         if (_session.state_of_the_state() & Session::Loading) {
251                 _session.StateReady.connect_same_thread (*this, boost::bind (&AudioTrack::set_state_part_two, this));
252         } else {
253                 set_state_part_two ();
254         }
255
256         return 0;
257 }
258
259 XMLNode&
260 AudioTrack::state (bool full_state)
261 {
262         XMLNode& root (Route::state(full_state));
263         XMLNode* freeze_node;
264         char buf[64];
265
266         if (_freeze_record.playlist) {
267                 XMLNode* inode;
268
269                 freeze_node = new XMLNode (X_("freeze-info"));
270                 freeze_node->add_property ("playlist", _freeze_record.playlist->name());
271                 freeze_node->add_property ("state", enum_2_string (_freeze_record.state));
272
273                 for (vector<FreezeRecordProcessorInfo*>::iterator i = _freeze_record.processor_info.begin(); i != _freeze_record.processor_info.end(); ++i) {
274                         inode = new XMLNode (X_("processor"));
275                         (*i)->id.print (buf, sizeof (buf));
276                         inode->add_property (X_("id"), buf);
277                         inode->add_child_copy ((*i)->state);
278
279                         freeze_node->add_child_nocopy (*inode);
280                 }
281
282                 root.add_child_nocopy (*freeze_node);
283         }
284
285         root.add_property (X_("mode"), enum_2_string (_mode));
286         root.add_child_nocopy (_rec_enable_control->get_state());
287         root.add_child_nocopy (_diskstream->get_state ());
288
289         return root;
290 }
291
292 void
293 AudioTrack::set_state_part_two ()
294 {
295         XMLNode* fnode;
296         XMLProperty* prop;
297         LocaleGuard lg (X_("POSIX"));
298
299         /* This is called after all session state has been restored but before
300            have been made ports and connections are established.
301         */
302
303         if (pending_state == 0) {
304                 return;
305         }
306
307         if ((fnode = find_named_node (*pending_state, X_("freeze-info"))) != 0) {
308
309                 _freeze_record.state = Frozen;
310
311                 for (vector<FreezeRecordProcessorInfo*>::iterator i = _freeze_record.processor_info.begin(); i != _freeze_record.processor_info.end(); ++i) {
312                         delete *i;
313                 }
314                 _freeze_record.processor_info.clear ();
315
316                 if ((prop = fnode->property (X_("playlist"))) != 0) {
317                         boost::shared_ptr<Playlist> pl = _session.playlists->by_name (prop->value());
318                         if (pl) {
319                                 _freeze_record.playlist = boost::dynamic_pointer_cast<AudioPlaylist> (pl);
320                         } else {
321                                 _freeze_record.playlist.reset ();
322                                 _freeze_record.state = NoFreeze;
323                         return;
324                         }
325                 }
326
327                 if ((prop = fnode->property (X_("state"))) != 0) {
328                         _freeze_record.state = FreezeState (string_2_enum (prop->value(), _freeze_record.state));
329                 }
330
331                 XMLNodeConstIterator citer;
332                 XMLNodeList clist = fnode->children();
333
334                 for (citer = clist.begin(); citer != clist.end(); ++citer) {
335                         if ((*citer)->name() != X_("processor")) {
336                                 continue;
337                         }
338
339                         if ((prop = (*citer)->property (X_("id"))) == 0) {
340                                 continue;
341                         }
342
343                         FreezeRecordProcessorInfo* frii = new FreezeRecordProcessorInfo (*((*citer)->children().front()),
344                                                                                    boost::shared_ptr<Processor>());
345                         frii->id = prop->value ();
346                         _freeze_record.processor_info.push_back (frii);
347                 }
348         }
349 }
350
351 int
352 AudioTrack::roll (nframes_t nframes, framepos_t start_frame, framepos_t end_frame, int declick,
353                   bool can_record, bool rec_monitors_input, bool& need_butler)
354 {
355         Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
356         if (!lm.locked()) {
357                 return 0;
358         }
359
360         int dret;
361         Sample* b;
362         Sample* tmpb;
363         nframes_t transport_frame;
364         boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
365         
366         automation_snapshot (start_frame, false);
367
368         if (n_outputs().n_total() == 0 && _processors.empty()) {
369                 return 0;
370         }
371
372         if (!_active) {
373                 silence (nframes);
374                 return 0;
375         }
376
377         transport_frame = _session.transport_frame();
378
379         if ((nframes = check_initial_delay (nframes, transport_frame)) == 0) {
380
381                 /* need to do this so that the diskstream sets its
382                    playback distance to zero, thus causing diskstream::commit
383                    to do nothing.
384                 */
385                 return diskstream->process (transport_frame, 0, can_record, rec_monitors_input, need_butler);
386         }
387
388         _silent = false;
389         _amp->apply_gain_automation(false);
390
391         if ((dret = diskstream->process (transport_frame, nframes, can_record, rec_monitors_input, need_butler)) != 0) {
392                 silence (nframes);
393                 return dret;
394         }
395
396         /* special condition applies */
397
398         if (_meter_point == MeterInput) {
399                 _input->process_input (_meter, start_frame, end_frame, nframes);
400         }
401
402         if (diskstream->record_enabled() && !can_record && !_session.config.get_auto_input()) {
403
404                 /* not actually recording, but we want to hear the input material anyway,
405                    at least potentially (depending on monitoring options)
406                  */
407
408                 passthru (start_frame, end_frame, nframes, false);
409
410         } else if ((b = diskstream->playback_buffer(0)) != 0) {
411
412                 /*
413                   XXX is it true that the earlier test on n_outputs()
414                   means that we can avoid checking it again here? i think
415                   so, because changing the i/o configuration of an IO
416                   requires holding the AudioEngine lock, which we hold
417                   while in the process() tree.
418                 */
419
420
421                 /* copy the diskstream data to all output buffers */
422
423                 size_t limit = input_streams ().n_audio();
424                 BufferSet& bufs = _session.get_scratch_buffers ();
425                 const size_t blimit = bufs.count().n_audio();
426
427                 uint32_t n;
428                 uint32_t i;
429
430                 if (limit > blimit) {
431
432                         /* example case: auditioner configured for stereo output,
433                            but loaded with an 8 channel file. there are only
434                            2 passthrough buffers, but n_process_buffers() will
435                            return 8.
436
437                            arbitrary decision: map all channels in the diskstream
438                            to the outputs available.
439                         */
440
441                         float scaling = limit/blimit;
442
443                         for (i = 0, n = 1; i < blimit; ++i, ++n) {
444
445                                 /* first time through just copy a channel into
446                                    the output buffer.
447                                 */
448
449                                 Sample* bb = bufs.get_audio (i).data();
450
451                                 for (nframes_t xx = 0; xx < nframes; ++xx) {
452                                         bb[xx] = b[xx] * scaling;
453                                 }
454
455                                 if (n < diskstream->n_channels().n_audio()) {
456                                         tmpb = diskstream->playback_buffer(n);
457                                         if (tmpb!=0) {
458                                                 b = tmpb;
459                                         }
460                                 }
461                         }
462
463                         for (;i < limit; ++i, ++n) {
464
465                                 /* for all remaining channels, sum with existing
466                                    data in the output buffers
467                                 */
468
469                                 bufs.get_audio (i%blimit).accumulate_with_gain_from (b, nframes, 0, scaling);
470
471                                 if (n < diskstream->n_channels().n_audio()) {
472                                         tmpb = diskstream->playback_buffer(n);
473                                         if (tmpb!=0) {
474                                                 b = tmpb;
475                                         }
476                                 }
477
478                         }
479
480                         limit = blimit;
481
482                 } else {
483                         for (i = 0, n = 1; i < limit; ++i, ++n) {
484                                 memcpy (bufs.get_audio (i).data(), b, sizeof (Sample) * nframes);
485                                 if (n < diskstream->n_channels().n_audio()) {
486                                         tmpb = diskstream->playback_buffer(n);
487                                         if (tmpb!=0) {
488                                                 b = tmpb;
489                                         }
490                                 }
491                         }
492
493                         /* try to leave any MIDI buffers alone */
494
495                         ChanCount chn;
496                         chn.set_audio (limit);
497                         chn.set_midi (_input->n_ports().n_midi());
498                         bufs.set_count (chn);
499                 }
500
501                 /* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
502
503                 if (!diskstream->record_enabled() && _session.transport_rolling()) {
504 #ifdef XXX_MOVE_THIS_TO_AMP
505                         Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
506
507                         if (am.locked() && gain_control()->automation_playback()) {
508                                 _amp->apply_gain_automation(
509                                                 gain_control()->list()->curve().rt_safe_get_vector (
510                                                         start_frame, end_frame, _session.gain_automation_buffer(), nframes));
511                         }
512 #endif
513                 }
514
515                 process_output_buffers (bufs, start_frame, end_frame, nframes, (!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick);
516
517         } else {
518                 /* problem with the diskstream; just be quiet for a bit */
519                 silence (nframes);
520         }
521
522         return 0;
523 }
524
525 int
526 AudioTrack::export_stuff (BufferSet& buffers, framepos_t start, framecnt_t nframes, bool enable_processing)
527 {
528         boost::scoped_array<gain_t> gain_buffer (new gain_t[nframes]);
529         boost::scoped_array<Sample> mix_buffer (new Sample[nframes]);
530         boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
531
532         Glib::RWLock::ReaderLock rlock (_processor_lock);
533
534         boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist>(diskstream->playlist());
535         assert(apl);
536
537         assert ((framecnt_t) buffers.get_audio(0).capacity() >= nframes);
538
539         if (apl->read (buffers.get_audio(0).data(), mix_buffer.get(), gain_buffer.get(), start, nframes) != nframes) {
540                 return -1;
541         }
542
543         assert(buffers.count().n_audio() >= 1);
544         uint32_t n=1;
545         Sample* b = buffers.get_audio(0).data();
546         BufferSet::audio_iterator bi = buffers.audio_begin();
547         ++bi;
548         for ( ; bi != buffers.audio_end(); ++bi, ++n) {
549                 if (n < diskstream->n_channels().n_audio()) {
550                         if (apl->read (bi->data(), mix_buffer.get(), gain_buffer.get(), start, nframes, n) != nframes) {
551                                 return -1;
552                         }
553                         b = bi->data();
554                 }
555                 else {
556                         /* duplicate last across remaining buffers */
557                         memcpy (bi->data(), b, sizeof (Sample) * nframes);
558                 }
559         }
560
561         // If no processing is required, there's no need to go any further.
562         if (!enable_processing) {
563                 return 0;
564         }
565
566         /* note: only run processors during export. other layers in the machinery
567            will already have checked that there are no external port processors.
568            Also, don't run deliveries that write to real output ports, and don't
569            run meters.
570         */
571
572         for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
573                 boost::shared_ptr<Processor> processor = boost::dynamic_pointer_cast<Processor> (*i);
574                 boost::shared_ptr<Delivery> delivery = boost::dynamic_pointer_cast<Delivery> (*i);
575                 boost::shared_ptr<PeakMeter> meter = boost::dynamic_pointer_cast<PeakMeter> (*i);
576                 
577                 if (processor && (!delivery || !Delivery::role_requires_output_ports (delivery->role())) && !meter) {
578                         processor->run (buffers, start, start+nframes, nframes, true);
579                 }
580         }
581
582         return 0;
583 }
584
585 boost::shared_ptr<Region>
586 AudioTrack::bounce (InterThreadInfo& itt)
587 {
588         vector<boost::shared_ptr<Source> > srcs;
589         return _session.write_one_track (*this, _session.current_start_frame(), _session.current_end_frame(), false, srcs, itt);
590 }
591
592 boost::shared_ptr<Region>
593 AudioTrack::bounce_range (nframes_t start, nframes_t end, InterThreadInfo& itt, bool enable_processing)
594 {
595         vector<boost::shared_ptr<Source> > srcs;
596         return _session.write_one_track (*this, start, end, false, srcs, itt, enable_processing);
597 }
598
599 void
600 AudioTrack::freeze_me (InterThreadInfo& itt)
601 {
602         vector<boost::shared_ptr<Source> > srcs;
603         string new_playlist_name;
604         boost::shared_ptr<Playlist> new_playlist;
605         string dir;
606         string region_name;
607         boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
608
609         if ((_freeze_record.playlist = boost::dynamic_pointer_cast<AudioPlaylist>(diskstream->playlist())) == 0) {
610                 return;
611         }
612
613         uint32_t n = 1;
614
615         while (n < (UINT_MAX-1)) {
616
617                 string candidate;
618
619                 candidate = string_compose ("<F%2>%1", _freeze_record.playlist->name(), n);
620
621                 if (_session.playlists->by_name (candidate) == 0) {
622                         new_playlist_name = candidate;
623                         break;
624                 }
625
626                 ++n;
627
628         }
629
630         if (n == (UINT_MAX-1)) {
631           error << string_compose (X_("There are too many frozen versions of playlist \"%1\""
632                             " to create another one"), _freeze_record.playlist->name())
633                << endmsg;
634                 return;
635         }
636
637         boost::shared_ptr<Region> res;
638
639         if ((res = _session.write_one_track (*this, _session.current_start_frame(), _session.current_end_frame(), true, srcs, itt)) == 0) {
640                 return;
641         }
642
643         _freeze_record.processor_info.clear ();
644
645         {
646                 Glib::RWLock::ReaderLock lm (_processor_lock);
647
648                 for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); ++r) {
649
650                         boost::shared_ptr<Processor> processor;
651
652                         if ((processor = boost::dynamic_pointer_cast<Processor>(*r)) != 0) {
653
654                                 FreezeRecordProcessorInfo* frii  = new FreezeRecordProcessorInfo ((*r)->get_state(), processor);
655
656                                 frii->id = processor->id();
657
658                                 _freeze_record.processor_info.push_back (frii);
659
660                                 /* now deactivate the processor */
661
662                                 processor->deactivate ();
663                                 _session.set_dirty ();
664                         }
665                 }
666         }
667
668         new_playlist = PlaylistFactory::create (DataType::AUDIO, _session, new_playlist_name, false);
669
670         /* XXX need main outs automation state _freeze_record.pan_automation_state = _mainpanner->automation_state(); */
671
672         region_name = new_playlist_name;
673
674         /* create a new region from all filesources, keep it private */
675
676         PropertyList plist;
677         
678         plist.add (Properties::start, 0);
679         plist.add (Properties::length, srcs[0]->length(srcs[0]->timeline_position()));
680         plist.add (Properties::name, region_name);
681         plist.add (Properties::whole_file, true);
682
683         boost::shared_ptr<Region> region (RegionFactory::create (srcs, plist, false));
684
685         new_playlist->set_orig_diskstream_id (_diskstream->id());
686         new_playlist->add_region (region, _session.current_start_frame());
687         new_playlist->set_frozen (true);
688         region->set_locked (true);
689
690         diskstream->use_playlist (boost::dynamic_pointer_cast<AudioPlaylist>(new_playlist));
691         diskstream->set_record_enabled (false);
692
693         /* reset stuff that has already been accounted for in the freeze process */
694
695         set_gain (1.0, this);
696         _amp->gain_control()->set_automation_state (Off);
697         /* XXX need to use _main_outs _panner->set_automation_state (Off); */
698
699         _freeze_record.state = Frozen;
700         FreezeChange(); /* EMIT SIGNAL */
701 }
702
703 void
704 AudioTrack::unfreeze ()
705 {
706         if (_freeze_record.playlist) {
707                 audio_diskstream()->use_playlist (_freeze_record.playlist);
708
709                 {
710                         Glib::RWLock::ReaderLock lm (_processor_lock); // should this be a write lock? jlc
711                         for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
712                                 for (vector<FreezeRecordProcessorInfo*>::iterator ii = _freeze_record.processor_info.begin(); ii != _freeze_record.processor_info.end(); ++ii) {
713                                         if ((*ii)->id == (*i)->id()) {
714                                                 (*i)->set_state (((*ii)->state), Stateful::current_state_version);
715                                                 break;
716                                         }
717                                 }
718                         }
719                 }
720
721                 _freeze_record.playlist.reset ();
722                 /* XXX need to use _main_outs _panner->set_automation_state (_freeze_record.pan_automation_state); */
723         }
724
725         _freeze_record.state = UnFrozen;
726         FreezeChange (); /* EMIT SIGNAL */
727 }
728
729 boost::shared_ptr<AudioFileSource>
730 AudioTrack::write_source (uint32_t n)
731 {
732         boost::shared_ptr<AudioDiskstream> ds = boost::dynamic_pointer_cast<AudioDiskstream> (_diskstream);
733         assert (ds);
734         return ds->write_source (n);
735 }
736