2024-02-14 18:33:34 -05:00
/*
* Copyright ( C ) 2023 Robin Gareus < robin @ gareus . org >
2024-03-10 16:54:06 -04:00
* Copyright ( C ) 2023 - 2024 Adrien Gesta - Fline < dev . agfline @ posteo . net >
2024-02-14 18:33:34 -05:00
*
* 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 .
*/
2024-04-17 17:57:12 -04:00
# include <fcntl.h> // O_WRONLY
2024-03-10 16:54:06 -04:00
# include <glib/gstdio.h> // g_unlink()
2024-02-14 18:33:34 -05:00
# include "pbd/basename.h"
# include "pbd/convert.h"
# include "pbd/file_utils.h"
# include "ardour/audio_track.h"
# include "ardour/audioengine.h"
# include "ardour/audioregion.h"
# include "ardour/filename_extensions.h"
# include "ardour/import_status.h"
# include "ardour/playlist.h"
# include "ardour/plugin_manager.h"
# include "ardour/region_factory.h"
# include "ardour/source_factory.h"
# include "ardour/utils.h"
# include "aaf/libaaf.h"
# include "aaf/utils.h"
# include "ardour_ui.h"
# include "public_editor.h"
# include "pbd/i18n.h"
using namespace std ;
using namespace PBD ;
using namespace ARDOUR ;
static void
2024-03-10 16:54:06 -04:00
aaf_debug_callback ( struct aafLog * log , void * ctxdata , int libid , int type , const char * srcfile , const char * srcfunc , int lineno , const char * msg , void * user )
2024-02-14 18:33:34 -05:00
{
2024-04-17 17:57:12 -04:00
const char * eol = " " ;
if ( libid ! = LOG_SRC_ID_TRACE & & libid ! = LOG_SRC_ID_DUMP ) {
switch ( type ) {
case VERB_SUCCESS :
PBD : : info < < string_compose ( " [libaaf] %1:%2 in %3(): " , srcfile , lineno , srcfunc ) ;
break ;
case VERB_ERROR :
PBD : : error < < string_compose ( " [libaaf] %1:%2 in %3(): " , srcfile , lineno , srcfunc ) ;
break ;
case VERB_WARNING :
PBD : : warning < < string_compose ( " [libaaf] %1:%2 in %3(): " , srcfile , lineno , srcfunc ) ;
break ;
// case VERB_DEBUG: PBD::debug << string_compose ("[libaaf] %1:%2 in %3(): ", srcfile, lineno, srcfunc); break;
2024-03-10 16:54:06 -04:00
}
}
2024-04-17 17:57:12 -04:00
if ( libid ! = LOG_SRC_ID_DUMP ) {
2024-03-10 16:54:06 -04:00
eol = " \n " ;
}
2024-04-17 17:57:12 -04:00
switch ( type ) {
case VERB_SUCCESS :
PBD : : info < < msg < < eol ;
break ;
case VERB_ERROR :
PBD : : error < < msg < < eol ;
break ;
case VERB_WARNING :
PBD : : warning < < msg < < eol ;
break ;
// case VERB_DEBUG: PBD::debug << msg << eol; break;
2024-03-10 16:54:06 -04:00
}
2024-03-19 15:39:37 -04:00
LOG_BUFFER_RESET ( log ) ;
2024-02-14 18:33:34 -05:00
}
static std : : shared_ptr < AudioTrack >
get_nth_audio_track ( uint32_t nth , std : : shared_ptr < RouteList const > routes )
{
RouteList rl = * ( routes ) ;
rl . sort ( Stripable : : Sorter ( ) ) ;
for ( auto const & r : rl ) {
std : : shared_ptr < AudioTrack > at = std : : dynamic_pointer_cast < AudioTrack > ( r ) ;
if ( ! at ) {
continue ;
}
if ( nth - - = = 0 ) {
return at ;
}
}
return std : : shared_ptr < AudioTrack > ( ) ;
}
static std : : shared_ptr < AudioTrack >
prepare_audio_track ( aafiAudioTrack * aafTrack , Session * s )
{
/* Use existing track */
std : : shared_ptr < AudioTrack > track = get_nth_audio_track ( ( aafTrack - > number - 1 ) , s - > get_routes ( ) ) ;
if ( track ) {
return track ;
}
/* ..or create a new track */
uint32_t outputs = 2 ;
if ( s - > master_out ( ) ) {
outputs = max ( outputs , s - > master_out ( ) - > n_inputs ( ) . n_audio ( ) ) ;
}
2024-03-10 16:54:06 -04:00
list < std : : shared_ptr < AudioTrack > > at ( s - > new_audio_track ( aafTrack - > format , outputs , NULL , 1 , aafTrack - > name , PresentationInfo : : max_order ) ) ;
2024-02-14 18:33:34 -05:00
if ( at . empty ( ) ) {
PBD : : fatal < < " AAF: Could not create new audio track. " < < endmsg ;
abort ( ) ; /*NOTREACHED*/
}
return at . back ( ) ;
}
static bool
2024-04-17 17:57:12 -04:00
import_sndfile_as_region ( Session * s , struct aafiAudioEssencePointer * aafAudioEssencePtrList , SrcQuality quality , timepos_t & pos , SourceList * * oneClipSources , ImportStatus & status , vector < std : : shared_ptr < Region > > & regions )
2024-02-14 18:33:34 -05:00
{
2024-04-17 17:57:12 -04:00
SourceList * sources = NULL ;
2024-02-14 18:33:34 -05:00
2024-04-17 17:57:12 -04:00
if ( aafAudioEssencePtrList - > user ) {
sources = ( SourceList * ) aafAudioEssencePtrList - > user ;
} else {
sources = new SourceList ;
2024-02-14 18:33:34 -05:00
2024-04-17 17:57:12 -04:00
/* Import the source */
status . clear ( ) ;
2024-03-10 16:54:06 -04:00
2024-04-17 17:57:12 -04:00
status . current = 1 ;
status . total = 1 ;
status . freeze = false ;
status . quality = quality ;
status . replace_existing_source = false ;
status . split_midi_channels = false ;
status . import_markers = false ;
status . done = false ;
status . cancel = false ;
2024-03-10 16:54:06 -04:00
2024-04-17 17:57:12 -04:00
int channelCount = 0 ;
2024-02-14 18:33:34 -05:00
2024-04-17 17:57:12 -04:00
aafiAudioEssencePointer * aafAudioEssencePtr = NULL ;
AAFI_foreachEssencePointer ( aafAudioEssencePtrList , aafAudioEssencePtr )
{
if ( aafAudioEssencePtr - > essenceFile - > usable_file_path )
status . paths . push_back ( aafAudioEssencePtr - > essenceFile - > usable_file_path ) ;
else
status . paths . push_back ( aafAudioEssencePtr - > essenceFile - > original_file_path ) ;
2024-02-14 18:33:34 -05:00
2024-04-17 17:57:12 -04:00
channelCount + + ;
PBD : : info < < string_compose ( " AAF: Preparing to import clip channel %1: %2 \n " , channelCount , aafAudioEssencePtr - > essenceFile - > unique_name ) ;
}
2024-02-14 18:33:34 -05:00
2024-04-17 17:57:12 -04:00
s - > import_files ( status ) ;
status . progress = 1.0 ;
sources - > clear ( ) ;
/* FIXME: There is no way to tell if cancel button was pressed
* or if the file failed to import , just that one of these occurred .
* We want status . cancel to reflect the user ' s choice only
*/
if ( status . cancel & & status . current > 1 ) {
/* Succeeded to import file, assume user hit cancel */
return false ;
} else if ( status . cancel & & status . current = = 1 ) {
/* Failed to import file, assume user did not hit cancel */
status . cancel = false ;
return false ;
}
2024-02-14 18:33:34 -05:00
2024-04-17 17:57:12 -04:00
for ( int i = 0 ; i < channelCount ; i + + ) {
2024-05-07 05:32:25 -04:00
PropertyList proplist ;
2024-04-17 17:57:12 -04:00
sources - > push_back ( status . sources . at ( i ) ) ;
2024-05-07 05:32:25 -04:00
proplist . add ( ARDOUR : : Properties : : start , 0 ) ;
proplist . add ( ARDOUR : : Properties : : length , timecnt_t ( ( * sources ) [ 0 ] - > length ( ) , pos ) ) ;
proplist . add ( ARDOUR : : Properties : : name , aafAudioEssencePtrList - > essenceFile - > unique_name ) ;
proplist . add ( ARDOUR : : Properties : : layer , 0 ) ;
proplist . add ( ARDOUR : : Properties : : whole_file , true ) ;
proplist . add ( ARDOUR : : Properties : : external , true ) ;
RegionFactory : : create ( * sources , proplist ) ;
2024-04-17 17:57:12 -04:00
}
/* build peakfiles */
for ( SourceList : : iterator x = sources - > begin ( ) ; x ! = sources - > end ( ) ; + + x ) {
SourceFactory : : setup_peakfile ( * x , true ) ;
}
2024-02-14 18:33:34 -05:00
2024-04-17 17:57:12 -04:00
aafAudioEssencePtrList - > user = sources ;
2024-02-14 18:33:34 -05:00
}
2024-04-17 17:57:12 -04:00
* oneClipSources = sources ;
2024-02-14 18:33:34 -05:00
/* Put the source on a region */
2024-05-07 11:06:47 -04:00
string region_name ;
2024-02-14 18:33:34 -05:00
/* take all the sources we have and package them up as a region */
2024-04-17 17:57:12 -04:00
region_name = region_name_from_path ( status . paths . front ( ) , ( sources - > size ( ) > 1 ) , false ) ;
2024-02-14 18:33:34 -05:00
/* we checked in import_sndfiles() that there were not too many */
while ( RegionFactory : : region_by_name ( region_name ) ) {
region_name = bump_name_once ( region_name , ' . ' ) ;
}
return true ;
}
static std : : shared_ptr < Region >
create_region ( vector < std : : shared_ptr < Region > > source_regions , aafiAudioClip * aafAudioClip , SourceList & oneClipSources , aafPosition_t clipOffset , aafRational_t samplerate_r )
{
2024-03-10 16:54:06 -04:00
string unique_file_name = aafAudioClip - > essencePointerList - > essenceFile - > unique_name ; // XXX
2024-02-14 18:33:34 -05:00
2024-03-10 16:54:06 -04:00
aafPosition_t clipPos = aafi_convertUnit ( aafAudioClip - > pos , aafAudioClip - > track - > edit_rate , & samplerate_r ) ;
aafPosition_t clipLen = aafi_convertUnit ( aafAudioClip - > len , aafAudioClip - > track - > edit_rate , & samplerate_r ) ;
aafPosition_t essenceOffset = aafi_convertUnit ( aafAudioClip - > essence_offset , aafAudioClip - > track - > edit_rate , & samplerate_r ) ;
2024-02-14 18:33:34 -05:00
PropertyList proplist ;
proplist . add ( ARDOUR : : Properties : : start , essenceOffset ) ;
proplist . add ( ARDOUR : : Properties : : length , clipLen ) ;
proplist . add ( ARDOUR : : Properties : : name , unique_file_name ) ;
proplist . add ( ARDOUR : : Properties : : layer , 0 ) ;
proplist . add ( ARDOUR : : Properties : : whole_file , false ) ;
proplist . add ( ARDOUR : : Properties : : external , true ) ;
/* NOTE: region position is set when calling add_region() */
std : : shared_ptr < Region > region = RegionFactory : : create ( oneClipSources , proplist ) ;
for ( SourceList : : iterator source = oneClipSources . begin ( ) ; source ! = oneClipSources . end ( ) ; + + source ) {
/* position displayed in Ardour source list */
( * source ) - > set_natural_position ( timepos_t ( clipPos + clipOffset ) ) ;
for ( vector < std : : shared_ptr < Region > > : : iterator region = source_regions . begin ( ) ; region ! = source_regions . end ( ) ; + + region ) {
if ( ( * region ) - > source ( 0 ) = = * source ) {
/* Enable "Move to Original Position" */
( * region ) - > set_position ( timepos_t ( clipPos + clipOffset - essenceOffset ) ) ;
}
}
}
return region ;
}
static void
set_region_gain ( aafiAudioClip * aafAudioClip , std : : shared_ptr < Region > region , Session * s )
{
if ( aafAudioClip - > gain & & aafAudioClip - > gain - > flags & AAFI_AUDIO_GAIN_CONSTANT ) {
std : : dynamic_pointer_cast < AudioRegion > ( region ) - > set_scale_amplitude ( aafRationalToFloat ( aafAudioClip - > gain - > value [ 0 ] ) ) ;
}
if ( aafAudioClip - > automation ) {
aafiAudioGain * level = aafAudioClip - > automation ;
std : : shared_ptr < AudioRegion > ar = std : : dynamic_pointer_cast < AudioRegion > ( region ) ;
std : : shared_ptr < AutomationList > al = ar - > envelope ( ) ;
2024-03-10 16:54:06 -04:00
for ( unsigned int i = 0 ; i < level - > pts_cnt ; + + i ) {
2024-02-14 18:33:34 -05:00
al - > fast_simple_add ( timepos_t ( aafRationalToFloat ( level - > time [ i ] ) * region - > length ( ) . samples ( ) ) , aafRationalToFloat ( level - > value [ i ] ) ) ;
}
}
}
static FadeShape
aaf_fade_interpol_to_ardour_fade_shape ( aafiInterpolation_e interpol )
{
switch ( interpol & AAFI_INTERPOL_MASK ) {
case AAFI_INTERPOL_NONE :
return FadeConstantPower ;
case AAFI_INTERPOL_LINEAR :
return FadeLinear ;
case AAFI_INTERPOL_LOG :
return FadeConstantPower ;
case AAFI_INTERPOL_CONSTANT :
return FadeConstantPower ;
case AAFI_INTERPOL_POWER :
return FadeConstantPower ;
case AAFI_INTERPOL_BSPLINE :
return FadeConstantPower ;
default :
return FadeConstantPower ;
}
}
static void
2024-02-14 19:38:50 -05:00
set_region_fade ( aafiAudioClip * aafAudioClip , std : : shared_ptr < Region > region , aafRational_t * samplerate )
2024-02-14 18:33:34 -05:00
{
if ( aafAudioClip = = NULL ) {
return ;
}
2024-03-10 16:54:06 -04:00
aafiTransition * fadein = aafi_getFadeIn ( aafAudioClip ) ;
aafiTransition * fadeout = aafi_getFadeOut ( aafAudioClip ) ;
aafiTransition * xfade = ( aafAudioClip - > timelineItem - > prev ) ? aafi_timelineItemToCrossFade ( aafAudioClip - > timelineItem - > prev ) : NULL ;
2024-02-14 18:33:34 -05:00
if ( xfade ) {
if ( fadein = = NULL ) {
fadein = xfade ;
} else {
PBD : : warning < < " Clip has both fadein and crossfade : crossfade will be ignored. " < < endmsg ;
}
}
FadeShape fade_shape ;
samplecnt_t fade_len ;
if ( fadein ! = NULL ) {
2024-04-17 17:57:12 -04:00
fade_shape = aaf_fade_interpol_to_ardour_fade_shape ( ( aafiInterpolation_e ) ( fadein - > flags & AAFI_INTERPOL_MASK ) ) ;
2024-03-10 16:54:06 -04:00
fade_len = aafi_convertUnit ( fadein - > len , aafAudioClip - > track - > edit_rate , samplerate ) ;
2024-02-14 18:33:34 -05:00
std : : dynamic_pointer_cast < AudioRegion > ( region ) - > set_fade_in ( fade_shape , fade_len ) ;
}
if ( fadeout ! = NULL ) {
2024-04-17 17:57:12 -04:00
fade_shape = aaf_fade_interpol_to_ardour_fade_shape ( ( aafiInterpolation_e ) ( fadeout - > flags & AAFI_INTERPOL_MASK ) ) ;
2024-03-10 16:54:06 -04:00
fade_len = aafi_convertUnit ( fadeout - > len , aafAudioClip - > track - > edit_rate , samplerate ) ;
2024-02-14 18:33:34 -05:00
std : : dynamic_pointer_cast < AudioRegion > ( region ) - > set_fade_out ( fade_shape , fade_len ) ;
}
}
static void
set_session_timecode ( AAF_Iface * aafi , Session * s )
{
using namespace Timecode ;
uint16_t aafFPS = aafi - > Timecode - > fps ;
TimecodeFormat ardourtc ;
/*
* Fractional timecodes are never explicitly set into tc - > fps , so we deduce
* them based on edit_rate value .
*/
switch ( aafFPS ) {
case 24 :
if ( aafi - > Timecode - > edit_rate - > numerator = = 24000 & &
aafi - > Timecode - > edit_rate - > denominator = = 1001 ) {
ardourtc = timecode_23976 ;
} else {
ardourtc = timecode_24 ;
}
break ;
case 25 :
if ( aafi - > Timecode - > edit_rate - > numerator = = 25000 & &
aafi - > Timecode - > edit_rate - > denominator = = 1001 ) {
ardourtc = timecode_24976 ;
} else {
ardourtc = timecode_25 ;
}
break ;
case 30 :
if ( aafi - > Timecode - > edit_rate - > numerator = = 30000 & &
aafi - > Timecode - > edit_rate - > denominator = = 1001 ) {
if ( aafi - > Timecode - > drop ) {
ardourtc = timecode_2997drop ;
} else {
ardourtc = timecode_2997 ;
}
} else {
if ( aafi - > Timecode - > drop ) {
ardourtc = timecode_30drop ;
} else {
ardourtc = timecode_30 ;
}
}
break ;
case 60 :
if ( aafi - > Timecode - > edit_rate - > numerator = = 60000 & &
aafi - > Timecode - > edit_rate - > denominator = = 1001 ) {
ardourtc = timecode_5994 ;
} else {
ardourtc = timecode_60 ;
}
break ;
default :
2024-03-10 16:54:06 -04:00
PBD : : error < < string_compose ( " Unknown AAF timecode fps : %1 (%2/%3). " , aafFPS , aafi - > Timecode - > edit_rate - > numerator , aafi - > Timecode - > edit_rate - > denominator ) < < endmsg ;
2024-02-14 18:33:34 -05:00
return ;
}
s - > config . set_timecode_format ( ardourtc ) ;
}
/* Create and open Sesssion from AAF
* return > 0 if file is not a [ valid ] AAF
* return < 0 if session creation failed .
* return 0 on success . path and snapshot are set .
*/
int
ARDOUR_UI : : new_session_from_aaf ( string const & aaf , string const & target_dir , string & path , string & snapshot )
{
if ( PBD : : downcase ( aaf ) . find ( advanced_authoring_format_suffix ) = = string : : npos ) {
return 1 ;
}
if ( _session ) {
if ( unload_session ( false ) ) {
/* unload cancelled by user */
return 1 ;
}
}
2024-03-10 16:54:06 -04:00
/* Possible libaaf log to external file : part 1/2 */
// string logfile = Glib::build_filename (g_get_tmp_dir (), "aaf-import-XXXXXX.log");
// int logfd = g_mkstemp_full (&logfile[0], O_WRONLY, 0700);
//
// fprintf(stderr, "Logfile: %s\n",&logfile[0] );
//
// if (logfd < 0) {
// error << _("AAF: Could not prepare log file") << endmsg;
// fprintf(stderr, "AAF: Could not prepare log file\n" );
// return -1;
// }
//
// FILE *logfp = fdopen( logfd, "w" );
//
// if (!logfp) {
// error << _("AAF: Could not prepare log file") << endmsg;
// fprintf(stderr, "AAF: Could not prepare log file\n" );
// return -1;
// }
2024-02-14 18:33:34 -05:00
AAF_Iface * aafi = aafi_alloc ( NULL ) ;
2024-03-10 16:54:06 -04:00
if ( ! aafi ) {
error < < " AAF: Could not init AAF library. " < < endmsg ;
return - 1 ;
}
/* protools options must be set (there is no sens not setting them with Ardour) */
uint32_t aaf_protools_options = ( AAFI_PROTOOLS_OPT_REPLACE_CLIP_FADES | AAFI_PROTOOLS_OPT_REMOVE_SAMPLE_ACCURATE_EDIT ) ;
2024-02-14 18:33:34 -05:00
aafi_set_option_int ( aafi , " trace " , 1 ) ;
aafi_set_option_int ( aafi , " protools " , aaf_protools_options ) ;
2024-03-10 16:54:06 -04:00
// aafi_set_option_str (aafi, "media_location", media_location_path.c_str ());
2024-02-14 18:33:34 -05:00
2024-03-10 16:54:06 -04:00
aafi_set_debug ( aafi , VERB_DEBUG , 0 , NULL , & aaf_debug_callback , this ) ;
2024-02-14 18:33:34 -05:00
if ( aafi_load_file ( aafi , aaf . c_str ( ) ) ) {
error < < " AAF: Could not load AAF file. " < < endmsg ;
aafi_release ( & aafi ) ;
return - 1 ;
}
/* extract or set session name */
2024-05-10 10:01:43 -04:00
if ( /* Temporary - in the absence of user-options, don't rely on extracted session names which can be meaningless... aafi->compositionName && aafi->compositionName[0] != */ 0x00 ) {
2024-04-17 17:57:12 -04:00
string compositionName = string ( aafi - > compositionName ) ;
snapshot = laaf_util_clean_filename ( & compositionName [ 0 ] ) ;
2024-02-14 18:33:34 -05:00
} else {
snapshot = basename_nosuffix ( aaf ) ;
}
snapshot = legalize_for_universal_path ( snapshot ) ;
path = Glib : : build_filename ( target_dir , snapshot ) ;
if ( Glib : : file_test ( path , Glib : : FILE_TEST_EXISTS ) ) {
2024-04-17 17:57:12 -04:00
error < < string_compose ( _ ( " AAF: Destination '%1' already exists. " ) , path ) < < endmsg ;
2024-02-14 18:33:34 -05:00
snapshot = " " ; // XXX?
path = " " ;
aafi_release ( & aafi ) ;
return - 1 ;
}
/* Create media cache */
GError * err = NULL ;
2024-04-17 17:57:12 -04:00
char * td = g_dir_make_tmp ( " aaf-cache-XXXXXX " , & err ) ;
2024-02-14 18:33:34 -05:00
if ( ! td ) {
2024-04-17 17:57:12 -04:00
error < < string_compose ( _ ( " AAF: Could not prepare media cache: %1 " ) , err - > message ) < < endmsg ;
2024-02-14 18:33:34 -05:00
aafi_release ( & aafi ) ;
return - 1 ;
}
const string media_cache_path = PBD : : canonical_path ( td ) ;
g_free ( td ) ;
g_clear_error ( & err ) ;
/* all systems go. create sessions */
BusProfile bus_profile ;
bus_profile . master_out_channels = 2 ;
aafRational_t samplerate_r ;
samplerate_r . numerator = aafi - > Audio - > samplerate ;
samplerate_r . denominator = 1 ;
std : : string restore_backend ;
2024-04-17 17:57:12 -04:00
if ( ! AudioEngine : : instance ( ) - > running ( ) ) {
AudioEngine * e = AudioEngine : : instance ( ) ;
2024-02-14 18:33:34 -05:00
restore_backend = e - > current_backend_name ( ) ;
e - > set_backend ( " None (Dummy) " , " " , " " ) ;
e - > start ( ) ;
PluginManager : : instance ( ) . refresh ( true ) ;
attach_to_engine ( ) ;
}
2024-04-17 17:57:12 -04:00
if ( ! AudioEngine : : instance ( ) - > running ( ) ) {
PBD : : error < < _ ( " AAF: Could not start [dummy] engine for AAF import . " ) < < endmsg ;
2024-02-14 18:33:34 -05:00
return - 1 ;
}
build_session_stage_two ( path , snapshot , " " , bus_profile , false , Temporal : : AudioTime , aafi - > Audio - > samplerate ) ;
if ( ! _session ) {
aafi_release ( & aafi ) ;
PBD : : remove_directory ( media_cache_path ) ;
if ( ! restore_backend . empty ( ) ) {
2024-04-17 17:57:12 -04:00
AudioEngine : : instance ( ) - > stop ( ) ;
AudioEngine : : instance ( ) - > set_backend ( restore_backend , " " , " " ) ;
2024-02-14 18:33:34 -05:00
}
2024-04-17 17:57:12 -04:00
error < < _ ( " AAF: Could not create new session for AAF import . " ) < < endmsg ;
2024-02-14 18:33:34 -05:00
return - 1 ;
}
2024-03-10 16:54:06 -04:00
/* Possible libaaf log to external file : part 2/2
* Moving log file from temp / to session /
*/
// string newlogfile = Glib::build_filename (path, "aaf-import.log");
//
// if (!PBD::copy_file (logfile, newlogfile)) {
// // if (g_rename (logfile.c_str(), newlogfile.c_str()) != 0) {
// error << string_compose (_("Could not copy logfile from \"%1\" to \"%2\": %3"),
// logfile, newlogfile, strerror (errno)) << endmsg;
// fprintf(stderr, "Could not copy logfile from \"%s\" to \"%s\": %s\n", logfile.c_str(), newlogfile.c_str(), strerror (errno) );
// } else {
// fprintf(stderr, "Copied logfile from \"%s\" to \"%s\"\n", logfile.c_str(), newlogfile.c_str() );
// g_unlink(logfile.c_str ());
// logfile = newlogfile;
// fprintf(stderr, "New logfile : \"%s\"\n", logfile.c_str() );
// }
2024-02-14 18:33:34 -05:00
switch ( aafi - > Audio - > samplesize ) {
case 16 :
_session - > config . set_native_file_data_format ( ARDOUR : : FormatInt16 ) ;
break ;
case 24 :
_session - > config . set_native_file_data_format ( ARDOUR : : FormatInt24 ) ;
break ;
case 32 :
_session - > config . set_native_file_data_format ( ARDOUR : : FormatFloat ) ;
break ;
default :
break ;
}
/* Import Sources */
2024-04-17 17:57:12 -04:00
SourceList * oneClipSources ;
2024-02-14 18:33:34 -05:00
ARDOUR : : ImportStatus import_status ;
vector < std : : shared_ptr < Region > > source_regions ;
timepos_t pos = timepos_t : : max ( Temporal : : AudioTime ) ;
2024-04-17 17:57:12 -04:00
aafiAudioTrack * aafAudioTrack = NULL ;
aafiTimelineItem * aafAudioItem = NULL ;
aafiAudioClip * aafAudioClip = NULL ;
aafiAudioEssencePointer * aafAudioEssencePtr = NULL ;
2024-02-14 18:33:34 -05:00
2024-03-10 16:54:06 -04:00
aafPosition_t sessionStart = aafi_convertUnit ( aafi - > compositionStart , aafi - > compositionStart_editRate , & samplerate_r ) ;
AAFI_foreachAudioTrack ( aafi , aafAudioTrack )
2024-02-14 18:33:34 -05:00
{
std : : shared_ptr < AudioTrack > track = prepare_audio_track ( aafAudioTrack , _session ) ;
2024-03-10 16:54:06 -04:00
AAFI_foreachTrackItem ( aafAudioTrack , aafAudioItem )
2024-02-14 18:33:34 -05:00
{
2024-03-10 16:54:06 -04:00
aafAudioClip = aafi_timelineItemToAudioClip ( aafAudioItem ) ;
if ( ! aafAudioClip ) {
2024-02-14 18:33:34 -05:00
continue ;
}
2024-02-14 19:38:50 -05:00
if ( aafAudioClip - > essencePointerList = = NULL ) {
2024-04-17 17:57:12 -04:00
error < < _ ( " AAF: Clip has no essence. " ) < < endmsg ;
2024-02-14 18:33:34 -05:00
continue ;
}
2024-04-17 17:57:12 -04:00
int essenceError = 0 ;
char * essenceName = aafAudioClip - > essencePointerList - > essenceFile - > name ;
2024-02-14 18:33:34 -05:00
2024-04-17 17:57:12 -04:00
AAFI_foreachEssencePointer ( aafAudioClip - > essencePointerList , aafAudioEssencePtr )
{
2024-03-10 16:54:06 -04:00
struct aafiAudioEssenceFile * audioEssenceFile = aafAudioEssencePtr - > essenceFile ;
2024-02-14 18:33:34 -05:00
2024-03-10 16:54:06 -04:00
if ( ! audioEssenceFile ) {
2024-04-17 17:57:12 -04:00
PBD : : error < < string_compose ( _ ( " AAF: Could not create new region for clip '%1': Missing audio essence " ) , audioEssenceFile - > unique_name ) < < endmsg ;
2024-03-10 16:54:06 -04:00
essenceError + + ;
2024-02-14 19:38:50 -05:00
continue ;
}
2024-02-14 18:33:34 -05:00
2024-03-14 07:47:21 -04:00
if ( audioEssenceFile - > is_embedded ) {
2024-03-10 16:54:06 -04:00
if ( aafi_extractAudioEssenceFile ( aafi , audioEssenceFile , AAFI_EXTRACT_DEFAULT , media_cache_path . c_str ( ) , 0 , 0 , NULL , NULL ) < 0 ) {
PBD : : error < < string_compose ( " AAF: Could not extract audio file '%1' from AAF. " , audioEssenceFile - > unique_name ) < < endmsg ;
essenceError + + ;
continue ;
}
} else if ( ! audioEssenceFile - > is_embedded & & ! audioEssenceFile - > usable_file_path ) {
PBD : : error < < string_compose ( " AAF: Could not locate external audio file: '%1' " , audioEssenceFile - > original_file_path ) < < endmsg ;
essenceError + + ;
2024-02-14 19:38:50 -05:00
continue ;
}
2024-03-10 16:54:06 -04:00
}
2024-02-14 18:33:34 -05:00
2024-03-10 16:54:06 -04:00
if ( essenceError ) {
PBD : : error < < string_compose ( " AAF: Error parsing audio essence pointerlist : %1 \n " , essenceName ) ;
continue ;
}
2024-02-14 19:38:50 -05:00
2024-04-17 17:57:12 -04:00
if ( ! import_sndfile_as_region ( _session , aafAudioClip - > essencePointerList , SrcBest , pos , & oneClipSources , import_status , source_regions ) ) {
2024-03-10 16:54:06 -04:00
PBD : : error < < string_compose ( " AAF: Could not import '%1' to session. " , essenceName ) < < endmsg ;
continue ;
2024-04-17 17:57:12 -04:00
} else {
AAFI_foreachEssencePointer ( aafAudioClip - > essencePointerList , aafAudioEssencePtr )
{
2024-03-10 16:54:06 -04:00
if ( aafAudioEssencePtr - > essenceFile - > is_embedded ) {
g_unlink ( aafAudioEssencePtr - > essenceFile - > usable_file_path ) ;
}
2024-02-14 19:38:50 -05:00
}
2024-03-10 16:54:06 -04:00
}
2024-02-14 18:33:34 -05:00
2024-04-17 17:57:12 -04:00
if ( ! oneClipSources | | oneClipSources - > size ( ) = = 0 ) {
error < < string_compose ( _ ( " AAF: Could not create new region for clip '%1': Region has no source " ) , essenceName ) < < endmsg ;
2024-03-10 16:54:06 -04:00
continue ;
}
2024-02-14 19:38:50 -05:00
2024-04-17 17:57:12 -04:00
std : : shared_ptr < Region > region = create_region ( source_regions , aafAudioClip , * oneClipSources , sessionStart , samplerate_r ) ;
2024-03-10 16:54:06 -04:00
if ( ! region ) {
2024-04-17 17:57:12 -04:00
error < < string_compose ( _ ( " AAF: Could not create new region for clip '%1' " ) , essenceName ) < < endmsg ;
2024-03-10 16:54:06 -04:00
continue ;
2024-02-14 18:33:34 -05:00
}
2024-02-14 19:38:50 -05:00
2024-03-10 16:54:06 -04:00
/* converts whatever edit_rate clip is in, to samples */
aafPosition_t clipPos = aafi_convertUnit ( aafAudioClip - > pos , aafAudioClip - > track - > edit_rate , & samplerate_r ) ;
track - > playlist ( ) - > add_region ( region , timepos_t ( clipPos + sessionStart ) ) ;
set_region_gain ( aafAudioClip , region , _session ) ;
set_region_fade ( aafAudioClip , region , & samplerate_r ) ;
if ( aafAudioClip - > mute ) {
region - > set_muted ( true ) ;
}
2024-02-14 18:33:34 -05:00
}
}
2024-04-17 17:57:12 -04:00
// oneClipSources.clear ();
2024-03-10 16:54:06 -04:00
aafiMarker * marker = NULL ;
2024-02-14 18:33:34 -05:00
2024-04-17 17:57:12 -04:00
AAFI_foreachMarker ( aafi , marker )
{
2024-03-10 16:54:06 -04:00
aafPosition_t markerStart = sessionStart + aafi_convertUnit ( marker - > start , marker - > edit_rate , & samplerate_r ) ;
aafPosition_t markerEnd = sessionStart + aafi_convertUnit ( ( marker - > start + marker - > length ) , marker - > edit_rate , & samplerate_r ) ;
2024-02-14 18:33:34 -05:00
Location * location ;
if ( marker - > length = = 0 ) {
2024-03-10 16:54:06 -04:00
location = new Location ( * _session , timepos_t ( markerStart ) , timepos_t ( markerStart ) , marker - > name , Location : : Flags ( Location : : IsMark ) ) ;
2024-02-14 18:33:34 -05:00
} else {
2024-03-10 16:54:06 -04:00
location = new Location ( * _session , timepos_t ( markerStart ) , timepos_t ( markerEnd ) , marker - > name , Location : : Flags ( Location : : IsRangeMarker ) ) ;
2024-02-14 18:33:34 -05:00
}
_session - > locations ( ) - > add ( location , true ) ;
}
/* set session range */
2024-02-14 19:38:50 -05:00
aafRational_t nominal_sample_rate ;
nominal_sample_rate . numerator = _session - > nominal_sample_rate ( ) ;
nominal_sample_rate . denominator = 1 ;
2024-03-10 16:54:06 -04:00
samplepos_t start = samplepos_t ( aafi_convertUnit ( aafi - > compositionStart , aafi - > compositionStart_editRate , & nominal_sample_rate ) ) ;
samplepos_t end = samplepos_t ( aafi_convertUnit ( aafi - > compositionLength , aafi - > compositionLength_editRate , & nominal_sample_rate ) ) + start ;
2024-02-14 18:33:34 -05:00
_session - > maybe_update_session_range ( timepos_t ( start ) , timepos_t ( end ) ) ;
/* set timecode */
set_session_timecode ( aafi , _session ) ;
the_editor ( ) . access_action ( " Editor " , " zoom-to-session " ) ;
/* Cleanup */
import_status . progress = 1.0 ;
import_status . done = true ;
import_status . sources . clear ( ) ;
import_status . all_done = true ;
_session - > save_state ( " " ) ;
source_regions . clear ( ) ;
PBD : : remove_directory ( media_cache_path ) ;
aafi_release ( & aafi ) ;
if ( ! restore_backend . empty ( ) ) {
2024-04-17 17:57:12 -04:00
AudioEngine : : instance ( ) - > stop ( ) ;
AudioEngine : : instance ( ) - > set_backend ( restore_backend , " " , " " ) ;
2024-02-14 18:33:34 -05:00
}
return 0 ;
}