2006-03-22 12:03:00 -05:00
/*
2019-08-02 17:26:43 -04:00
* Copyright ( C ) 2006 - 2014 David Robillard < d @ drobilla . net >
* Copyright ( C ) 2006 - 2017 Paul Davis < paul @ linuxaudiosystems . com >
* Copyright ( C ) 2006 Taybin Rutkin < taybin @ taybin . com >
* Copyright ( C ) 2007 Tim Mayberry < mojofunk @ gmail . com >
* Copyright ( C ) 2009 - 2012 Carl Hetherington < carl @ carlh . net >
* Copyright ( C ) 2012 - 2019 Robin Gareus < robin @ gareus . org >
* Copyright ( C ) 2013 - 2014 Colin Fletcher < colin . m . fletcher @ googlemail . com >
* Copyright ( C ) 2015 - 2017 Nick Mainsbridge < mainsbridge @ gmail . com >
*
* 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 . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2006-03-22 12:03:00 -05:00
2007-04-12 19:20:37 -04:00
# include <sys/types.h>
# include <sys/stat.h>
2007-10-11 18:07:47 -04:00
# include <sys/time.h>
2007-04-12 19:20:37 -04:00
# include <errno.h>
# include <unistd.h>
2008-03-17 16:54:03 -04:00
# include <algorithm>
2007-04-12 19:20:37 -04:00
2007-10-11 18:07:47 -04:00
# include <sndfile.h>
2021-01-24 17:26:19 -05:00
# include "pbd/integer_division.h"
2009-02-25 13:26:51 -05:00
# include "pbd/pthread_utils.h"
# include "pbd/basename.h"
# include "pbd/shortpath.h"
2010-03-02 13:05:26 -05:00
# include "pbd/stateful_diff_command.h"
2006-03-22 12:03:00 -05:00
2017-07-16 22:55:52 -04:00
# include "widgets/choice.h"
2006-03-22 12:03:00 -05:00
2009-02-25 13:26:51 -05:00
# include "ardour/audio_track.h"
# include "ardour/audiofilesource.h"
2012-05-24 02:09:29 -04:00
# include "ardour/audioregion.h"
# include "ardour/midi_region.h"
# include "ardour/midi_track.h"
# include "ardour/operations.h"
2017-01-20 15:47:09 -05:00
# include "ardour/profile.h"
2009-02-25 13:26:51 -05:00
# include "ardour/region_factory.h"
2010-05-19 19:36:18 -04:00
# include "ardour/smf_source.h"
2012-05-24 02:09:29 -04:00
# include "ardour/source_factory.h"
2022-01-10 22:06:52 -05:00
# include "ardour/triggerbox.h"
2012-05-24 02:09:29 -04:00
# include "ardour/utils.h"
2009-02-25 13:26:51 -05:00
# include "pbd/memento_command.h"
2006-03-22 12:03:00 -05:00
2019-12-14 17:31:24 -05:00
# include "ardour_message.h"
2006-03-22 12:03:00 -05:00
# include "ardour_ui.h"
2014-12-20 01:11:28 -05:00
# include "cursor_context.h"
2006-03-22 12:03:00 -05:00
# include "editor.h"
# include "sfdb_ui.h"
# include "editing.h"
# include "audio_time_axis.h"
2008-02-18 14:45:52 -05:00
# include "midi_time_axis.h"
2008-09-26 04:29:30 -04:00
# include "session_import_dialog.h"
2008-12-12 09:43:24 -05:00
# include "gui_thread.h"
2010-04-14 18:16:46 -04:00
# include "interthread_progress_window.h"
2010-11-16 09:53:16 -05:00
# include "mouse_cursors.h"
# include "editor_cursors.h"
2022-02-09 20:21:53 -05:00
# include "utils.h"
2006-03-22 12:03:00 -05:00
2016-07-14 14:44:52 -04:00
# include "pbd/i18n.h"
2006-03-22 12:03:00 -05:00
using namespace std ;
using namespace ARDOUR ;
Large nasty commit in the form of a 5000 line patch chock-full of completely
unecessary changes. (Sorry, doing a "sprint" based thing, this is the end of the first one)
Achieved MIDI track and bus creation, associated Jack port and diskstream creation, and minimal GUI stuff for creating them. Should be set to start work on actually recording and playing midi to/from disk now.
Relevant (significant) changes:
- Creation of a Buffer class. Base class is type agnostic so things can point to a buffer but not care what kind it is (otherwise it'd be a template). Derived into AudioBuffer and MidiBuffer, with a type tag because checking type is necessary in parts of the code where dynamic_cast wouldn't be wise. Originally I considered this a hack, but passing around a type proved to be a very good solution to all the other problems (below). There is a 1:1 mapping between jack port data types and ardour Buffer types (with a conversion function), but that's easily removed if it ever becomes necessary. Having the type scoped in the Buffer class is maybe not the best spot for it, but whatever (this is proof of concept kinda stuff right now...)
- IO now has a "default" port type (passed to the constructor and stored as a member), used by ensure_io (and similar) to create n ports. IO::register_***_port has a type argument that defaults to the default type if not passed. Rationale: previous IO API is identical, no changes needed to existing code, but path is paved for multiple port types in one IO, which we will need for eg synth plugin inserts, among other things. This is not quite ideal (best would be to only have the two port register functions and have them take a type), but the alternative is a lot of work (namely destroying the 'ensure' functions and everything that uses them) for very little gain. (I am convinced after quite a few tries at the whiteboard that subclassing IO in any way is not a feasible option, look at it's inheritance diagram in Doxygen and you can see why)
- AudioEngine::register_audio_input_port is now register_input_port and takes a type argument. Ditto for output.
- (Most significant change) AudioDiskstream abstracted into Distream, and sibling MidiDiskstream created. Very much still a work in progress, but Diskstream is there to switch references over to (most already are), which is the important part. It is still unclear what the MIDI diskstream's relation to channels is, but I'm pretty sure they will be single channel only (so SMF Type 0) since noone can come up with a reason otherwise.
- MidiTrack creation. Same thing as AudioTrack but with a different default type basically. No big deal here.
- Random cleanups and variable renamings etc. because I have OCD and can't help myself. :)
Known broken: Loading of sessions containing MIDI tracks.
git-svn-id: svn://localhost/ardour2/branches/midi@641 d708f5d6-7413-0410-9779-e7cbd77b26cf
2006-06-26 12:01:34 -04:00
using namespace PBD ;
2006-03-22 12:03:00 -05:00
using namespace Gtk ;
2007-03-19 03:07:38 -04:00
using namespace Gtkmm2ext ;
2006-03-22 12:03:00 -05:00
using namespace Editing ;
2020-11-11 11:31:52 -05:00
using namespace Temporal ;
2010-09-14 12:51:02 -04:00
using std : : string ;
2006-03-22 12:03:00 -05:00
/* Functions supporting the incorporation of external (non-captured) audio material into ardour */
void
2007-10-11 18:07:47 -04:00
Editor : : add_external_audio_action ( ImportMode mode_hint )
2006-03-22 12:03:00 -05:00
{
2009-12-17 13:24:23 -05:00
if ( _session = = 0 ) {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( _ ( " You can't import or embed an audiofile until you have a session loaded. " ) ) ;
2007-10-11 18:07:47 -04:00
msg . run ( ) ;
return ;
}
2011-06-01 13:00:29 -04:00
2007-10-11 18:07:47 -04:00
if ( sfbrowser = = 0 ) {
2015-10-08 20:05:41 -04:00
sfbrowser = new SoundFileOmega ( _ ( " Add Existing Media " ) , _session , 0 , 0 , true , mode_hint ) ;
2007-10-11 18:07:47 -04:00
} else {
sfbrowser - > set_mode ( mode_hint ) ;
2006-03-22 12:03:00 -05:00
}
2007-10-11 18:07:47 -04:00
external_audio_dialog ( ) ;
2006-03-22 12:03:00 -05:00
}
void
2007-10-11 18:07:47 -04:00
Editor : : external_audio_dialog ( )
2006-03-22 12:03:00 -05:00
{
2010-09-14 11:45:21 -04:00
vector < string > paths ;
2011-07-26 13:22:10 -04:00
uint32_t audio_track_cnt ;
uint32_t midi_track_cnt ;
2007-10-11 18:07:47 -04:00
2009-12-17 13:24:23 -05:00
if ( _session = = 0 ) {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( _ ( " You can't import or embed an audiofile until you have a session loaded. " ) ) ;
2006-03-22 12:03:00 -05:00
msg . run ( ) ;
return ;
}
2009-10-14 12:10:01 -04:00
2011-07-26 13:22:10 -04:00
audio_track_cnt = 0 ;
midi_track_cnt = 0 ;
2006-03-22 12:03:00 -05:00
2007-10-11 18:07:47 -04:00
for ( TrackSelection : : iterator x = selection - > tracks . begin ( ) ; x ! = selection - > tracks . end ( ) ; + + x ) {
2009-07-09 13:58:13 -04:00
AudioTimeAxisView * atv = dynamic_cast < AudioTimeAxisView * > ( * x ) ;
2009-10-14 12:10:01 -04:00
2011-07-26 13:22:10 -04:00
if ( atv ) {
if ( atv - > is_audio_track ( ) ) {
audio_track_cnt + + ;
2015-10-04 14:51:05 -04:00
}
2011-07-26 13:22:10 -04:00
} else {
MidiTimeAxisView * mtv = dynamic_cast < MidiTimeAxisView * > ( * x ) ;
if ( mtv ) {
if ( mtv - > is_midi_track ( ) ) {
midi_track_cnt + + ;
}
}
2007-10-11 18:07:47 -04:00
}
}
if ( sfbrowser = = 0 ) {
2012-12-23 15:34:43 -05:00
sfbrowser = new SoundFileOmega ( _ ( " Add Existing Media " ) , _session , audio_track_cnt , midi_track_cnt , true ) ;
2007-10-11 18:07:47 -04:00
} else {
2011-07-26 13:22:10 -04:00
sfbrowser - > reset ( audio_track_cnt , midi_track_cnt ) ;
2007-10-11 18:07:47 -04:00
}
sfbrowser - > show_all ( ) ;
2008-02-16 17:43:18 -05:00
}
2008-09-26 04:29:30 -04:00
void
Editor : : session_import_dialog ( )
{
2009-12-17 13:24:23 -05:00
SessionImportDialog dialog ( _session ) ;
2008-09-26 04:29:30 -04:00
dialog . run ( ) ;
}
2008-02-16 17:43:18 -05:00
typedef std : : map < PBD : : ID , boost : : shared_ptr < ARDOUR : : Source > > SourceMap ;
/**
2012-06-09 11:04:11 -04:00
* Updating is still disabled , see note in libs / ardour / import . cc Session : : import_files ( )
2008-02-16 17:43:18 -05:00
*
* 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 )
{
string wave_name ( Glib : : path_get_basename ( path ) ) ;
2010-11-09 17:18:52 -05:00
bool already_exists = false ;
2010-11-25 15:37:39 -05:00
uint32_t existing ;
2008-02-16 17:43:18 -05:00
2010-11-25 15:37:39 -05:00
if ( ( existing = _session - > count_sources_by_origin ( path ) ) > 0 ) {
already_exists = true ;
}
2007-10-11 18:07:47 -04:00
2008-02-16 17:43:18 -05:00
int function = 1 ;
2010-11-09 17:18:52 -05:00
if ( already_exists ) {
2008-02-16 17:43:18 -05:00
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);
2009-08-01 20:32:51 -04:00
message = string_compose ( _ ( " The session already contains a source file named %1. Do you want to import %1 as a new file, or skip it? " ) , wave_name ) ;
2008-02-16 17:43:18 -05:00
} else {
2009-08-01 20:32:51 -04:00
message = string_compose ( _ ( " The session already contains a source file named %1. Do you want to import %2 as a new source, or skip it? " ) , wave_name , wave_name ) ;
2008-02-16 17:43:18 -05:00
}
2019-12-14 17:31:24 -05:00
ArdourMessageDialog dialog ( message , false , Gtk : : MESSAGE_QUESTION , Gtk : : BUTTONS_NONE , true ) ;
2008-02-16 17:43:18 -05:00
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 ) ;
}
2009-10-14 12:10:01 -04:00
2008-02-16 17:43:18 -05:00
//dialog.add_button("Skip all", 4); // All or rest?
function = dialog . run ( ) ;
dialog . hide ( ) ;
2006-03-22 12:03:00 -05:00
}
2008-02-16 17:43:18 -05:00
return function ;
2006-03-22 12:03:00 -05:00
}
2007-10-11 18:07:47 -04:00
boost : : shared_ptr < AudioTrack >
Editor : : get_nth_selected_audio_track ( int nth ) const
2006-03-22 12:03:00 -05:00
{
2009-07-09 13:58:13 -04:00
AudioTimeAxisView * atv ;
2007-10-11 18:07:47 -04:00
TrackSelection : : iterator x ;
2009-10-14 12:10:01 -04:00
2007-10-11 18:07:47 -04:00
for ( x = selection - > tracks . begin ( ) ; nth > 0 & & x ! = selection - > tracks . end ( ) ; + + x ) {
2006-03-22 12:03:00 -05:00
2009-07-09 13:58:13 -04:00
atv = dynamic_cast < AudioTimeAxisView * > ( * x ) ;
2009-10-14 12:10:01 -04:00
2007-10-11 18:07:47 -04:00
if ( ! atv ) {
continue ;
} else if ( atv - > is_audio_track ( ) ) {
- - nth ;
}
2006-03-22 12:03:00 -05:00
}
2009-10-14 12:10:01 -04:00
2007-10-11 18:07:47 -04:00
if ( x = = selection - > tracks . end ( ) ) {
2009-07-09 13:58:13 -04:00
atv = dynamic_cast < AudioTimeAxisView * > ( selection - > tracks . back ( ) ) ;
2007-10-11 18:07:47 -04:00
} else {
2009-07-09 13:58:13 -04:00
atv = dynamic_cast < AudioTimeAxisView * > ( * x ) ;
2007-10-11 18:07:47 -04:00
}
2009-10-14 12:10:01 -04:00
2007-10-11 18:07:47 -04:00
if ( ! atv | | ! atv - > is_audio_track ( ) ) {
return boost : : shared_ptr < AudioTrack > ( ) ;
}
2009-10-14 12:10:01 -04:00
2007-10-11 18:07:47 -04:00
return atv - > audio_track ( ) ;
2009-10-14 12:10:01 -04:00
}
2006-03-22 12:03:00 -05:00
2008-02-18 14:45:52 -05:00
boost : : shared_ptr < MidiTrack >
Editor : : get_nth_selected_midi_track ( int nth ) const
{
2009-07-09 13:58:13 -04:00
MidiTimeAxisView * mtv ;
2008-02-18 14:45:52 -05:00
TrackSelection : : iterator x ;
2009-10-14 12:10:01 -04:00
2008-02-18 14:45:52 -05:00
for ( x = selection - > tracks . begin ( ) ; nth > 0 & & x ! = selection - > tracks . end ( ) ; + + x ) {
2009-07-09 13:58:13 -04:00
mtv = dynamic_cast < MidiTimeAxisView * > ( * x ) ;
2009-10-14 12:10:01 -04:00
2008-02-18 14:45:52 -05:00
if ( ! mtv ) {
continue ;
} else if ( mtv - > is_midi_track ( ) ) {
- - nth ;
}
}
2009-10-14 12:10:01 -04:00
2008-02-18 14:45:52 -05:00
if ( x = = selection - > tracks . end ( ) ) {
2009-07-09 13:58:13 -04:00
mtv = dynamic_cast < MidiTimeAxisView * > ( selection - > tracks . back ( ) ) ;
2008-02-18 14:45:52 -05:00
} else {
2009-07-09 13:58:13 -04:00
mtv = dynamic_cast < MidiTimeAxisView * > ( * x ) ;
2008-02-18 14:45:52 -05:00
}
2009-10-14 12:10:01 -04:00
2008-02-18 14:45:52 -05:00
if ( ! mtv | | ! mtv - > is_midi_track ( ) ) {
return boost : : shared_ptr < MidiTrack > ( ) ;
}
2009-10-14 12:10:01 -04:00
2008-02-18 14:45:52 -05:00
return mtv - > midi_track ( ) ;
2009-10-14 12:10:01 -04:00
}
2008-02-18 14:45:52 -05:00
2016-12-16 11:49:52 -05:00
void
2020-10-19 14:37:54 -04:00
Editor : : import_smf_tempo_map ( Evoral : : SMF const & smf , timepos_t const & pos )
2016-12-16 11:49:52 -05:00
{
if ( ! _session ) {
return ;
}
const size_t num_tempos = smf . num_tempos ( ) ;
if ( num_tempos = = 0 ) {
return ;
}
2021-01-24 17:25:43 -05:00
/* we have to create this in order to start the update process, but
we ' re going to throw it away by creating our own new map and
populating it . This will go out of scope when we return from this
method .
*/
TempoMap : : SharedPtr ignore ( TempoMap : : write_copy ( ) ) ;
/* cannot create an empty TempoMap, so create one with "default" single
values for tempo and meter , then overwrite them .
*/
2022-04-08 11:23:39 -04:00
TempoMap : : WritableSharedPtr new_map ( new TempoMap ( Tempo ( 120 , 4 ) , Meter ( 4 , 4 ) ) ) ;
2017-01-04 11:49:59 -05:00
Meter last_meter ( 4.0 , 4.0 ) ;
bool have_initial_meter = false ;
2016-12-16 11:49:52 -05:00
for ( size_t n = 0 ; n < num_tempos ; + + n ) {
Evoral : : SMF : : Tempo * t = smf . nth_tempo ( n ) ;
assert ( t ) ;
2017-02-27 11:11:22 -05:00
Tempo tempo ( t - > tempo ( ) , 32.0 / ( double ) t - > notes_per_note ) ;
2021-01-24 17:26:19 -05:00
cerr < < " new tempo from SMF : " < < tempo < < endl ;
2016-12-16 11:49:52 -05:00
Meter meter ( t - > numerator , t - > denominator ) ;
2021-01-24 17:26:19 -05:00
cerr < < " new meter from SMF : " < < meter < < endl ;
2020-07-23 19:46:49 -04:00
Temporal : : BBT_Time bbt ; /* 1|1|0 which is correct for the no-meter case */
2017-01-04 11:49:59 -05:00
if ( have_initial_meter ) {
2021-01-24 17:26:19 -05:00
2021-03-25 12:24:20 -04:00
bbt = new_map - > bbt_at ( timepos_t ( Temporal : : Beats ( int_div_round ( t - > time_pulses * 4 , ( size_t ) smf . ppqn ( ) ) , 0 ) ) ) ;
2021-01-24 17:26:19 -05:00
new_map - > set_tempo ( tempo , bbt ) ;
2017-01-04 11:49:59 -05:00
if ( ! ( meter = = last_meter ) ) {
2020-11-25 19:05:24 -05:00
new_map - > set_meter ( meter , bbt ) ;
2017-01-04 11:49:59 -05:00
}
} else {
2020-11-25 19:05:24 -05:00
new_map - > set_meter ( meter , bbt ) ;
new_map - > set_tempo ( tempo , bbt ) ;
2017-01-04 11:49:59 -05:00
have_initial_meter = true ;
2016-12-16 11:49:52 -05:00
}
2017-01-04 11:49:59 -05:00
last_meter = meter ;
2016-12-16 11:49:52 -05:00
}
2020-11-25 19:05:24 -05:00
TempoMap : : update ( new_map ) ;
2016-12-16 11:49:52 -05:00
}
2021-05-07 16:57:41 -04:00
void
2020-10-19 14:37:54 -04:00
Editor : : import_smf_markers ( Evoral : : SMF & smf , timepos_t const & pos )
2021-05-07 16:57:41 -04:00
{
if ( ! _session ) {
return ;
}
smf . load_markers ( ) ;
Evoral : : SMF : : Markers const & markers = smf . markers ( ) ;
if ( markers . empty ( ) ) {
return ;
}
for ( Evoral : : SMF : : Markers : : const_iterator m = markers . begin ( ) ; m ! = markers . end ( ) ; + + m ) {
2020-10-19 14:37:54 -04:00
Beats beats = Beats : : from_double ( m - > time_pulses / ( double ) smf . ppqn ( ) ) ;
2021-07-04 11:38:03 -04:00
Location * loc = new Location ( * _session , timepos_t ( beats ) , timepos_t ( Temporal : : BeatTime ) , m - > text , Location : : IsMark ) ;
2021-05-07 16:57:41 -04:00
_session - > locations ( ) - > add ( loc ) ;
}
}
2007-10-11 18:07:47 -04:00
void
2019-04-08 13:53:33 -04:00
Editor : : do_import ( vector < string > paths ,
ImportDisposition disposition ,
ImportMode mode ,
SrcQuality quality ,
MidiTrackNameSource midi_track_name_source ,
2016-12-16 09:57:14 -05:00
MidiTempoMapDisposition smf_tempo_disposition ,
2020-09-26 11:14:59 -04:00
timepos_t & pos ,
2021-05-07 16:57:41 -04:00
ARDOUR : : PluginInfoPtr instrument ,
2020-09-26 11:14:59 -04:00
bool with_markers )
2007-10-11 18:07:47 -04:00
{
2008-02-18 14:45:52 -05:00
boost : : shared_ptr < Track > track ;
2010-09-14 11:45:21 -04:00
vector < string > to_import ;
2007-10-11 18:07:47 -04:00
int nth = 0 ;
2020-12-03 23:34:48 -05:00
bool use_timestamp = ( pos = = timepos_t : : max ( pos . time_domain ( ) ) ) ;
2021-07-07 23:24:02 -04:00
std : : string const & pgroup_id = Playlist : : generate_pgroup_id ( ) ;
2007-01-09 18:24:54 -05:00
2021-05-07 16:57:41 -04:00
/* XXX nutempo2: we will import markers using music (beat) time, which
will make any imported tempo map irrelevant . Not doing that ( in 6.7 ,
before nutempo2 ) is much more complicated because we don ' t know
which file may have the tempo map , and if we ' re importing that
it will change the marker positions . So for now , there ' s an implicit
limitation that if you import more than 1 MIDI file and the first
has markers but the second has the tempo map , the markers could be
in the wrong position .
*/
if ( with_markers | | ( smf_tempo_disposition = = SMFTempoUse ) ) {
bool tempo_map_done = false ;
2016-12-16 11:49:52 -05:00
for ( vector < string > : : iterator a = paths . begin ( ) ; a ! = paths . end ( ) ; + + a ) {
2021-05-07 16:57:41 -04:00
2016-12-16 11:49:52 -05:00
Evoral : : SMF smf ;
2021-05-07 16:57:41 -04:00
2016-12-16 11:49:52 -05:00
if ( smf . open ( * a ) ) {
continue ;
}
2021-05-07 16:57:41 -04:00
/* Find the first MIDI file with a tempo map, and import it
before we do anything else .
*/
if ( ! tempo_map_done & & smf_tempo_disposition = = SMFTempoUse ) {
if ( smf . num_tempos ( ) > 0 ) {
import_smf_tempo_map ( smf , pos ) ;
2021-05-08 20:38:39 -04:00
tempo_map_done = true ;
2021-05-07 16:57:41 -04:00
}
2016-12-16 11:49:52 -05:00
}
2021-05-07 16:57:41 -04:00
if ( with_markers ) {
import_smf_markers ( smf , pos ) ;
}
2016-12-16 11:49:52 -05:00
smf . close ( ) ;
}
}
2010-04-09 21:35:11 -04:00
current_interthread_info = & import_status ;
import_status . current = 1 ;
import_status . total = paths . size ( ) ;
2010-09-29 18:59:39 -04:00
import_status . all_done = false ;
2016-12-14 07:31:16 -05:00
import_status . midi_track_name_source = midi_track_name_source ;
2010-04-09 21:35:11 -04:00
2010-04-14 18:16:46 -04:00
ImportProgressWindow ipw ( & import_status , _ ( " Import " ) , _ ( " Cancel Import " ) ) ;
2010-04-09 21:35:11 -04:00
2013-07-23 11:28:45 -04:00
if ( disposition = = Editing : : ImportMergeFiles ) {
2008-12-12 09:43:24 -05:00
2008-02-16 17:43:18 -05:00
/* create 1 region from all paths, add to 1 track,
ignore " track "
*/
2008-12-12 09:43:24 -05:00
2008-02-16 17:43:18 -05:00
bool cancel = false ;
2010-09-14 11:45:21 -04:00
for ( vector < string > : : iterator a = paths . begin ( ) ; a ! = paths . end ( ) ; + + a ) {
2008-02-16 17:43:18 -05:00
int check = check_whether_and_how_to_import ( * a , false ) ;
if ( check = = 2 ) {
cancel = true ;
break ;
2007-10-11 18:07:47 -04:00
}
2008-02-16 17:43:18 -05:00
}
2007-01-28 12:44:13 -05:00
2020-05-19 12:10:05 -04:00
if ( ! cancel ) {
2010-11-25 15:37:39 -05:00
ipw . show ( ) ;
2021-07-07 23:24:02 -04:00
import_sndfiles ( paths , disposition , mode , quality , pos , 1 , 1 , track , pgroup_id , false , instrument ) ;
2020-02-24 20:37:52 -05:00
import_status . clear ( ) ;
2007-10-11 18:07:47 -04:00
}
2007-01-09 18:24:54 -05:00
2008-02-16 17:43:18 -05:00
} else {
2008-12-12 09:43:24 -05:00
2010-11-25 15:37:39 -05:00
bool replace = false ;
2006-03-22 17:18:08 -05:00
2020-04-17 14:38:46 -04:00
for ( vector < string > : : iterator a = paths . begin ( ) ; a ! = paths . end ( ) & & ! import_status . cancel ; + + a ) {
2009-10-14 12:10:01 -04:00
2010-11-25 15:37:39 -05:00
const int check = check_whether_and_how_to_import ( * a , true ) ;
2011-06-01 13:00:29 -04:00
2010-03-04 18:03:04 -05:00
switch ( check ) {
case 2 :
// user said skip
continue ;
case 0 :
fatal < < " Updating existing sources should be disabled! " < < endmsg ;
2014-11-14 04:47:43 -05:00
abort ( ) ; /* NOTREACHED*/
2010-03-04 18:03:04 -05:00
break ;
case 1 :
replace = false ;
break ;
default :
fatal < < " Illegal return " < < check < < " from check_whether_and_how_to_import()! " < < endmsg ;
2014-11-14 04:47:43 -05:00
abort ( ) ; /* NOTREACHED*/
2009-08-01 20:32:26 -04:00
}
2009-10-14 12:10:01 -04:00
2010-11-25 15:37:39 -05:00
/* have to reset this for every file we handle */
2011-06-01 13:00:29 -04:00
2010-11-25 15:37:39 -05:00
if ( use_timestamp ) {
2020-12-03 23:34:48 -05:00
pos = timepos_t : : max ( pos . time_domain ( ) ) ;
2010-11-25 15:37:39 -05:00
}
2010-08-12 15:43:36 -04:00
2010-11-25 15:37:39 -05:00
ipw . show ( ) ;
2011-06-01 13:00:29 -04:00
2013-07-23 11:28:45 -04:00
switch ( disposition ) {
2010-11-25 15:37:39 -05:00
case Editing : : ImportDistinctFiles :
2011-06-01 13:00:29 -04:00
2010-11-25 15:37:39 -05:00
to_import . clear ( ) ;
to_import . push_back ( * a ) ;
2011-06-01 13:00:29 -04:00
2010-11-25 15:37:39 -05:00
if ( mode = = Editing : : ImportToTrack ) {
track = get_nth_selected_audio_track ( nth + + ) ;
}
2011-06-01 13:00:29 -04:00
2021-07-07 23:24:02 -04:00
import_sndfiles ( to_import , disposition , mode , quality , pos , 1 , - 1 , track , pgroup_id , replace , instrument ) ;
2020-02-24 20:37:52 -05:00
import_status . clear ( ) ;
2010-11-25 15:37:39 -05:00
break ;
2011-06-01 13:00:29 -04:00
2010-11-25 15:37:39 -05:00
case Editing : : ImportDistinctChannels :
2011-06-01 13:00:29 -04:00
2010-11-25 15:37:39 -05:00
to_import . clear ( ) ;
to_import . push_back ( * a ) ;
2011-06-01 13:00:29 -04:00
2021-07-07 23:24:02 -04:00
import_sndfiles ( to_import , disposition , mode , quality , pos , - 1 , - 1 , track , pgroup_id , replace , instrument ) ;
2020-02-24 20:37:52 -05:00
import_status . clear ( ) ;
2010-11-25 15:37:39 -05:00
break ;
2011-06-01 13:00:29 -04:00
2010-11-25 15:37:39 -05:00
case Editing : : ImportSerializeFiles :
2011-06-01 13:00:29 -04:00
2010-11-25 15:37:39 -05:00
to_import . clear ( ) ;
to_import . push_back ( * a ) ;
2010-03-04 18:03:04 -05:00
2021-07-07 23:24:02 -04:00
import_sndfiles ( to_import , disposition , mode , quality , pos , 1 , 1 , track , pgroup_id , replace , instrument ) ;
2020-02-24 20:37:52 -05:00
import_status . clear ( ) ;
2010-11-25 15:37:39 -05:00
break ;
2010-03-04 18:03:04 -05:00
2010-11-25 15:37:39 -05:00
case Editing : : ImportMergeFiles :
// Not entered, handled in earlier if() branch
break ;
}
}
2007-10-11 18:07:47 -04:00
}
2010-09-29 18:59:39 -04:00
import_status . all_done = true ;
2007-10-11 18:07:47 -04:00
}
2007-01-09 18:24:54 -05:00
2007-10-11 18:07:47 -04:00
void
2020-09-26 11:14:59 -04:00
Editor : : do_embed ( vector < string > paths , ImportDisposition import_as , ImportMode mode , timepos_t & pos , ARDOUR : : PluginInfoPtr instrument )
2007-10-11 18:07:47 -04:00
{
2008-02-18 14:45:52 -05:00
boost : : shared_ptr < Track > track ;
2007-10-11 18:07:47 -04:00
bool check_sample_rate = true ;
2010-09-14 11:45:21 -04:00
vector < string > to_embed ;
2007-10-11 18:07:47 -04:00
bool multi = paths . size ( ) > 1 ;
int nth = 0 ;
2020-12-03 23:34:48 -05:00
bool use_timestamp = ( pos = = timepos_t : : max ( pos . time_domain ( ) ) ) ;
2021-07-07 23:24:02 -04:00
std : : string const & pgroup_id = Playlist : : generate_pgroup_id ( ) ;
2007-01-09 18:24:54 -05:00
2013-07-23 11:28:45 -04:00
switch ( import_as ) {
2007-10-11 18:07:47 -04:00
case Editing : : ImportDistinctFiles :
2010-09-14 11:45:21 -04:00
for ( vector < string > : : iterator a = paths . begin ( ) ; a ! = paths . end ( ) ; + + a ) {
2007-01-09 18:24:54 -05:00
2011-06-16 11:18:01 -04:00
/* have to reset this for every file we handle */
if ( use_timestamp ) {
2020-12-03 23:34:48 -05:00
pos = timepos_t : : max ( pos . time_domain ( ) ) ;
2011-06-16 11:18:01 -04:00
}
2007-10-11 18:07:47 -04:00
to_embed . clear ( ) ;
to_embed . push_back ( * a ) ;
2007-01-09 18:24:54 -05:00
2007-10-11 18:07:47 -04:00
if ( mode = = Editing : : ImportToTrack ) {
track = get_nth_selected_audio_track ( nth + + ) ;
}
2007-01-09 18:24:54 -05:00
2021-07-07 23:24:02 -04:00
if ( embed_sndfiles ( to_embed , multi , check_sample_rate , import_as , mode , pos , 1 , - 1 , track , pgroup_id , instrument ) < - 1 ) {
2020-05-19 12:10:05 -04:00
/* error, bail out */
return ;
2007-10-11 18:07:47 -04:00
}
}
break ;
2009-10-14 12:10:01 -04:00
2007-10-11 18:07:47 -04:00
case Editing : : ImportDistinctChannels :
2010-09-14 11:45:21 -04:00
for ( vector < string > : : iterator a = paths . begin ( ) ; a ! = paths . end ( ) ; + + a ) {
2007-01-09 18:24:54 -05:00
2011-06-16 11:18:01 -04:00
/* have to reset this for every file we handle */
if ( use_timestamp ) {
2020-12-03 23:34:48 -05:00
pos = timepos_t : : max ( pos . time_domain ( ) ) ;
2011-06-16 11:18:01 -04:00
}
2007-10-11 18:07:47 -04:00
to_embed . clear ( ) ;
to_embed . push_back ( * a ) ;
2021-07-07 23:24:02 -04:00
if ( embed_sndfiles ( to_embed , multi , check_sample_rate , import_as , mode , pos , - 1 , - 1 , track , pgroup_id , instrument ) < - 1 ) {
2020-05-19 12:10:05 -04:00
/* error, bail out */
return ;
2007-01-09 18:24:54 -05:00
}
2007-10-11 18:07:47 -04:00
}
break ;
2007-01-09 18:24:54 -05:00
2007-10-11 18:07:47 -04:00
case Editing : : ImportMergeFiles :
2021-07-07 23:24:02 -04:00
if ( embed_sndfiles ( paths , multi , check_sample_rate , import_as , mode , pos , 1 , 1 , track , pgroup_id , instrument ) < - 1 ) {
2020-05-19 12:10:05 -04:00
/* error, bail out */
return ;
2007-10-11 18:07:47 -04:00
}
2010-11-25 15:37:39 -05:00
break ;
2007-10-11 18:07:47 -04:00
case Editing : : ImportSerializeFiles :
2010-09-14 11:45:21 -04:00
for ( vector < string > : : iterator a = paths . begin ( ) ; a ! = paths . end ( ) ; + + a ) {
2007-10-11 18:07:47 -04:00
2011-06-16 11:18:01 -04:00
/* have to reset this for every file we handle */
if ( use_timestamp ) {
2020-12-03 23:34:48 -05:00
pos = timepos_t : : max ( pos . time_domain ( ) ) ;
2011-06-16 11:18:01 -04:00
}
2007-10-11 18:07:47 -04:00
to_embed . clear ( ) ;
to_embed . push_back ( * a ) ;
2021-07-07 23:24:02 -04:00
if ( embed_sndfiles ( to_embed , multi , check_sample_rate , import_as , mode , pos , 1 , 1 , track , pgroup_id , instrument ) < - 1 ) {
2020-05-19 12:10:05 -04:00
/* error, bail out */
return ;
2007-01-09 18:24:54 -05:00
}
}
2007-10-11 18:07:47 -04:00
break ;
2007-01-09 18:24:54 -05:00
}
2006-03-22 12:03:00 -05:00
}
2006-03-22 17:18:08 -05:00
int
2014-12-24 20:07:10 -05:00
Editor : : import_sndfiles ( vector < string > paths ,
ImportDisposition disposition ,
ImportMode mode ,
SrcQuality quality ,
2020-10-19 14:37:54 -04:00
timepos_t & pos ,
2014-12-24 20:07:10 -05:00
int target_regions ,
int target_tracks ,
boost : : shared_ptr < Track > & track ,
2021-07-07 23:24:02 -04:00
std : : string const & pgroup_id ,
2014-12-24 20:07:10 -05:00
bool replace ,
ARDOUR : : PluginInfoPtr instrument )
2006-03-22 12:03:00 -05:00
{
2020-05-19 12:30:04 -04:00
/* skip periodic saves while importing */
Session : : StateProtector sp ( _session ) ;
2020-04-17 14:38:46 -04:00
2007-01-09 18:24:54 -05:00
import_status . paths = paths ;
2006-03-22 12:03:00 -05:00
import_status . done = false ;
import_status . freeze = false ;
2007-10-11 18:07:47 -04:00
import_status . quality = quality ;
2008-02-16 17:43:18 -05:00
import_status . replace_existing_source = replace ;
2016-10-05 15:01:21 -04:00
import_status . split_midi_channels = ( disposition = = Editing : : ImportDistinctChannels ) ;
2008-12-12 09:43:24 -05:00
import_status . mode = mode ;
import_status . pos = pos ;
import_status . target_tracks = target_tracks ;
import_status . target_regions = target_regions ;
import_status . track = track ;
import_status . replace = replace ;
2011-06-01 13:00:29 -04:00
2014-12-20 01:11:28 -05:00
CursorContext : : Handle cursor_ctx = CursorContext : : create ( * this , _cursors - > wait ) ;
2008-12-12 09:43:24 -05:00
gdk_flush ( ) ;
2006-03-22 12:03:00 -05:00
2012-06-09 11:04:11 -04:00
/* start import thread for this spec. this will ultimately call Session::import_files()
2008-12-12 09:43:24 -05:00
which , if successful , will add the files as regions to the region list . its up to us
( the GUI ) to direct additional steps after that .
2006-03-22 12:03:00 -05:00
*/
2008-12-12 09:43:24 -05:00
2009-12-08 22:05:14 -05:00
pthread_create_and_store ( " import " , & import_status . thread , _import_thread , this ) ;
2006-03-22 12:03:00 -05:00
pthread_detach ( import_status . thread ) ;
2009-10-14 12:10:01 -04:00
2008-12-12 09:43:24 -05:00
while ( ! import_status . done & & ! import_status . cancel ) {
2006-03-22 12:03:00 -05:00
gtk_main_iteration ( ) ;
}
2007-03-18 02:07:08 -04:00
2016-05-21 17:30:11 -04:00
// wait for thread to terminate
while ( ! import_status . done ) {
gtk_main_iteration ( ) ;
}
2009-10-14 12:10:01 -04:00
2010-09-29 19:02:32 -04:00
int result = - 1 ;
2008-12-12 09:43:24 -05:00
if ( ! import_status . cancel & & ! import_status . sources . empty ( ) ) {
2010-09-29 19:02:32 -04:00
result = add_sources (
import_status . paths ,
import_status . sources ,
import_status . pos ,
2013-07-23 11:28:45 -04:00
disposition ,
2010-09-29 19:02:32 -04:00
import_status . mode ,
import_status . target_regions ,
import_status . target_tracks ,
2021-07-07 23:24:02 -04:00
track , pgroup_id , false , instrument
2010-09-29 19:02:32 -04:00
) ;
2009-10-14 12:10:01 -04:00
2008-12-12 09:43:24 -05:00
/* update position from results */
2009-10-14 12:10:01 -04:00
2008-12-12 09:43:24 -05:00
pos = import_status . pos ;
2007-10-11 18:07:47 -04:00
}
2010-09-29 19:02:32 -04:00
return result ;
2006-03-22 12:03:00 -05:00
}
2006-03-22 17:18:08 -05:00
int
2014-12-24 20:07:10 -05:00
Editor : : embed_sndfiles ( vector < string > paths ,
bool multifile ,
bool & check_sample_rate ,
ImportDisposition disposition ,
ImportMode mode ,
2020-10-19 14:37:54 -04:00
timepos_t & pos ,
2014-12-24 20:07:10 -05:00
int target_regions ,
int target_tracks ,
boost : : shared_ptr < Track > & track ,
2021-07-07 23:24:02 -04:00
std : : string const & pgroup_id ,
2014-12-24 20:07:10 -05:00
ARDOUR : : PluginInfoPtr instrument )
2006-03-22 12:03:00 -05:00
{
2006-08-29 17:21:48 -04:00
boost : : shared_ptr < AudioFileSource > source ;
SourceList sources ;
2006-03-22 12:03:00 -05:00
string linked_path ;
SoundFileInfo finfo ;
2020-05-19 12:30:04 -04:00
/* skip periodic saves while importing */
Session : : StateProtector sp ( _session ) ;
2014-12-20 01:11:28 -05:00
CursorContext : : Handle cursor_ctx = CursorContext : : create ( * this , _cursors - > wait ) ;
2017-07-01 12:42:24 -04:00
gdk_flush ( ) ;
2006-03-22 12:03:00 -05:00
2010-09-14 11:45:21 -04:00
for ( vector < string > : : iterator p = paths . begin ( ) ; p ! = paths . end ( ) ; + + p ) {
2006-03-22 12:03:00 -05:00
2010-09-14 11:45:21 -04:00
string path = * p ;
2010-11-09 12:24:17 -05:00
string error_msg ;
2009-10-14 12:10:01 -04:00
2007-01-09 18:24:54 -05:00
/* note that we temporarily truncated _id at the colon */
2009-10-14 12:10:01 -04:00
2007-01-09 18:24:54 -05:00
if ( ! AudioFileSource : : get_soundfile_info ( path , finfo , error_msg ) ) {
2007-10-11 18:07:47 -04:00
error < < string_compose ( _ ( " Editor: cannot open file \" %1 \" , (%2) " ) , path , error_msg ) < < endmsg ;
2014-12-20 01:11:28 -05:00
return - 3 ;
2007-01-09 18:24:54 -05:00
}
2009-10-14 12:10:01 -04:00
2019-12-06 12:11:19 -05:00
if ( ! finfo . seekable ) {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( string_compose ( _ ( " %1 \n This audiofile cannot be embedded. It must be imported! " ) , short_path ( path , 40 ) ) , false , Gtk : : MESSAGE_ERROR ) ;
2019-12-06 12:11:19 -05:00
msg . run ( ) ;
return - 2 ;
}
2017-09-18 12:39:17 -04:00
if ( check_sample_rate & & ( finfo . samplerate ! = ( int ) _session - > sample_rate ( ) ) ) {
2007-01-09 18:24:54 -05:00
vector < string > choices ;
2009-10-14 12:10:01 -04:00
2007-10-11 18:07:47 -04:00
if ( multifile ) {
2007-01-09 18:24:54 -05:00
choices . push_back ( _ ( " Cancel entire import " ) ) ;
choices . push_back ( _ ( " Don't embed it " ) ) ;
choices . push_back ( _ ( " Embed all without questions " ) ) ;
2009-10-14 12:10:01 -04:00
2017-07-16 22:55:52 -04:00
ArdourWidgets : : Choice rate_choice (
2009-12-22 20:26:33 -05:00
_ ( " Sample rate " ) ,
2009-10-14 12:10:01 -04:00
string_compose ( _ ( " %1 \n This audiofile's sample rate doesn't match the session sample rate! " ) ,
2007-03-18 02:07:08 -04:00
short_path ( path , 40 ) ) ,
2009-12-22 20:26:33 -05:00
choices , false
) ;
2009-10-14 12:10:01 -04:00
2007-01-28 12:44:13 -05:00
int resx = rate_choice . run ( ) ;
2009-10-14 12:10:01 -04:00
2007-01-28 12:44:13 -05:00
switch ( resx ) {
case 0 : /* stop a multi-file import */
2014-12-20 01:11:28 -05:00
return - 2 ;
2007-07-16 18:04:52 -04:00
case 1 : /* don't embed this one */
2014-12-20 01:11:28 -05:00
return - 1 ;
2007-01-28 12:44:13 -05:00
case 2 : /* do it, and the rest without asking */
check_sample_rate = false ;
break ;
case 3 : /* do it */
break ;
default :
2014-12-20 01:11:28 -05:00
return - 2 ;
2007-01-28 12:44:13 -05:00
}
2007-01-09 18:24:54 -05:00
} else {
choices . push_back ( _ ( " Cancel " ) ) ;
2007-01-28 12:44:13 -05:00
choices . push_back ( _ ( " Embed it anyway " ) ) ;
2009-10-14 12:10:01 -04:00
2017-07-16 22:55:52 -04:00
ArdourWidgets : : Choice rate_choice (
2009-12-22 20:26:33 -05:00
_ ( " Sample rate " ) ,
2007-01-28 12:44:13 -05:00
string_compose ( _ ( " %1 \n This audiofile's sample rate doesn't match the session sample rate! " ) , path ) ,
2009-12-22 20:26:33 -05:00
choices , false
) ;
2009-10-14 12:10:01 -04:00
2007-01-28 12:44:13 -05:00
int resx = rate_choice . run ( ) ;
2009-10-14 12:10:01 -04:00
2007-01-28 12:44:13 -05:00
switch ( resx ) {
case 0 : /* don't import */
2014-12-20 01:11:28 -05:00
return - 1 ;
2007-01-28 12:44:13 -05:00
case 1 : /* do it */
break ;
default :
2014-12-20 01:11:28 -05:00
return - 2 ;
2007-01-28 12:44:13 -05:00
}
2007-01-09 18:24:54 -05:00
}
2006-08-31 15:17:00 -04:00
}
2009-10-14 12:10:01 -04:00
2007-10-11 18:07:47 -04:00
for ( int n = 0 ; n < finfo . channels ; + + n ) {
2013-07-23 11:28:45 -04:00
2007-01-09 18:24:54 -05:00
try {
2007-03-18 02:07:08 -04:00
/* check if we have this thing embedded already */
boost : : shared_ptr < Source > s ;
2014-05-29 16:27:33 -04:00
if ( ( s = _session - > audio_source_by_path_and_channel ( path , n ) ) = = 0 ) {
2008-03-17 16:54:03 -04:00
2009-02-16 13:08:22 -05:00
source = boost : : dynamic_pointer_cast < AudioFileSource > (
2013-03-30 14:02:26 -04:00
SourceFactory : : createExternal ( DataType : : AUDIO , * _session ,
2015-10-04 14:51:05 -04:00
path , n ,
2020-02-25 23:35:07 -05:00
Source : : Flag ( 0 ) ,
2009-02-16 13:08:22 -05:00
true , true ) ) ;
2007-03-18 02:07:08 -04:00
} else {
source = boost : : dynamic_pointer_cast < AudioFileSource > ( s ) ;
}
2007-01-28 12:44:13 -05:00
2007-01-09 18:24:54 -05:00
sources . push_back ( source ) ;
2009-10-14 12:10:01 -04:00
}
2007-01-09 18:24:54 -05:00
catch ( failed_constructor & err ) {
error < < string_compose ( _ ( " could not open %1 " ) , path ) < < endmsg ;
2014-12-20 01:11:28 -05:00
return - 3 ;
2007-01-09 18:24:54 -05:00
}
2009-10-14 12:10:01 -04:00
2014-02-21 20:44:34 -05:00
gtk_main_iteration ( ) ;
2007-01-09 18:24:54 -05:00
}
}
2014-12-20 01:11:28 -05:00
if ( ! sources . empty ( ) ) {
2021-07-07 23:24:02 -04:00
return add_sources ( paths , sources , pos , disposition , mode , target_regions , target_tracks , track , pgroup_id , true , instrument ) ;
2006-03-22 12:03:00 -05:00
}
2006-11-19 11:45:16 -05:00
2014-12-20 01:11:28 -05:00
return 0 ;
2007-10-11 18:07:47 -04:00
}
int
2014-12-24 20:07:10 -05:00
Editor : : add_sources ( vector < string > paths ,
SourceList & sources ,
2020-10-19 14:37:54 -04:00
timepos_t & pos ,
2014-12-24 20:07:10 -05:00
ImportDisposition disposition ,
ImportMode mode ,
int target_regions ,
int target_tracks ,
boost : : shared_ptr < Track > & track ,
2021-07-07 23:24:02 -04:00
std : : string const & pgroup_id ,
2014-12-24 20:07:10 -05:00
bool /*add_channel_suffix*/ ,
ARDOUR : : PluginInfoPtr instrument )
2007-10-11 18:07:47 -04:00
{
2008-02-18 14:45:52 -05:00
vector < boost : : shared_ptr < Region > > regions ;
2010-09-14 11:45:21 -04:00
string region_name ;
2007-10-11 18:07:47 -04:00
uint32_t input_chan = 0 ;
uint32_t output_chan = 0 ;
2009-10-01 16:40:51 -04:00
bool use_timestamp ;
2014-06-02 11:20:37 -04:00
vector < string > track_names ;
2020-12-03 23:34:48 -05:00
use_timestamp = ( pos = = timepos_t : : max ( pos . time_domain ( ) ) ) ;
2007-10-11 18:07:47 -04:00
2008-02-18 22:24:44 -05:00
// kludge (for MIDI we're abusing "channel" for "track" here)
2010-05-19 19:36:18 -04:00
if ( SMFSource : : safe_midi_file_extension ( paths . front ( ) ) ) {
2008-02-18 22:24:44 -05:00
target_regions = - 1 ;
2010-05-19 19:36:18 -04:00
}
2008-02-18 14:45:52 -05:00
2007-10-11 18:07:47 -04:00
if ( target_regions = = 1 ) {
/* take all the sources we have and package them up as a region */
region_name = region_name_from_path ( paths . front ( ) , ( sources . size ( ) > 1 ) , false ) ;
2009-10-14 12:10:01 -04:00
2010-11-25 15:37:39 -05:00
/* we checked in import_sndfiles() that there were not too many */
2010-11-05 16:36:44 -04:00
2010-11-25 15:37:39 -05:00
while ( RegionFactory : : region_by_name ( region_name ) ) {
region_name = bump_name_once ( region_name , ' . ' ) ;
}
2010-11-05 16:36:44 -04:00
2011-06-01 13:00:29 -04:00
PropertyList plist ;
2020-12-23 12:49:43 -05:00
plist . add ( ARDOUR : : Properties : : start , timecnt_t ( sources [ 0 ] - > type ( ) = = DataType : : AUDIO ? Temporal : : AudioTime : Temporal : : BeatTime ) ) ;
2020-10-19 14:37:54 -04:00
plist . add ( ARDOUR : : Properties : : length , sources [ 0 ] - > length ( ) ) ;
2010-02-18 08:59:49 -05:00
plist . add ( ARDOUR : : Properties : : name , region_name ) ;
plist . add ( ARDOUR : : Properties : : layer , 0 ) ;
plist . add ( ARDOUR : : Properties : : whole_file , true ) ;
plist . add ( ARDOUR : : Properties : : external , true ) ;
boost : : shared_ptr < Region > r = RegionFactory : : create ( sources , plist ) ;
2009-10-01 16:40:51 -04:00
2020-02-24 14:15:53 -05:00
if ( boost : : dynamic_pointer_cast < AudioRegion > ( r ) ) {
2009-10-01 16:40:51 -04:00
boost : : dynamic_pointer_cast < AudioRegion > ( r ) - > special_set_position ( sources [ 0 ] - > natural_position ( ) ) ;
2016-12-16 11:49:52 -05:00
}
2009-10-14 12:10:01 -04:00
2009-10-01 16:40:51 -04:00
regions . push_back ( r ) ;
2014-06-02 11:20:37 -04:00
/* if we're creating a new track, name it after the cleaned-up
* and " merged " region name .
*/
track_names . push_back ( region_name ) ;
2009-10-14 12:10:01 -04:00
2008-12-12 09:43:24 -05:00
} else if ( target_regions = = - 1 | | target_regions > 1 ) {
2007-10-11 18:07:47 -04:00
/* take each source and create a region for each one */
SourceList just_one ;
SourceList : : iterator x ;
uint32_t n ;
for ( n = 0 , x = sources . begin ( ) ; x ! = sources . end ( ) ; + + x , + + n ) {
just_one . clear ( ) ;
just_one . push_back ( * x ) ;
2009-10-14 12:10:01 -04:00
2011-05-13 15:55:52 -04:00
boost : : shared_ptr < FileSource > fs = boost : : dynamic_pointer_cast < FileSource > ( * x ) ;
2013-07-23 11:28:45 -04:00
if ( sources . size ( ) > 1 & & disposition = = ImportDistinctChannels ) {
/* generate a per-channel region name so that things work as
* intended
*/
2015-07-31 23:41:26 -04:00
2013-07-23 11:28:45 -04:00
string path ;
if ( fs ) {
region_name = basename_nosuffix ( fs - > path ( ) ) ;
} else {
region_name = ( * x ) - > name ( ) ;
}
2015-07-31 23:41:26 -04:00
2014-06-02 11:20:37 -04:00
if ( sources . size ( ) = = 2 ) {
2013-07-23 11:28:45 -04:00
if ( n = = 0 ) {
region_name + = " -L " ;
} else {
region_name + = " -R " ;
}
2014-06-02 11:20:37 -04:00
} else if ( sources . size ( ) > 2 ) {
region_name + = string_compose ( " -%1 " , n + 1 ) ;
2013-07-23 11:28:45 -04:00
}
2015-07-31 23:41:26 -04:00
2014-06-02 11:20:37 -04:00
track_names . push_back ( region_name ) ;
2015-07-31 23:41:26 -04:00
2013-07-23 11:28:45 -04:00
} else {
if ( fs ) {
region_name = region_name_from_path ( fs - > path ( ) , false , false , sources . size ( ) , n ) ;
2014-06-02 11:20:37 -04:00
} else {
2013-07-23 11:28:45 -04:00
region_name = ( * x ) - > name ( ) ;
}
2014-06-02 11:20:37 -04:00
2014-09-13 10:34:01 -04:00
if ( SMFSource : : safe_midi_file_extension ( paths . front ( ) ) ) {
2014-09-13 13:57:04 -04:00
string track_name = string_compose ( " %1-t%2 " , PBD : : basename_nosuffix ( fs - > path ( ) ) , ( n + 1 ) ) ;
2014-09-13 10:34:01 -04:00
track_names . push_back ( track_name ) ;
} else {
track_names . push_back ( PBD : : basename_nosuffix ( paths [ n ] ) ) ;
}
2011-05-13 15:55:52 -04:00
}
2007-10-11 18:07:47 -04:00
2011-04-21 11:19:22 -04:00
PropertyList plist ;
2011-05-17 19:07:46 -04:00
/* Fudge region length to ensure it is non-zero; make it 1 beat at 120bpm
2022-01-28 17:52:27 -05:00
for want of a better idea .
2011-05-17 19:07:46 -04:00
*/
2022-01-28 17:52:27 -05:00
timepos_t len = ( * x ) - > length ( ) ;
2020-12-23 12:49:43 -05:00
cerr < < " for " < < ( * x ) - > name ( ) < < " source length appears to be " < < len < < endl ;
2022-01-28 17:52:27 -05:00
if ( len . is_zero ( ) ) {
if ( ( * x ) - > type ( ) = = DataType : : AUDIO ) {
len = timepos_t ( _session - > sample_rate ( ) ) / 2 ;
} else {
len = timepos_t ( Beats ( 1 , 0 ) ) ;
}
2020-12-23 12:49:43 -05:00
cerr < < " reset to use " < < len < < endl ;
2011-04-21 11:19:22 -04:00
}
2011-06-01 13:00:29 -04:00
2022-01-28 17:52:27 -05:00
plist . add ( ARDOUR : : Properties : : start , timepos_t ( ( * x ) - > type ( ) = = DataType : : AUDIO ? Temporal : : AudioTime : Temporal : : BeatTime ) ) ;
2011-04-21 11:19:22 -04:00
plist . add ( ARDOUR : : Properties : : length , len ) ;
2010-02-18 08:59:49 -05:00
plist . add ( ARDOUR : : Properties : : name , region_name ) ;
plist . add ( ARDOUR : : Properties : : layer , 0 ) ;
plist . add ( ARDOUR : : Properties : : whole_file , true ) ;
plist . add ( ARDOUR : : Properties : : external , true ) ;
boost : : shared_ptr < Region > r = RegionFactory : : create ( just_one , plist ) ;
2009-10-14 12:10:01 -04:00
2020-02-24 14:15:53 -05:00
if ( boost : : dynamic_pointer_cast < AudioRegion > ( r ) ) {
2009-10-01 16:40:51 -04:00
boost : : dynamic_pointer_cast < AudioRegion > ( r ) - > special_set_position ( ( * x ) - > natural_position ( ) ) ;
}
2009-10-14 12:10:01 -04:00
2009-10-01 16:40:51 -04:00
regions . push_back ( r ) ;
2007-10-11 18:07:47 -04:00
}
}
if ( target_regions = = 1 ) {
2020-10-19 14:37:54 -04:00
input_chan = regions . front ( ) - > sources ( ) . size ( ) ;
2007-10-11 18:07:47 -04:00
} else {
if ( target_tracks = = 1 ) {
input_chan = regions . size ( ) ;
} else {
input_chan = 1 ;
}
}
2007-01-28 12:44:13 -05:00
2022-01-24 12:52:51 -05:00
# ifdef MIXBUS
if ( mode = = ImportAsTrigger ) {
/* Mixbus will only ever use stereo tracks when using DnD to import to triggers */
input_chan = 2 ;
}
# endif
2006-10-21 15:01:50 -04:00
if ( Config - > get_output_auto_connect ( ) & AutoConnectMaster ) {
2009-12-17 13:24:23 -05:00
output_chan = ( _session - > master_out ( ) ? _session - > master_out ( ) - > n_inputs ( ) . n_audio ( ) : input_chan ) ;
2006-03-22 12:03:00 -05:00
} else {
output_chan = input_chan ;
}
2007-01-09 18:24:54 -05:00
2007-10-11 18:07:47 -04:00
int n = 0 ;
2020-10-19 14:37:54 -04:00
timecnt_t rlen ;
2007-10-11 18:07:47 -04:00
2012-06-09 11:04:24 -04:00
begin_reversible_command ( Operations : : insert_file ) ;
2014-06-02 11:20:37 -04:00
/* we only use tracks names when importing to new tracks, but we
* require that one is defined for every region , just to keep
* the API simpler .
*/
assert ( regions . size ( ) = = track_names . size ( ) ) ;
2015-07-31 23:41:26 -04:00
2011-06-01 13:00:29 -04:00
for ( vector < boost : : shared_ptr < Region > > : : iterator r = regions . begin ( ) ; r ! = regions . end ( ) ; + + r , + + n ) {
2010-11-25 15:37:39 -05:00
boost : : shared_ptr < AudioRegion > ar = boost : : dynamic_pointer_cast < AudioRegion > ( * r ) ;
2011-06-01 13:00:29 -04:00
2010-12-07 09:45:51 -05:00
if ( use_timestamp ) {
2017-07-01 12:42:24 -04:00
if ( ar ) {
/* get timestamp for this region */
const boost : : shared_ptr < Source > s ( ar - > sources ( ) . front ( ) ) ;
const boost : : shared_ptr < AudioSource > as = boost : : dynamic_pointer_cast < AudioSource > ( s ) ;
assert ( as ) ;
if ( as - > natural_position ( ) ! = 0 ) {
pos = as - > natural_position ( ) ;
} else if ( target_tracks = = 1 ) {
/* hmm, no timestamp available, put it after the previous region
*/
if ( n = = 0 ) {
pos = get_preferred_edit_position ( ) ;
} else {
pos + = rlen ;
}
} else {
pos = get_preferred_edit_position ( ) ;
}
} else {
/* should really get first position in MIDI file, but for now, use edit position*/
pos = get_preferred_edit_position ( ) ;
}
}
2015-07-31 23:41:26 -04:00
2021-07-07 23:24:02 -04:00
finish_bringing_in_material ( * r , input_chan , output_chan , pos , mode , track , track_names [ n ] , pgroup_id , instrument ) ;
2006-03-22 12:03:00 -05:00
2020-11-30 12:59:17 -05:00
rlen = ( * r ) - > length ( ) ;
2011-06-01 13:00:29 -04:00
2010-11-25 15:37:39 -05:00
if ( target_tracks ! = 1 ) {
track . reset ( ) ;
2011-06-01 13:00:29 -04:00
} else {
2010-11-25 15:37:39 -05:00
if ( ! use_timestamp | | ! ar ) {
/* line each one up right after the other */
2020-11-30 12:59:17 -05:00
pos + = ( * r ) - > length ( ) ;
2010-11-25 15:37:39 -05:00
}
}
2007-10-11 18:07:47 -04:00
}
2012-06-09 11:04:24 -04:00
commit_reversible_command ( ) ;
2015-07-31 23:41:26 -04:00
2007-10-11 18:07:47 -04:00
/* setup peak file building in another thread */
for ( SourceList : : iterator x = sources . begin ( ) ; x ! = sources . end ( ) ; + + x ) {
SourceFactory : : setup_peakfile ( * x , true ) ;
}
return 0 ;
}
2009-10-14 12:10:01 -04:00
2006-03-22 12:03:00 -05:00
int
2014-12-24 20:07:10 -05:00
Editor : : finish_bringing_in_material ( boost : : shared_ptr < Region > region ,
uint32_t in_chans ,
uint32_t out_chans ,
2020-10-19 14:37:54 -04:00
timepos_t & pos ,
2014-12-24 20:07:10 -05:00
ImportMode mode ,
boost : : shared_ptr < Track > & existing_track ,
2021-07-07 23:24:02 -04:00
string const & new_track_name ,
string const & pgroup_id ,
2014-12-24 20:07:10 -05:00
ARDOUR : : PluginInfoPtr instrument )
2006-07-27 21:08:57 -04:00
{
2008-02-18 14:45:52 -05:00
boost : : shared_ptr < AudioRegion > ar = boost : : dynamic_pointer_cast < AudioRegion > ( region ) ;
boost : : shared_ptr < MidiRegion > mr = boost : : dynamic_pointer_cast < MidiRegion > ( region ) ;
2006-07-27 21:08:57 -04:00
switch ( mode ) {
case ImportAsRegion :
/* relax, its been done */
break ;
2009-10-14 12:10:01 -04:00
2006-03-22 12:03:00 -05:00
case ImportToTrack :
2007-10-11 18:07:47 -04:00
{
if ( ! existing_track ) {
2008-02-18 14:45:52 -05:00
if ( ar ) {
existing_track = get_nth_selected_audio_track ( 0 ) ;
} else if ( mr ) {
existing_track = get_nth_selected_midi_track ( 0 ) ;
}
2006-03-22 12:03:00 -05:00
2007-10-11 18:07:47 -04:00
if ( ! existing_track ) {
return - 1 ;
}
2006-03-22 12:03:00 -05:00
}
2007-10-11 18:07:47 -04:00
2010-04-21 16:42:22 -04:00
boost : : shared_ptr < Playlist > playlist = existing_track - > playlist ( ) ;
2010-03-01 19:00:00 -05:00
boost : : shared_ptr < Region > copy ( RegionFactory : : create ( region , region - > properties ( ) ) ) ;
2011-01-20 19:58:45 -05:00
playlist - > clear_changes ( ) ;
2021-05-23 11:42:33 -04:00
playlist - > clear_owned_changes ( ) ;
2007-10-11 18:07:47 -04:00
playlist - > add_region ( copy , pos ) ;
2021-06-02 18:34:13 -04:00
if ( should_ripple ( ) ) {
do_ripple ( playlist , pos , copy - > length ( ) , copy , true ) ;
} else {
playlist - > rdiff_and_add_command ( _session ) ;
2021-05-23 11:42:33 -04:00
}
2006-03-22 12:03:00 -05:00
break ;
2007-10-11 18:07:47 -04:00
}
2022-01-03 17:51:33 -05:00
case ImportAsTrigger :
/* fallthrough */
2006-03-22 12:03:00 -05:00
case ImportAsTrack :
2009-10-14 12:10:01 -04:00
{
2007-10-11 18:07:47 -04:00
if ( ! existing_track ) {
2008-02-18 14:45:52 -05:00
if ( ar ) {
2022-01-14 16:42:00 -05:00
list < boost : : shared_ptr < AudioTrack > > at (
_session - > new_audio_track ( in_chans , out_chans ,
0 , 1 , string ( ) ,
PresentationInfo : : max_order ,
Normal ,
true ,
mode = = ImportAsTrigger
) ) ;
2008-02-18 14:45:52 -05:00
if ( at . empty ( ) ) {
return - 1 ;
}
2021-07-07 23:24:02 -04:00
for ( list < boost : : shared_ptr < AudioTrack > > : : iterator i = at . begin ( ) ; i ! = at . end ( ) ; + + i ) {
if ( Config - > get_strict_io ( ) ) {
2016-03-28 11:37:27 -04:00
( * i ) - > set_strict_io ( true ) ;
}
2021-07-07 23:24:02 -04:00
( * i ) - > playlist ( ) - > set_pgroup_id ( pgroup_id ) ;
2016-03-28 11:37:27 -04:00
}
2008-02-18 14:45:52 -05:00
existing_track = at . front ( ) ;
} else if ( mr ) {
2014-12-24 20:07:10 -05:00
list < boost : : shared_ptr < MidiTrack > > mt (
_session - > new_midi_track ( ChanCount ( DataType : : MIDI , 1 ) ,
2022-01-14 16:42:00 -05:00
ChanCount ( DataType : : MIDI , 1 ) ,
2017-01-20 15:47:09 -05:00
Config - > get_strict_io ( ) | | Profile - > get_mixbus ( ) ,
2016-05-17 08:21:05 -04:00
instrument , ( Plugin : : PresetRecord * ) 0 ,
( RouteGroup * ) 0 ,
1 ,
string ( ) ,
2021-07-17 17:46:18 -04:00
PresentationInfo : : max_order ,
Normal ,
2022-01-14 16:42:00 -05:00
true ,
mode = = ImportAsTrigger
2021-07-17 17:46:18 -04:00
) ) ;
2008-02-18 14:45:52 -05:00
if ( mt . empty ( ) ) {
return - 1 ;
}
2021-07-07 23:24:02 -04:00
for ( list < boost : : shared_ptr < MidiTrack > > : : iterator i = mt . begin ( ) ; i ! = mt . end ( ) ; + + i ) {
if ( Config - > get_strict_io ( ) ) {
( * i ) - > set_strict_io ( true ) ;
}
( * i ) - > playlist ( ) - > set_pgroup_id ( pgroup_id ) ;
}
2008-02-18 14:45:52 -05:00
existing_track = mt . front ( ) ;
2007-10-11 18:07:47 -04:00
}
2011-06-01 13:00:29 -04:00
2014-06-02 11:20:37 -04:00
if ( ! new_track_name . empty ( ) ) {
existing_track - > set_name ( new_track_name ) ;
} else {
existing_track - > set_name ( region - > name ( ) ) ;
}
2006-08-24 03:37:17 -04:00
}
2007-10-11 18:07:47 -04:00
2022-01-03 17:51:33 -05:00
if ( mode = = ImportAsTrigger ) {
boost : : shared_ptr < Region > copy ( RegionFactory : : create ( region , true ) ) ;
2022-01-19 17:50:47 -05:00
for ( int s = 0 ; s < default_triggers_per_box ; + + s ) {
2022-01-03 20:25:08 -05:00
if ( ! existing_track - > triggerbox ( ) - > trigger ( s ) - > region ( ) ) {
existing_track - > triggerbox ( ) - > set_from_selection ( s , copy ) ;
2022-02-09 20:21:53 -05:00
# if 1 /* assume drop from sidebar */
ARDOUR_UI_UTILS : : copy_patch_changes ( _session - > the_auditioner ( ) , existing_track - > triggerbox ( ) - > trigger ( s ) ) ;
# endif
2022-01-03 20:25:08 -05:00
break ;
}
}
2022-01-03 17:51:33 -05:00
} else {
boost : : shared_ptr < Playlist > playlist = existing_track - > playlist ( ) ;
boost : : shared_ptr < Region > copy ( RegionFactory : : create ( region , true ) ) ;
playlist - > clear_changes ( ) ;
playlist - > add_region ( copy , pos ) ;
_session - > add_command ( new StatefulDiffCommand ( playlist ) ) ;
}
2006-03-22 12:03:00 -05:00
break ;
}
2006-07-27 21:08:57 -04:00
}
2006-03-22 12:03:00 -05:00
return 0 ;
}
void *
Editor : : _import_thread ( void * arg )
{
2009-12-04 14:24:09 -05:00
SessionEvent : : create_per_thread_pool ( " import events " , 64 ) ;
2006-03-22 12:03:00 -05:00
Editor * ed = ( Editor * ) arg ;
return ed - > import_thread ( ) ;
}
void *
Editor : : import_thread ( )
{
2020-11-28 00:28:35 -05:00
Temporal : : TempoMap : : fetch ( ) ;
2012-06-09 11:04:11 -04:00
_session - > import_files ( import_status ) ;
2006-03-22 12:03:00 -05:00
return 0 ;
}