improvements (?) for window visibility during session loading - time to test on linux
[ardour.git] / gtk2_ardour / editor_audio_import.cc
1 /*
2     Copyright (C) 2000-2006 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/time.h>
23 #include <errno.h>
24 #include <unistd.h>
25
26 #include <sndfile.h>
27
28 #include <pbd/pthread_utils.h>
29 #include <pbd/basename.h>
30 #include <pbd/shortpath.h>
31
32 #include <gtkmm2ext/choice.h>
33 #include <gtkmm2ext/window_title.h>
34
35 #include <ardour/session.h>
36 #include <ardour/audioplaylist.h>
37 #include <ardour/audioregion.h>
38 #include <ardour/audio_diskstream.h>
39 #include <ardour/utils.h>
40 #include <ardour/audio_track.h>
41 #include <ardour/audioplaylist.h>
42 #include <ardour/audiofilesource.h>
43 #include <ardour/region_factory.h>
44 #include <ardour/source_factory.h>
45 #include <pbd/memento_command.h>
46
47 #include "ardour_ui.h"
48 #include "editor.h"
49 #include "sfdb_ui.h"
50 #include "editing.h"
51 #include "audio_time_axis.h"
52 #include "utils.h"
53
54 #include "i18n.h"
55
56 using namespace std;
57 using namespace ARDOUR;
58 using namespace PBD;
59 using namespace sigc;
60 using namespace Gtk;
61 using namespace Gtkmm2ext;
62 using namespace Editing;
63 using Glib::ustring;
64
65 /* Functions supporting the incorporation of external (non-captured) audio material into ardour */
66
67 void
68 Editor::add_external_audio_action (ImportMode mode)
69 {
70 }
71
72 void
73 Editor::external_audio_dialog ()
74 {
75         vector<Glib::ustring> paths;
76
77         if (session == 0) {
78                 MessageDialog msg (0, _("You can't import or embed an audiofile until you have a session loaded."));
79                 msg.run ();
80                 return;
81         }
82         
83         if (sfbrowser == 0) {
84                 sfbrowser = new SoundFileOmega (*this, _("Add existing audio"), session, selection->tracks.size());
85         } else {
86                 sfbrowser->reset (selection->tracks.size());
87         }
88
89         sfbrowser->show_all ();
90
91   again:
92         int response = sfbrowser->run ();
93
94         switch (response) {
95         case RESPONSE_APPLY:
96                 // leave the dialog open
97                 break;
98
99         case RESPONSE_OK:
100                 sfbrowser->hide ();
101                 break;
102
103         default:
104                 // cancel from the browser - we are done
105                 sfbrowser->hide ();
106                 return;
107         }
108
109         /* lets do it */
110         
111         paths = sfbrowser->get_paths ();
112
113         ImportPosition pos = sfbrowser->get_position ();
114         ImportMode mode = sfbrowser->get_mode ();
115         ImportDisposition chns = sfbrowser->get_channel_disposition ();
116         nframes64_t where;
117
118         switch (pos) {
119         case ImportAtEditCursor:
120                 where = edit_cursor->current_frame;
121                 break;
122         case ImportAtTimestamp:
123                 where = -1;
124                 break;
125         case ImportAtPlayhead:
126                 where = playhead_cursor->current_frame;
127                 break;
128         case ImportAtStart:
129                 where = session->current_start_frame();
130                 break;
131         }
132
133         SrcQuality quality = sfbrowser->get_src_quality();
134
135         if (sfbrowser->copy_files_btn.get_active()) {
136                 do_import (paths, chns, mode, quality, where);
137         } else {
138                 do_embed (paths, chns, mode, where);
139         }
140
141         if (response == RESPONSE_APPLY) {
142                 sfbrowser->clear_selection ();
143                 goto again;
144         }
145 }
146
147 boost::shared_ptr<AudioTrack>
148 Editor::get_nth_selected_audio_track (int nth) const
149 {
150         AudioTimeAxisView* atv;
151         TrackSelection::iterator x;
152         
153         for (x = selection->tracks.begin(); nth > 0 && x != selection->tracks.end(); ++x) {
154                 if (dynamic_cast<AudioTimeAxisView*>(*x)) {
155                         --nth;
156                 }
157         }
158         
159         if (x == selection->tracks.end()) {
160                 atv = dynamic_cast<AudioTimeAxisView*>(selection->tracks.back());
161         } else {
162                 atv = dynamic_cast<AudioTimeAxisView*>(*x);
163         }
164         
165         if (!atv) {
166                 return boost::shared_ptr<AudioTrack>();
167         }
168         
169         return atv->audio_track();
170 }       
171
172 void
173 Editor::do_import (vector<ustring> paths, ImportDisposition chns, ImportMode mode, SrcQuality quality, nframes64_t& pos)
174 {
175         boost::shared_ptr<AudioTrack> track;
176         vector<ustring> to_import;
177         bool ok = false;
178         int nth = 0;
179
180         if (interthread_progress_window == 0) {
181                 build_interthread_progress_window ();
182         }
183
184         switch (chns) {
185         case Editing::ImportDistinctFiles:
186                 for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
187
188                         to_import.clear ();
189                         to_import.push_back (*a);
190
191                         if (mode == Editing::ImportToTrack) {
192                                 track = get_nth_selected_audio_track (nth++);
193                         }
194                         
195                         if (import_sndfiles (to_import, mode, quality, pos, 1, -1, track)) {
196                                 goto out;
197                         }
198
199                 }
200                 break;
201
202         case Editing::ImportDistinctChannels:
203                 for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
204
205                         to_import.clear ();
206                         to_import.push_back (*a);
207
208                         if (import_sndfiles (to_import, mode, quality, pos, -1, -1, track)) {
209                                 goto out;
210                         }
211
212                 }
213                 break;
214
215         case Editing::ImportMergeFiles:
216                 /* create 1 region from all paths, add to 1 track,
217                    ignore "track"
218                 */
219                 if (import_sndfiles (paths, mode, quality, pos, 1, 1, track)) {
220                         goto out;
221                 }
222                 break;
223
224         case Editing::ImportSerializeFiles:
225                 for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
226
227                         to_import.clear ();
228                         to_import.push_back (*a);
229                         
230                         /* create 1 region from this path, add to 1 track,
231                            reuse "track" across paths
232                         */
233
234                         if (import_sndfiles (to_import, mode, quality, pos, 1, 1, track)) {
235                                 goto out;
236                         }
237
238                 }
239                 break;
240         }
241
242         ok = true;
243         
244   out:  
245         if (ok) {
246                 session->save_state ("");
247         }
248
249         interthread_progress_window->hide_all ();
250 }
251
252 bool
253 Editor::idle_do_embed (vector<ustring> paths, ImportDisposition chns, ImportMode mode, nframes64_t& pos)
254 {
255         _do_embed (paths, chns, mode, pos);
256         return false;
257 }
258
259 void
260 Editor::do_embed (vector<ustring> paths, ImportDisposition chns, ImportMode mode, nframes64_t& pos)
261 {
262 #ifdef GTKOSX
263         Glib::signal_idle().connect (bind (mem_fun (*this, &Editor::idle_do_embed), paths, chns, mode, pos));
264 #else
265         _do_embed (paths, chns, mode, pos);
266 #endif
267 }
268
269 void
270 Editor::_do_embed (vector<ustring> paths, ImportDisposition chns, ImportMode mode, nframes64_t& pos)
271 {
272         boost::shared_ptr<AudioTrack> track;
273         bool check_sample_rate = true;
274         bool ok = false;
275         vector<ustring> to_embed;
276         bool multi = paths.size() > 1;
277         int nth = 0;
278
279         switch (chns) {
280         case Editing::ImportDistinctFiles:
281                 for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
282
283                         to_embed.clear ();
284                         to_embed.push_back (*a);
285
286                         if (mode == Editing::ImportToTrack) {
287                                 track = get_nth_selected_audio_track (nth++);
288                         }
289
290                         if (embed_sndfiles (to_embed, multi, check_sample_rate, mode, pos, 1, -1, track) < -1) {
291                                 goto out;
292                         }
293                 }
294                 break;
295                 
296         case Editing::ImportDistinctChannels:
297                 for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
298
299                         to_embed.clear ();
300                         to_embed.push_back (*a);
301
302                         if (embed_sndfiles (to_embed, multi, check_sample_rate, mode, pos, -1, -1, track) < -1) {
303                                 goto out;
304                         }
305                 }
306                 break;
307
308         case Editing::ImportMergeFiles:
309                 if (embed_sndfiles (paths, multi, check_sample_rate, mode, pos, 1, 1, track) < -1) {
310                         goto out;
311                 }
312         break;
313
314         case Editing::ImportSerializeFiles:
315                 for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
316
317                         to_embed.clear ();
318                         to_embed.push_back (*a);
319
320                         if (embed_sndfiles (to_embed, multi, check_sample_rate, mode, pos, 1, 1, track) < -1) {
321                                 goto out;
322                         }
323                 }
324                 break;
325         }
326
327         ok = true;
328         
329   out:  
330         if (ok) {
331                 session->save_state ("");
332         }
333 }
334
335 int
336 Editor::import_sndfiles (vector<ustring> paths, ImportMode mode, SrcQuality quality, nframes64_t& pos, 
337                          int target_regions, int target_tracks, boost::shared_ptr<AudioTrack>& track)
338 {
339         WindowTitle title = string_compose (_("importing %1"), paths.front());
340
341         interthread_progress_window->set_title (title.get_string());
342         interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
343         interthread_progress_window->show_all ();
344         interthread_progress_bar.set_fraction (0.0f);
345         interthread_cancel_label.set_text (_("Cancel Import"));
346         current_interthread_info = &import_status;
347
348         import_status.paths = paths;
349         import_status.done = false;
350         import_status.cancel = false;
351         import_status.freeze = false;
352         import_status.done = 0.0;
353         import_status.quality = quality;
354
355         interthread_progress_connection = Glib::signal_timeout().connect 
356                 (bind (mem_fun(*this, &Editor::import_progress_timeout), (gpointer) 0), 100);
357         
358         track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
359         ARDOUR_UI::instance()->flush_pending ();
360
361         /* start import thread for this spec. this will ultimately call Session::import_audiofile()
362            and if successful will add the file(s) as a region to the session region list.
363         */
364         
365         pthread_create_and_store ("import", &import_status.thread, 0, _import_thread, this);
366         pthread_detach (import_status.thread);
367         
368         while (!(import_status.done || import_status.cancel)) {
369                 gtk_main_iteration ();
370         }
371
372         interthread_progress_window->hide ();
373         
374         import_status.done = true;
375         interthread_progress_connection.disconnect ();
376         
377         /* import thread finished - see if we should build a new track */
378
379         boost::shared_ptr<AudioRegion> r;
380         
381         if (import_status.cancel || import_status.sources.empty()) {
382                 goto out;
383         }
384
385         if (add_sources (paths, import_status.sources, pos, mode, target_regions, target_tracks, track, false) == 0) {
386                 session->save_state ("");
387         }
388
389   out:
390         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
391         return 0;
392 }
393
394 int
395 Editor::embed_sndfiles (vector<Glib::ustring> paths, bool multifile,
396                         bool& check_sample_rate, ImportMode mode, nframes64_t& pos, int target_regions, int target_tracks,
397                         boost::shared_ptr<AudioTrack>& track)
398 {
399         boost::shared_ptr<AudioFileSource> source;
400         SourceList sources;
401         string linked_path;
402         SoundFileInfo finfo;
403         int ret = 0;
404
405         track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
406         ARDOUR_UI::instance()->flush_pending ();
407
408         for (vector<Glib::ustring>::iterator p = paths.begin(); p != paths.end(); ++p) {
409
410                 ustring path = *p;
411
412                 /* lets see if we can link it into the session */
413                 
414                 linked_path = session->sound_dir();
415                 linked_path += '/';
416                 linked_path += Glib::path_get_basename (path);
417                 
418                 if (link (path.c_str(), linked_path.c_str()) == 0) {
419
420                         /* there are many reasons why link(2) might have failed.
421                            but if it succeeds, we now have a link in the
422                            session sound dir that will protect against
423                            unlinking of the original path. nice.
424                         */
425                         
426                         path = linked_path;
427
428                 } else {
429
430                         /* one possible reason is that its already linked */
431
432                         if (errno == EEXIST) {
433                                 struct stat sb;
434
435                                 if (stat (linked_path.c_str(), &sb) == 0) {
436                                         if (sb.st_nlink > 1) { // its a hard link, assume its the one we want
437                                                 path = linked_path;
438                                         }
439                                 }
440                         }
441                 }
442                 
443                 /* note that we temporarily truncated _id at the colon */
444                 
445                 string error_msg;
446
447                 if (!AudioFileSource::get_soundfile_info (path, finfo, error_msg)) {
448                         error << string_compose(_("Editor: cannot open file \"%1\", (%2)"), path, error_msg ) << endmsg;
449                         goto out;
450                 }
451                 
452                 if (check_sample_rate  && (finfo.samplerate != (int) session->frame_rate())) {
453                         vector<string> choices;
454                         
455                         if (multifile) {
456                                 choices.push_back (_("Cancel entire import"));
457                                 choices.push_back (_("Don't embed it"));
458                                 choices.push_back (_("Embed all without questions"));
459                         
460                                 Gtkmm2ext::Choice rate_choice (
461                                         string_compose (_("%1\nThis audiofile's sample rate doesn't match the session sample rate!"), 
462                                                         short_path (path, 40)),
463                                         choices, false);
464                                 
465                                 int resx = rate_choice.run ();
466                                 
467                                 switch (resx) {
468                                 case 0: /* stop a multi-file import */
469                                         ret = -2;
470                                         goto out;
471                                 case 1: /* don't embed this one */
472                                         ret = -1;
473                                         goto out;
474                                 case 2: /* do it, and the rest without asking */
475                                         check_sample_rate = false;
476                                         break;
477                                 case 3: /* do it */
478                                         break;
479                                 default:
480                                         ret = -2;
481                                         goto out;
482                                 }
483                         } else {
484                                 choices.push_back (_("Cancel"));
485                                 choices.push_back (_("Embed it anyway"));
486                         
487                                 Gtkmm2ext::Choice rate_choice (
488                                         string_compose (_("%1\nThis audiofile's sample rate doesn't match the session sample rate!"), path),
489                                         choices, false);
490                                 
491                                 int resx = rate_choice.run ();
492                                 
493                                 switch (resx) {
494                                 case 0: /* don't import */
495                                         ret = -1;
496                                         goto out;
497                                 case 1: /* do it */
498                                         break;
499                                 default:
500                                         ret = -2;
501                                         goto out;
502                                 }
503                         }
504                 }
505                 
506                 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
507
508                 for (int n = 0; n < finfo.channels; ++n) {
509                         try {
510
511                                 /* check if we have this thing embedded already */
512
513                                 boost::shared_ptr<Source> s;
514
515                                 if ((s = session->source_by_path_and_channel (path, n)) == 0) {
516                                         source = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable 
517                                                                                                (*session, path,  n,
518                                                                                                 (mode == ImportAsTapeTrack ? 
519                                                                                                  AudioFileSource::Destructive : 
520                                                                                                  AudioFileSource::Flag (0)),
521                                                                                                 true, true));
522                                 } else {
523                                         source = boost::dynamic_pointer_cast<AudioFileSource> (s);
524                                 }
525
526                                 sources.push_back(source);
527                         } 
528                         
529                         catch (failed_constructor& err) {
530                                 error << string_compose(_("could not open %1"), path) << endmsg;
531                                 goto out;
532                         }
533                         
534                         ARDOUR_UI::instance()->flush_pending ();
535                 }
536         }
537
538         if (sources.empty()) {
539                 goto out;
540         }
541
542         ret = add_sources (paths, sources, pos, mode, target_regions, target_tracks, track, true);
543
544   out:
545         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
546         return ret;
547 }
548
549 int
550 Editor::add_sources (vector<Glib::ustring> paths, SourceList& sources, nframes64_t& pos, ImportMode mode, 
551                      int target_regions, int target_tracks, boost::shared_ptr<AudioTrack>& track, bool add_channel_suffix)
552 {
553         vector<boost::shared_ptr<AudioRegion> > regions;
554         ustring region_name;
555         uint32_t input_chan = 0;
556         uint32_t output_chan = 0;
557
558         if (pos == -1) { // "use timestamp"
559                 if (sources[0]->natural_position() != 0) {
560                         pos = sources[0]->natural_position();
561                 } else {
562                         // XXX is this the best alternative ?
563                         pos = edit_cursor->current_frame;
564                 }
565         }
566
567         if (target_regions == 1) {
568
569                 /* take all the sources we have and package them up as a region */
570
571                 region_name = region_name_from_path (paths.front(), (sources.size() > 1), false);
572                 
573                 regions.push_back (boost::dynamic_pointer_cast<AudioRegion> 
574                                    (RegionFactory::create (sources, 0, sources[0]->length(), region_name, 0,
575                                                            Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External))));
576                 
577         } else if (target_regions == -1) {
578
579                 /* take each source and create a region for each one */
580
581                 SourceList just_one;
582                 SourceList::iterator x;
583                 uint32_t n;
584
585                 for (n = 0, x = sources.begin(); x != sources.end(); ++x, ++n) {
586
587                         just_one.clear ();
588                         just_one.push_back (*x);
589                         
590                         boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (*x);
591
592                         region_name = region_name_from_path (afs->path(), false, true, sources.size(), n);
593
594                         regions.push_back (boost::dynamic_pointer_cast<AudioRegion> 
595                                            (RegionFactory::create (just_one, 0, (*x)->length(), region_name, 0,
596                                                                    Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External))));
597
598                 }
599         }
600
601         if (target_regions == 1) {
602                 input_chan = regions.front()->n_channels();
603         } else {
604                 if (target_tracks == 1) {
605                         input_chan = regions.size();
606                 } else {
607                         input_chan = 1;
608                 }
609         }
610
611         if (Config->get_output_auto_connect() & AutoConnectMaster) {
612                 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
613         } else {
614                 output_chan = input_chan;
615         }
616
617         int n = 0;
618
619         for (vector<boost::shared_ptr<AudioRegion> >::iterator r = regions.begin(); r != regions.end(); ++r, ++n) {
620
621                 finish_bringing_in_audio (*r, input_chan, output_chan, pos, mode, track);
622
623                 if (target_tracks != 1) {
624                         track.reset ();
625                 } else {
626                         pos += (*r)->length();
627                 } 
628         }
629
630         /* setup peak file building in another thread */
631
632         for (SourceList::iterator x = sources.begin(); x != sources.end(); ++x) {
633                 SourceFactory::setup_peakfile (*x, true);
634         }
635
636         return 0;
637 }
638         
639 int
640 Editor::finish_bringing_in_audio (boost::shared_ptr<AudioRegion> region, uint32_t in_chans, uint32_t out_chans, nframes64_t& pos, 
641                                   ImportMode mode, boost::shared_ptr<AudioTrack>& existing_track)
642 {
643         switch (mode) {
644         case ImportAsRegion:
645                 /* relax, its been done */
646                 break;
647                 
648         case ImportToTrack:
649         {
650                 if (!existing_track) {
651
652                         if (selection->tracks.empty()) {
653                                 return -1;
654                         }
655                         
656                         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(selection->tracks.front());
657                         
658                         if (!atv) {
659                                 return -1;
660                         }
661                         
662                         existing_track = atv->audio_track();
663                 }
664
665                 boost::shared_ptr<Playlist> playlist = existing_track->diskstream()->playlist();
666                 boost::shared_ptr<AudioRegion> copy (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region)));
667                 begin_reversible_command (_("insert sndfile"));
668                 XMLNode &before = playlist->get_state();
669                 playlist->add_region (copy, pos);
670                 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
671                 commit_reversible_command ();
672                 break;
673         }
674
675         case ImportAsTrack:
676         { 
677                 if (!existing_track) {
678                         list<boost::shared_ptr<AudioTrack> > at (session->new_audio_track (in_chans, out_chans, Normal, 1));
679
680                         if (at.empty()) {
681                                 return -1;
682                         }
683
684                         existing_track = at.front();
685                         existing_track->set_name (region->name(), this);
686                 }
687
688                 boost::shared_ptr<AudioRegion> copy (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region)));
689                 existing_track->diskstream()->playlist()->add_region (copy, pos);
690                 break;
691         }
692
693
694         case ImportAsTapeTrack:
695         {
696                 list<boost::shared_ptr<AudioTrack> > at (session->new_audio_track (in_chans, out_chans, Destructive));
697                 if (!at.empty()) {
698                         boost::shared_ptr<AudioRegion> copy (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region)));
699                         at.front()->set_name (basename_nosuffix (copy->name()), this);
700                         at.front()->diskstream()->playlist()->add_region (copy, pos);
701                 }
702                 break;
703         }
704         }
705
706         return 0;
707 }
708
709 void *
710 Editor::_import_thread (void *arg)
711 {
712         PBD::ThreadCreated (pthread_self(), X_("Import"));
713
714         Editor *ed = (Editor *) arg;
715         return ed->import_thread ();
716 }
717
718 void *
719 Editor::import_thread ()
720 {
721         session->import_audiofile (import_status);
722         pthread_exit_pbd (0);
723         /*NOTREACHED*/
724         return 0;
725 }
726
727 gint
728 Editor::import_progress_timeout (void *arg)
729 {
730         interthread_progress_label.set_text (import_status.doing_what);
731
732         if (import_status.freeze) {
733                 interthread_cancel_button.set_sensitive(false);
734         } else {
735                 interthread_cancel_button.set_sensitive(true);
736         }
737
738         if (import_status.doing_what == "building peak files") {
739                 interthread_progress_bar.pulse ();
740                 return FALSE;
741         } else {
742                 interthread_progress_bar.set_fraction (import_status.progress);
743         }
744
745         return !(import_status.done || import_status.cancel);
746 }
747