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