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