Add a stock question image to the choices dialog, other general dialog love.. Forgot...
[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     $Id$
19 */
20
21 #include <pbd/pthread_utils.h>
22 #include <pbd/basename.h>
23
24 #include <gtkmm2ext/choice.h>
25
26 #include <ardour/session.h>
27 #include <ardour/audioplaylist.h>
28 #include <ardour/audioregion.h>
29 #include <ardour/diskstream.h>
30 #include <ardour/filesource.h>
31 #include <ardour/externalsource.h>
32 #include <ardour/utils.h>
33 #include <ardour/audio_track.h>
34 #include <ardour/audioplaylist.h>
35
36 #include "ardour_ui.h"
37 #include "editor.h"
38 #include "sfdb_ui.h"
39 #include "editing.h"
40 #include "audio_time_axis.h"
41
42 #include "i18n.h"
43
44 using namespace std;
45 using namespace ARDOUR;
46 using namespace sigc;
47 using namespace Gtk;
48 using namespace Editing;
49
50 /* Functions supporting the incorporation of external (non-captured) audio material into ardour */
51
52 void
53 Editor::add_external_audio_action (ImportMode mode)
54 {
55         jack_nframes_t& pos = edit_cursor->current_frame;
56         AudioTrack* track = 0;
57
58         if (!selection->tracks.empty()) {
59                 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(selection->tracks.front());
60                 if (atv) {
61                         track = atv->audio_track();
62                 }
63         }
64
65         bring_in_external_audio (mode, track, pos, false);
66 }
67
68 void
69 Editor::bring_in_external_audio (ImportMode mode, AudioTrack* track, jack_nframes_t& pos, bool prompt)
70 {
71         if (session == 0) {
72                 MessageDialog msg (0, _("You can't import or embed an audiofile until you have a session loaded."));
73                 msg.run ();
74                 return;
75         }
76
77         SoundFileOmega sfdb (_("Add existing audio to session"));
78         sfdb.set_session (session);
79         sfdb.set_mode (mode);
80
81         switch (sfdb.run()) {
82         case SoundFileOmega::ResponseImport:
83                 do_import (sfdb.get_paths(), sfdb.get_split(), mode, track, pos, prompt);
84                 break;
85                 
86         case SoundFileOmega::ResponseEmbed:
87                 do_embed (sfdb.get_paths(), sfdb.get_split(), mode, track, pos, prompt);
88                 break;
89
90         default:
91                 break;
92         }
93 }
94
95 void
96 Editor::do_import (vector<Glib::ustring> paths, bool split, ImportMode mode, AudioTrack* track, jack_nframes_t& pos, bool prompt)
97 {
98         /* SFDB sets "multichan" to true to indicate "split channels"
99            so reverse the setting to match the way libardour
100            interprets it.
101         */
102         
103         import_status.multichan = !split;
104
105         if (interthread_progress_window == 0) {
106                 build_interthread_progress_window ();
107         }
108         
109         /* for each path that was selected, import it and then potentially create a new track
110            containing the new region as the sole contents.
111         */
112
113         for (vector<Glib::ustring>::iterator i = paths.begin(); i != paths.end(); ++i ) {
114                 import_sndfile (*i, mode, track, pos);
115         }
116
117         interthread_progress_window->hide_all ();
118 }
119
120 void
121 Editor::do_embed (vector<Glib::ustring> paths, bool split, ImportMode mode, AudioTrack* track, jack_nframes_t& pos, bool prompt)
122 {
123         bool multiple_files = paths.size() > 1;
124         bool check_sample_rate = true;
125         vector<Glib::ustring>::iterator i;
126         
127         for (i = paths.begin(); i != paths.end(); ++i) {
128                 int ret = embed_sndfile (*i, split, multiple_files, check_sample_rate, mode, track, pos, prompt);
129
130                 if (ret < -1) {
131                         break;
132                 }
133         }
134
135         if (i == paths.end()) {
136                 session->save_state ("");
137         }
138 }
139
140 int
141 Editor::import_sndfile (Glib::ustring path, ImportMode mode, AudioTrack* track, jack_nframes_t& pos)
142 {
143         interthread_progress_window->set_title (string_compose (_("ardour: importing %1"), path));
144         interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
145         interthread_progress_window->show_all ();
146         interthread_progress_bar.set_fraction (0.0f);
147         interthread_cancel_label.set_text (_("Cancel Import"));
148         current_interthread_info = &import_status;
149
150         import_status.pathname = path;
151         import_status.done = false;
152         import_status.cancel = false;
153         import_status.freeze = false;
154         import_status.done = 0.0;
155         
156         interthread_progress_connection = Glib::signal_timeout().connect 
157                 (bind (mem_fun(*this, &Editor::import_progress_timeout), (gpointer) 0), 100);
158         
159         track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
160         ARDOUR_UI::instance()->flush_pending ();
161
162         /* start import thread for this path. this will ultimately call Session::import_audiofile()
163            and if successful will add the file as a region to the session region list.
164         */
165         
166         pthread_create_and_store ("import", &import_status.thread, 0, _import_thread, this);
167         pthread_detach (import_status.thread);
168         
169         while (!(import_status.done || import_status.cancel)) {
170                 gtk_main_iteration ();
171         }
172         
173         import_status.done = true;
174         interthread_progress_connection.disconnect ();
175         
176         /* import thread finished - see if we should build a new track */
177         
178         if (!import_status.new_regions.empty()) {
179                 AudioRegion& region (*import_status.new_regions.front());
180                 finish_bringing_in_audio (region, region.n_channels(), region.n_channels(), track, pos, mode);
181         }
182
183         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
184         return 0;
185 }
186
187 int
188 Editor::embed_sndfile (Glib::ustring path, bool split, bool multiple_files, bool& check_sample_rate, ImportMode mode, 
189                        AudioTrack* track, jack_nframes_t& pos, bool prompt)
190 {
191         ExternalSource *source = 0; /* keep g++ quiet */
192         AudioRegion::SourceList sources;
193         AudioRegion* region;
194         string idspec;
195         string linked_path;
196         SoundFileInfo finfo;
197         string region_name;
198         uint32_t input_chan;
199         uint32_t output_chan;
200
201         track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
202         ARDOUR_UI::instance()->flush_pending ();
203
204         /* lets see if we can link it into the session */
205         
206         linked_path = session->sound_dir();
207         linked_path += PBD::basename (path);
208
209         if (link (path.c_str(), linked_path.c_str()) == 0) {
210
211                 /* there are many reasons why link(2) might have failed.
212                    but if it succeeds, we now have a link in the
213                    session sound dir that will protect against
214                    unlinking of the original path. nice.
215                 */
216
217                 path = linked_path;
218         }
219
220         /* note that we temporarily truncated _id at the colon */
221
222         string error_msg;
223
224         if (!ExternalSource::get_soundfile_info (path, finfo, error_msg)) {
225                 error << string_compose(_("Editor: cannot open file \"%1\", (%2)"), selection, error_msg ) << endmsg;
226                 return 0;
227         }
228         
229         if (check_sample_rate  && (finfo.samplerate != (int) session->frame_rate())) {
230                 vector<string> choices;
231                 
232                 if (multiple_files) {
233                         choices.push_back (_("Cancel entire import"));
234                         choices.push_back (_("Don't embed it"));
235                         choices.push_back (_("Embed all without questions"));
236                 } else {
237                         choices.push_back (_("Cancel"));
238                 }
239
240                 choices.push_back (_("Embed it anyway"));
241                 
242                 Gtkmm2ext::Choice rate_choice (
243                         string_compose (_("%1\nThis audiofile's sample rate doesn't match the session sample rate!"), path),
244                         choices, false);
245                 
246                 switch (rate_choice.run()) {
247                 case 0: /* stop a multi-file import */
248                 case 1: /* don't import this one */
249                         return -1;
250                 case 2: /* do it, and the rest without asking */
251                         check_sample_rate = false;
252                         break;
253                 case 3: /* do it */
254                         break;
255                 default:
256                         return -2;
257                 }
258         }
259         
260         track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
261         ARDOUR_UI::instance()->flush_pending ();
262         
263         /* make the proper number of channels in the region */
264
265         for (int n = 0; n < finfo.channels; ++n)
266         {
267                 idspec = path;
268                 idspec += string_compose(":%1", n);
269                 
270                 try {
271                         source = ExternalSource::create (idspec.c_str());
272                         sources.push_back(source);
273                 } 
274                 
275                  catch (failed_constructor& err) {
276                          error << string_compose(_("could not open %1"), path) << endmsg;
277                          goto out;
278                  }
279                 
280                  ARDOUR_UI::instance()->flush_pending ();
281         }
282         
283         if (sources.empty()) {
284                 goto out;
285         }
286         
287         region_name = PBD::basename_nosuffix (path);
288         region_name += "-0";
289         
290         region = new AudioRegion (sources, 0, sources[0]->length(), region_name, 0,
291                                   Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External));
292         
293         input_chan = finfo.channels;
294
295         if (session->get_output_auto_connect() & Session::AutoConnectMaster) {
296                 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
297         } else {
298                 output_chan = input_chan;
299         }
300         
301         finish_bringing_in_audio (*region, input_chan, output_chan, track, pos, mode);
302         
303   out:
304         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
305         return 0;
306 }
307
308 int
309  Editor::finish_bringing_in_audio (AudioRegion& region, uint32_t in_chans, uint32_t out_chans, AudioTrack* track, jack_nframes_t& pos, ImportMode mode)
310  {
311          switch (mode) {
312          case ImportAsRegion:
313                  /* relax, its been done */
314                  break;
315                 
316         case ImportToTrack:
317                 if (track) {
318                         Playlist* playlist  = track->disk_stream().playlist();
319                         
320                         AudioRegion* copy = new AudioRegion (region);
321                         begin_reversible_command (_("insert sndfile"));
322                         session->add_undo (playlist->get_memento());
323                         playlist->add_region (*copy, pos);
324                         session->add_redo_no_execute (playlist->get_memento());
325                         commit_reversible_command ();
326
327                         pos += region.length();
328                 }
329                 break;
330                 
331         case ImportAsTrack:
332                 AudioTrack* at = session->new_audio_track (in_chans, out_chans);
333                 AudioRegion* copy = new AudioRegion (region);
334                 at->disk_stream().playlist()->add_region (*copy, pos);
335                 break;
336         }
337
338         return 0;
339 }
340
341 void *
342 Editor::_import_thread (void *arg)
343 {
344         PBD::ThreadCreated (pthread_self(), X_("Import"));
345
346         Editor *ed = (Editor *) arg;
347         return ed->import_thread ();
348 }
349
350 void *
351 Editor::import_thread ()
352 {
353         session->import_audiofile (import_status);
354         pthread_exit_pbd (0);
355         /*NOTREACHED*/
356         return 0;
357 }
358
359 gint
360 Editor::import_progress_timeout (void *arg)
361 {
362         interthread_progress_label.set_text (import_status.doing_what);
363
364         if (import_status.freeze) {
365                 interthread_cancel_button.set_sensitive(false);
366         } else {
367                 interthread_cancel_button.set_sensitive(true);
368         }
369
370         if (import_status.doing_what == "building peak files") {
371                 interthread_progress_bar.pulse ();
372                 return FALSE;
373         } else {
374                 interthread_progress_bar.set_fraction (import_status.progress);
375         }
376
377         return !(import_status.done || import_status.cancel);
378 }
379