2006-03-22 17:03:00 +00:00
/*
Copyright ( C ) 2000 - 2006 Paul Davis
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2007-04-06 02:48:29 +00:00
# include <sys/types.h>
# include <sys/stat.h>
2007-09-12 19:10:04 +00:00
# include <sys/time.h>
2007-04-06 02:48:29 +00:00
# include <errno.h>
# include <unistd.h>
2008-02-27 14:40:59 +00:00
# include <algorithm>
2007-04-06 02:48:29 +00:00
2007-08-26 01:54:34 +00:00
# include <sndfile.h>
2006-03-22 17:03:00 +00:00
# include <pbd/pthread_utils.h>
# include <pbd/basename.h>
2007-04-06 02:27:24 +00:00
# include <pbd/shortpath.h>
2006-03-22 17:03:00 +00:00
# include <gtkmm2ext/choice.h>
2007-03-18 16:45:43 +00:00
# include <gtkmm2ext/window_title.h>
2006-03-22 17:03:00 +00:00
# include <ardour/session.h>
# include <ardour/audioplaylist.h>
# include <ardour/audioregion.h>
2006-06-22 23:40:55 +00:00
# include <ardour/audio_diskstream.h>
2006-03-22 17:03:00 +00:00
# include <ardour/utils.h>
# include <ardour/audio_track.h>
# include <ardour/audioplaylist.h>
2006-06-22 23:40:55 +00:00
# include <ardour/audiofilesource.h>
2006-08-25 01:07:15 +00:00
# include <ardour/region_factory.h>
2006-08-29 00:23:45 +00:00
# include <ardour/source_factory.h>
2008-02-15 06:41:22 +00:00
# include <ardour/session.h>
2006-07-29 03:17:11 +00:00
# include <pbd/memento_command.h>
2006-03-22 17:03:00 +00:00
# include "ardour_ui.h"
# include "editor.h"
# include "sfdb_ui.h"
# include "editing.h"
# include "audio_time_axis.h"
2007-01-29 20:02:43 +00:00
# include "utils.h"
2006-03-22 17:03:00 +00:00
# include "i18n.h"
using namespace std ;
using namespace ARDOUR ;
2006-06-22 23:40:55 +00:00
using namespace PBD ;
2006-03-22 17:03:00 +00:00
using namespace sigc ;
using namespace Gtk ;
2007-03-18 16:45:43 +00:00
using namespace Gtkmm2ext ;
2006-03-22 17:03:00 +00:00
using namespace Editing ;
2006-12-21 18:38:00 +00:00
using Glib : : ustring ;
2006-03-22 17:03:00 +00:00
/* Functions supporting the incorporation of external (non-captured) audio material into ardour */
void
2007-09-27 16:17:21 +00:00
Editor : : add_external_audio_action ( ImportMode mode_hint )
2006-03-22 17:03:00 +00:00
{
2007-09-27 16:17:21 +00:00
if ( session = = 0 ) {
MessageDialog msg ( 0 , _ ( " You can't import or embed an audiofile until you have a session loaded. " ) ) ;
msg . run ( ) ;
return ;
}
if ( sfbrowser = = 0 ) {
2007-09-27 19:45:47 +00:00
sfbrowser = new SoundFileOmega ( * this , _ ( " Add existing audio " ) , session , 0 , true , mode_hint ) ;
2007-09-27 16:17:21 +00:00
} else {
sfbrowser - > set_mode ( mode_hint ) ;
}
external_audio_dialog ( ) ;
2006-03-22 17:03:00 +00:00
}
void
2007-08-26 01:54:34 +00:00
Editor : : external_audio_dialog ( )
2006-03-22 17:03:00 +00:00
{
2007-08-26 01:54:34 +00:00
vector < Glib : : ustring > paths ;
2007-09-24 20:00:48 +00:00
uint32_t track_cnt ;
2007-08-26 01:54:34 +00:00
2006-03-22 17:03:00 +00:00
if ( session = = 0 ) {
MessageDialog msg ( 0 , _ ( " You can't import or embed an audiofile until you have a session loaded. " ) ) ;
msg . run ( ) ;
return ;
}
2007-09-04 03:01:57 +00:00
2007-09-24 20:00:48 +00:00
track_cnt = 0 ;
for ( TrackSelection : : iterator x = selection - > tracks . begin ( ) ; x ! = selection - > tracks . end ( ) ; + + x ) {
AudioTimeAxisView * atv = dynamic_cast < AudioTimeAxisView * > ( * x ) ;
if ( ! atv ) {
continue ;
} else if ( atv - > is_audio_track ( ) ) {
track_cnt + + ;
}
}
2007-09-04 03:01:57 +00:00
if ( sfbrowser = = 0 ) {
2007-09-27 19:45:47 +00:00
sfbrowser = new SoundFileOmega ( * this , _ ( " Add existing audio " ) , session , track_cnt , true ) ;
2007-09-04 21:01:32 +00:00
} else {
2007-09-24 20:00:48 +00:00
sfbrowser - > reset ( track_cnt ) ;
2007-09-04 03:01:57 +00:00
}
2006-03-22 17:03:00 +00:00
2007-09-04 03:01:57 +00:00
sfbrowser - > show_all ( ) ;
2006-03-22 17:03:00 +00:00
2007-08-26 01:54:34 +00:00
2008-02-15 06:41:22 +00:00
bool keepRunning ;
2007-09-09 15:30:01 +00:00
2008-02-15 06:41:22 +00:00
do {
keepRunning = false ;
2007-09-24 15:41:23 +00:00
2008-02-15 06:41:22 +00:00
int response = sfbrowser - > run ( ) ;
2007-08-26 01:54:34 +00:00
2008-02-15 06:41:22 +00:00
switch ( response ) {
case RESPONSE_APPLY :
// leave the dialog open
break ;
2007-08-26 01:54:34 +00:00
2008-02-15 06:41:22 +00:00
case RESPONSE_OK :
sfbrowser - > hide ( ) ;
break ;
2007-08-30 20:25:47 +00:00
2008-02-15 06:41:22 +00:00
default :
// cancel from the browser - we are done
sfbrowser - > hide ( ) ;
return ;
}
2007-08-30 20:25:47 +00:00
2008-02-15 06:41:22 +00:00
/* lets do it */
paths = sfbrowser - > get_paths ( ) ;
ImportPosition pos = sfbrowser - > get_position ( ) ;
ImportMode mode = sfbrowser - > get_mode ( ) ;
ImportDisposition chns = sfbrowser - > get_channel_disposition ( ) ;
nframes64_t where ;
switch ( pos ) {
case ImportAtEditPoint :
where = get_preferred_edit_position ( ) ;
break ;
case ImportAtTimestamp :
where = - 1 ;
break ;
case ImportAtPlayhead :
where = playhead_cursor - > current_frame ;
break ;
case ImportAtStart :
where = session - > current_start_frame ( ) ;
break ;
}
2007-09-11 14:34:21 +00:00
2008-02-15 06:41:22 +00:00
SrcQuality quality = sfbrowser - > get_src_quality ( ) ;
if ( sfbrowser - > copy_files_btn . get_active ( ) ) {
do_import ( paths , chns , mode , quality , where ) ;
} else {
do_embed ( paths , chns , mode , where ) ;
}
if ( response = = RESPONSE_APPLY ) {
sfbrowser - > clear_selection ( ) ;
keepRunning = true ;
}
} while ( keepRunning ) ;
}
typedef std : : map < PBD : : ID , boost : : shared_ptr < AudioSource > > AudioSourceList ;
/**
* Updating is still disabled , see note in libs / ardour / import . cc Session : : import_audiofiles ( )
*
* all_or_nothing :
* true = show " Update " , " Import " and " Skip "
* false = show " Import " , and " Cancel "
*
* Returns :
* 0 To update an existing source of the same name
* 1 To import / embed the file normally ( make sure the new name will be unique )
* 2 If the user wants to skip this file
* */
int
Editor : : check_whether_and_how_to_import ( string path , bool all_or_nothing )
{
2008-02-15 20:37:41 +00:00
string wave_name ( Glib : : path_get_basename ( path ) ) ;
2008-02-15 06:41:22 +00:00
AudioSourceList all_sources = session - > get_audio_sources ( ) ;
bool wave_name_exists = false ;
for ( AudioSourceList : : iterator i = all_sources . begin ( ) ; i ! = all_sources . end ( ) ; + + i ) {
boost : : shared_ptr < AudioFileSource > afs = boost : : dynamic_pointer_cast < AudioFileSource > ( i - > second ) ;
2008-02-15 20:37:41 +00:00
string tmp ( Glib : : path_get_basename ( afs - > path ( ) ) ) ;
2008-02-15 06:41:22 +00:00
if ( tmp = = wave_name ) {
wave_name_exists = true ;
break ;
}
2007-08-26 01:54:34 +00:00
}
2007-09-09 15:30:01 +00:00
2008-02-15 06:41:22 +00:00
int function = 1 ;
if ( wave_name_exists ) {
string message ;
if ( all_or_nothing ) {
// updating is still disabled
//message = string_compose(_("The session already contains a source file named %1. Do you want to update that file (and thus all regions using the file) or import this file as a new file?"),wave_name);
message = string_compose ( _ ( " The session already contains a source file named %1. This file will be imported as a new file, please confirm. " ) , wave_name ) ;
} else {
2008-03-24 13:22:49 +00:00
message = string_compose ( _ ( " A source file %1 already exists. This operation will not update that source but import the file %2 as a new source, please confirm. " ) , wave_name , wave_name ) ;
2008-02-15 06:41:22 +00:00
}
MessageDialog dialog ( message , false , Gtk : : MESSAGE_QUESTION , Gtk : : BUTTONS_NONE , true ) ;
if ( all_or_nothing ) {
// disabled
//dialog.add_button("Update", 0);
dialog . add_button ( " Import " , 1 ) ;
dialog . add_button ( " Skip " , 2 ) ;
} else {
dialog . add_button ( " Import " , 1 ) ;
dialog . add_button ( " Cancel " , 2 ) ;
}
//dialog.add_button("Skip all", 4); // All or rest?
dialog . show ( ) ;
function = dialog . run ( ) ;
dialog . hide ( ) ;
2007-09-09 15:30:01 +00:00
}
2008-02-15 06:41:22 +00:00
return function ;
2007-08-26 01:54:34 +00:00
}
2007-09-04 21:01:32 +00:00
boost : : shared_ptr < AudioTrack >
Editor : : get_nth_selected_audio_track ( int nth ) const
{
AudioTimeAxisView * atv ;
TrackSelection : : iterator x ;
for ( x = selection - > tracks . begin ( ) ; nth > 0 & & x ! = selection - > tracks . end ( ) ; + + x ) {
2007-09-24 20:00:48 +00:00
atv = dynamic_cast < AudioTimeAxisView * > ( * x ) ;
if ( ! atv ) {
continue ;
} else if ( atv - > is_audio_track ( ) ) {
2007-09-04 21:01:32 +00:00
- - nth ;
}
}
if ( x = = selection - > tracks . end ( ) ) {
atv = dynamic_cast < AudioTimeAxisView * > ( selection - > tracks . back ( ) ) ;
} else {
atv = dynamic_cast < AudioTimeAxisView * > ( * x ) ;
}
2007-09-24 20:00:48 +00:00
if ( ! atv | | ! atv - > is_audio_track ( ) ) {
2007-09-04 21:01:32 +00:00
return boost : : shared_ptr < AudioTrack > ( ) ;
}
return atv - > audio_track ( ) ;
}
2008-02-27 13:56:14 +00:00
bool
Editor : : idle_do_import ( vector < ustring > paths , ImportDisposition chns , ImportMode mode , SrcQuality quality , nframes64_t & pos )
{
_do_import ( paths , chns , mode , quality , pos ) ;
return false ;
}
2007-08-26 01:54:34 +00:00
void
2007-09-11 14:34:21 +00:00
Editor : : do_import ( vector < ustring > paths , ImportDisposition chns , ImportMode mode , SrcQuality quality , nframes64_t & pos )
2008-02-27 13:56:14 +00:00
{
# ifdef GTKOSX
Glib : : signal_idle ( ) . connect ( bind ( mem_fun ( * this , & Editor : : idle_do_import ) , paths , chns , mode , quality , pos ) ) ;
# else
_do_import ( paths , chns , mode , quality , pos ) ;
# endif
}
void
Editor : : _do_import ( vector < ustring > paths , ImportDisposition chns , ImportMode mode , SrcQuality quality , nframes64_t & pos )
2007-08-26 01:54:34 +00:00
{
2007-09-04 15:01:49 +00:00
boost : : shared_ptr < AudioTrack > track ;
2007-09-03 22:46:21 +00:00
vector < ustring > to_import ;
2008-02-15 06:41:22 +00:00
bool ok = true ;
2007-09-04 21:01:32 +00:00
int nth = 0 ;
2006-03-22 17:03:00 +00:00
if ( interthread_progress_window = = 0 ) {
build_interthread_progress_window ( ) ;
}
2008-02-15 06:41:22 +00:00
if ( chns = = Editing : : ImportMergeFiles ) {
/* create 1 region from all paths, add to 1 track,
ignore " track "
*/
bool cancel = false ;
for ( vector < ustring > : : iterator a = paths . begin ( ) ; a ! = paths . end ( ) & & ok ; + + a ) {
int check = check_whether_and_how_to_import ( * a , false ) ;
if ( check = = 2 ) {
cancel = true ;
break ;
2007-09-04 15:01:49 +00:00
}
2008-02-15 06:41:22 +00:00
}
2007-09-04 15:01:49 +00:00
2008-02-15 06:41:22 +00:00
if ( ! cancel ) {
if ( import_sndfiles ( paths , mode , quality , pos , 1 , 1 , track , false ) ) {
ok = false ;
}
2007-09-04 15:01:49 +00:00
}
2008-02-15 06:41:22 +00:00
} else {
bool replace ;
2006-12-21 18:38:00 +00:00
2008-02-15 06:41:22 +00:00
for ( vector < ustring > : : iterator a = paths . begin ( ) ; a ! = paths . end ( ) & & ok ; + + a ) {
2006-12-21 18:38:00 +00:00
2008-02-15 06:41:22 +00:00
int check = check_whether_and_how_to_import ( * a , true ) ;
if ( check = = 2 ) {
// skip
continue ;
2007-09-03 22:46:21 +00:00
}
2007-09-04 15:01:49 +00:00
2008-02-15 06:41:22 +00:00
if ( check = = 0 ) {
fatal < < " Updating existing sources should be disabled! " < < endl ;
replace = true ;
} else if ( check = = 1 ) {
replace = false ;
}
2006-12-21 18:38:00 +00:00
2008-02-15 06:41:22 +00:00
switch ( chns ) {
case Editing : : ImportDistinctFiles :
2007-09-04 15:01:49 +00:00
2008-02-15 06:41:22 +00:00
to_import . clear ( ) ;
to_import . push_back ( * a ) ;
2007-09-04 15:01:49 +00:00
2008-02-15 06:41:22 +00:00
if ( mode = = Editing : : ImportToTrack ) {
track = get_nth_selected_audio_track ( nth + + ) ;
}
2007-09-04 15:01:49 +00:00
2008-02-15 06:41:22 +00:00
if ( import_sndfiles ( to_import , mode , quality , pos , 1 , - 1 , track , replace ) ) {
ok = false ;
}
break ;
case Editing : : ImportDistinctChannels :
to_import . clear ( ) ;
to_import . push_back ( * a ) ;
if ( import_sndfiles ( to_import , mode , quality , pos , - 1 , - 1 , track , replace ) ) {
ok = false ;
}
break ;
case Editing : : ImportSerializeFiles :
to_import . clear ( ) ;
to_import . push_back ( * a ) ;
/* create 1 region from this path, add to 1 track,
reuse " track " across paths
*/
if ( import_sndfiles ( to_import , mode , quality , pos , 1 , 1 , track , replace ) ) {
ok = false ;
}
break ;
case Editing : : ImportMergeFiles :
// Not entered
break ;
2007-09-04 15:01:49 +00:00
}
2008-02-15 06:41:22 +00:00
}
2007-09-04 15:01:49 +00:00
2008-02-15 06:41:22 +00:00
if ( ok ) {
session - > save_state ( " " ) ;
2007-09-04 15:01:49 +00:00
}
2007-09-03 22:46:21 +00:00
2008-02-15 06:41:22 +00:00
interthread_progress_window - > hide_all ( ) ;
2006-03-22 17:03:00 +00:00
}
}
2007-08-16 23:17:35 +00:00
bool
2007-09-03 22:46:21 +00:00
Editor : : idle_do_embed ( vector < ustring > paths , ImportDisposition chns , ImportMode mode , nframes64_t & pos )
2007-08-16 23:17:35 +00:00
{
2007-09-02 15:17:13 +00:00
_do_embed ( paths , chns , mode , pos ) ;
2007-08-16 23:17:35 +00:00
return false ;
}
2006-03-22 17:03:00 +00:00
void
2007-09-03 22:46:21 +00:00
Editor : : do_embed ( vector < ustring > paths , ImportDisposition chns , ImportMode mode , nframes64_t & pos )
2007-08-16 23:17:35 +00:00
{
# ifdef GTKOSX
2007-09-02 15:17:13 +00:00
Glib : : signal_idle ( ) . connect ( bind ( mem_fun ( * this , & Editor : : idle_do_embed ) , paths , chns , mode , pos ) ) ;
2007-08-16 23:17:35 +00:00
# else
2007-09-02 15:17:13 +00:00
_do_embed ( paths , chns , mode , pos ) ;
2007-08-16 23:17:35 +00:00
# endif
}
void
2007-09-03 22:46:21 +00:00
Editor : : _do_embed ( vector < ustring > paths , ImportDisposition chns , ImportMode mode , nframes64_t & pos )
2006-03-22 17:03:00 +00:00
{
2007-09-04 15:01:49 +00:00
boost : : shared_ptr < AudioTrack > track ;
2006-03-22 17:03:00 +00:00
bool check_sample_rate = true ;
2007-08-30 20:25:47 +00:00
bool ok = false ;
vector < ustring > to_embed ;
2007-09-04 15:01:49 +00:00
bool multi = paths . size ( ) > 1 ;
2007-09-04 21:01:32 +00:00
int nth = 0 ;
2007-09-04 15:01:49 +00:00
2007-08-30 20:25:47 +00:00
switch ( chns ) {
2007-09-02 15:17:13 +00:00
case Editing : : ImportDistinctFiles :
2007-09-04 15:01:49 +00:00
for ( vector < ustring > : : iterator a = paths . begin ( ) ; a ! = paths . end ( ) ; + + a ) {
to_embed . clear ( ) ;
to_embed . push_back ( * a ) ;
2007-09-04 21:01:32 +00:00
if ( mode = = Editing : : ImportToTrack ) {
track = get_nth_selected_audio_track ( nth + + ) ;
}
2007-09-04 15:01:49 +00:00
if ( embed_sndfiles ( to_embed , multi , check_sample_rate , mode , pos , 1 , - 1 , track ) < - 1 ) {
goto out ;
}
}
break ;
2007-09-02 15:17:13 +00:00
case Editing : : ImportDistinctChannels :
2007-08-30 20:25:47 +00:00
for ( vector < ustring > : : iterator a = paths . begin ( ) ; a ! = paths . end ( ) ; + + a ) {
2006-12-21 18:38:00 +00:00
2007-08-30 20:25:47 +00:00
to_embed . clear ( ) ;
to_embed . push_back ( * a ) ;
2006-12-21 18:38:00 +00:00
2007-09-04 15:01:49 +00:00
if ( embed_sndfiles ( to_embed , multi , check_sample_rate , mode , pos , - 1 , - 1 , track ) < - 1 ) {
2007-08-30 20:25:47 +00:00
goto out ;
2006-12-21 18:38:00 +00:00
}
2006-03-22 22:18:08 +00:00
}
2007-08-30 20:25:47 +00:00
break ;
2006-03-22 17:03:00 +00:00
2007-09-02 15:17:13 +00:00
case Editing : : ImportMergeFiles :
2007-09-04 15:01:49 +00:00
if ( embed_sndfiles ( paths , multi , check_sample_rate , mode , pos , 1 , 1 , track ) < - 1 ) {
2007-08-30 20:25:47 +00:00
goto out ;
2006-12-21 18:38:00 +00:00
}
2007-09-04 21:01:32 +00:00
break ;
2007-09-04 15:01:49 +00:00
case Editing : : ImportSerializeFiles :
for ( vector < ustring > : : iterator a = paths . begin ( ) ; a ! = paths . end ( ) ; + + a ) {
to_embed . clear ( ) ;
to_embed . push_back ( * a ) ;
if ( embed_sndfiles ( to_embed , multi , check_sample_rate , mode , pos , 1 , 1 , track ) < - 1 ) {
goto out ;
}
}
break ;
2006-12-21 18:38:00 +00:00
}
2007-08-30 20:25:47 +00:00
ok = true ;
2006-12-21 18:38:00 +00:00
2007-08-30 20:25:47 +00:00
out :
if ( ok ) {
2006-03-22 22:18:08 +00:00
session - > save_state ( " " ) ;
}
2006-03-22 17:03:00 +00:00
}
2006-03-22 22:18:08 +00:00
int
2007-09-11 14:34:21 +00:00
Editor : : import_sndfiles ( vector < ustring > paths , ImportMode mode , SrcQuality quality , nframes64_t & pos ,
2008-02-15 06:41:22 +00:00
int target_regions , int target_tracks , boost : : shared_ptr < AudioTrack > & track , bool replace )
2006-03-22 17:03:00 +00:00
{
2007-03-18 16:45:43 +00:00
WindowTitle title = string_compose ( _ ( " importing %1 " ) , paths . front ( ) ) ;
interthread_progress_window - > set_title ( title . get_string ( ) ) ;
2006-03-22 17:03:00 +00:00
interthread_progress_window - > set_position ( Gtk : : WIN_POS_MOUSE ) ;
interthread_progress_bar . set_fraction ( 0.0f ) ;
interthread_cancel_label . set_text ( _ ( " Cancel Import " ) ) ;
current_interthread_info = & import_status ;
2006-12-21 18:38:00 +00:00
import_status . paths = paths ;
2006-03-22 17:03:00 +00:00
import_status . done = false ;
import_status . cancel = false ;
import_status . freeze = false ;
import_status . done = 0.0 ;
2007-09-11 14:34:21 +00:00
import_status . quality = quality ;
2008-02-15 06:41:22 +00:00
import_status . replace_existing_source = replace ;
2007-09-11 14:34:21 +00:00
2006-03-22 17:03:00 +00:00
interthread_progress_connection = Glib : : signal_timeout ( ) . connect
2008-02-27 14:40:59 +00:00
( bind ( mem_fun ( * this , & Editor : : import_progress_timeout ) , ( gpointer ) 0 ) , 500 ) ;
2006-03-22 17:03:00 +00:00
2008-02-26 16:34:45 +00:00
track_canvas - > get_window ( ) - > set_cursor ( Gdk : : Cursor ( Gdk : : WATCH ) ) ;
2006-03-22 17:03:00 +00:00
ARDOUR_UI : : instance ( ) - > flush_pending ( ) ;
2006-12-21 18:38:00 +00:00
/* start import thread for this spec. this will ultimately call Session::import_audiofile()
and if successful will add the file ( s ) as a region to the session region list .
2006-03-22 17:03:00 +00:00
*/
pthread_create_and_store ( " import " , & import_status . thread , 0 , _import_thread , this ) ;
pthread_detach ( import_status . thread ) ;
while ( ! ( import_status . done | | import_status . cancel ) ) {
gtk_main_iteration ( ) ;
}
2007-02-27 19:01:38 +00:00
interthread_progress_window - > hide ( ) ;
2006-03-22 17:03:00 +00:00
import_status . done = true ;
interthread_progress_connection . disconnect ( ) ;
/* import thread finished - see if we should build a new track */
2007-09-02 15:17:13 +00:00
2007-09-03 22:46:21 +00:00
boost : : shared_ptr < AudioRegion > r ;
2006-03-22 17:03:00 +00:00
2007-09-03 22:46:21 +00:00
if ( import_status . cancel | | import_status . sources . empty ( ) ) {
goto out ;
2006-03-22 17:03:00 +00:00
}
2007-09-09 13:04:23 +00:00
if ( add_sources ( paths , import_status . sources , pos , mode , target_regions , target_tracks , track , false ) = = 0 ) {
2007-09-03 22:46:21 +00:00
session - > save_state ( " " ) ;
}
out :
2008-02-26 16:34:45 +00:00
track_canvas - > get_window ( ) - > set_cursor ( * current_canvas_cursor ) ;
2006-03-22 22:18:08 +00:00
return 0 ;
2006-03-22 17:03:00 +00:00
}
2006-03-22 22:18:08 +00:00
int
2007-09-04 15:01:49 +00:00
Editor : : embed_sndfiles ( vector < Glib : : ustring > paths , bool multifile ,
bool & check_sample_rate , ImportMode mode , nframes64_t & pos , int target_regions , int target_tracks ,
boost : : shared_ptr < AudioTrack > & track )
2006-03-22 17:03:00 +00:00
{
2006-08-29 00:23:45 +00:00
boost : : shared_ptr < AudioFileSource > source ;
2006-08-25 01:07:15 +00:00
SourceList sources ;
2006-03-22 17:03:00 +00:00
string linked_path ;
SoundFileInfo finfo ;
2007-01-25 17:42:19 +00:00
int ret = 0 ;
2006-03-22 17:03:00 +00:00
2008-02-26 16:34:45 +00:00
track_canvas - > get_window ( ) - > set_cursor ( Gdk : : Cursor ( Gdk : : WATCH ) ) ;
2006-03-22 17:03:00 +00:00
ARDOUR_UI : : instance ( ) - > flush_pending ( ) ;
2006-12-21 18:38:00 +00:00
for ( vector < Glib : : ustring > : : iterator p = paths . begin ( ) ; p ! = paths . end ( ) ; + + p ) {
2006-03-22 17:03:00 +00:00
2006-12-21 18:38:00 +00:00
ustring path = * p ;
2006-03-22 17:03:00 +00:00
2006-12-21 18:38:00 +00:00
/* lets see if we can link it into the session */
2006-03-22 22:18:08 +00:00
2006-12-21 18:38:00 +00:00
linked_path = session - > sound_dir ( ) ;
linked_path + = ' / ' ;
linked_path + = Glib : : path_get_basename ( path ) ;
if ( link ( path . c_str ( ) , linked_path . c_str ( ) ) = = 0 ) {
2007-04-06 02:48:29 +00:00
2006-12-21 18:38:00 +00:00
/* there are many reasons why link(2) might have failed.
but if it succeeds , we now have a link in the
session sound dir that will protect against
unlinking of the original path . nice .
*/
path = linked_path ;
2007-04-06 02:48:29 +00:00
} else {
/* one possible reason is that its already linked */
if ( errno = = EEXIST ) {
struct stat sb ;
if ( stat ( linked_path . c_str ( ) , & sb ) = = 0 ) {
if ( sb . st_nlink > 1 ) { // its a hard link, assume its the one we want
path = linked_path ;
}
}
}
2006-03-22 22:18:08 +00:00
}
2006-12-21 18:38:00 +00:00
/* note that we temporarily truncated _id at the colon */
2006-03-22 22:18:08 +00:00
2006-12-21 18:38:00 +00:00
string error_msg ;
2007-08-16 23:17:35 +00:00
2006-12-21 18:38:00 +00:00
if ( ! AudioFileSource : : get_soundfile_info ( path , finfo , error_msg ) ) {
2007-08-16 23:17:35 +00:00
error < < string_compose ( _ ( " Editor: cannot open file \" %1 \" , (%2) " ) , path , error_msg ) < < endmsg ;
2007-01-25 17:42:19 +00:00
goto out ;
2006-12-21 18:38:00 +00:00
}
2006-03-22 22:18:08 +00:00
2006-12-21 18:38:00 +00:00
if ( check_sample_rate & & ( finfo . samplerate ! = ( int ) session - > frame_rate ( ) ) ) {
vector < string > choices ;
2007-09-04 15:01:49 +00:00
if ( multifile ) {
2006-12-21 18:38:00 +00:00
choices . push_back ( _ ( " Cancel entire import " ) ) ;
choices . push_back ( _ ( " Don't embed it " ) ) ;
choices . push_back ( _ ( " Embed all without questions " ) ) ;
2007-01-25 17:42:19 +00:00
Gtkmm2ext : : Choice rate_choice (
2007-01-29 20:02:43 +00:00
string_compose ( _ ( " %1 \n This audiofile's sample rate doesn't match the session sample rate! " ) ,
short_path ( path , 40 ) ) ,
2007-01-25 17:42:19 +00:00
choices , false ) ;
int resx = rate_choice . run ( ) ;
switch ( resx ) {
case 0 : /* stop a multi-file import */
2007-07-06 03:11:52 +00:00
ret = - 2 ;
goto out ;
case 1 : /* don't embed this one */
2007-01-25 17:42:19 +00:00
ret = - 1 ;
goto out ;
case 2 : /* do it, and the rest without asking */
check_sample_rate = false ;
break ;
case 3 : /* do it */
break ;
default :
ret = - 2 ;
goto out ;
}
2006-12-21 18:38:00 +00:00
} else {
choices . push_back ( _ ( " Cancel " ) ) ;
2007-01-25 17:42:19 +00:00
choices . push_back ( _ ( " Embed it anyway " ) ) ;
2006-12-21 18:38:00 +00:00
2007-01-25 17:42:19 +00:00
Gtkmm2ext : : Choice rate_choice (
string_compose ( _ ( " %1 \n This audiofile's sample rate doesn't match the session sample rate! " ) , path ) ,
choices , false ) ;
int resx = rate_choice . run ( ) ;
switch ( resx ) {
case 0 : /* don't import */
ret = - 1 ;
goto out ;
case 1 : /* do it */
break ;
default :
ret = - 2 ;
goto out ;
}
2006-12-21 18:38:00 +00:00
}
2006-08-31 13:23:43 +00:00
}
2006-03-22 22:18:08 +00:00
2008-02-26 16:34:45 +00:00
track_canvas - > get_window ( ) - > set_cursor ( Gdk : : Cursor ( Gdk : : WATCH ) ) ;
2007-01-25 17:42:19 +00:00
2007-09-03 22:46:21 +00:00
for ( int n = 0 ; n < finfo . channels ; + + n ) {
2006-12-21 18:38:00 +00:00
try {
2007-03-15 19:42:42 +00:00
/* check if we have this thing embedded already */
boost : : shared_ptr < Source > s ;
if ( ( s = session - > source_by_path_and_channel ( path , n ) ) = = 0 ) {
2008-02-27 13:56:14 +00:00
cerr < < " add embed/import source with defer_peaks = true \n " ;
2007-03-15 19:42:42 +00:00
source = boost : : dynamic_pointer_cast < AudioFileSource > ( SourceFactory : : createReadable
( * session , path , n ,
( mode = = ImportAsTapeTrack ?
AudioFileSource : : Destructive :
2007-09-09 16:44:43 +00:00
AudioFileSource : : Flag ( 0 ) ) ,
true , true ) ) ;
2007-03-15 19:42:42 +00:00
} else {
source = boost : : dynamic_pointer_cast < AudioFileSource > ( s ) ;
}
2007-01-25 17:42:19 +00:00
2006-12-21 18:38:00 +00:00
sources . push_back ( source ) ;
}
catch ( failed_constructor & err ) {
error < < string_compose ( _ ( " could not open %1 " ) , path ) < < endmsg ;
goto out ;
}
ARDOUR_UI : : instance ( ) - > flush_pending ( ) ;
}
}
2006-03-22 17:03:00 +00:00
if ( sources . empty ( ) ) {
goto out ;
}
2006-11-11 00:14:12 +00:00
2007-09-09 13:04:23 +00:00
ret = add_sources ( paths , sources , pos , mode , target_regions , target_tracks , track , true ) ;
2007-09-03 22:46:21 +00:00
out :
2008-02-26 16:34:45 +00:00
track_canvas - > get_window ( ) - > set_cursor ( * current_canvas_cursor ) ;
2007-09-03 22:46:21 +00:00
return ret ;
}
int
2007-09-04 15:01:49 +00:00
Editor : : add_sources ( vector < Glib : : ustring > paths , SourceList & sources , nframes64_t & pos , ImportMode mode ,
2007-09-09 13:04:23 +00:00
int target_regions , int target_tracks , boost : : shared_ptr < AudioTrack > & track , bool add_channel_suffix )
2007-09-03 22:46:21 +00:00
{
2007-09-04 15:01:49 +00:00
vector < boost : : shared_ptr < AudioRegion > > regions ;
2007-09-03 22:46:21 +00:00
ustring region_name ;
uint32_t input_chan = 0 ;
uint32_t output_chan = 0 ;
2006-11-11 00:14:12 +00:00
2007-08-30 20:25:47 +00:00
if ( pos = = - 1 ) { // "use timestamp"
if ( sources [ 0 ] - > natural_position ( ) ! = 0 ) {
pos = sources [ 0 ] - > natural_position ( ) ;
} else {
2007-11-07 17:05:46 +00:00
pos = get_preferred_edit_position ( ) ;
2007-08-30 20:25:47 +00:00
}
}
2007-09-04 15:01:49 +00:00
if ( target_regions = = 1 ) {
2007-01-25 17:42:19 +00:00
2007-08-30 20:25:47 +00:00
/* take all the sources we have and package them up as a region */
2007-09-09 13:04:23 +00:00
region_name = region_name_from_path ( paths . front ( ) , ( sources . size ( ) > 1 ) , false ) ;
2007-08-30 20:25:47 +00:00
2007-09-04 15:01:49 +00:00
regions . push_back ( boost : : dynamic_pointer_cast < AudioRegion >
( RegionFactory : : create ( sources , 0 , sources [ 0 ] - > length ( ) , region_name , 0 ,
Region : : Flag ( Region : : DefaultFlags | Region : : WholeFile | Region : : External ) ) ) ) ;
2007-08-30 20:25:47 +00:00
2007-09-04 15:01:49 +00:00
} else if ( target_regions = = - 1 ) {
2007-08-30 20:25:47 +00:00
/* take each source and create a region for each one */
SourceList just_one ;
SourceList : : iterator x ;
2007-09-09 13:04:23 +00:00
uint32_t n ;
2007-09-02 15:17:13 +00:00
2007-09-09 13:04:23 +00:00
for ( n = 0 , x = sources . begin ( ) ; x ! = sources . end ( ) ; + + x , + + n ) {
2007-08-30 20:25:47 +00:00
just_one . clear ( ) ;
just_one . push_back ( * x ) ;
2007-09-09 13:04:23 +00:00
2007-09-04 15:01:49 +00:00
boost : : shared_ptr < AudioFileSource > afs = boost : : dynamic_pointer_cast < AudioFileSource > ( * x ) ;
2007-09-09 13:04:23 +00:00
region_name = region_name_from_path ( afs - > path ( ) , false , true , sources . size ( ) , n ) ;
2007-09-04 15:01:49 +00:00
regions . push_back ( boost : : dynamic_pointer_cast < AudioRegion >
( RegionFactory : : create ( just_one , 0 , ( * x ) - > length ( ) , region_name , 0 ,
Region : : Flag ( Region : : DefaultFlags | Region : : WholeFile | Region : : External ) ) ) ) ;
2007-08-30 20:25:47 +00:00
2007-09-04 15:01:49 +00:00
}
}
2007-09-02 15:17:13 +00:00
2007-09-04 21:01:32 +00:00
if ( target_regions = = 1 ) {
input_chan = regions . front ( ) - > n_channels ( ) ;
} else {
if ( target_tracks = = 1 ) {
input_chan = regions . size ( ) ;
} else {
input_chan = 1 ;
}
}
2007-09-02 15:17:13 +00:00
2007-09-04 15:01:49 +00:00
if ( Config - > get_output_auto_connect ( ) & AutoConnectMaster ) {
output_chan = ( session - > master_out ( ) ? session - > master_out ( ) - > n_inputs ( ) : input_chan ) ;
} else {
output_chan = input_chan ;
}
2007-08-30 20:25:47 +00:00
2007-09-09 13:04:23 +00:00
int n = 0 ;
2007-09-04 15:01:49 +00:00
2007-09-09 13:04:23 +00:00
for ( vector < boost : : shared_ptr < AudioRegion > > : : iterator r = regions . begin ( ) ; r ! = regions . end ( ) ; + + r , + + n ) {
2007-09-04 15:01:49 +00:00
2007-09-09 13:04:23 +00:00
finish_bringing_in_audio ( * r , input_chan , output_chan , pos , mode , track ) ;
2007-09-12 19:10:04 +00:00
2007-09-04 15:01:49 +00:00
if ( target_tracks ! = 1 ) {
track . reset ( ) ;
} else {
pos + = ( * r ) - > length ( ) ;
}
2006-03-22 17:03:00 +00:00
}
2006-12-21 18:38:00 +00:00
2007-09-12 19:10:04 +00:00
/* setup peak file building in another thread */
for ( SourceList : : iterator x = sources . begin ( ) ; x ! = sources . end ( ) ; + + x ) {
SourceFactory : : setup_peakfile ( * x , true ) ;
}
2007-09-03 22:46:21 +00:00
return 0 ;
2006-03-22 17:03:00 +00:00
}
2007-09-03 22:46:21 +00:00
2006-03-22 17:03:00 +00:00
int
2007-09-02 15:17:13 +00:00
Editor : : finish_bringing_in_audio ( boost : : shared_ptr < AudioRegion > region , uint32_t in_chans , uint32_t out_chans , nframes64_t & pos ,
2007-09-04 21:01:32 +00:00
ImportMode mode , boost : : shared_ptr < AudioTrack > & existing_track )
2006-08-04 02:18:45 +00:00
{
switch ( mode ) {
case ImportAsRegion :
/* relax, its been done */
break ;
2006-03-22 17:03:00 +00:00
case ImportToTrack :
2007-09-02 15:17:13 +00:00
{
2007-09-04 21:01:32 +00:00
if ( ! existing_track ) {
2007-09-24 20:00:48 +00:00
existing_track = get_nth_selected_audio_track ( 0 ) ;
if ( ! existing_track ) {
2007-09-04 21:01:32 +00:00
return - 1 ;
}
2006-03-22 17:03:00 +00:00
}
2007-09-04 21:01:32 +00:00
boost : : shared_ptr < Playlist > playlist = existing_track - > diskstream ( ) - > playlist ( ) ;
2007-09-02 15:17:13 +00:00
boost : : shared_ptr < AudioRegion > copy ( boost : : dynamic_pointer_cast < AudioRegion > ( RegionFactory : : create ( region ) ) ) ;
begin_reversible_command ( _ ( " insert sndfile " ) ) ;
XMLNode & before = playlist - > get_state ( ) ;
playlist - > add_region ( copy , pos ) ;
session - > add_command ( new MementoCommand < Playlist > ( * playlist , & before , & playlist - > get_state ( ) ) ) ;
commit_reversible_command ( ) ;
break ;
}
2006-03-22 17:03:00 +00:00
case ImportAsTrack :
2006-08-04 02:18:45 +00:00
{
2007-09-02 15:17:13 +00:00
if ( ! existing_track ) {
list < boost : : shared_ptr < AudioTrack > > at ( session - > new_audio_track ( in_chans , out_chans , Normal , 1 ) ) ;
2007-09-09 13:04:23 +00:00
2007-09-02 15:17:13 +00:00
if ( at . empty ( ) ) {
return - 1 ;
}
2007-09-09 13:04:23 +00:00
2007-09-02 15:17:13 +00:00
existing_track = at . front ( ) ;
2007-09-09 13:04:23 +00:00
existing_track - > set_name ( region - > name ( ) , this ) ;
2006-08-16 20:22:44 +00:00
}
2007-09-09 13:04:23 +00:00
2007-09-02 15:17:13 +00:00
boost : : shared_ptr < AudioRegion > copy ( boost : : dynamic_pointer_cast < AudioRegion > ( RegionFactory : : create ( region ) ) ) ;
existing_track - > diskstream ( ) - > playlist ( ) - > add_region ( copy , pos ) ;
2006-08-04 02:18:45 +00:00
break ;
}
2007-09-02 15:17:13 +00:00
2006-08-04 02:18:45 +00:00
case ImportAsTapeTrack :
{
2006-08-17 02:12:20 +00:00
list < boost : : shared_ptr < AudioTrack > > at ( session - > new_audio_track ( in_chans , out_chans , Destructive ) ) ;
2006-08-16 20:22:44 +00:00
if ( ! at . empty ( ) ) {
2006-08-25 01:07:15 +00:00
boost : : shared_ptr < AudioRegion > copy ( boost : : dynamic_pointer_cast < AudioRegion > ( RegionFactory : : create ( region ) ) ) ;
2007-08-30 20:25:47 +00:00
at . front ( ) - > set_name ( basename_nosuffix ( copy - > name ( ) ) , this ) ;
2006-08-25 01:07:15 +00:00
at . front ( ) - > diskstream ( ) - > playlist ( ) - > add_region ( copy , pos ) ;
2006-08-16 20:22:44 +00:00
}
2006-03-22 17:03:00 +00:00
break ;
}
2006-08-04 02:18:45 +00:00
}
2006-03-22 17:03:00 +00:00
return 0 ;
}
void *
Editor : : _import_thread ( void * arg )
{
PBD : : ThreadCreated ( pthread_self ( ) , X_ ( " Import " ) ) ;
Editor * ed = ( Editor * ) arg ;
return ed - > import_thread ( ) ;
}
void *
Editor : : import_thread ( )
{
2008-01-04 03:37:07 +00:00
session - > import_audiofiles ( import_status ) ;
2006-03-22 17:03:00 +00:00
pthread_exit_pbd ( 0 ) ;
/*NOTREACHED*/
return 0 ;
}
gint
Editor : : import_progress_timeout ( void * arg )
{
2008-02-27 14:40:59 +00:00
bool reset = false ;
if ( ! interthread_progress_window - > is_visible ( ) ) {
interthread_progress_window - > show_all ( ) ;
reset = true ;
}
2006-03-22 17:03:00 +00:00
interthread_progress_label . set_text ( import_status . doing_what ) ;
if ( import_status . freeze ) {
interthread_cancel_button . set_sensitive ( false ) ;
} else {
interthread_cancel_button . set_sensitive ( true ) ;
}
if ( import_status . doing_what = = " building peak files " ) {
interthread_progress_bar . pulse ( ) ;
return FALSE ;
} else {
2008-02-27 14:40:59 +00:00
float val = import_status . progress ;
interthread_progress_bar . set_fraction ( min ( max ( 0.0f , val ) , 1.0f ) ) ;
2006-03-22 17:03:00 +00:00
}
2008-02-27 14:40:59 +00:00
if ( reset ) {
/* the window is now visible, speed up the updates */
interthread_progress_connection . disconnect ( ) ;
interthread_progress_connection = Glib : : signal_timeout ( ) . connect
( bind ( mem_fun ( * this , & Editor : : import_progress_timeout ) , ( gpointer ) 0 ) , 100 ) ;
return false ;
} else {
return ! ( import_status . done | | import_status . cancel ) ;
}
2006-03-22 17:03:00 +00:00
}