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