fix crash bug caused by incorrectly setting transience of audio clocks in the SoundFi...
[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 <sys/time.h>
23 #include <errno.h>
24 #include <unistd.h>
25
26 #include <sndfile.h>
27
28 #include <pbd/pthread_utils.h>
29 #include <pbd/basename.h>
30 #include <pbd/shortpath.h>
31
32 #include <gtkmm2ext/choice.h>
33 #include <gtkmm2ext/window_title.h>
34
35 #include <ardour/session.h>
36 #include <ardour/audioplaylist.h>
37 #include <ardour/audioregion.h>
38 #include <ardour/audio_diskstream.h>
39 #include <ardour/utils.h>
40 #include <ardour/audio_track.h>
41 #include <ardour/audioplaylist.h>
42 #include <ardour/audiofilesource.h>
43 #include <ardour/region_factory.h>
44 #include <ardour/source_factory.h>
45 #include <pbd/memento_command.h>
46
47 #include "ardour_ui.h"
48 #include "editor.h"
49 #include "sfdb_ui.h"
50 #include "editing.h"
51 #include "audio_time_axis.h"
52 #include "utils.h"
53
54 #include "i18n.h"
55
56 using namespace std;
57 using namespace ARDOUR;
58 using namespace PBD;
59 using namespace sigc;
60 using namespace Gtk;
61 using namespace Gtkmm2ext;
62 using namespace Editing;
63 using Glib::ustring;
64
65 /* Functions supporting the incorporation of external (non-captured) audio material into ardour */
66
67 void
68 Editor::add_external_audio_action (ImportMode mode_hint)
69 {
70         if (session == 0) {
71                 MessageDialog msg (0, _("You can't import or embed an audiofile until you have a session loaded."));
72                 msg.run ();
73                 return;
74         }
75         
76         if (sfbrowser == 0) {
77                 sfbrowser = new SoundFileOmega (*this, _("Add existing audio"), session, 0, true, mode_hint);
78         } else {
79                 sfbrowser->set_mode (mode_hint);
80         }
81
82         external_audio_dialog ();
83 }
84
85 void
86 Editor::external_audio_dialog ()
87 {
88         vector<Glib::ustring> paths;
89         uint32_t track_cnt;
90
91         if (session == 0) {
92                 MessageDialog msg (0, _("You can't import or embed an audiofile until you have a session loaded."));
93                 msg.run ();
94                 return;
95         }
96         
97         track_cnt = 0;
98
99         for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
100                 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*x);
101                 
102                 if (!atv) {
103                         continue;
104                 } else if (atv->is_audio_track()) {
105                         track_cnt++;
106                 }
107         }
108
109         if (sfbrowser == 0) {
110                 sfbrowser = new SoundFileOmega (*this, _("Add existing audio"), session, track_cnt, true);
111         } else {
112                 sfbrowser->reset (track_cnt);
113         }
114
115         sfbrowser->show_all ();
116
117   again:
118         int response = sfbrowser->run ();
119
120         switch (response) {
121         case RESPONSE_APPLY:
122                 // leave the dialog open
123                 break;
124
125         case RESPONSE_OK:
126                 sfbrowser->hide ();
127                 break;
128
129         default:
130                 // cancel from the browser - we are done
131                 sfbrowser->hide ();
132                 return;
133         }
134
135         /* lets do it */
136         
137         paths = sfbrowser->get_paths ();
138
139         ImportPosition pos = sfbrowser->get_position ();
140         ImportMode mode = sfbrowser->get_mode ();
141         ImportDisposition chns = sfbrowser->get_channel_disposition ();
142         nframes64_t where;
143
144         switch (pos) {
145         case ImportAtEditCursor:
146                 where = edit_cursor->current_frame;
147                 break;
148         case ImportAtTimestamp:
149                 where = -1;
150                 break;
151         case ImportAtPlayhead:
152                 where = playhead_cursor->current_frame;
153                 break;
154         case ImportAtStart:
155                 where = session->current_start_frame();
156                 break;
157         }
158
159         SrcQuality quality = sfbrowser->get_src_quality();
160
161         if (sfbrowser->copy_files_btn.get_active()) {
162                 do_import (paths, chns, mode, quality, where);
163         } else {
164                 do_embed (paths, chns, mode, where);
165         }
166
167         if (response == RESPONSE_APPLY) {
168                 sfbrowser->clear_selection ();
169                 goto again;
170         }
171 }
172
173 boost::shared_ptr<AudioTrack>
174 Editor::get_nth_selected_audio_track (int nth) const
175 {
176         AudioTimeAxisView* atv;
177         TrackSelection::iterator x;
178         
179         for (x = selection->tracks.begin(); nth > 0 && x != selection->tracks.end(); ++x) {
180
181                 atv = dynamic_cast<AudioTimeAxisView*>(*x);
182                 
183                 if (!atv) {
184                         continue;
185                 } else if (atv->is_audio_track()) {
186                         --nth;
187                 }
188         }
189         
190         if (x == selection->tracks.end()) {
191                 atv = dynamic_cast<AudioTimeAxisView*>(selection->tracks.back());
192         } else {
193                 atv = dynamic_cast<AudioTimeAxisView*>(*x);
194         }
195         
196         if (!atv || !atv->is_audio_track()) {
197                 return boost::shared_ptr<AudioTrack>();
198         }
199         
200         return atv->audio_track();
201 }       
202
203 void
204 Editor::do_import (vector<ustring> paths, ImportDisposition chns, ImportMode mode, SrcQuality quality, nframes64_t& pos)
205 {
206         boost::shared_ptr<AudioTrack> track;
207         vector<ustring> to_import;
208         bool ok = false;
209         int nth = 0;
210
211         if (interthread_progress_window == 0) {
212                 build_interthread_progress_window ();
213         }
214
215         switch (chns) {
216         case Editing::ImportDistinctFiles:
217                 for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
218
219                         to_import.clear ();
220                         to_import.push_back (*a);
221
222                         if (mode == Editing::ImportToTrack) {
223                                 track = get_nth_selected_audio_track (nth++);
224                         }
225                         
226                         if (import_sndfiles (to_import, mode, quality, pos, 1, -1, track)) {
227                                 goto out;
228                         }
229
230                 }
231                 break;
232
233         case Editing::ImportDistinctChannels:
234                 for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
235
236                         to_import.clear ();
237                         to_import.push_back (*a);
238
239                         if (import_sndfiles (to_import, mode, quality, pos, -1, -1, track)) {
240                                 goto out;
241                         }
242
243                 }
244                 break;
245
246         case Editing::ImportMergeFiles:
247                 /* create 1 region from all paths, add to 1 track,
248                    ignore "track"
249                 */
250                 if (import_sndfiles (paths, mode, quality, pos, 1, 1, track)) {
251                         goto out;
252                 }
253                 break;
254
255         case Editing::ImportSerializeFiles:
256                 for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
257
258                         to_import.clear ();
259                         to_import.push_back (*a);
260                         
261                         /* create 1 region from this path, add to 1 track,
262                            reuse "track" across paths
263                         */
264
265                         if (import_sndfiles (to_import, mode, quality, pos, 1, 1, track)) {
266                                 goto out;
267                         }
268
269                 }
270                 break;
271         }
272
273         ok = true;
274         
275   out:  
276         if (ok) {
277                 session->save_state ("");
278         }
279
280         interthread_progress_window->hide_all ();
281 }
282
283 bool
284 Editor::idle_do_embed (vector<ustring> paths, ImportDisposition chns, ImportMode mode, nframes64_t& pos)
285 {
286         _do_embed (paths, chns, mode, pos);
287         return false;
288 }
289
290 void
291 Editor::do_embed (vector<ustring> paths, ImportDisposition chns, ImportMode mode, nframes64_t& pos)
292 {
293 #ifdef GTKOSX
294         Glib::signal_idle().connect (bind (mem_fun (*this, &Editor::idle_do_embed), paths, chns, mode, pos));
295 #else
296         _do_embed (paths, chns, mode, pos);
297 #endif
298 }
299
300 void
301 Editor::_do_embed (vector<ustring> paths, ImportDisposition chns, ImportMode mode, nframes64_t& pos)
302 {
303         boost::shared_ptr<AudioTrack> track;
304         bool check_sample_rate = true;
305         bool ok = false;
306         vector<ustring> to_embed;
307         bool multi = paths.size() > 1;
308         int nth = 0;
309
310         switch (chns) {
311         case Editing::ImportDistinctFiles:
312                 for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
313
314                         to_embed.clear ();
315                         to_embed.push_back (*a);
316
317                         if (mode == Editing::ImportToTrack) {
318                                 track = get_nth_selected_audio_track (nth++);
319                         }
320
321                         if (embed_sndfiles (to_embed, multi, check_sample_rate, mode, pos, 1, -1, track) < -1) {
322                                 goto out;
323                         }
324                 }
325                 break;
326                 
327         case Editing::ImportDistinctChannels:
328                 for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
329
330                         to_embed.clear ();
331                         to_embed.push_back (*a);
332
333                         if (embed_sndfiles (to_embed, multi, check_sample_rate, mode, pos, -1, -1, track) < -1) {
334                                 goto out;
335                         }
336                 }
337                 break;
338
339         case Editing::ImportMergeFiles:
340                 if (embed_sndfiles (paths, multi, check_sample_rate, mode, pos, 1, 1, track) < -1) {
341                         goto out;
342                 }
343         break;
344
345         case Editing::ImportSerializeFiles:
346                 for (vector<ustring>::iterator a = paths.begin(); a != paths.end(); ++a) {
347
348                         to_embed.clear ();
349                         to_embed.push_back (*a);
350
351                         if (embed_sndfiles (to_embed, multi, check_sample_rate, mode, pos, 1, 1, track) < -1) {
352                                 goto out;
353                         }
354                 }
355                 break;
356         }
357
358         ok = true;
359         
360   out:  
361         if (ok) {
362                 session->save_state ("");
363         }
364 }
365
366 int
367 Editor::import_sndfiles (vector<ustring> paths, ImportMode mode, SrcQuality quality, nframes64_t& pos, 
368                          int target_regions, int target_tracks, boost::shared_ptr<AudioTrack>& track)
369 {
370         WindowTitle title = string_compose (_("importing %1"), paths.front());
371
372         interthread_progress_window->set_title (title.get_string());
373         interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
374         interthread_progress_window->show_all ();
375         interthread_progress_bar.set_fraction (0.0f);
376         interthread_cancel_label.set_text (_("Cancel Import"));
377         current_interthread_info = &import_status;
378
379         import_status.paths = paths;
380         import_status.done = false;
381         import_status.cancel = false;
382         import_status.freeze = false;
383         import_status.done = 0.0;
384         import_status.quality = quality;
385
386         interthread_progress_connection = Glib::signal_timeout().connect 
387                 (bind (mem_fun(*this, &Editor::import_progress_timeout), (gpointer) 0), 100);
388         
389         track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
390         ARDOUR_UI::instance()->flush_pending ();
391
392         /* start import thread for this spec. this will ultimately call Session::import_audiofile()
393            and if successful will add the file(s) as a region to the session region list.
394         */
395         
396         pthread_create_and_store ("import", &import_status.thread, 0, _import_thread, this);
397         pthread_detach (import_status.thread);
398         
399         while (!(import_status.done || import_status.cancel)) {
400                 gtk_main_iteration ();
401         }
402
403         interthread_progress_window->hide ();
404         
405         import_status.done = true;
406         interthread_progress_connection.disconnect ();
407         
408         /* import thread finished - see if we should build a new track */
409
410         boost::shared_ptr<AudioRegion> r;
411         
412         if (import_status.cancel || import_status.sources.empty()) {
413                 goto out;
414         }
415
416         if (add_sources (paths, import_status.sources, pos, mode, target_regions, target_tracks, track, false) == 0) {
417                 session->save_state ("");
418         }
419
420   out:
421         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
422         return 0;
423 }
424
425 int
426 Editor::embed_sndfiles (vector<Glib::ustring> paths, bool multifile,
427                         bool& check_sample_rate, ImportMode mode, nframes64_t& pos, int target_regions, int target_tracks,
428                         boost::shared_ptr<AudioTrack>& track)
429 {
430         boost::shared_ptr<AudioFileSource> source;
431         SourceList sources;
432         string linked_path;
433         SoundFileInfo finfo;
434         int ret = 0;
435
436         track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
437         ARDOUR_UI::instance()->flush_pending ();
438
439         for (vector<Glib::ustring>::iterator p = paths.begin(); p != paths.end(); ++p) {
440
441                 ustring path = *p;
442
443                 /* lets see if we can link it into the session */
444                 
445                 linked_path = session->sound_dir();
446                 linked_path += '/';
447                 linked_path += Glib::path_get_basename (path);
448                 
449                 if (link (path.c_str(), linked_path.c_str()) == 0) {
450
451                         /* there are many reasons why link(2) might have failed.
452                            but if it succeeds, we now have a link in the
453                            session sound dir that will protect against
454                            unlinking of the original path. nice.
455                         */
456                         
457                         path = linked_path;
458
459                 } else {
460
461                         /* one possible reason is that its already linked */
462
463                         if (errno == EEXIST) {
464                                 struct stat sb;
465
466                                 if (stat (linked_path.c_str(), &sb) == 0) {
467                                         if (sb.st_nlink > 1) { // its a hard link, assume its the one we want
468                                                 path = linked_path;
469                                         }
470                                 }
471                         }
472                 }
473                 
474                 /* note that we temporarily truncated _id at the colon */
475                 
476                 string error_msg;
477
478                 if (!AudioFileSource::get_soundfile_info (path, finfo, error_msg)) {
479                         error << string_compose(_("Editor: cannot open file \"%1\", (%2)"), path, error_msg ) << endmsg;
480                         goto out;
481                 }
482                 
483                 if (check_sample_rate  && (finfo.samplerate != (int) session->frame_rate())) {
484                         vector<string> choices;
485                         
486                         if (multifile) {
487                                 choices.push_back (_("Cancel entire import"));
488                                 choices.push_back (_("Don't embed it"));
489                                 choices.push_back (_("Embed all without questions"));
490                         
491                                 Gtkmm2ext::Choice rate_choice (
492                                         string_compose (_("%1\nThis audiofile's sample rate doesn't match the session sample rate!"), 
493                                                         short_path (path, 40)),
494                                         choices, false);
495                                 
496                                 int resx = rate_choice.run ();
497                                 
498                                 switch (resx) {
499                                 case 0: /* stop a multi-file import */
500                                         ret = -2;
501                                         goto out;
502                                 case 1: /* don't embed this one */
503                                         ret = -1;
504                                         goto out;
505                                 case 2: /* do it, and the rest without asking */
506                                         check_sample_rate = false;
507                                         break;
508                                 case 3: /* do it */
509                                         break;
510                                 default:
511                                         ret = -2;
512                                         goto out;
513                                 }
514                         } else {
515                                 choices.push_back (_("Cancel"));
516                                 choices.push_back (_("Embed it anyway"));
517                         
518                                 Gtkmm2ext::Choice rate_choice (
519                                         string_compose (_("%1\nThis audiofile's sample rate doesn't match the session sample rate!"), path),
520                                         choices, false);
521                                 
522                                 int resx = rate_choice.run ();
523                                 
524                                 switch (resx) {
525                                 case 0: /* don't import */
526                                         ret = -1;
527                                         goto out;
528                                 case 1: /* do it */
529                                         break;
530                                 default:
531                                         ret = -2;
532                                         goto out;
533                                 }
534                         }
535                 }
536                 
537                 track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
538
539                 for (int n = 0; n < finfo.channels; ++n) {
540                         try {
541
542                                 /* check if we have this thing embedded already */
543
544                                 boost::shared_ptr<Source> s;
545
546                                 if ((s = session->source_by_path_and_channel (path, n)) == 0) {
547                                         source = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable 
548                                                                                                (*session, path,  n,
549                                                                                                 (mode == ImportAsTapeTrack ? 
550                                                                                                  AudioFileSource::Destructive : 
551                                                                                                  AudioFileSource::Flag (0)),
552                                                                                                 true, true));
553                                 } else {
554                                         source = boost::dynamic_pointer_cast<AudioFileSource> (s);
555                                 }
556
557                                 sources.push_back(source);
558                         } 
559                         
560                         catch (failed_constructor& err) {
561                                 error << string_compose(_("could not open %1"), path) << endmsg;
562                                 goto out;
563                         }
564                         
565                         ARDOUR_UI::instance()->flush_pending ();
566                 }
567         }
568
569         if (sources.empty()) {
570                 goto out;
571         }
572
573         ret = add_sources (paths, sources, pos, mode, target_regions, target_tracks, track, true);
574
575   out:
576         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
577         return ret;
578 }
579
580 int
581 Editor::add_sources (vector<Glib::ustring> paths, SourceList& sources, nframes64_t& pos, ImportMode mode, 
582                      int target_regions, int target_tracks, boost::shared_ptr<AudioTrack>& track, bool add_channel_suffix)
583 {
584         vector<boost::shared_ptr<AudioRegion> > regions;
585         ustring region_name;
586         uint32_t input_chan = 0;
587         uint32_t output_chan = 0;
588
589         if (pos == -1) { // "use timestamp"
590                 if (sources[0]->natural_position() != 0) {
591                         pos = sources[0]->natural_position();
592                 } else {
593                         // XXX is this the best alternative ?
594                         pos = edit_cursor->current_frame;
595                 }
596         }
597
598         if (target_regions == 1) {
599
600                 /* take all the sources we have and package them up as a region */
601
602                 region_name = region_name_from_path (paths.front(), (sources.size() > 1), false);
603                 
604                 regions.push_back (boost::dynamic_pointer_cast<AudioRegion> 
605                                    (RegionFactory::create (sources, 0, sources[0]->length(), region_name, 0,
606                                                            Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External))));
607                 
608         } else if (target_regions == -1) {
609
610                 /* take each source and create a region for each one */
611
612                 SourceList just_one;
613                 SourceList::iterator x;
614                 uint32_t n;
615
616                 for (n = 0, x = sources.begin(); x != sources.end(); ++x, ++n) {
617
618                         just_one.clear ();
619                         just_one.push_back (*x);
620                         
621                         boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (*x);
622
623                         region_name = region_name_from_path (afs->path(), false, true, sources.size(), n);
624
625                         regions.push_back (boost::dynamic_pointer_cast<AudioRegion> 
626                                            (RegionFactory::create (just_one, 0, (*x)->length(), region_name, 0,
627                                                                    Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External))));
628
629                 }
630         }
631
632         if (target_regions == 1) {
633                 input_chan = regions.front()->n_channels();
634         } else {
635                 if (target_tracks == 1) {
636                         input_chan = regions.size();
637                 } else {
638                         input_chan = 1;
639                 }
640         }
641
642         if (Config->get_output_auto_connect() & AutoConnectMaster) {
643                 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
644         } else {
645                 output_chan = input_chan;
646         }
647
648         int n = 0;
649
650         for (vector<boost::shared_ptr<AudioRegion> >::iterator r = regions.begin(); r != regions.end(); ++r, ++n) {
651
652                 finish_bringing_in_audio (*r, input_chan, output_chan, pos, mode, track);
653
654                 if (target_tracks != 1) {
655                         track.reset ();
656                 } else {
657                         pos += (*r)->length();
658                 } 
659         }
660
661         /* setup peak file building in another thread */
662
663         for (SourceList::iterator x = sources.begin(); x != sources.end(); ++x) {
664                 SourceFactory::setup_peakfile (*x, true);
665         }
666
667         return 0;
668 }
669         
670 int
671 Editor::finish_bringing_in_audio (boost::shared_ptr<AudioRegion> region, uint32_t in_chans, uint32_t out_chans, nframes64_t& pos, 
672                                   ImportMode mode, boost::shared_ptr<AudioTrack>& existing_track)
673 {
674         switch (mode) {
675         case ImportAsRegion:
676                 /* relax, its been done */
677                 break;
678                 
679         case ImportToTrack:
680         {
681                 if (!existing_track) {
682
683                         existing_track = get_nth_selected_audio_track (0);
684
685                         if (!existing_track) {
686                                 return -1;
687                         }
688                 }
689
690                 boost::shared_ptr<Playlist> playlist = existing_track->diskstream()->playlist();
691                 boost::shared_ptr<AudioRegion> copy (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region)));
692                 begin_reversible_command (_("insert sndfile"));
693                 XMLNode &before = playlist->get_state();
694                 playlist->add_region (copy, pos);
695                 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
696                 commit_reversible_command ();
697                 break;
698         }
699
700         case ImportAsTrack:
701         { 
702                 if (!existing_track) {
703                         list<boost::shared_ptr<AudioTrack> > at (session->new_audio_track (in_chans, out_chans, Normal, 1));
704
705                         if (at.empty()) {
706                                 return -1;
707                         }
708
709                         existing_track = at.front();
710                         existing_track->set_name (region->name(), this);
711                 }
712
713                 boost::shared_ptr<AudioRegion> copy (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region)));
714                 existing_track->diskstream()->playlist()->add_region (copy, pos);
715                 break;
716         }
717
718
719         case ImportAsTapeTrack:
720         {
721                 list<boost::shared_ptr<AudioTrack> > at (session->new_audio_track (in_chans, out_chans, Destructive));
722                 if (!at.empty()) {
723                         boost::shared_ptr<AudioRegion> copy (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region)));
724                         at.front()->set_name (basename_nosuffix (copy->name()), this);
725                         at.front()->diskstream()->playlist()->add_region (copy, pos);
726                 }
727                 break;
728         }
729         }
730
731         return 0;
732 }
733
734 void *
735 Editor::_import_thread (void *arg)
736 {
737         PBD::ThreadCreated (pthread_self(), X_("Import"));
738
739         Editor *ed = (Editor *) arg;
740         return ed->import_thread ();
741 }
742
743 void *
744 Editor::import_thread ()
745 {
746         session->import_audiofile (import_status);
747         pthread_exit_pbd (0);
748         /*NOTREACHED*/
749         return 0;
750 }
751
752 gint
753 Editor::import_progress_timeout (void *arg)
754 {
755         interthread_progress_label.set_text (import_status.doing_what);
756
757         if (import_status.freeze) {
758                 interthread_cancel_button.set_sensitive(false);
759         } else {
760                 interthread_cancel_button.set_sensitive(true);
761         }
762
763         if (import_status.doing_what == "building peak files") {
764                 interthread_progress_bar.pulse ();
765                 return FALSE;
766         } else {
767                 interthread_progress_bar.set_fraction (import_status.progress);
768         }
769
770         return !(import_status.done || import_status.cancel);
771 }
772