Work towards removal of Session's Diskstream list.
[ardour.git] / libs / ardour / midi_track.cc
1 /*
2     Copyright (C) 2006 Paul Davis 
3         By Dave Robillard, 2006
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
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #include <pbd/error.h>
20 #include <sigc++/retype.h>
21 #include <sigc++/retype_return.h>
22 #include <sigc++/bind.h>
23
24 #include <ardour/midi_track.h>
25 #include <ardour/midi_diskstream.h>
26 #include <ardour/session.h>
27 #include <ardour/redirect.h>
28 #include <ardour/midi_region.h>
29 #include <ardour/midi_source.h>
30 #include <ardour/route_group_specialized.h>
31 #include <ardour/insert.h>
32 #include <ardour/midi_playlist.h>
33 #include <ardour/panner.h>
34 #include <ardour/utils.h>
35
36 #include "i18n.h"
37
38 using namespace std;
39 using namespace ARDOUR;
40 using namespace PBD;
41
42 MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mode)
43         : Track (sess, name, flag, mode, Buffer::MIDI)
44 {
45         MidiDiskstream::Flag dflags = MidiDiskstream::Flag (0);
46
47         if (_flags & Hidden) {
48                 dflags = MidiDiskstream::Flag (dflags | MidiDiskstream::Hidden);
49         } else {
50                 dflags = MidiDiskstream::Flag (dflags | MidiDiskstream::Recordable);
51         }
52
53         if (mode == Destructive) {
54                 dflags = MidiDiskstream::Flag (dflags | MidiDiskstream::Destructive);
55         }
56
57         MidiDiskstream* ds = new MidiDiskstream (_session, name, dflags);
58         
59         _declickable = true;
60         _freeze_record.state = NoFreeze;
61         _saved_meter_point = _meter_point;
62         _mode = mode;
63
64         set_diskstream (*ds, this);
65 }
66
67 MidiTrack::MidiTrack (Session& sess, const XMLNode& node)
68         : Track (sess, node)
69 {
70         _freeze_record.state = NoFreeze;
71         set_state (node);
72         _declickable = true;
73         _saved_meter_point = _meter_point;
74 }
75
76 MidiTrack::~MidiTrack ()
77 {
78         if (_diskstream) {
79                 _diskstream->unref();
80         }
81 }
82
83 #if 0
84 void
85 MidiTrack::handle_smpte_offset_change ()
86 {
87         diskstream
88 }
89 #endif
90
91
92 int
93 MidiTrack::set_diskstream (MidiDiskstream& ds, void *src)
94 {
95         if (_diskstream) {
96                 _diskstream->unref();
97         }
98
99         _diskstream = &ds.ref();
100         _diskstream->set_io (*this);
101         _diskstream->set_destructive (_mode == Destructive);
102
103         _diskstream->set_record_enabled (false, this);
104         //_diskstream->monitor_input (false);
105
106         ic_connection.disconnect();
107         ic_connection = input_changed.connect (mem_fun (*_diskstream, &MidiDiskstream::handle_input_change));
108
109         DiskstreamChanged (src); /* EMIT SIGNAL */
110
111         return 0;
112 }       
113
114 int 
115 MidiTrack::use_diskstream (string name)
116 {
117         MidiDiskstream *dstream;
118
119         if ((dstream = dynamic_cast<MidiDiskstream*>(_session.diskstream_by_name (name))) == 0) {
120           error << string_compose(_("MidiTrack: midi diskstream \"%1\" not known by session"), name) << endmsg;
121                 return -1;
122         }
123         
124         return set_diskstream (*dstream, this);
125 }
126
127 int 
128 MidiTrack::use_diskstream (const PBD::ID& id)
129 {
130         MidiDiskstream *dstream;
131
132         if ((dstream = dynamic_cast<MidiDiskstream*>(_session.diskstream_by_id (id))) == 0) {
133                 error << string_compose(_("MidiTrack: midi diskstream \"%1\" not known by session"), id) << endmsg;
134                 return -1;
135         }
136         
137         return set_diskstream (*dstream, this);
138 }
139
140 bool
141 MidiTrack::record_enabled () const
142 {
143         return _diskstream->record_enabled ();
144 }
145
146 void
147 MidiTrack::set_record_enable (bool yn, void *src)
148 {
149         if (_freeze_record.state == Frozen) {
150                 return;
151         }
152 #if 0
153         if (_mix_group && src != _mix_group && _mix_group->is_active()) {
154                 _mix_group->apply (&MidiTrack::set_record_enable, yn, _mix_group);
155                 return;
156         }
157
158         /* keep track of the meter point as it was before we rec-enabled */
159
160         if (!diskstream->record_enabled()) {
161                 _saved_meter_point = _meter_point;
162         }
163         
164         diskstream->set_record_enabled (yn, src);
165
166         if (diskstream->record_enabled()) {
167                 set_meter_point (MeterInput, this);
168         } else {
169                 set_meter_point (_saved_meter_point, this);
170         }
171
172         if (_session.get_midi_feedback()) {
173                 _midi_rec_enable_control.send_feedback (record_enabled());
174         }
175 #endif
176 }
177
178 MidiDiskstream&
179 MidiTrack::midi_diskstream() const
180 {
181         return *dynamic_cast<MidiDiskstream*>(_diskstream);
182 }
183
184 int
185 MidiTrack::set_state (const XMLNode& node)
186 {
187         const XMLProperty *prop;
188         XMLNodeConstIterator iter;
189
190         if (Route::set_state (node)) {
191                 return -1;
192         }
193
194         if ((prop = node.property (X_("mode"))) != 0) {
195                 if (prop->value() == X_("normal")) {
196                         _mode = Normal;
197                 } else if (prop->value() == X_("destructive")) {
198                         _mode = Destructive;
199                 } else {
200                         warning << string_compose ("unknown midi track mode \"%1\" seen and ignored", prop->value()) << endmsg;
201                         _mode = Normal;
202                 }
203         } else {
204                 _mode = Normal;
205         }
206
207         if ((prop = node.property ("diskstream-id")) == 0) {
208                 
209                 /* some old sessions use the diskstream name rather than the ID */
210
211                 if ((prop = node.property ("diskstream")) == 0) {
212                         fatal << _("programming error: MidiTrack given state without diskstream!") << endmsg;
213                         /*NOTREACHED*/
214                         return -1;
215                 }
216
217                 if (use_diskstream (prop->value())) {
218                         return -1;
219                 }
220
221         } else {
222                 
223                 PBD::ID id (prop->value());
224                 
225                 if (use_diskstream (id)) {
226                         return -1;
227                 }
228         }
229
230
231         XMLNodeList nlist;
232         XMLNodeConstIterator niter;
233         XMLNode *child;
234
235         nlist = node.children();
236         for (niter = nlist.begin(); niter != nlist.end(); ++niter){
237                 child = *niter;
238
239                 if (child->name() == X_("remote_control")) {
240                         if ((prop = child->property (X_("id"))) != 0) {
241                                 int32_t x;
242                                 sscanf (prop->value().c_str(), "%d", &x);
243                                 set_remote_control_id (x);
244                         }
245                 }
246         }
247
248         pending_state = const_cast<XMLNode*> (&node);
249
250         _session.StateReady.connect (mem_fun (*this, &MidiTrack::set_state_part_two));
251
252         return 0;
253 }
254
255 XMLNode& 
256 MidiTrack::state(bool full_state)
257 {
258         XMLNode& root (Route::state(full_state));
259         XMLNode* freeze_node;
260         char buf[64];
261
262         if (_freeze_record.playlist) {
263                 XMLNode* inode;
264
265                 freeze_node = new XMLNode (X_("freeze-info"));
266                 freeze_node->add_property ("playlist", _freeze_record.playlist->name());
267                 snprintf (buf, sizeof (buf), "%d", (int) _freeze_record.state);
268                 freeze_node->add_property ("state", buf);
269
270                 for (vector<FreezeRecordInsertInfo*>::iterator i = _freeze_record.insert_info.begin(); i != _freeze_record.insert_info.end(); ++i) {
271                         inode = new XMLNode (X_("insert"));
272                         (*i)->id.print (buf);
273                         inode->add_property (X_("id"), buf);
274                         inode->add_child_copy ((*i)->state);
275                 
276                         freeze_node->add_child_nocopy (*inode);
277                 }
278
279                 root.add_child_nocopy (*freeze_node);
280         }
281
282         /* Alignment: act as a proxy for the diskstream */
283         
284         XMLNode* align_node = new XMLNode (X_("alignment"));
285         switch (_diskstream->alignment_style()) {
286         case ExistingMaterial:
287                 snprintf (buf, sizeof (buf), X_("existing"));
288                 break;
289         case CaptureTime:
290                 snprintf (buf, sizeof (buf), X_("capture"));
291                 break;
292         }
293         align_node->add_property (X_("style"), buf);
294         root.add_child_nocopy (*align_node);
295
296         XMLNode* remote_control_node = new XMLNode (X_("remote_control"));
297         snprintf (buf, sizeof (buf), "%d", _remote_control_id);
298         remote_control_node->add_property (X_("id"), buf);
299         root.add_child_nocopy (*remote_control_node);
300
301         switch (_mode) {
302         case Normal:
303                 root.add_property (X_("mode"), X_("normal"));
304                 break;
305         case Destructive:
306                 root.add_property (X_("mode"), X_("destructive"));
307                 break;
308         }
309
310         /* we don't return diskstream state because we don't
311            own the diskstream exclusively. control of the diskstream
312            state is ceded to the Session, even if we create the
313            diskstream.
314         */
315
316         _diskstream->id().print (buf);
317         root.add_property ("diskstream-id", buf);
318
319         return root;
320 }
321
322 void
323 MidiTrack::set_state_part_two ()
324 {
325         XMLNode* fnode;
326         XMLProperty* prop;
327         LocaleGuard lg (X_("POSIX"));
328
329         /* This is called after all session state has been restored but before
330            have been made ports and connections are established.
331         */
332
333         if (pending_state == 0) {
334                 return;
335         }
336
337         if ((fnode = find_named_node (*pending_state, X_("freeze-info"))) != 0) {
338
339                 
340                 _freeze_record.have_mementos = false;
341                 _freeze_record.state = Frozen;
342                 
343                 for (vector<FreezeRecordInsertInfo*>::iterator i = _freeze_record.insert_info.begin(); i != _freeze_record.insert_info.end(); ++i) {
344                         delete *i;
345                 }
346                 _freeze_record.insert_info.clear ();
347                 
348                 if ((prop = fnode->property (X_("playlist"))) != 0) {
349                         Playlist* pl = _session.playlist_by_name (prop->value());
350                         if (pl) {
351                                 _freeze_record.playlist = dynamic_cast<MidiPlaylist*> (pl);
352                         } else {
353                                 _freeze_record.playlist = 0;
354                                 _freeze_record.state = NoFreeze;
355                         return;
356                         }
357                 }
358                 
359                 if ((prop = fnode->property (X_("state"))) != 0) {
360                         _freeze_record.state = (FreezeState) atoi (prop->value().c_str());
361                 }
362                 
363                 XMLNodeConstIterator citer;
364                 XMLNodeList clist = fnode->children();
365                 
366                 for (citer = clist.begin(); citer != clist.end(); ++citer) {
367                         if ((*citer)->name() != X_("insert")) {
368                                 continue;
369                         }
370                         
371                         if ((prop = (*citer)->property (X_("id"))) == 0) {
372                                 continue;
373                         }
374                         
375                         FreezeRecordInsertInfo* frii = new FreezeRecordInsertInfo (*((*citer)->children().front()));
376                         frii->insert = 0;
377                         frii->id = prop->value ();
378                         _freeze_record.insert_info.push_back (frii);
379                 }
380         }
381
382         /* Alignment: act as a proxy for the diskstream */
383
384         if ((fnode = find_named_node (*pending_state, X_("alignment"))) != 0) {
385
386                 if ((prop = fnode->property (X_("style"))) != 0) {
387                         if (prop->value() == "existing") {
388                                 _diskstream->set_persistent_align_style (ExistingMaterial);
389                         } else if (prop->value() == "capture") {
390                                 _diskstream->set_persistent_align_style (CaptureTime);
391                         }
392                 }
393         }
394         return;
395 }       
396
397 uint32_t
398 MidiTrack::n_process_buffers ()
399 {
400         return max ((uint32_t) _diskstream->n_channels(), redirect_max_outs);
401 }
402
403 void
404 MidiTrack::passthru_silence (jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset, int declick, bool meter)
405 {
406         uint32_t nbufs = n_process_buffers ();
407         process_output_buffers (_session.get_silent_buffers (nbufs), nbufs, start_frame, end_frame, nframes, offset, true, declick, meter);
408 }
409
410 int 
411 MidiTrack::no_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t offset, 
412                      bool session_state_changing, bool can_record, bool rec_monitors_input)
413 {
414         if (n_outputs() == 0) {
415                 return 0;
416         }
417
418         if (!_active) {
419                 silence (nframes, offset);
420                 return 0;
421         }
422
423         if (session_state_changing) {
424
425                 /* XXX is this safe to do against transport state changes? */
426
427                 passthru_silence (start_frame, end_frame, nframes, offset, 0, false);
428                 return 0;
429         }
430
431         midi_diskstream().check_record_status (start_frame, nframes, can_record);
432
433         bool send_silence;
434         
435         if (_have_internal_generator) {
436                 /* since the instrument has no input streams,
437                    there is no reason to send any signal
438                    into the route.
439                 */
440                 send_silence = true;
441         } else {
442
443                 if (_session.get_auto_input()) {
444                         if (Config->get_use_sw_monitoring()) {
445                                 send_silence = false;
446                         } else {
447                                 send_silence = true;
448                         }
449                 } else {
450                         if (_diskstream->record_enabled()) {
451                                 if (Config->get_use_sw_monitoring()) {
452                                         send_silence = false;
453                                 } else {
454                                         send_silence = true;
455                                 }
456                         } else {
457                                 send_silence = true;
458                         }
459                 }
460         }
461
462         apply_gain_automation = false;
463
464         if (send_silence) {
465                 
466                 /* if we're sending silence, but we want the meters to show levels for the signal,
467                    meter right here.
468                 */
469                 
470                 if (_have_internal_generator) {
471                         passthru_silence (start_frame, end_frame, nframes, offset, 0, true);
472                 } else {
473                         if (_meter_point == MeterInput) {
474                                 just_meter_input (start_frame, end_frame, nframes, offset);
475                         }
476                         passthru_silence (start_frame, end_frame, nframes, offset, 0, false);
477                 }
478
479         } else {
480         
481                 /* we're sending signal, but we may still want to meter the input. 
482                  */
483
484                 passthru (start_frame, end_frame, nframes, offset, 0, (_meter_point == MeterInput));
485         }
486
487         return 0;
488 }
489
490 int
491 MidiTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t offset, int declick,
492                   bool can_record, bool rec_monitors_input)
493 {
494 #if 0
495         int dret;
496         Sample* b;
497         Sample* tmpb;
498         jack_nframes_t transport_frame;
499
500         {
501                 Glib::RWLock::ReaderLock lm (redirect_lock, Glib::TRY_LOCK);
502                 if (lm.locked()) {
503                         // automation snapshot can also be called from the non-rt context
504                         // and it uses the redirect list, so we take the lock out here
505                         automation_snapshot (start_frame);
506                 }
507         }
508         
509         if (n_outputs() == 0 && _redirects.empty()) {
510                 return 0;
511         }
512
513         if (!_active) {
514                 silence (nframes, offset);
515                 return 0;
516         }
517
518         transport_frame = _session.transport_frame();
519
520         if ((nframes = check_initial_delay (nframes, offset, transport_frame)) == 0) {
521                 /* need to do this so that the diskstream sets its
522                    playback distance to zero, thus causing diskstream::commit
523                    to do nothing.
524                 */
525                 return diskstream->process (transport_frame, 0, 0, can_record, rec_monitors_input);
526         } 
527
528         _silent = false;
529         apply_gain_automation = false;
530
531         if ((dret = diskstream->process (transport_frame, nframes, offset, can_record, rec_monitors_input)) != 0) {
532                 
533                 silence (nframes, offset);
534
535                 return dret;
536         }
537
538         /* special condition applies */
539         
540         if (_meter_point == MeterInput) {
541                 just_meter_input (start_frame, end_frame, nframes, offset);
542         }
543
544         if (diskstream->record_enabled() && !can_record && !_session.get_auto_input()) {
545
546                 /* not actually recording, but we want to hear the input material anyway,
547                    at least potentially (depending on monitoring options)
548                  */
549
550                 passthru (start_frame, end_frame, nframes, offset, 0, true);
551
552         } else if ((b = diskstream->playback_buffer(0)) != 0) {
553
554                 /*
555                   XXX is it true that the earlier test on n_outputs()
556                   means that we can avoid checking it again here? i think
557                   so, because changing the i/o configuration of an IO
558                   requires holding the AudioEngine lock, which we hold
559                   while in the process() tree.
560                 */
561
562                 
563                 /* copy the diskstream data to all output buffers */
564                 
565                 vector<Sample*>& bufs = _session.get_passthru_buffers ();
566                 uint32_t limit = n_process_buffers ();
567                 
568                 uint32_t n;
569                 uint32_t i;
570
571
572                 for (i = 0, n = 1; i < limit; ++i, ++n) {
573                         memcpy (bufs[i], b, sizeof (Sample) * nframes); 
574                         if (n < diskstream->n_channels()) {
575                                 tmpb = diskstream->playback_buffer(n);
576                                 if (tmpb!=0) {
577                                         b = tmpb;
578                                 }
579                         }
580                 }
581
582                 /* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
583
584                 if (!diskstream->record_enabled() && _session.transport_rolling()) {
585                         Glib::Mutex::Lock am (automation_lock, Glib::TRY_LOCK);
586                         
587                         if (am.locked() && gain_automation_playback()) {
588                                 apply_gain_automation = _gain_automation_curve.rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
589                         }
590                 }
591
592                 process_output_buffers (bufs, limit, start_frame, end_frame, nframes, offset, (!_session.get_record_enabled() || !_session.get_do_not_record_plugins()), declick, (_meter_point != MeterInput));
593                 
594         } else {
595                 /* problem with the diskstream; just be quiet for a bit */
596                 silence (nframes, offset);
597         }
598 #endif
599         return 0;
600 }
601
602 int
603 MidiTrack::silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t offset, 
604                          bool can_record, bool rec_monitors_input)
605 {
606         if (n_outputs() == 0 && _redirects.empty()) {
607                 return 0;
608         }
609
610         if (!_active) {
611                 silence (nframes, offset);
612                 return 0;
613         }
614
615         _silent = true;
616         apply_gain_automation = false;
617
618         silence (nframes, offset);
619
620         return midi_diskstream().process (_session.transport_frame() + offset, nframes, offset, can_record, rec_monitors_input);
621 }
622
623 int
624 MidiTrack::set_name (string str, void *src)
625 {
626         int ret;
627
628         if (record_enabled() && _session.actively_recording()) {
629                 /* this messes things up if done while recording */
630                 return -1;
631         }
632
633         if (_diskstream->set_name (str, src)) {
634                 return -1;
635         }
636
637         /* save state so that the statefile fully reflects any filename changes */
638
639         if ((ret = IO::set_name (str, src)) == 0) {
640                 _session.save_state ("");
641         }
642         return ret;
643 }
644
645 int
646 MidiTrack::export_stuff (vector<unsigned char*>& buffers, char * workbuf, uint32_t nbufs, jack_nframes_t start, jack_nframes_t nframes)
647 {
648 #if 0
649         gain_t  gain_automation[nframes];
650         gain_t  gain_buffer[nframes];
651         float   mix_buffer[nframes];
652         RedirectList::iterator i;
653         bool post_fader_work = false;
654         gain_t this_gain = _gain;
655         vector<Sample*>::iterator bi;
656         Sample * b;
657         
658         Glib::RWLock::ReaderLock rlock (redirect_lock);
659                 
660         if (diskstream->playlist()->read (buffers[0], mix_buffer, gain_buffer, workbuf, start, nframes) != nframes) {
661                 return -1;
662         }
663
664         uint32_t n=1;
665         bi = buffers.begin();
666         b = buffers[0];
667         ++bi;
668         for (; bi != buffers.end(); ++bi, ++n) {
669                 if (n < diskstream->n_channels()) {
670                         if (diskstream->playlist()->read ((*bi), mix_buffer, gain_buffer, workbuf, start, nframes, n) != nframes) {
671                                 return -1;
672                         }
673                         b = (*bi);
674                 }
675                 else {
676                         /* duplicate last across remaining buffers */
677                         memcpy ((*bi), b, sizeof (Sample) * nframes); 
678                 }
679         }
680
681
682         /* note: only run inserts during export. other layers in the machinery
683            will already have checked that there are no external port inserts.
684         */
685         
686         for (i = _redirects.begin(); i != _redirects.end(); ++i) {
687                 Insert *insert;
688                 
689                 if ((insert = dynamic_cast<Insert*>(*i)) != 0) {
690                         switch (insert->placement()) {
691                         case PreFader:
692                                 insert->run (buffers, nbufs, nframes, 0);
693                                 break;
694                         case PostFader:
695                                 post_fader_work = true;
696                                 break;
697                         }
698                 }
699         }
700         
701         if (_gain_automation_curve.automation_state() == Play) {
702                 
703                 _gain_automation_curve.get_vector (start, start + nframes, gain_automation, nframes);
704
705                 for (bi = buffers.begin(); bi != buffers.end(); ++bi) {
706                         Sample *b = *bi;
707                         for (jack_nframes_t n = 0; n < nframes; ++n) {
708                                 b[n] *= gain_automation[n];
709                         }
710                 }
711
712         } else {
713
714                 for (bi = buffers.begin(); bi != buffers.end(); ++bi) {
715                         Sample *b = *bi;
716                         for (jack_nframes_t n = 0; n < nframes; ++n) {
717                                 b[n] *= this_gain;
718                         }
719                 }
720         }
721
722         if (post_fader_work) {
723
724                 for (i = _redirects.begin(); i != _redirects.end(); ++i) {
725                         PluginInsert *insert;
726                         
727                         if ((insert = dynamic_cast<PluginInsert*>(*i)) != 0) {
728                                 switch ((*i)->placement()) {
729                                 case PreFader:
730                                         break;
731                                 case PostFader:
732                                         insert->run (buffers, nbufs, nframes, 0);
733                                         break;
734                                 }
735                         }
736                 }
737         } 
738 #endif
739         return 0;
740 }
741
742 void
743 MidiTrack::set_latency_delay (jack_nframes_t longest_session_latency)
744 {
745         Route::set_latency_delay (longest_session_latency);
746         _diskstream->set_roll_delay (_roll_delay);
747 }
748
749 void
750 MidiTrack::bounce (InterThreadInfo& itt)
751 {
752         //vector<MidiSource*> srcs;
753         //_session.write_one_midi_track (*this, 0, _session.current_end_frame(), false, srcs, itt);
754 }
755
756
757 void
758 MidiTrack::bounce_range (jack_nframes_t start, jack_nframes_t end, InterThreadInfo& itt)
759 {
760         //vector<MidiSource*> srcs;
761         //_session.write_one_midi_track (*this, start, end, false, srcs, itt);
762 }
763
764 void
765 MidiTrack::freeze (InterThreadInfo& itt)
766 {
767 #if 0
768         Insert* insert;
769         vector<MidiSource*> srcs;
770         string new_playlist_name;
771         Playlist* new_playlist;
772         string dir;
773         AudioRegion* region;
774         string region_name;
775         
776         if ((_freeze_record.playlist = diskstream->playlist()) == 0) {
777                 return;
778         }
779
780         uint32_t n = 1;
781
782         while (n < (UINT_MAX-1)) {
783          
784                 string candidate;
785                 
786                 candidate = string_compose ("<F%2>%1", _freeze_record.playlist->name(), n);
787
788                 if (_session.playlist_by_name (candidate) == 0) {
789                         new_playlist_name = candidate;
790                         break;
791                 }
792
793                 ++n;
794
795         } 
796
797         if (n == (UINT_MAX-1)) {
798           PBD::error << string_compose (X_("There Are too many frozen versions of playlist \"%1\""
799                             " to create another one"), _freeze_record.playlist->name())
800                << endmsg;
801                 return;
802         }
803
804         if (_session.write_one_midi_track (*this, 0, _session.current_end_frame(), true, srcs, itt)) {
805                 return;
806         }
807
808         _freeze_record.insert_info.clear ();
809         _freeze_record.have_mementos = true;
810
811         {
812                 Glib::RWLock::ReaderLock lm (redirect_lock);
813                 
814                 for (RedirectList::iterator r = _redirects.begin(); r != _redirects.end(); ++r) {
815                         
816                         if ((insert = dynamic_cast<Insert*>(*r)) != 0) {
817                                 
818                                 FreezeRecordInsertInfo* frii  = new FreezeRecordInsertInfo ((*r)->get_state());
819                                 
820                                 frii->insert = insert;
821                                 frii->id = insert->id();
822                                 frii->memento = (*r)->get_memento();
823                                 
824                                 _freeze_record.insert_info.push_back (frii);
825                                 
826                                 /* now deactivate the insert */
827                                 
828                                 insert->set_active (false, this);
829                         }
830                 }
831         }
832
833         new_playlist = new MidiPlaylist (_session, new_playlist_name, false);
834         region_name = new_playlist_name;
835
836         /* create a new region from all filesources, keep it private */
837
838         region = new AudioRegion (srcs, 0, srcs[0]->length(), 
839                                   region_name, 0, 
840                                   (AudioRegion::Flag) (AudioRegion::WholeFile|AudioRegion::DefaultFlags),
841                                   false);
842
843         new_playlist->set_orig_diskstream_id (diskstream->id());
844         new_playlist->add_region (*region, 0);
845         new_playlist->set_frozen (true);
846         region->set_locked (true);
847
848         diskstream->use_playlist (dynamic_cast<MidiPlaylist*>(new_playlist));
849         diskstream->set_record_enabled (false, this);
850
851         _freeze_record.state = Frozen;
852         FreezeChange(); /* EMIT SIGNAL */
853 #endif
854 }
855
856 void
857 MidiTrack::unfreeze ()
858 {
859 #if 0
860         if (_freeze_record.playlist) {
861                 diskstream->use_playlist (_freeze_record.playlist);
862
863                 if (_freeze_record.have_mementos) {
864
865                         for (vector<FreezeRecordInsertInfo*>::iterator i = _freeze_record.insert_info.begin(); i != _freeze_record.insert_info.end(); ++i) {
866                                 (*i)->memento ();
867                         }
868
869                 } else {
870
871                         Glib::RWLock::ReaderLock lm (redirect_lock); // should this be a write lock? jlc
872                         for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
873                                 for (vector<FreezeRecordInsertInfo*>::iterator ii = _freeze_record.insert_info.begin(); ii != _freeze_record.insert_info.end(); ++ii) {
874                                         if ((*ii)->id == (*i)->id()) {
875                                                 (*i)->set_state (((*ii)->state));
876                                                 break;
877                                         }
878                                 }
879                         }
880                 }
881                 
882                 _freeze_record.playlist = 0;
883         }
884 #endif
885         _freeze_record.state = UnFrozen;
886         FreezeChange (); /* EMIT SIGNAL */
887 }
888
889 void
890 MidiTrack::set_mode (TrackMode m)
891 {
892         if (_diskstream) {
893                 if (_mode != m) {
894                         _mode = m;
895                         _diskstream->set_destructive (m == Destructive);
896                         ModeChanged();
897                 }
898         }
899 }