2019-09-23 16:49:06 -04:00
/*
* Copyright ( C ) 2005 - 2007 Doug McLain < doug @ nostar . net >
* Copyright ( C ) 2005 - 2017 Tim Mayberry < mojofunk @ gmail . com >
* Copyright ( C ) 2005 - 2019 Paul Davis < paul @ linuxaudiosystems . com >
* Copyright ( C ) 2005 Karsten Wiese < fzuuzf @ googlemail . com >
* Copyright ( C ) 2005 Taybin Rutkin < taybin @ taybin . com >
* Copyright ( C ) 2006 - 2015 David Robillard < d @ drobilla . net >
* Copyright ( C ) 2007 - 2012 Carl Hetherington < carl @ carlh . net >
* Copyright ( C ) 2008 - 2010 Sakari Bergen < sakari . bergen @ beatwaves . net >
* Copyright ( C ) 2012 - 2019 Robin Gareus < robin @ gareus . org >
* Copyright ( C ) 2013 - 2015 Colin Fletcher < colin . m . fletcher @ googlemail . com >
* Copyright ( C ) 2013 - 2016 John Emmas < john @ creativepost . co . uk >
* Copyright ( C ) 2013 - 2016 Nick Mainsbridge < mainsbridge @ gmail . com >
* Copyright ( C ) 2014 - 2018 Ben Loftis < ben @ harrisonconsoles . com >
* Copyright ( C ) 2015 André Nusser < andre . nusser @ googlemail . com >
* Copyright ( C ) 2016 - 2018 Len Ovens < len @ ovenwerks . net >
* Copyright ( C ) 2017 Johannes Mueller < github @ johannes - mueller . org >
*
* 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 .
*/
# ifdef WAF_BUILD
# include "gtk2ardour-config.h"
# include "gtk2ardour-version.h"
# endif
2022-02-23 18:32:09 -05:00
# include <glibmm/error.h>
2019-09-23 16:49:06 -04:00
# include <gtkmm/progressbar.h>
# include <gtkmm/stock.h>
# include "pbd/basename.h"
2019-09-26 00:08:59 -04:00
# include "pbd/localtime_r.h"
2019-09-23 16:49:06 -04:00
# include "pbd/unwind.h"
# include "gtkmm2ext/application.h"
2019-10-09 22:52:26 -04:00
# include "gtkmm2ext/doi.h"
2024-09-30 13:21:36 -04:00
# include "gtkmm2ext/utils.h"
2019-09-23 16:49:06 -04:00
# include "widgets/prompter.h"
# include "ardour/audioengine.h"
# include "ardour/filename_extensions.h"
2021-07-06 18:17:17 -04:00
# include "ardour/plugin_manager.h"
2019-09-24 16:10:02 -04:00
# include "ardour/profile.h"
2019-09-23 16:49:06 -04:00
# include "ardour/session.h"
# include "ardour/session_utils.h"
# include "ardour/session_state_utils.h"
# include "ardour/session_directory.h"
2024-07-11 21:04:53 -04:00
# include "ardour/wrong_program.h"
2019-09-23 16:49:06 -04:00
2019-12-14 17:31:24 -05:00
# include "ardour_message.h"
2019-09-23 16:49:06 -04:00
# include "ardour_ui.h"
# include "engine_dialog.h"
2020-02-17 19:26:45 -05:00
# include "missing_filesource_dialog.h"
2019-09-23 16:49:06 -04:00
# include "missing_plugin_dialog.h"
# include "opts.h"
2021-07-06 18:17:17 -04:00
# include "plugin_scan_dialog.h"
2019-09-23 16:49:06 -04:00
# include "public_editor.h"
# include "save_as_dialog.h"
# include "session_dialog.h"
# include "session_archive_dialog.h"
# include "timers.h"
2022-10-23 13:26:07 -04:00
# include "ui_config.h"
2019-09-23 16:49:06 -04:00
# include "utils.h"
2019-09-24 05:17:32 -04:00
# ifdef WINDOWS_VST_SUPPORT
# include <fst.h>
# endif
2019-09-26 00:08:59 -04:00
# include "pbd/i18n.h"
2019-09-23 16:49:06 -04:00
using namespace ARDOUR ;
using namespace ARDOUR_UI_UTILS ;
using namespace PBD ;
using namespace Gtk ;
using namespace std ;
using namespace ArdourWidgets ;
bool
ARDOUR_UI : : ask_about_loading_existing_session ( const std : : string & session_path )
{
std : : string str = string_compose ( _ ( " This session \n %1 \n already exists. Do you want to open it? " ) , session_path ) ;
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( str ,
false ,
Gtk : : MESSAGE_WARNING ,
Gtk : : BUTTONS_YES_NO ,
true ) ;
2019-09-23 16:49:06 -04:00
msg . set_name ( X_ ( " OpenExistingDialog " ) ) ;
msg . set_title ( _ ( " Open Existing Session " ) ) ;
msg . set_wmclass ( X_ ( " existing_session " ) , PROGRAM_NAME ) ;
msg . set_position ( Gtk : : WIN_POS_CENTER ) ;
switch ( msg . run ( ) ) {
case RESPONSE_YES :
return true ;
break ;
}
return false ;
}
2020-01-09 17:51:53 -05:00
void
2023-09-14 13:36:10 -04:00
ARDOUR_UI : : build_session_from_dialog ( SessionDialog & sd , const std : : string & session_path , const std : : string & session_name , std : : string const & session_template , Temporal : : TimeDomain domain )
2019-09-23 16:49:06 -04:00
{
BusProfile bus_profile ;
if ( nsm ) {
bus_profile . master_out_channels = 2 ;
2023-09-14 13:36:10 -04:00
} else if ( Profile - > get_mixbus ( ) ) {
2019-09-24 16:10:02 -04:00
bus_profile . master_out_channels = 2 ;
2019-09-23 16:49:06 -04:00
} else {
/* get settings from advanced section of NSD */
bus_profile . master_out_channels = ( uint32_t ) sd . master_channel_count ( ) ;
}
2023-10-01 17:06:29 -04:00
build_session ( session_path , session_name , session_template , bus_profile , false , ! sd . was_new_name_edited ( ) , domain ) ;
2019-09-23 16:49:06 -04:00
}
2019-10-09 22:52:26 -04:00
/** This is only ever used once Ardour is already running with a session
* loaded . The startup case is handled by StartupFSM
*/
2019-09-23 16:49:06 -04:00
void
2019-11-01 17:48:16 -04:00
ARDOUR_UI : : start_session_load ( bool create_new )
2019-09-23 16:49:06 -04:00
{
/* deal with any existing DIRTY session now, rather than later. don't
* treat a non - dirty session this way , so that it stays visible
* as we bring up the new session dialog .
*/
if ( _session & & ARDOUR_UI : : instance ( ) - > video_timeline ) {
ARDOUR_UI : : instance ( ) - > video_timeline - > sync_session_state ( ) ;
}
if ( _session & & _session - > dirty ( ) ) {
if ( unload_session ( false ) ) {
/* unload cancelled by user */
2019-10-09 22:52:26 -04:00
return ;
2019-09-23 16:49:06 -04:00
}
}
2019-11-01 17:48:16 -04:00
SessionDialog * session_dialog = new SessionDialog ( create_new , string ( ) , Config - > get_default_session_parent_dir ( ) , string ( ) , true ) ;
2019-10-09 22:52:26 -04:00
session_dialog - > signal_response ( ) . connect ( sigc : : bind ( sigc : : mem_fun ( * this , & ARDOUR_UI : : session_dialog_response_handler ) , session_dialog ) ) ;
2024-06-10 12:47:07 -04:00
session_dialog - > set_position ( WIN_POS_CENTER ) ;
2019-10-09 22:52:26 -04:00
session_dialog - > present ( ) ;
}
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
void
ARDOUR_UI : : session_dialog_response_handler ( int response , SessionDialog * session_dialog )
{
string session_name ;
string session_path ;
string template_name ;
2023-09-14 13:36:10 -04:00
Temporal : : TimeDomain session_domain ;
2019-10-09 22:52:26 -04:00
bool likely_new = false ;
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
session_path = " " ;
session_name = " " ;
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
switch ( response ) {
case RESPONSE_ACCEPT :
break ;
default :
return ; /* back to main event loop */
2019-09-23 16:49:06 -04:00
}
2019-10-09 22:52:26 -04:00
session_name = session_dialog - > session_name ( likely_new ) ;
session_path = session_dialog - > session_folder ( ) ;
2023-09-14 13:36:10 -04:00
session_domain = session_dialog - > session_domain ( ) ;
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
if ( nsm ) {
likely_new = true ;
}
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
/* could be an archived session, so test for that and use the
* result if it was
*/
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
if ( ! likely_new ) {
int rv = ARDOUR : : inflate_session ( session_name , Config - > get_default_session_parent_dir ( ) , session_path , session_name ) ;
2019-09-23 16:49:06 -04:00
2021-03-11 13:37:10 -05:00
if ( rv < 0 ) {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( * session_dialog , string_compose ( _ ( " Extracting session-archive failed: %1 " ) , inflate_error ( rv ) ) ) ;
2019-10-09 22:52:26 -04:00
msg . run ( ) ;
return ; /* back to main event loop */
} else if ( rv = = 0 ) {
session_dialog - > set_provided_session ( session_name , session_path ) ;
2024-02-14 18:33:34 -05:00
} else {
rv = new_session_from_aaf ( session_name , Config - > get_default_session_parent_dir ( ) , session_path , session_name ) ;
if ( rv < 0 ) {
ArdourMessageDialog msg ( * session_dialog , _ ( " Extracting AAF failed " ) ) ;
msg . run ( ) ;
return ; /* back to main event loop */
} else if ( rv = = 0 ) {
session_dialog - > set_provided_session ( session_name , session_path ) ;
/* we got a session now */
session_dialog - > hide ( ) ;
delete_when_idle ( session_dialog ) ;
return ;
}
2019-09-23 16:49:06 -04:00
}
2019-10-09 22:52:26 -04:00
}
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
string : : size_type suffix = session_name . find ( statefile_suffix ) ;
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
if ( suffix ! = string : : npos ) {
session_name = session_name . substr ( 0 , suffix ) ;
}
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
/* this shouldn't happen, but we catch it just in case it does */
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
if ( session_name . empty ( ) ) {
return ; /* back to main event loop */
}
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
if ( session_dialog - > use_session_template ( ) ) {
template_name = session_dialog - > session_template_name ( ) ;
_session_is_new = true ;
}
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
if ( session_name [ 0 ] = = G_DIR_SEPARATOR | |
2019-09-23 16:49:06 -04:00
# ifdef PLATFORM_WINDOWS
2019-10-09 22:52:26 -04:00
( session_name . length ( ) > 3 & & session_name [ 1 ] = = ' : ' & & session_name [ 2 ] = = G_DIR_SEPARATOR )
2019-09-23 16:49:06 -04:00
# else
2019-10-09 22:52:26 -04:00
( session_name . length ( ) > 2 & & session_name [ 0 ] = = ' . ' & & session_name [ 1 ] = = G_DIR_SEPARATOR ) | |
( session_name . length ( ) > 3 & & session_name [ 0 ] = = ' . ' & & session_name [ 1 ] = = ' . ' & & session_name [ 2 ] = = G_DIR_SEPARATOR )
2019-09-23 16:49:06 -04:00
# endif
)
2019-10-09 22:52:26 -04:00
{
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
/* absolute path or cwd-relative path specified for session name: infer session folder
from what was given .
*/
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
session_path = Glib : : path_get_dirname ( session_name ) ;
session_name = Glib : : path_get_basename ( session_name ) ;
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
} else {
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
session_path = session_dialog - > session_folder ( ) ;
2019-09-23 16:49:06 -04:00
2020-06-09 14:19:10 -04:00
std : : string const & illegal = Session : : session_name_is_legal ( session_name ) ;
2019-09-23 16:49:06 -04:00
2020-06-09 14:19:10 -04:00
if ( ! illegal . empty ( ) ) {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( * session_dialog ,
string_compose ( _ ( " To ensure compatibility with various systems \n "
" session names may not contain a '%1' character " ) ,
illegal ) ) ;
2019-10-09 22:52:26 -04:00
msg . run ( ) ;
return ; /* back to main event loop */
2019-09-23 16:49:06 -04:00
}
2019-10-09 22:52:26 -04:00
}
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
if ( Glib : : file_test ( session_path , Glib : : FileTest ( G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR ) ) ) {
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
if ( likely_new & & ! nsm ) {
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
std : : string existing = Glib : : build_filename ( session_path , session_name ) ;
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
if ( ! ask_about_loading_existing_session ( existing ) ) {
return ; /* back to main event loop */
2019-09-23 16:49:06 -04:00
}
2019-10-09 22:52:26 -04:00
}
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
_session_is_new = false ;
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
} else {
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
if ( ! likely_new ) {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( string_compose ( _ ( " There is no existing session at \" %1 \" " ) , session_path ) ) ;
2019-10-09 22:52:26 -04:00
msg . run ( ) ;
return ; /* back to main event loop */
}
2019-09-23 16:49:06 -04:00
2020-06-09 14:19:10 -04:00
std : : string const & illegal = Session : : session_name_is_legal ( session_name ) ;
2019-09-23 16:49:06 -04:00
2020-06-09 14:19:10 -04:00
if ( ! illegal . empty ( ) ) {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( * session_dialog , string_compose ( _ ( " To ensure compatibility with various systems \n "
" session names may not contain a '%1' character " ) , illegal ) ) ;
2019-10-09 22:52:26 -04:00
msg . run ( ) ;
return ; /* back to main event loop */
2019-09-23 16:49:06 -04:00
}
2019-10-09 22:52:26 -04:00
_session_is_new = true ;
}
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
/* OK, parameters provided ... good to go. */
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
session_dialog - > hide ( ) ;
delete_when_idle ( session_dialog ) ;
2019-09-23 16:49:06 -04:00
2020-01-09 17:51:53 -05:00
if ( ! template_name . empty ( ) | | likely_new ) {
2019-09-23 16:49:06 -04:00
2023-09-14 13:36:10 -04:00
build_session_from_dialog ( * session_dialog , session_path , session_name , template_name , session_domain ) ;
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
} else {
2019-09-23 16:49:06 -04:00
2019-10-09 22:52:26 -04:00
load_session ( session_path , session_name , template_name ) ;
}
2019-09-23 16:49:06 -04:00
}
void
ARDOUR_UI : : close_session ( )
{
if ( unload_session ( true ) ) {
return ;
}
2019-11-01 17:48:16 -04:00
start_session_load ( false ) ;
2019-09-23 16:49:06 -04:00
}
/** @param snap_name Snapshot name (without .ardour suffix).
* @ return - 2 if the load failed because we are not connected to the AudioEngine .
*/
int
ARDOUR_UI : : load_session ( const std : : string & path , const std : : string & snap_name , std : : string mix_template )
{
/* load_session calls flush_pending() which allows
* GUI interaction and potentially loading another session
* ( that was easy via snapshot sidebar ) .
Fix typos in gtk2_ardour/ directory
Found via `codespell -q 3 -S *.po,./share/patchfiles,./libs -L ba,buss,busses,doubleclick,hsi,ontop,ro,seh,siz,sur,te,trough,ue`
2022-01-26 12:35:38 -05:00
* Recursing into load_session ( ) from load_session ( ) and recursive
2019-09-23 16:49:06 -04:00
* event loops causes all kind of crashes .
*/
assert ( ! session_load_in_progress ) ;
if ( session_load_in_progress ) {
return - 1 ;
}
PBD : : Unwinder < bool > lsu ( session_load_in_progress , true ) ;
int unload_status ;
2019-12-11 16:52:46 -05:00
bool had_session = false ;
2019-09-23 16:49:06 -04:00
if ( _session ) {
2019-12-11 16:52:46 -05:00
had_session = true ;
2019-09-23 16:49:06 -04:00
unload_status = unload_session ( ) ;
2019-12-11 16:52:46 -05:00
if ( unload_status ! = 0 ) {
hide_splash ( ) ;
return - 1 ;
}
}
if ( had_session ) {
float sr ;
SampleFormat sf ;
string pv ;
Session : : get_info_from_path ( Glib : : build_filename ( path , snap_name + statefile_suffix ) , sr , sf , pv ) ;
/* this will stop the engine if the SR is different */
audio_midi_setup - > set_desired_sample_rate ( sr ) ;
if ( ! AudioEngine : : instance ( ) - > running ( ) ) {
audio_midi_setup - > set_position ( WIN_POS_CENTER ) ;
audio_midi_setup - > present ( ) ;
2020-01-09 17:51:53 -05:00
_engine_dialog_connection = audio_midi_setup - > signal_response ( ) . connect ( sigc : : bind ( sigc : : mem_fun ( * this , & ARDOUR_UI : : audio_midi_setup_reconfigure_done ) , path , snap_name , mix_template ) ) ;
2019-12-11 16:52:46 -05:00
/* not done yet, but we're avoiding modal dialogs */
return 0 ;
}
}
return load_session_stage_two ( path , snap_name , mix_template ) ;
}
void
ARDOUR_UI : : audio_midi_setup_reconfigure_done ( int response , std : : string path , std : : string snap_name , std : : string mix_template )
{
2020-01-25 12:27:12 -05:00
_engine_dialog_connection . disconnect ( ) ;
2019-12-11 16:52:46 -05:00
switch ( response ) {
case Gtk : : RESPONSE_DELETE_EVENT :
break ;
default :
if ( ! AudioEngine : : instance ( ) - > running ( ) ) {
return ; // keep dialog visible, maybe try again
2019-09-23 16:49:06 -04:00
}
}
2019-12-11 16:52:46 -05:00
audio_midi_setup - > hide ( ) ;
( void ) load_session_stage_two ( path , snap_name , mix_template ) ;
}
int
ARDOUR_UI : : load_session_stage_two ( const std : : string & path , const std : : string & snap_name , std : : string mix_template )
{
Session * new_session ;
int retval = - 1 ;
2019-10-11 16:29:55 -04:00
BootMessage ( string_compose ( _ ( " Please wait while %1 loads your session " ) , PROGRAM_NAME ) ) ;
2019-09-23 16:49:06 -04:00
try {
new_session = new Session ( * AudioEngine : : instance ( ) , path , snap_name , 0 , mix_template ) ;
}
/* this one is special */
catch ( AudioEngine : : PortRegistrationFailure const & err ) {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( err . what ( ) ,
true ,
Gtk : : MESSAGE_INFO ,
Gtk : : BUTTONS_CLOSE ) ;
2019-09-23 16:49:06 -04:00
msg . set_title ( _ ( " Port Registration Error " ) ) ;
msg . set_secondary_text ( _ ( " Click the Close button to try again. " ) ) ;
msg . set_position ( Gtk : : WIN_POS_CENTER ) ;
int response = msg . run ( ) ;
msg . hide ( ) ;
switch ( response ) {
case RESPONSE_CANCEL :
exit ( EXIT_FAILURE ) ;
default :
break ;
}
goto out ;
}
catch ( SessionException const & e ) {
2022-02-23 11:25:15 -05:00
gchar * escaped_error_txt = 0 ;
2020-02-28 01:31:43 -05:00
stringstream ss ;
dump_errors ( ss , 6 ) ;
dump_errors ( cerr ) ;
clear_errors ( ) ;
2022-02-23 11:25:15 -05:00
{
const std : : string & tmp = ss . str ( ) ;
escaped_error_txt = g_markup_escape_text ( tmp . c_str ( ) , - 1 ) ;
}
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( string_compose (
2020-02-28 01:31:43 -05:00
_ ( " Session \" %1 (snapshot %2) \" did not load successfully: \n %3%4%5 " ) ,
2022-02-23 11:25:15 -05:00
path , snap_name , e . what ( ) , ss . str ( ) . empty ( ) ? " " : " \n \n --- " , escaped_error_txt ) ,
2020-02-28 01:31:43 -05:00
false ,
2019-12-14 17:31:24 -05:00
Gtk : : MESSAGE_INFO ,
BUTTONS_OK ) ;
2019-09-23 16:49:06 -04:00
msg . set_title ( _ ( " Loading Error " ) ) ;
msg . set_position ( Gtk : : WIN_POS_CENTER ) ;
( void ) msg . run ( ) ;
msg . hide ( ) ;
2023-07-02 17:53:29 -04:00
g_free ( escaped_error_txt ) ;
2019-09-23 16:49:06 -04:00
goto out ;
}
2024-07-11 21:04:53 -04:00
catch ( ARDOUR : : WrongProgram const & wp ) {
std : : string first_word = wp . creator . substr ( 0 , wp . creator . find ( ' ' ) ) ;
ArdourMessageDialog msg ( string_compose ( " <span size= \" large \" >%1 \n cannot load sessions \n last modified by \n %2</span> " , PROGRAM_NAME , first_word ) ,
true ,
Gtk : : MESSAGE_ERROR ,
BUTTONS_OK ) ;
msg . set_title ( _ ( " Session not loaded " ) ) ;
msg . set_position ( Gtk : : WIN_POS_CENTER ) ;
( void ) msg . run ( ) ;
msg . hide ( ) ;
goto out ;
}
2022-02-23 18:32:09 -05:00
catch ( Glib : : Error const & e ) {
const std : : string & glib_what = e . what ( ) ;
gchar * escaped_error_txt = 0 ;
stringstream ss ;
dump_errors ( ss , 6 ) ;
dump_errors ( cerr ) ;
clear_errors ( ) ;
{
const std : : string & tmp = ss . str ( ) ;
escaped_error_txt = g_markup_escape_text ( tmp . c_str ( ) , - 1 ) ;
}
ArdourMessageDialog msg ( string_compose (
_ ( " Session \" %1 (snapshot %2) \" did not load successfully. \n Glib Error \n Domain: %3 \n Code: %4 \n What: %5 \n %6%7 " ) ,
path , snap_name ,
g_quark_to_string ( e . domain ( ) ) , e . code ( ) , glib_what . c_str ( ) ,
ss . str ( ) . empty ( ) ? " " : " \n \n --- " , escaped_error_txt ) ,
true ,
Gtk : : MESSAGE_INFO ,
BUTTONS_OK ) ;
msg . set_title ( _ ( " Loading Error " ) ) ;
msg . set_position ( Gtk : : WIN_POS_CENTER ) ;
( void ) msg . run ( ) ;
msg . hide ( ) ;
2023-07-02 17:53:29 -04:00
g_free ( escaped_error_txt ) ;
2022-02-23 18:32:09 -05:00
goto out ;
}
2019-09-23 16:49:06 -04:00
catch ( . . . ) {
2022-02-23 11:25:15 -05:00
gchar * escaped_error_txt = 0 ;
2020-02-28 01:31:43 -05:00
stringstream ss ;
dump_errors ( ss , 6 ) ;
dump_errors ( cerr ) ;
clear_errors ( ) ;
2019-09-23 16:49:06 -04:00
2022-02-23 11:25:15 -05:00
{
const std : : string & tmp = ss . str ( ) ;
escaped_error_txt = g_markup_escape_text ( tmp . c_str ( ) , - 1 ) ;
}
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( string_compose (
2020-02-28 01:31:43 -05:00
_ ( " Session \" %1 (snapshot %2) \" did not load successfully.%3%4 " ) ,
2022-02-23 11:25:15 -05:00
path , snap_name , ss . str ( ) . empty ( ) ? " " : " \n \n --- " , escaped_error_txt ) ,
2019-12-14 17:31:24 -05:00
true ,
Gtk : : MESSAGE_INFO ,
BUTTONS_OK ) ;
2019-09-23 16:49:06 -04:00
msg . set_title ( _ ( " Loading Error " ) ) ;
msg . set_position ( Gtk : : WIN_POS_CENTER ) ;
( void ) msg . run ( ) ;
msg . hide ( ) ;
2023-07-02 17:53:29 -04:00
g_free ( escaped_error_txt ) ;
2019-09-23 16:49:06 -04:00
goto out ;
}
2020-02-29 01:33:58 -05:00
if ( new_session - > had_destructive_tracks ( ) ) {
ArdourMessageDialog msg ( string_compose ( _ ( " This session (from an older version of %1) used at least \n one \" tape track \" (aka \" destructive recording \" . \n \n "
" This is no longer supported by the program. The tape track(s) have been setup as normal tracks. \n \n "
" If you need to continue using tape tracks/destructive recording \n "
" please use an older version of %1 to work on this session " ) , PROGRAM_NAME ) ,
true ,
Gtk : : MESSAGE_INFO ,
BUTTONS_OK ) ;
msg . set_title ( _ ( " Tape Tracks No Longer Supported " ) ) ;
msg . set_position ( Gtk : : WIN_POS_CENTER ) ;
( void ) msg . run ( ) ;
msg . hide ( ) ;
}
2020-02-17 19:26:45 -05:00
{
list < string > const u = new_session - > missing_filesources ( DataType : : MIDI ) ;
if ( ! u . empty ( ) ) {
2021-07-06 18:33:50 -04:00
MissingFileSourceDialog d ( _main_window , _session , u , DataType : : MIDI ) ;
2020-02-17 19:26:45 -05:00
d . run ( ) ;
}
}
2019-09-23 16:49:06 -04:00
{
list < string > const u = new_session - > unknown_processors ( ) ;
2021-07-06 18:17:17 -04:00
bool scan_now = false ;
2019-09-23 16:49:06 -04:00
if ( ! u . empty ( ) ) {
2021-07-06 18:33:50 -04:00
MissingPluginDialog d ( _main_window , _session , u , PluginManager : : instance ( ) . cache_valid ( ) ) ;
2021-07-06 18:17:17 -04:00
if ( d . run ( ) = = RESPONSE_YES ) {
scan_now = true ;
}
}
if ( scan_now ) {
PluginScanDialog psd ( false , true ) ;
psd . start ( ) ;
2019-09-23 16:49:06 -04:00
}
2021-10-06 21:46:44 -04:00
if ( ! u . empty ( ) ) {
2022-10-23 13:26:07 -04:00
if ( scan_now | | UIConfiguration : : instance ( ) . get_show_manager_if_plugins_are_missing ( ) ) {
show_plugin_manager ( ) ;
}
2021-10-06 21:46:44 -04:00
}
2019-09-23 16:49:06 -04:00
}
if ( ! new_session - > writable ( ) ) {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( _ ( " This session has been opened in read-only mode. \n \n You will not be able to record or save. " ) ,
true ,
Gtk : : MESSAGE_INFO ,
BUTTONS_OK ) ;
2019-09-23 16:49:06 -04:00
msg . set_title ( _ ( " Read-only Session " ) ) ;
msg . set_position ( Gtk : : WIN_POS_CENTER ) ;
( void ) msg . run ( ) ;
msg . hide ( ) ;
}
/* Now the session been created, add the transport controls */
new_session - > add_controllable ( roll_controllable ) ;
new_session - > add_controllable ( stop_controllable ) ;
new_session - > add_controllable ( goto_start_controllable ) ;
new_session - > add_controllable ( goto_end_controllable ) ;
new_session - > add_controllable ( auto_loop_controllable ) ;
new_session - > add_controllable ( play_selection_controllable ) ;
new_session - > add_controllable ( rec_controllable ) ;
set_session ( new_session ) ;
if ( _session ) {
_session - > set_clean ( ) ;
}
{
Timers : : TimerSuspender t ;
flush_pending ( 10 ) ;
}
retval = 0 ;
if ( ! mix_template . empty ( ) ) {
/* if mix_template is given, assume this is a new session */
string metascript = Glib : : build_filename ( mix_template , " template.lua " ) ;
meta_session_setup ( metascript ) ;
}
out :
/* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
* which is queued by set_session ( ) .
* If session - loading fails we hide it explicitly .
* This covers both cases in a central place .
*/
if ( retval ) {
hide_splash ( ) ;
}
return retval ;
}
int
2023-09-14 13:36:10 -04:00
ARDOUR_UI : : build_session ( const std : : string & path , const std : : string & snap_name , const std : : string & session_template , BusProfile const & bus_profile , bool from_startup_fsm , bool unnamed , Temporal : : TimeDomain domain )
2019-09-23 16:49:06 -04:00
{
int x ;
x = unload_session ( ) ;
if ( x < 0 ) {
return - 1 ;
} else if ( x > 0 ) {
return 0 ;
}
_session_is_new = true ;
2020-01-09 17:51:53 -05:00
/* when running from startup FSM all is fine,
* engine should be running and the FSM will also have
* asked for the SR ( even if try - autostart - engine is set )
*/
if ( from_startup_fsm & & AudioEngine : : instance ( ) - > running ( ) ) {
2023-09-14 13:36:10 -04:00
return build_session_stage_two ( path , snap_name , session_template , bus_profile , unnamed , domain ) ;
2020-01-09 17:51:53 -05:00
}
2020-01-09 20:13:36 -05:00
/* Sample-rate cannot be changed when JACK is running */
if ( ! ARDOUR : : AudioEngine : : instance ( ) - > setup_required ( ) & & AudioEngine : : instance ( ) - > running ( ) ) {
2023-09-14 13:36:10 -04:00
return build_session_stage_two ( path , snap_name , session_template , bus_profile , unnamed , domain ) ;
2020-01-09 20:13:36 -05:00
}
2020-01-09 17:51:53 -05:00
2020-01-10 12:11:42 -05:00
/* Work-around missing "OK" button:
* When the engine is running . The way to proceed w / o engine re - start
* is to simply close the dialog . This is not obvious .
*
* Ideally an engine restart should be avoided since it can invalidate
* latency - calibration .
*/
ARDOUR : : AudioEngine : : instance ( ) - > stop ( ) ;
2020-01-09 17:51:53 -05:00
/* Ask for the Sample-rate to use with the new session */
audio_midi_setup - > set_position ( WIN_POS_CENTER ) ;
audio_midi_setup - > set_modal ( ) ;
audio_midi_setup - > present ( ) ;
2024-10-18 19:51:44 -04:00
_engine_dialog_connection = audio_midi_setup - > signal_response ( ) . connect ( std : : bind ( & ARDOUR_UI : : audio_midi_setup_for_new_session_done , this , _1 , path , snap_name , session_template , bus_profile , unnamed , domain ) ) ;
2020-01-09 17:51:53 -05:00
/* not done yet, but we're avoiding modal dialogs */
return 0 ;
}
void
2023-09-14 13:36:10 -04:00
ARDOUR_UI : : audio_midi_setup_for_new_session_done ( int response , std : : string path , std : : string snap_name , std : : string template_name , BusProfile const & bus_profile , bool unnamed , Temporal : : TimeDomain domain )
2020-01-09 17:51:53 -05:00
{
2020-01-25 12:27:12 -05:00
_engine_dialog_connection . disconnect ( ) ;
2020-01-09 17:51:53 -05:00
switch ( response ) {
case Gtk : : RESPONSE_DELETE_EVENT :
audio_midi_setup - > set_modal ( false ) ;
break ;
default :
break ;
}
if ( ! AudioEngine : : instance ( ) - > running ( ) ) {
return ; // keep dialog visible, maybe try again
2019-09-23 16:49:06 -04:00
}
2020-01-09 17:51:53 -05:00
audio_midi_setup - > set_modal ( false ) ;
audio_midi_setup - > hide ( ) ;
2019-09-23 16:49:06 -04:00
2023-09-14 13:36:10 -04:00
build_session_stage_two ( path , snap_name , template_name , bus_profile , unnamed , domain ) ;
2020-01-09 17:51:53 -05:00
}
int
2024-02-14 18:33:19 -05:00
ARDOUR_UI : : build_session_stage_two ( std : : string const & path , std : : string const & snap_name , std : : string const & session_template , BusProfile const & bus_profile , bool unnamed , Temporal : : TimeDomain domain , samplecnt_t samplerate )
2020-01-09 17:51:53 -05:00
{
Session * new_session ;
2020-01-30 12:07:01 -05:00
bool meta_session = ! session_template . empty ( ) & & session_template . substr ( 0 , 11 ) = = " urn:ardour: " ;
2020-01-09 17:51:53 -05:00
try {
2024-02-14 18:33:19 -05:00
new_session = new Session ( * AudioEngine : : instance ( ) , path , snap_name , bus_profile . master_out_channels > 0 ? & bus_profile : NULL , meta_session ? " " : session_template , unnamed , samplerate ) ;
2020-01-09 17:51:53 -05:00
}
2019-09-23 16:49:06 -04:00
catch ( SessionException const & e ) {
2022-02-23 11:25:15 -05:00
gchar * escaped_error_txt = 0 ;
2020-02-28 01:31:43 -05:00
stringstream ss ;
dump_errors ( ss , 6 ) ;
2019-09-23 16:49:06 -04:00
cerr < < " Here are the errors associated with this failed session: \n " ;
dump_errors ( cerr ) ;
cerr < < " --------- \n " ;
2020-02-28 01:31:43 -05:00
clear_errors ( ) ;
2022-02-23 11:25:15 -05:00
{
const std : : string & tmp = ss . str ( ) ;
escaped_error_txt = g_markup_escape_text ( tmp . c_str ( ) , - 1 ) ;
}
ArdourMessageDialog msg ( string_compose ( _ ( " Could not create session in \" %1 \" : %2%3%4 " ) , path , e . what ( ) , ss . str ( ) . empty ( ) ? " " : " \n \n --- " , escaped_error_txt ) ) ;
2019-09-23 16:49:06 -04:00
msg . set_title ( _ ( " Loading Error " ) ) ;
msg . set_position ( Gtk : : WIN_POS_CENTER ) ;
msg . run ( ) ;
2023-07-02 17:53:29 -04:00
g_free ( escaped_error_txt ) ;
2019-09-23 16:49:06 -04:00
return - 1 ;
}
2022-02-23 18:32:09 -05:00
catch ( Glib : : Error const & e ) {
const std : : string & glib_what = e . what ( ) ;
gchar * escaped_error_txt = 0 ;
stringstream ss ;
dump_errors ( ss , 6 ) ;
dump_errors ( cerr ) ;
clear_errors ( ) ;
{
const std : : string & tmp = ss . str ( ) ;
escaped_error_txt = g_markup_escape_text ( tmp . c_str ( ) , - 1 ) ;
}
ArdourMessageDialog msg ( string_compose (
2022-04-05 12:45:40 -04:00
_ ( " Could not create session in \" %1 \" . \n \n Glib Error \n Domain: %2 \n Code: %3 \n What: %4 \n %5%6 " ) ,
2022-02-23 18:32:09 -05:00
path ,
g_quark_to_string ( e . domain ( ) ) , e . code ( ) , glib_what . c_str ( ) ,
ss . str ( ) . empty ( ) ? " " : " \n \n --- " , escaped_error_txt ) ) ;
msg . set_title ( _ ( " Loading Error " ) ) ;
msg . set_position ( Gtk : : WIN_POS_CENTER ) ;
msg . run ( ) ;
2023-07-02 17:53:29 -04:00
g_free ( escaped_error_txt ) ;
2022-02-23 18:32:09 -05:00
return - 1 ;
}
2019-09-23 16:49:06 -04:00
catch ( . . . ) {
2022-02-23 11:25:15 -05:00
gchar * escaped_error_txt = 0 ;
2020-02-28 01:31:43 -05:00
stringstream ss ;
dump_errors ( ss , 6 ) ;
2019-09-23 16:49:06 -04:00
cerr < < " Here are the errors associated with this failed session: \n " ;
dump_errors ( cerr ) ;
cerr < < " --------- \n " ;
2020-02-28 01:31:43 -05:00
clear_errors ( ) ;
2022-02-23 11:25:15 -05:00
{
const std : : string & tmp = ss . str ( ) ;
escaped_error_txt = g_markup_escape_text ( tmp . c_str ( ) , - 1 ) ;
}
ArdourMessageDialog msg ( string_compose ( _ ( " Could not create session in \" %1 \" %2%3 " ) , path , ss . str ( ) . empty ( ) ? " " : " \n \n --- " , escaped_error_txt ) ) ;
2019-09-23 16:49:06 -04:00
msg . set_title ( _ ( " Loading Error " ) ) ;
msg . set_position ( Gtk : : WIN_POS_CENTER ) ;
msg . run ( ) ;
2023-07-02 17:53:29 -04:00
g_free ( escaped_error_txt ) ;
2019-09-23 16:49:06 -04:00
return - 1 ;
}
/* Give the new session the default GUI state, if such things exist */
XMLNode * n ;
n = Config - > instant_xml ( X_ ( " Editor " ) ) ;
if ( n ) {
n - > remove_nodes_and_delete ( " Selection " ) ; // no not apply selection to new sessions.
new_session - > add_instant_xml ( * n , false ) ;
}
n = Config - > instant_xml ( X_ ( " Mixer " ) ) ;
if ( n ) {
new_session - > add_instant_xml ( * n , false ) ;
}
n = Config - > instant_xml ( X_ ( " Preferences " ) ) ;
if ( n ) {
new_session - > add_instant_xml ( * n , false ) ;
}
/* Put the playhead at 0 and scroll fully left */
n = new_session - > instant_xml ( X_ ( " Editor " ) ) ;
if ( n ) {
n - > set_property ( X_ ( " playhead " ) , X_ ( " 0 " ) ) ;
n - > set_property ( X_ ( " left-frame " ) , X_ ( " 0 " ) ) ;
}
2023-09-14 13:36:10 -04:00
new_session - > config . set_default_time_domain ( domain ) ;
2019-09-23 16:49:06 -04:00
set_session ( new_session ) ;
new_session - > save_state ( new_session - > name ( ) ) ;
2020-01-30 12:07:01 -05:00
if ( meta_session ) {
2020-01-09 17:51:53 -05:00
meta_session_setup ( session_template . substr ( 11 ) ) ;
}
2019-09-23 16:49:06 -04:00
return 0 ;
}
/** Ask the user for the name of a new snapshot and then take it.
*/
void
ARDOUR_UI : : snapshot_session ( bool switch_to_it )
{
if ( switch_to_it & & _session - > dirty ( ) ) {
vector < string > actions ;
actions . push_back ( _ ( " Abort saving snapshot " ) ) ;
actions . push_back ( _ ( " Don't save now, just snapshot " ) ) ;
actions . push_back ( _ ( " Save it first " ) ) ;
switch ( ask_about_saving_session ( actions ) ) {
case - 1 :
return ;
break ;
case 1 :
if ( save_state_canfail ( " " ) ) {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( _main_window ,
2019-09-23 16:49:06 -04:00
string_compose ( _ ( " \
% 1 was unable to save your session . \ n \ n \
If you still wish to proceed , please use the \ n \ n \
\ " Don't save now \" option. " ) , PROGRAM_NAME ) ) ;
msg . run ( ) ;
return ;
}
/* fallthrough */
case 0 :
_session - > remove_pending_capture_state ( ) ;
break ;
}
}
Prompter prompter ( true ) ;
prompter . set_name ( " Prompter " ) ;
prompter . add_button ( Gtk : : Stock : : SAVE , Gtk : : RESPONSE_ACCEPT ) ;
if ( switch_to_it ) {
prompter . set_title ( _ ( " Snapshot and switch " ) ) ;
prompter . set_prompt ( _ ( " New session name " ) ) ;
} else {
prompter . set_title ( _ ( " Take Snapshot " ) ) ;
prompter . set_prompt ( _ ( " Name of new snapshot " ) ) ;
}
if ( switch_to_it ) {
prompter . set_initial_text ( _session - > snap_name ( ) ) ;
} else {
Glib : : DateTime tm ( g_date_time_new_now_local ( ) ) ;
prompter . set_initial_text ( tm . format ( " %FT%H.%M.%S " ) ) ;
}
bool finished = false ;
while ( ! finished ) {
switch ( prompter . run ( ) ) {
case RESPONSE_ACCEPT :
{
finished = process_snapshot_session_prompter ( prompter , switch_to_it ) ;
break ;
}
default :
finished = true ;
break ;
}
}
}
/** Ask the user for a new session name and then rename the session to it.
*/
void
2020-03-24 16:10:26 -04:00
ARDOUR_UI : : rename_session ( bool for_unnamed )
2019-09-23 16:49:06 -04:00
{
if ( ! _session ) {
return ;
}
2020-05-18 18:02:48 -04:00
Prompter prompter ( true , false ) ;
2019-09-23 16:49:06 -04:00
string name ;
prompter . set_name ( " Prompter " ) ;
2020-05-18 18:02:48 -04:00
2022-02-07 16:19:22 -05:00
prompter . add_button ( Gtk : : Stock : : CANCEL , Gtk : : RESPONSE_CANCEL ) ;
2019-09-23 16:49:06 -04:00
prompter . add_button ( Gtk : : Stock : : SAVE , Gtk : : RESPONSE_ACCEPT ) ;
2020-05-18 18:02:48 -04:00
2020-03-24 16:10:26 -04:00
if ( for_unnamed ) {
prompter . set_title ( _ ( " Name Session " ) ) ;
prompter . set_prompt ( _ ( " Session name " ) ) ;
} else {
prompter . set_title ( _ ( " Rename Session " ) ) ;
prompter . set_prompt ( _ ( " New session name " ) ) ;
}
2019-09-23 16:49:06 -04:00
again :
switch ( prompter . run ( ) ) {
case RESPONSE_ACCEPT :
{
prompter . get_result ( name ) ;
bool do_rename = ( name . length ( ) ! = 0 ) ;
if ( do_rename ) {
2020-06-09 14:19:10 -04:00
std : : string const & illegal = Session : : session_name_is_legal ( name ) ;
2019-09-23 16:49:06 -04:00
2020-06-09 14:19:10 -04:00
if ( ! illegal . empty ( ) ) {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( string_compose ( _ ( " To ensure compatibility with various systems \n "
2019-09-23 16:49:06 -04:00
" session names may not contain a '%1' character " ) , illegal ) ) ;
msg . run ( ) ;
goto again ;
}
switch ( _session - > rename ( name ) ) {
case - 1 : {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( _ ( " That name is already in use by another directory/folder. Please try again. " ) ) ;
2019-09-23 16:49:06 -04:00
msg . run ( ) ;
goto again ;
break ;
}
case 0 :
break ;
default : {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( _ ( " Renaming this session failed. \n Things could be seriously messed up at this point " ) ) ;
2019-09-23 16:49:06 -04:00
msg . run ( ) ;
break ;
}
}
}
break ;
}
default :
break ;
}
}
bool
ARDOUR_UI : : save_as_progress_update ( float fraction , int64_t cnt , int64_t total , Gtk : : Label * label , Gtk : : ProgressBar * bar )
{
char buf [ 256 ] ;
snprintf ( buf , sizeof ( buf ) , _ ( " Copied % " PRId64 " of % " PRId64 ) , cnt , total ) ;
label - > set_text ( buf ) ;
bar - > set_fraction ( fraction ) ;
/* process events, redraws, etc. */
while ( gtk_events_pending ( ) ) {
gtk_main_iteration ( ) ;
}
return true ; /* continue with save-as */
}
void
ARDOUR_UI : : save_session_as ( )
{
if ( ! _session ) {
return ;
}
2020-04-19 12:38:44 -04:00
if ( _session - > unnamed ( ) ) {
save_state ( " " , false ) ;
return ;
}
2019-09-23 16:49:06 -04:00
if ( _session - > dirty ( ) ) {
vector < string > actions ;
actions . push_back ( _ ( " Abort save-as " ) ) ;
actions . push_back ( _ ( " Don't save now, just save-as " ) ) ;
actions . push_back ( _ ( " Save it first " ) ) ;
switch ( ask_about_saving_session ( actions ) ) {
case - 1 :
return ;
break ;
case 1 :
if ( save_state_canfail ( " " ) ) {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( _main_window ,
2019-09-23 16:49:06 -04:00
string_compose ( _ ( " \
% 1 was unable to save your session . \ n \ n \
If you still wish to proceed , please use the \ n \ n \
\ " Don't save now \" option. " ) , PROGRAM_NAME ) ) ;
msg . run ( ) ;
return ;
}
/* fallthrough */
case 0 :
_session - > remove_pending_capture_state ( ) ;
break ;
}
}
if ( ! save_as_dialog ) {
save_as_dialog = new SaveAsDialog ;
}
save_as_dialog - > set_name ( _session - > name ( ) ) ;
int response = save_as_dialog - > run ( ) ;
save_as_dialog - > hide ( ) ;
switch ( response ) {
2020-02-27 17:27:42 -05:00
case Gtk : : RESPONSE_OK :
break ;
default :
return ;
2019-09-23 16:49:06 -04:00
}
Session : : SaveAs sa ;
sa . new_parent_folder = save_as_dialog - > new_parent_folder ( ) ;
sa . new_name = save_as_dialog - > new_name ( ) ;
sa . switch_to = save_as_dialog - > switch_to ( ) ;
sa . copy_media = save_as_dialog - > copy_media ( ) ;
sa . copy_external = save_as_dialog - > copy_external ( ) ;
sa . include_media = save_as_dialog - > include_media ( ) ;
/* Only bother with a progress dialog if we're going to copy
media into the save - as target . Without that choice , this
will be very fast because we ' re only talking about a few kB ' s to
perhaps a couple of MB ' s of data .
*/
ArdourDialog progress_dialog ( _ ( " Save As " ) , true ) ;
ScopedConnection c ;
if ( sa . include_media & & sa . copy_media ) {
Gtk : : Label * label = manage ( new Gtk : : Label ( ) ) ;
Gtk : : ProgressBar * progress_bar = manage ( new Gtk : : ProgressBar ( ) ) ;
progress_dialog . get_vbox ( ) - > pack_start ( * label ) ;
progress_dialog . get_vbox ( ) - > pack_start ( * progress_bar ) ;
label - > show ( ) ;
progress_bar - > show ( ) ;
/* this signal will be emitted from within this, the calling thread,
* after every file is copied . It provides information on percentage
* complete ( in terms of total data to copy ) , the number of files
* copied so far , and the total number to copy .
*/
2024-10-18 19:51:44 -04:00
sa . Progress . connect_same_thread ( c , std : : bind ( & ARDOUR_UI : : save_as_progress_update , this , _1 , _2 , _3 , label , progress_bar ) ) ;
2019-09-23 16:49:06 -04:00
progress_dialog . show_all ( ) ;
progress_dialog . present ( ) ;
}
if ( _session - > save_as ( sa ) ) {
/* ERROR MESSAGE */
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( string_compose ( _ ( " Save As failed: %1 " ) , sa . failure_message ) ) ;
2019-09-23 16:49:06 -04:00
msg . run ( ) ;
}
/* the logic here may seem odd: why isn't the condition sa.switch_to ?
* the trick is this : if the new session was copy with media included ,
* then Session : : save_as ( ) will have already done a neat trick to avoid
* us having to unload and load the new state . But if the media was not
* included , then this is required ( it avoids us having to otherwise
* drop all references to media ( sources ) .
*/
if ( ! sa . include_media & & sa . switch_to ) {
unload_session ( false ) ;
load_session ( sa . final_session_folder_name , sa . new_name ) ;
}
}
void
ARDOUR_UI : : archive_session ( )
{
if ( ! _session ) {
return ;
}
2020-03-25 12:45:00 -04:00
Glib : : DateTime gdt ( Glib : : DateTime : : create_now_local ( ) ) ;
2019-09-23 16:49:06 -04:00
SessionArchiveDialog sad ;
sad . set_name ( _session - > name ( ) + gdt . format ( " _%F_%H%M%S " ) ) ;
int response = sad . run ( ) ;
if ( response ! = Gtk : : RESPONSE_OK ) {
sad . hide ( ) ;
return ;
}
if ( _session - > archive_session ( sad . target_folder ( ) , sad . name ( ) , sad . encode_option ( ) , sad . compression_level ( ) , sad . only_used_sources ( ) , & sad ) ) {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( _ ( " Session Archiving failed. " ) ) ;
2019-09-23 16:49:06 -04:00
msg . run ( ) ;
}
}
void
ARDOUR_UI : : quick_snapshot_session ( bool switch_to_it )
{
2020-03-08 18:32:12 -04:00
if ( switch_to_it & & _session - > dirty ( ) ) {
save_state_canfail ( " " ) ;
}
2020-03-25 12:45:00 -04:00
save_state ( Glib : : DateTime : : create_now_local ( ) . format ( " %FT%H.%M.%S " ) , switch_to_it ) ;
2019-09-23 16:49:06 -04:00
}
bool
ARDOUR_UI : : process_snapshot_session_prompter ( Prompter & prompter , bool switch_to_it )
{
string snapname ;
prompter . get_result ( snapname ) ;
bool do_save = ( snapname . length ( ) ! = 0 ) ;
2024-09-15 18:37:19 -04:00
if ( do_save & & snapname = = _session - > snap_name ( ) ) {
ArdourMessageDialog msg ( _ ( " The currently loaded session name cannot be used as new snapshot. \n Just save the session for this operation. " ) ) ;
msg . run ( ) ;
return false ;
}
2019-09-23 16:49:06 -04:00
if ( do_save ) {
2020-06-09 14:19:10 -04:00
std : : string const & illegal = Session : : session_name_is_legal ( snapname ) ;
if ( ! illegal . empty ( ) ) {
2019-12-14 17:31:24 -05:00
ArdourMessageDialog msg ( string_compose ( _ ( " To ensure compatibility with various systems \n "
" snapshot names may not contain a '%1' character " ) , illegal ) ) ;
2019-09-23 16:49:06 -04:00
msg . run ( ) ;
return false ;
}
}
2023-06-07 11:37:40 -04:00
vector < std : : string > n = Session : : possible_states ( _session - > session_directory ( ) . root_path ( ) ) ;
2019-09-23 16:49:06 -04:00
if ( find ( n . begin ( ) , n . end ( ) , snapname ) ! = n . end ( ) ) {
do_save = overwrite_file_dialog ( prompter ,
_ ( " Confirm Snapshot Overwrite " ) ,
_ ( " A snapshot already exists with that name. Do you want to overwrite it? " ) ) ;
}
if ( do_save ) {
save_state ( snapname , switch_to_it ) ;
}
else {
return false ;
}
return true ;
}
void
ARDOUR_UI : : open_session ( )
{
if ( ! check_audioengine ( _main_window ) ) {
return ;
}
/* ardour sessions are folders */
Gtk : : FileChooserDialog open_session_selector ( _ ( " Open Session " ) , FILE_CHOOSER_ACTION_OPEN ) ;
open_session_selector . add_button ( Gtk : : Stock : : CANCEL , Gtk : : RESPONSE_CANCEL ) ;
open_session_selector . add_button ( Gtk : : Stock : : OPEN , Gtk : : RESPONSE_ACCEPT ) ;
open_session_selector . set_default_response ( Gtk : : RESPONSE_ACCEPT ) ;
if ( _session ) {
string session_parent_dir = Glib : : path_get_dirname ( _session - > path ( ) ) ;
open_session_selector . set_current_folder ( session_parent_dir ) ;
} else {
open_session_selector . set_current_folder ( Config - > get_default_session_parent_dir ( ) ) ;
}
Gtkmm2ext : : add_volume_shortcuts ( open_session_selector ) ;
try {
/* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
string default_session_folder = Config - > get_default_session_parent_dir ( ) ;
open_session_selector . add_shortcut_folder ( default_session_folder ) ;
}
catch ( Glib : : Error const & e ) {
std : : cerr < < " open_session_selector.add_shortcut_folder() threw Glib::Error " < < e . what ( ) < < std : : endl ;
}
FileFilter session_filter ;
session_filter . add_pattern ( string_compose ( X_ ( " *%1 " ) , ARDOUR : : statefile_suffix ) ) ;
session_filter . set_name ( string_compose ( _ ( " %1 sessions " ) , PROGRAM_NAME ) ) ;
open_session_selector . add_filter ( session_filter ) ;
FileFilter archive_filter ;
archive_filter . add_pattern ( string_compose ( X_ ( " *%1 " ) , ARDOUR : : session_archive_suffix ) ) ;
archive_filter . set_name ( _ ( " Session Archives " ) ) ;
open_session_selector . add_filter ( archive_filter ) ;
2024-02-14 18:33:34 -05:00
FileFilter aaf_filter ;
aaf_filter . add_pattern ( string_compose ( X_ ( " *%1 " ) , ARDOUR : : advanced_authoring_format_suffix ) ) ;
aaf_filter . set_name ( _ ( " Advanced Authoring Format (AAF) " ) ) ;
open_session_selector . add_filter ( aaf_filter ) ;
2024-02-19 10:42:17 -05:00
FileFilter all_filter ;
all_filter . add_pattern ( string_compose ( X_ ( " *%1 " ) , ARDOUR : : statefile_suffix ) ) ;
all_filter . add_pattern ( string_compose ( X_ ( " *%1 " ) , ARDOUR : : session_archive_suffix ) ) ;
all_filter . add_pattern ( string_compose ( X_ ( " *%1 " ) , ARDOUR : : advanced_authoring_format_suffix ) ) ;
all_filter . set_name ( _ ( " All supported files " ) ) ;
open_session_selector . add_filter ( all_filter ) ;
2019-09-23 16:49:06 -04:00
open_session_selector . set_filter ( session_filter ) ;
int response = open_session_selector . run ( ) ;
open_session_selector . hide ( ) ;
2020-02-27 17:27:42 -05:00
switch ( response ) {
case Gtk : : RESPONSE_ACCEPT :
break ;
default :
return ;
2019-09-23 16:49:06 -04:00
}
string session_path = open_session_selector . get_filename ( ) ;
string path , name ;
bool isnew ;
2024-02-14 18:33:34 -05:00
if ( session_path . empty ( ) ) {
return ;
}
int rv = ARDOUR : : inflate_session ( session_path , Config - > get_default_session_parent_dir ( ) , path , name ) ;
if ( rv = = 0 ) {
_session_is_new = false ;
load_session ( path , name ) ;
return ;
}
else if ( rv < 0 ) {
ArdourMessageDialog msg ( _main_window , string_compose ( _ ( " Extracting session-archive failed: %1 " ) , inflate_error ( rv ) ) ) ;
msg . run ( ) ;
return ;
}
rv = new_session_from_aaf ( session_path , Config - > get_default_session_parent_dir ( ) , path , name ) ;
if ( rv = = 0 ) {
_session_is_new = false ;
return ;
} else if ( rv < 0 ) {
ArdourMessageDialog msg ( _main_window , _ ( " Extracting AAF failed " ) ) ;
msg . run ( ) ;
return ;
}
if ( ARDOUR : : find_session ( session_path , path , name , isnew ) = = 0 ) {
_session_is_new = isnew ;
load_session ( path , name ) ;
2019-09-23 16:49:06 -04:00
}
}
void
ARDOUR_UI : : open_recent_session ( )
{
bool can_return = ( _session ! = 0 ) ;
SessionDialog recent_session_dialog ;
while ( true ) {
ResponseType r = ( ResponseType ) recent_session_dialog . run ( ) ;
switch ( r ) {
case RESPONSE_ACCEPT :
break ;
default :
if ( can_return ) {
recent_session_dialog . hide ( ) ;
return ;
} else {
exit ( EXIT_FAILURE ) ;
}
}
recent_session_dialog . hide ( ) ;
bool should_be_new ;
std : : string path = recent_session_dialog . session_folder ( ) ;
std : : string state = recent_session_dialog . session_name ( should_be_new ) ;
if ( should_be_new = = true ) {
continue ;
}
_session_is_new = false ;
if ( load_session ( path , state ) = = 0 ) {
break ;
}
can_return = false ;
}
}
int
ARDOUR_UI : : ask_about_saving_session ( const vector < string > & actions )
{
ArdourDialog window ( _ ( " Unsaved Session " ) ) ;
Gtk : : HBox dhbox ; // the hbox for the image and text
Gtk : : Label prompt_label ;
Gtk : : Image * dimage = manage ( new Gtk : : Image ( Stock : : DIALOG_WARNING , Gtk : : ICON_SIZE_DIALOG ) ) ;
string msg ;
assert ( actions . size ( ) > = 3 ) ;
window . add_button ( actions [ 0 ] , RESPONSE_REJECT ) ;
window . add_button ( actions [ 1 ] , RESPONSE_APPLY ) ;
window . add_button ( actions [ 2 ] , RESPONSE_ACCEPT ) ;
window . set_default_response ( RESPONSE_ACCEPT ) ;
2022-11-13 20:56:24 -05:00
window . set_keep_above ( true ) ;
2019-09-23 16:49:06 -04:00
Gtk : : Button noquit_button ( msg ) ;
noquit_button . set_name ( " EditorGTKButton " ) ;
string prompt ;
if ( _session - > snap_name ( ) = = _session - > name ( ) ) {
prompt = string_compose ( _ ( " The session \" %1 \" \n has not been saved. \n \n Any changes made this time \n will be lost unless you save it. \n \n What do you want to do? " ) ,
_session - > snap_name ( ) ) ;
} else {
prompt = string_compose ( _ ( " The snapshot \" %1 \" \n has not been saved. \n \n Any changes made this time \n will be lost unless you save it. \n \n What do you want to do? " ) ,
_session - > snap_name ( ) ) ;
}
prompt_label . set_text ( prompt ) ;
prompt_label . set_name ( X_ ( " PrompterLabel " ) ) ;
2022-01-26 18:04:44 -05:00
prompt_label . set_alignment ( ALIGN_START , ALIGN_START ) ;
2019-09-23 16:49:06 -04:00
2022-01-26 18:04:44 -05:00
dimage - > set_alignment ( ALIGN_CENTER , ALIGN_START ) ;
2019-09-23 16:49:06 -04:00
dhbox . set_homogeneous ( false ) ;
dhbox . pack_start ( * dimage , false , false , 5 ) ;
dhbox . pack_start ( prompt_label , true , false , 5 ) ;
window . get_vbox ( ) - > pack_start ( dhbox ) ;
window . set_name ( _ ( " Prompter " ) ) ;
window . set_modal ( true ) ;
window . set_resizable ( false ) ;
dhbox . show ( ) ;
prompt_label . show ( ) ;
dimage - > show ( ) ;
window . show ( ) ;
window . present ( ) ;
ResponseType r = ( ResponseType ) window . run ( ) ;
window . hide ( ) ;
switch ( r ) {
case RESPONSE_ACCEPT : // save and get out of here
return 1 ;
case RESPONSE_APPLY : // get out of here
return 0 ;
default :
break ;
}
return - 1 ;
}
void
ARDOUR_UI : : save_session_at_its_request ( std : : string snapshot_name )
{
if ( _session ) {
2023-02-03 01:56:49 -05:00
_session - > save_state ( snapshot_name , true ) ;
2019-09-23 16:49:06 -04:00
}
}
gint
ARDOUR_UI : : autosave_session ( )
{
if ( g_main_depth ( ) > 1 ) {
/* inside a recursive main loop,
give up because we may not be able to
take a lock .
*/
return 1 ;
}
if ( ! Config - > get_periodic_safety_backups ( ) ) {
return 1 ;
}
if ( _session ) {
_session - > maybe_write_autosave ( ) ;
}
return 1 ;
}