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