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