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