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