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