Skip to content
Snippets Groups Projects
Select Git revision
  • c1c896227da5f18841bd2b72723ce7eebdeba100
  • master default protected
  • develop
  • v2021.a
  • v2020.a
  • v2019.a
  • v2018.b
7 results

RedstartWindow.cpp

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    RedstartWindow.cpp 32.49 KiB
    /*
     *  --------------------------------------------------------------------------------------------
     *
     *    VVV        VVV A           Virtual Acoustics (VA) | http://www.virtualacoustics.org
     *     VVV      VVV AAA          Licensed under the Apache License, Version 2.0
     *      VVV    VVV   AAA
     *       VVV  VVV     AAA        Copyright 2015-2017
     *        VVVVVV       AAA       Institute of Technical Acoustics (ITA)
     *         VVVV         AAA      RWTH Aachen University
     *
     *  --------------------------------------------------------------------------------------------
     */
    
    #include <QErrorMessage>
    #include <QUrl>
    #include <QDesktopServices>
    #include <QHash>
    #include <QShortcut>
    #include <QFileDialog>
    
    #include "RedstartWindow.h"
    #include <ui_RedstartWindow.h>
    
    #include "RedstartRunSimpleExample.h"
    #include "RedstartSessionBinauralHeadphonesDialog.h"
    #include "RedstartSessionExperimentalTalkthroughDialog.h"
    #include "RedstartSessionImportDialog.h"
    #include "RedstartSessionWizardDialog.h"
    #include "RedstartUtils.h"
    #include "RedstartCoreOutputPlainTextEdit.h"
    #include "RedstartRunCirculatingSourceDialog.h"
    
    #include <VA.h>
    #include <VACore.h>
    #include <VANet.h>
    
    #include <ITAAsioInterface.h>
    #include <ITAPortaudioInterface.h>
    #include <ITAException.h>
    #include <ITANumericUtils.h>
    
    
    RedstartWindow::RedstartWindow( bool bFailSafeMode, bool bAutoStart, bool bSkipConfig, QWidget* pParent )
    	: QMainWindow( pParent )
    	, ui( new Ui::RedstartWindow )
    	, m_pVAInterface( NULL )
    {
    	ui->setupUi( this );
    
    	ui->statusBar->showMessage( "Welcome to VA." );
    
    	// Shortcuts
    	QShortcut* start_b = new QShortcut( this );
    	start_b->setKey( Qt::Key_F5 );
    	start_b->setContext( Qt::WindowShortcut );
    	QShortcut* start_c = new QShortcut( this );
    	start_c->setKey( QKeySequence( tr( "CTRL+R" ) ) );
    	start_c->setContext( Qt::WindowShortcut );
    
    	connect( start_b, SIGNAL( activated() ), this, SLOT( on_pushButton_start_stop_clicked() ) );
    	connect( start_c, SIGNAL( activated() ), this, SLOT( on_pushButton_start_stop_clicked() ) );
    
    	m_pVANetServer = IVANetServer::Create();
    	m_pVANetClient = IVANetClient::Create();
    
    	ui->comboBox_audio_driver->addItem( "ASIO" );
    	ui->comboBox_audio_driver->addItem( "Portaudio" );
    
    	ui->comboBox_audio_iface_sampling_rate->addItem( "44.1 kHz", AudioSamplingRate::FS_44kHz );
    	ui->comboBox_audio_iface_sampling_rate->addItem( "48 kHz", AudioSamplingRate::FS_48kHz );
    	//ui->comboBox_audio_iface_sampling_rate->addItem( "96 kHz", AudioSamplingRate::FS_96kHz );
    
    	ui->comboBox_audio_iface_buffer_size->addItem( "AUTO", AudioBufferSize::AUTO );
    
    	m_iPortaudioDefaultDevice = -1;
    
    	if( !bSkipConfig )
    		LoadConfiguration();
    
    	// Signals & slots
    	ConnectSignalsAndSlots();
    
    
    	ui->menuRun->setEnabled( false );
    
    	if( ui->checkBox_redstart_network_connect_as_client->isChecked() )
    		ui->groupBox_redstart_audio_iface->setEnabled( false );
    
    	if( ( ui->checkBox_redstart_auto_start->isChecked() || bAutoStart ) && !bFailSafeMode )
    		on_pushButton_start_stop_clicked();
    
    	m_pCirculatingSourceDialog = new RedstartRunCirculatingSourceDialog( this );
    
    }
    
    RedstartWindow::~RedstartWindow()
    {
    	StoreConfiguration();
    	if( m_pVANetServer->IsClientConnected() )
    	{
    		m_pVANetServer->Finalize();
    		delete m_pVAInterface;
    	}
    	delete m_pVANetServer;
    
    	if( m_pVANetClient->IsConnected() )
    		m_pVANetClient->Disconnect();
    	delete m_pVANetClient;
    }
    
    void RedstartWindow::ConnectSignalsAndSlots()
    {
    	// Input control
    	connect( ui->doubleSpinBox_input_gain, SIGNAL( valueChanged( double ) ), this, SLOT( CoreChangeInputSignalDecibel( double ) ) );
    	connect( this, SIGNAL( InputSignalChangedDecibel( double ) ), ui->doubleSpinBox_input_gain, SLOT( setValue( double ) ) );
    	connect( ui->dial_core_control_input_gain, SIGNAL( valueChanged( int ) ), this, SLOT( CoreChangeInputSignalDecibel( int ) ) );
    	connect( this, SIGNAL( InputSignalChangedDecibel( int ) ), ui->dial_core_control_input_gain, SLOT( setValue( int ) ) );
    	connect( this, SIGNAL( InputIsMutedChanged( bool ) ), ui->checkBox_core_control_input_mute, SLOT( setChecked( bool ) ) );
    	connect( ui->checkBox_core_control_input_mute, SIGNAL( stateChanged( int ) ), this, SLOT( CoreChangeInputIsMuted( int ) ) );
    
    	// Output control
    	connect( ui->doubleSpinBox_output_gain, SIGNAL( valueChanged( double ) ), this, SLOT( CoreChangeOutputSignalDecibel( double ) ) );
    	connect( this, SIGNAL( OutputSignalChangedDecibel( double ) ), ui->doubleSpinBox_output_gain, SLOT( setValue( double ) ) );
    	connect( ui->dial_core_control_output_gain, SIGNAL( valueChanged( int ) ), this, SLOT( CoreChangeOutputSignalDecibel( int ) ) );
    	connect( this, SIGNAL( OutputSignalChangedDecibel( int ) ), ui->dial_core_control_output_gain, SLOT( setValue( int ) ) );
    	connect( this, SIGNAL( OutputIsMutedChanged( bool ) ), ui->checkBox_core_control_output_mute, SLOT( setChecked( bool ) ) );
    	connect( ui->checkBox_core_control_output_mute, SIGNAL( stateChanged( int ) ), this, SLOT( CoreChangeOutputIsMuted( int ) ) );
    
    	//connect( &m_qRenderTimer, SIGNAL( timeout() ), this, SLOT( Render() ) );
    
    }
    
    void RedstartWindow::LoadConfiguration()
    {
    	RestoreWindowSize();
    
    	bool bValOK;
    	int iAudioBackend = m_qSettings.value( "Redstart/audio/backend_idx" ).toInt( &bValOK );
    	if( !bValOK )
    		iAudioBackend = AudioBackend::ASIO;
    	ui->comboBox_audio_driver->setCurrentIndex( iAudioBackend );
    
    	const int iBufferSizeIndex = m_qSettings.value( "Redstart/audio/buffersize_idx" ).toInt( &bValOK );
    	if( bValOK && iBufferSizeIndex < ui->comboBox_audio_iface_buffer_size->count() )
    		ui->comboBox_audio_iface_buffer_size->setCurrentIndex( iBufferSizeIndex );
    
    	const int iSamplingRateIndex = m_qSettings.value( "Redstart/audio/fs_idx" ).toInt( &bValOK );
    	if( bValOK && iSamplingRateIndex < ui->comboBox_audio_iface_sampling_rate->count() )
    		ui->comboBox_audio_iface_sampling_rate->setCurrentIndex( iSamplingRateIndex );
    
    	if( m_qSettings.contains( "Redstart/network/address" ) )
    		ui->lineEdit_redstart_network_address->setText( m_qSettings.value( "Redstart/network/address" ).toString() );
    	if( m_qSettings.contains( "Redstart/network/port" ) )
    		ui->lineEdit_redstart_network_address->setText( m_qSettings.value( "Redstart/network/port" ).toString() );
    	ui->checkBox_redstart_network_connect_as_client->setChecked( m_qSettings.value( "Redstart/network/client_mode" ).toBool() );
    
    	if( m_qSettings.contains( "Redstart/autostart" ) )
    	{
    		bool bAutostart = m_qSettings.value( "Redstart/autostart" ).toBool();
    		ui->checkBox_redstart_auto_start->setChecked( bAutostart );
    	}
    
    	m_iPortaudioDefaultDevice = m_qSettings.value( "Redstart/audio/portaudio_default_device", -1 ).toInt();
    
    	ui->checkBox_portaudio_default_device->setChecked( m_qSettings.value( "Redstart/audio/portaudio_use_default_device", true ).toBool() );
    
    	QVariantList voAudioDevices;
    	voAudioDevices = m_qSettings.value( "Redstart/audio/devicelist" ).toList();
    
    	for( const QVariant oAudioDevice : voAudioDevices )
    		m_voAudioDevices.push_back( CAudioDeviceSpecs( oAudioDevice.toHash() ) );
    
    	PopulateAudioDevices();
    
    	int iLastDevice = m_qSettings.value( "Redstart/audio/current_device", 0 ).toInt( &bValOK );
    	if( bValOK && ui->comboBox_audio_iface_device->count() >= iLastDevice )
    		ui->comboBox_audio_iface_device->setCurrentIndex( iLastDevice );
    
    	// Core control
    	ui->comboBox_core_settings_log_level->addItem( QString::fromStdString( m_pVAInterface->GetLogLevelStr( IVAInterface::VA_LOG_LEVEL_QUIET ) ) );
    	ui->comboBox_core_settings_log_level->addItem( QString::fromStdString( m_pVAInterface->GetLogLevelStr( IVAInterface::VA_LOG_LEVEL_ERROR ) ) );
    	ui->comboBox_core_settings_log_level->addItem( QString::fromStdString( m_pVAInterface->GetLogLevelStr( IVAInterface::VA_LOG_LEVEL_WARNING ) ) );
    	ui->comboBox_core_settings_log_level->addItem( QString::fromStdString( m_pVAInterface->GetLogLevelStr( IVAInterface::VA_LOG_LEVEL_INFO ) ) );
    	ui->comboBox_core_settings_log_level->addItem( QString::fromStdString( m_pVAInterface->GetLogLevelStr( IVAInterface::VA_LOG_LEVEL_VERBOSE ) ) );
    	ui->comboBox_core_settings_log_level->addItem( QString::fromStdString( m_pVAInterface->GetLogLevelStr( IVAInterface::VA_LOG_LEVEL_TRACE ) ) );
    
    	if( ui->listView_redstart_session_list->GetCurrentSessionID().isEmpty() == false )
    		ui->treeView_session_details->SetStruct( ui->listView_redstart_session_list->GetCurrentConfig() );
    }
    
    void RedstartWindow::StoreConfiguration()
    {
    	m_qSettings.setValue( "Redstart/gui/WindowGeometry", saveGeometry() );
    	m_qSettings.setValue( "Redstart/gui/WindowState", saveState() );
    
    	m_qSettings.setValue( "Redstart/audio/backend_idx", ui->comboBox_audio_driver->currentIndex() );
    
    	m_qSettings.setValue( "Redstart/audio/buffersize_idx", ui->comboBox_audio_iface_buffer_size->currentIndex() );
    	m_qSettings.setValue( "Redstart/audio/fs_idx", ui->comboBox_audio_iface_sampling_rate->currentIndex() );
    
    	m_qSettings.setValue( "Redstart/network/address", ui->lineEdit_redstart_network_address->text() );
    
    	bool bValOK;
    	int iPort = ui->lineEdit_redstart_network_address->text().toInt( &bValOK );
    	if( bValOK )
    		m_qSettings.setValue( "Redstart/network/port", iPort );
    
    	m_qSettings.setValue( "Redstart/network/client_mode", ui->checkBox_redstart_network_connect_as_client->isChecked() );
    	
    	bool bAutostart = ui->checkBox_redstart_auto_start->isChecked();
    	m_qSettings.setValue( "Redstart/autostart", bAutostart );
    
    	m_qSettings.setValue( "Redstart/audio/portaudio_default_device", m_iPortaudioDefaultDevice );
    	int iLastDevice = ui->comboBox_audio_iface_device->currentIndex();
    	m_qSettings.setValue( "Redstart/audio/current_device", iLastDevice );
    
    	m_qSettings.setValue( "Redstart/audio/portaudio_use_default_device", ui->checkBox_portaudio_default_device->isChecked() );
    
    	QVariantList voAudioDevices;
    	for( const CAudioDeviceSpecs& oDevice : m_voAudioDevices )
    		voAudioDevices.push_back( oDevice.asHash() );
    
    	m_qSettings.setValue( "Redstart/audio/devicelist", voAudioDevices );
    }
    
    void RedstartWindow::on_actionQuit_triggered()
    {
    	close();
    }
    
    void RedstartWindow::PostCoreStart()
    {
    	ui->pushButton_start_stop->setText( "Stop" );
    
    	// Switch UI elements enabled
    	ui->groupBox_redstart_audio_iface->setEnabled( false );
    	ui->groupBox_redstart_network->setEnabled( false );
    	ui->groupBox_session_list->setEnabled( false );
    	ui->groupBox_session_details->setEnabled( false );
    	ui->groupBox_core->setEnabled( true );
    	ui->groupBox_paths->setEnabled( true );
    	ui->groupBox_macros->setEnabled( true );
    	ui->menuRun->setEnabled( true );
    	ui->groupBox_core_control->setEnabled( true );
    	ui->graphicsView_input_levels->setEnabled( true );
    	ui->graphicsView_output_levels->setEnabled( true );
    	ui->groupBox_global_am->setEnabled( true );
    	ui->groupBox_output->setEnabled( true );
    
    	CVAVersionInfo oVersion;
    	m_pVAInterface->GetVersionInfo( &oVersion );
    	ui->lineEdit_core_settings_version->setText( QString::fromStdString( oVersion.ToString() ) );
    
    	CVAStruct oArgs;
    	oArgs[ "getloglevel" ] = true;
    	const CVAStruct oReturn = m_pVAInterface->CallModule( "VACore", oArgs );
    	const int iCurrentLogLevel = oReturn[ "loglevel" ];
    	ui->comboBox_core_settings_log_level->setCurrentIndex( iCurrentLogLevel );
    
    	CVAStruct oSearchPaths = m_pVAInterface->GetSearchPaths();
    	QStringList sPathList;
    	CVAStruct::const_iterator cit = oSearchPaths.Begin();
    	while( cit != oSearchPaths.End() )
    	{
    		const CVAStructValue& oValue( cit++->second );
    		if( oValue.IsString() )
    			sPathList << std::string( oValue ).c_str();
    	}
    	ui->listView_paths; // @todo
    }
    
    void RedstartWindow::PostCoreStop()
    {
    	ui->pushButton_start_stop->setText( "Start" );
    
    	// Switch UI elements enabled
    	ui->groupBox_redstart_audio_iface->setEnabled( true );
    	ui->groupBox_redstart_network->setEnabled( true );
    	ui->groupBox_session_list->setEnabled( true );
    	ui->groupBox_session_details->setEnabled( true );
    	ui->groupBox_core->setEnabled( false );
    	ui->groupBox_paths->setEnabled( false );
    	ui->groupBox_macros->setEnabled( false );
    	ui->menuRun->setEnabled( false );
    	ui->groupBox_core_control->setEnabled( false );
    	ui->graphicsView_input_levels->setEnabled( false );
    	ui->graphicsView_output_levels->setEnabled( false );
    	ui->groupBox_global_am->setEnabled( false );
    	ui->groupBox_output->setEnabled( false );
    
    
    	// Clear
    	ui->lineEdit_core_settings_version->clear();
    	ui->listView_paths->reset();
    
    	// Reset elements
    	bool bPreserveCoreControlValues = m_qSettings.value( "PreserveCoreControlValues", true ).toBool(); // @todo control this setting via preferences dialog
    	if( !bPreserveCoreControlValues )
    	{
    		emit InputSignalChangedDecibel( 0.0f );
    		emit OutputSignalChangedDecibel( 0.0f );
    		emit InputIsMutedChanged( false );
    		emit OutputIsMutedChanged( false );
    	}
    }
    
    void RedstartWindow::RestoreWindowSize()
    {
    	restoreGeometry( m_qSettings.value( "Redstart/gui/WindowGeometry" ).toByteArray() );
    	restoreState( m_qSettings.value( "Redstart/gui/WindowState" ).toByteArray() );
    }
    
    void RedstartWindow::HandleVAEvent( const CVAEvent* pEvent )
    {
    	// Handle pushable events
    	switch( pEvent->iEventType )
    	{
    	case CVAEvent::VA_EVENT_PROGRESS_UPDATE:
    		//ui->statusBar->showMessage( pEvent->sParam.c_str() );
    		break;
    	case CVAEvent::VA_EVENT_MEASURES_UPDATE:
    		UpdateMeasures( pEvent->vfInputRMSs, pEvent->vfInputPeaks, pEvent->vfOutputRMSs, pEvent->vfOutputPeaks );
    		break;
    	}
    
    	/* Don't handle events that have been triggered from this interface connection
    	if( pEvent->pSender == m_pVAInterface )
    	return;
    	*/
    
    	switch( pEvent->iEventType )
    	{
    	case CVAEvent::VA_EVENT_INPUT_GAIN_CHANGED:
    		emit InputSignalChangedDecibel( ratio_to_db20( pEvent->dVolume ) );
    		break;
    	case CVAEvent::VA_EVENT_OUTPUT_GAIN_CHANGED:
    		emit OutputSignalChangedDecibel( ratio_to_db20( pEvent->dVolume ) );
    		break;
    	case CVAEvent::VA_EVENT_INPUT_MUTING_CHANGED:
    		emit InputIsMutedChanged( pEvent->bMuted );
    		break;
    	case CVAEvent::VA_EVENT_OUTPUT_MUTING_CHANGED:
    		emit OutputIsMutedChanged( pEvent->bMuted );
    		break;
    	}
    }
    
    void RedstartWindow::UpdateMeasures( const std::vector< float >& vfInputRMSs, const std::vector< float >& vfInputPeaks, const std::vector< float >& vfOutputRMSs, const std::vector< float >& vfOutputPeaks )
    {
    	// @todo feed level meters 
    }
    
    void RedstartWindow::AcquireAsioDevices()
    {
    	std::vector< CAudioDeviceSpecs > voAudioDevices = m_voAudioDevices;
    
    	try
    	{
    		ITAsioInitializeLibrary();
    
    		long lDrivers = ITAsioGetNumDrivers();
    		if( lDrivers <= 0 )
    			ITA_EXCEPT1( INVALID_PARAMETER, "No ASIO-compatibel drivers could be found on this system." );
    
    		m_voAudioDevices.clear();
    
    		for( long i = 0; i < lDrivers; i++ )
    		{
    			CAudioDeviceSpecs oDeviceSpecs;
    			oDeviceSpecs.iDriverNumber = i;
    			oDeviceSpecs.iBackend = AudioBackend::ASIO;
    			oDeviceSpecs.sName = ITAsioGetDriverName( i );
    
    			try
    			{
    				ITAsioInitializeDriver( i );
    
    				long in = 0;
    				long out = 0;
    				ITAsioGetChannels( &in, &out );
    				oDeviceSpecs.iNumInputChannels = int( in );
    				oDeviceSpecs.iNumOutputChannels = int( out );
    
    				ITAsioFinalizeDriver();
    
    				oDeviceSpecs.bInitializable = true;
    
    			}
    			catch( const ITAException& )
    			{
    				oDeviceSpecs.bInitializable = false;
    				continue;
    			}
    
    			if( oDeviceSpecs.bInitializable )
    				m_voAudioDevices.push_back( oDeviceSpecs );
    		}
    
    		ITAsioFinalizeLibrary();
    	}
    	catch( const ITAException& e )
    	{
    		QString sErrorMessage = QString( "Error during ASIO device acquisition: %1" ).arg( QString::fromStdString( e.ToString() ) );
    		QErrorMessage oErrMsg;
    		oErrMsg.showMessage( sErrorMessage );
    		oErrMsg.exec();
    	}
    
    	for( const CAudioDeviceSpecs oDevice : voAudioDevices )
    		if( oDevice.iBackend != AudioBackend::ASIO )
    			m_voAudioDevices.push_back( oDevice );
    }
    
    void RedstartWindow::PopulateAudioDevices()
    {
    	ui->comboBox_audio_iface_device->clear();
    	int iCurrentBackend = ui->comboBox_audio_driver->currentIndex();
    	for( const CAudioDeviceSpecs& oDevice : m_voAudioDevices )
    	{
    		if( oDevice.iBackend == iCurrentBackend )
    			ui->comboBox_audio_iface_device->addItem( oDevice.sName, QVariant( oDevice.iDriverNumber ) );
    	}
    
    	if( ui->comboBox_audio_driver->currentIndex() == AudioBackend::PORTAUDIO )
    	{
    		ui->checkBox_portaudio_default_device->setEnabled( true );
    		if( ui->checkBox_portaudio_default_device->isChecked() )
    			ui->comboBox_audio_iface_device->setEnabled( false );
    		else
    			ui->comboBox_audio_iface_device->setEnabled( true );
    	}
    	else
    	{
    		ui->checkBox_portaudio_default_device->setEnabled( false );
    		ui->comboBox_audio_iface_device->setEnabled( true );
    	}
    }
    
    void RedstartWindow::AcquirePortaudioDevices()
    {
    	std::vector< CAudioDeviceSpecs > voAudioDevices = m_voAudioDevices;
    
    	try
    	{
    		ITAPortaudioInterface oPortaudio( 44100, 1024 );
    		oPortaudio.Initialize();
    		int lDrivers = oPortaudio.GetNumDevices();
    
    		if( lDrivers <= 0 )
    			ITA_EXCEPT1( INVALID_PARAMETER, "No Portaudio output devices could be found on this system." );
    
    		m_iPortaudioDefaultDevice = oPortaudio.GetDefaultOutputDevice();
    
    		m_voAudioDevices.clear();
    
    		for( long i = 0; i < lDrivers; i++ )
    		{
    			CAudioDeviceSpecs oDeviceSpecs;
    			oDeviceSpecs.iDriverNumber = i;
    			oDeviceSpecs.iBackend = AudioBackend::PORTAUDIO;
    			oDeviceSpecs.sName = oPortaudio.GetDeviceName( i ).c_str();
    
    			try
    			{
    				oPortaudio.GetNumChannels( i, oDeviceSpecs.iNumInputChannels, oDeviceSpecs.iNumOutputChannels );
    
    				oDeviceSpecs.bInitializable = true; // only a guess
    
    				if( i == oPortaudio.GetDefaultOutputDevice() )
    					oDeviceSpecs.bDefaultDevice = true;
    				else
    					oDeviceSpecs.bDefaultDevice = false;
    
    			}
    			catch( const ITAException& )
    			{
    				oDeviceSpecs.bInitializable = false;
    				continue;
    			}
    
    			if( oDeviceSpecs.bInitializable )
    				m_voAudioDevices.push_back( oDeviceSpecs );
    		}
    
    		oPortaudio.Finalize();
    	}
    	catch( const ITAException& e )
    	{
    		QString sErrorMessage = QString( "Error during Portaudio device acquisition: %1" ).arg( QString::fromStdString( e.ToString() ) );
    		QErrorMessage oErrMsg;
    		oErrMsg.showMessage( sErrorMessage );
    		oErrMsg.exec();
    	}
    
    	for( const CAudioDeviceSpecs oDevice : voAudioDevices )
    		if( oDevice.iBackend != AudioBackend::ASIO )
    			m_voAudioDevices.push_back( oDevice );
    }
    
    void RedstartWindow::on_pushButton_start_stop_clicked()
    {
    	try
    	{
    		if( !ui->checkBox_redstart_network_connect_as_client->isChecked() )
    		{
    			if( m_pVAInterface )
    			{
    				m_pVANetServer->Finalize();
    
    				if( m_pVAInterface->GetState() == IVAInterface::VA_CORESTATE_READY )
    					m_pVAInterface->Finalize();
    
    				delete m_pVAInterface;
    				m_pVAInterface = nullptr;
    
    				ui->statusBar->showMessage( "VA core has been stopped." );
    				PostCoreStop();
    			}
    			else
    			{
    				CVAStruct oVAConfigArgs = ui->listView_redstart_session_list->GetCurrentConfig();
    
    				// Override configs
    				std::string sBackend, sDevice;
    				switch( ui->comboBox_audio_driver->currentIndex() )
    				{
    				case AudioBackend::ASIO:
    				{
    					sBackend = "ASIO";
    					sDevice = ui->comboBox_audio_iface_device->currentText().toStdString();
    					break;
    				}
    				case AudioBackend::PORTAUDIO:
    				default:
    				{
    					sBackend = "Portaudio";
    					if( ui->checkBox_portaudio_default_device->isChecked() )
    						sDevice = "default";
    					else
    						sDevice = ui->comboBox_audio_iface_device->currentIndex();
    				}
    				}
    
    				oVAConfigArgs[ "Audio driver" ] = CVAStruct();
    				oVAConfigArgs[ "Audio driver" ][ "Driver" ] = sBackend;
    				oVAConfigArgs[ "Audio driver" ][ "Device" ] = sDevice;
    
    				if( !oVAConfigArgs.HasKey( "Paths" ) )
    					oVAConfigArgs[ "Paths" ] = CVAStruct();
    				oVAConfigArgs[ "Paths" ][ "redstart_data" ] = "data";
    				oVAConfigArgs[ "Paths" ][ "redstart_data_dev" ] = "../VACore/data";
    
    				m_pVAInterface = VACore::CreateCoreInstance( oVAConfigArgs );
    				m_pVAInterface->SetOutputStream( ui->plainTextEdit_core_output->GetOutputStream() );
    
    				m_pVAInterface->Initialize();
    				m_pVAInterface->AttachEventHandler( this );
    				m_pVANetServer->SetCoreInstance( m_pVAInterface );
    
    				bool bOK;
    				int iPort = ui->lineEdit_redstart_network_port->text().toInt( &bOK );
    				int iStatus = -1;
    				if( bOK )
    					iStatus = m_pVANetServer->Initialize( ui->lineEdit_redstart_network_address->text().toStdString(), iPort );
    				else
    					iStatus = m_pVANetServer->Initialize( ui->lineEdit_redstart_network_address->text().toStdString() );
    
    				if( m_pVAInterface->GetState() == IVAInterface::VA_CORESTATE_READY && iStatus == IVANetServer::VA_NO_ERROR )
    				{
    					ui->statusBar->showMessage( "VA core successfully initialized and network server started. Running session " + ui->listView_redstart_session_list->GetCurrentSessionID() + "." );
    
    					PostCoreStart();
    				}
    				else
    				{
    					ui->statusBar->showMessage( "VA core initialization failed." );
    					m_pVANetServer->Finalize();
    
    					delete m_pVAInterface;
    					m_pVAInterface = NULL;
    				}
    			}
    		}
    		else
    		{
    			// Client mode
    			if( m_pVANetClient->IsConnected() )
    				m_pVANetClient->Disconnect();
    
    			bool bOK;
    			int iPort = ui->lineEdit_redstart_network_port->text().toInt( &bOK );
    			int iStatus = -1;
    			if( bOK )
    				iStatus = m_pVANetClient->Initialize( ui->lineEdit_redstart_network_address->text().toStdString(), iPort );
    			else
    				iStatus = m_pVANetClient->Initialize( ui->lineEdit_redstart_network_address->text().toStdString() );
    
    			if( iStatus != IVANetClient::VA_NO_ERROR )
    			{
    				VA_EXCEPT2( INVALID_PARAMETER, "Could not initialize client, connection failed." );
    			}
    
    			m_pVAInterface = m_pVANetClient->GetCoreInstance();
    
    			// @todo attach network event handler to detect server connection loss or abortion
    			//m_pVANetClient->AttachEventHandler( this );
    		}
    	}
    	catch( const CVAException& ex )
    	{
    
    		if( m_pVAInterface )
    		{
    			delete m_pVAInterface;
    			m_pVAInterface = NULL;
    		}
    
    		ui->statusBar->showMessage( QString::fromStdString( ex.ToString() ) );
    		ui->checkBox_redstart_auto_start->setChecked( false );
    	}
    }
    
    void RedstartWindow::on_pushButton_refresh_clicked()
    {
    	const int iAudioBackend = ui->comboBox_audio_driver->currentIndex();
    	if( iAudioBackend == AudioBackend::PORTAUDIO )
    	{
    		AcquirePortaudioDevices();
    	}
    	else
    	{
    		AcquireAsioDevices();
    	}
    
    	PopulateAudioDevices();
    }
    
    void RedstartWindow::on_comboBox_audio_driver_currentIndexChanged( int )
    {
    	PopulateAudioDevices();
    }
    
    void RedstartWindow::on_comboBox_audio_iface_device_currentIndexChanged( int )
    {
    
    }
    
    void RedstartWindow::on_actionWebsite_triggered()
    {
    	QUrl urlVAWebsite( "http://www.virtualacoustics.org/work" );
    	QDesktopServices::openUrl( urlVAWebsite );
    }
    
    void RedstartWindow::on_actionGet_started_triggered()
    {
    	QUrl urlVAWebsiteGetStarted( "http://www.virtualacoustics.org/work/start.html" );
    	QDesktopServices::openUrl( urlVAWebsiteGetStarted );
    }
    
    void RedstartWindow::on_actionDocumentation_triggered()
    {
    	QUrl urlVAWebsiteDocumentation( "http://www.virtualacoustics.org/work/documentation.html" );
    	QDesktopServices::openUrl( urlVAWebsiteDocumentation );
    }
    
    void RedstartWindow::on_actionGet_help_triggered()
    {
    	QUrl urlVAWebsiteGetHelp( "http://www.virtualacoustics.org/work/help.html" );
    	QDesktopServices::openUrl( urlVAWebsiteGetHelp );
    }
    
    void RedstartWindow::on_checkBox_redstart_network_connect_as_client_clicked()
    {
    	if( ui->checkBox_redstart_network_connect_as_client->isChecked() )
    		ui->groupBox_redstart_audio_iface->setEnabled( false );
    	else
    		ui->groupBox_redstart_audio_iface->setEnabled( true );
    }
    
    void RedstartWindow::on_checkBox_portaudio_default_device_clicked()
    {
    	if( ui->checkBox_portaudio_default_device->isChecked() )
    	{
    		ui->comboBox_audio_iface_device->setEnabled( false );
    		if( ui->comboBox_audio_iface_device->count() >= m_iPortaudioDefaultDevice )
    			ui->comboBox_audio_iface_device->setCurrentIndex( m_iPortaudioDefaultDevice );
    	}
    	else
    		ui->comboBox_audio_iface_device->setEnabled( true );
    }
    
    void RedstartWindow::on_listView_redstart_session_list_clicked( const QModelIndex &index )
    {
    	if( ui->listView_redstart_session_list->model()->data( index ).isValid() )
    	{
    		std::string sSessionName = ui->listView_redstart_session_list->model()->data( index ).toString().toStdString();
    		CVAStruct oStruct = ui->listView_redstart_session_list->GetCurrentConfig();
    		ui->treeView_session_details->SetStruct( oStruct );
    	}
    }
    
    void RedstartWindow::on_actionBinauralHeadphones_triggered()
    {
    	RedstartSessionBinauralHeadphonesDialog d( this );
    	if( d.exec() )
    	{
    		// Enforce unique session id if id is already existing
    		QString sNewID = d.GetSessionName();
    		while( ui->listView_redstart_session_list->SessionNameExists( sNewID ) )
    			sNewID += "_new";
    		ui->listView_redstart_session_list->AddSession( sNewID, d.GetCoreConfig() ); // In any case save the session so no data is lost
    
    		CVAStruct oStruct = ui->listView_redstart_session_list->GetCurrentConfig();
    		ui->treeView_session_details->SetStruct( oStruct );
    	}
    }
    
    void RedstartWindow::on_actionImport_session_triggered()
    {
    	RedstartSessionImportDialog d( this );
    	if( d.exec() )
    	{
    		try
    		{
    			// Enforce unique session id if id is already existing
    			QString sNewID = d.GetSessionName();
    			while( ui->listView_redstart_session_list->SessionNameExists( sNewID ) )
    				sNewID += "_new";
    			ui->listView_redstart_session_list->AddSession( sNewID, d.GetCoreConfig() ); // In any case save the session so no data is lost
    			CVAStruct oStruct = ui->listView_redstart_session_list->GetCurrentConfig();
    			ui->treeView_session_details->SetStruct( oStruct );
    
    		}
    		catch( CVAException& e )
    		{
    			QString sErrorMessage = QString( "Could not run simple example scene: %1" ).arg( QString::fromStdString( e.ToString() ) );
    			QErrorMessage oErrMsg;
    			oErrMsg.showMessage( sErrorMessage );
    			oErrMsg.exec();
    		}
    	}
    }
    
    void RedstartWindow::on_actionDefault_experimental_session_triggered()
    {
    	RedstartSessionExperimentalTalkthroughDialog d( this );
    	if( d.exec() )
    	{
    		// Enforce unique session id if id is already existing
    		QString sNewID = d.GetSessionName();
    		while( ui->listView_redstart_session_list->SessionNameExists( sNewID ) )
    			sNewID += "_new";
    		ui->listView_redstart_session_list->AddSession( sNewID, d.GetCoreConfig() ); // In any case save the session so no data is lost
    
    		CVAStruct oStruct = ui->listView_redstart_session_list->GetCurrentConfig();
    		ui->treeView_session_details->SetStruct( oStruct );
    	}
    }
    
    void RedstartWindow::on_actionCirculating_source_triggered()
    {
    	if( !m_pVAInterface )
    		return;
    
    	m_pCirculatingSourceDialog->SetVAInterface( m_pVAInterface );
    	m_pCirculatingSourceDialog->exec();
    	m_pCirculatingSourceDialog->hide();
    }
    
    void RedstartWindow::on_actionAmbisonics_triggered()
    {
    
    }
    
    void RedstartWindow::on_actionExport_to_file_triggered()
    {
    	QFileDialog fd;
    	fd.setNameFilters( QStringList() << "INI files (*.ini)" << "Any file (*.*)" );
    	fd.setViewMode( QFileDialog::Detail );
    	fd.setAcceptMode( QFileDialog::AcceptSave );
    
    	QDir oLastDir( m_qSettings.value( "Redstart/last_browse_folder" ).toString() );
    	if( oLastDir.exists() )
    		fd.setDirectory( oLastDir );
    	else
    		fd.setDirectory( QDir( QApplication::applicationDirPath() ) );
    
    	QString sFileName = ui->listView_redstart_session_list->GetCurrentSessionID();
    	if( sFileName.isEmpty() == false )
    		fd.selectFile( sFileName + ".ini" );
    
    	if( fd.exec() )
    	{
    		QStringList lFiles = fd.selectedFiles();
    		if( lFiles.empty() == false )
    		{
    			QString sFilePath = lFiles[ 0 ];
    			QFileInfo oFile( sFilePath );
    			if( fd.directory().exists() )
    				m_qSettings.setValue( "Redstart/last_browse_folder", oFile.absolutePath() );
    
    			try
    			{
    				CVAStruct oConfig = ui->listView_redstart_session_list->GetCurrentConfig();
    				VACore::StoreCoreConfigToFile( oConfig, sFilePath.toStdString() );
    			}
    			catch( CVAException& e )
    			{
    				QString sErrorMessage = QString( "Could not export session configuration: %1" ).arg( QString::fromStdString( e.ToString() ) );
    				QErrorMessage oErrMsg;
    				oErrMsg.showMessage( sErrorMessage );
    				oErrMsg.exec();
    			}
    		}
    	}
    }
    
    void RedstartWindow::on_actionRemove_triggered()
    {
    	ui->listView_redstart_session_list->RemoveCurrentSession();
    
    	CVAStruct oStruct;
    	if( !ui->listView_redstart_session_list->GetCurrentSessionID().isEmpty() )
    		oStruct = ui->listView_redstart_session_list->GetCurrentConfig();
    
    	ui->treeView_session_details->SetStruct( oStruct );
    }
    
    void RedstartWindow::on_actionEdit_session_triggered()
    {
    	RedstartSessionWizardDialog d( this );
    
    	QString sCurrentSessionID = ui->listView_redstart_session_list->GetCurrentSessionID();
    	CVAStruct oCurrentConfig;
    	if( sCurrentSessionID.isEmpty() )
    		return;
    
    	oCurrentConfig = ui->listView_redstart_session_list->GetCurrentConfig();
    	d.SetSession( sCurrentSessionID, ConvertVAStructToQHash( oCurrentConfig ) );
    
    	if( d.exec() )
    	{
    		bool bEnforceDuplicate = true;
    		if( sCurrentSessionID != d.GetSessionName() && !ui->listView_redstart_session_list->SessionNameExists( d.GetSessionName() ) )
    		{
    			ui->listView_redstart_session_list->RenameSession( sCurrentSessionID, d.GetSessionName() );
    			bEnforceDuplicate = false;
    		}
    
    		QVariantHash oNewConfig = d.GetCoreConfig();
    		if( d.GetDuplicationRequested() || bEnforceDuplicate )
    		{
    			// Enforce unique session id if duplicate requested or session should be renamed to an already existing session
    			QString sNewID = d.GetSessionName();
    			while( ui->listView_redstart_session_list->SessionNameExists( sNewID ) )
    				sNewID += "_copy";
    
    			ui->listView_redstart_session_list->AddSession( sNewID, oNewConfig );
    		}
    		else
    		{
    			ui->listView_redstart_session_list->UpdateSession( d.GetSessionName(), oNewConfig );
    		}
    
    		ui->treeView_session_details->SetStruct( ConvertQHashToVAStruct( oNewConfig ) );
    	}
    }
    
    void RedstartWindow::on_actionSession_wizard_triggered()
    {
    	RedstartSessionWizardDialog d( this );
    
    	d.SetDuplicationOptionDeactivated();
    
    	if( d.exec() )
    	{
    		QVariantHash oNewConfig = d.GetCoreConfig();
    		if( ui->listView_redstart_session_list->SessionNameExists( d.GetSessionName() ) )
    		{
    			// Enforce unique session id if id is already existing
    			QString sNewID = d.GetSessionName();
    			while( ui->listView_redstart_session_list->SessionNameExists( sNewID ) )
    				sNewID += "_new";
    			ui->listView_redstart_session_list->AddSession( sNewID, oNewConfig ); // In any case save the session so no data is lost
    		}
    		else
    		{
    			ui->listView_redstart_session_list->AddSession( d.GetSessionName(), oNewConfig );
    		}
    
    		ui->treeView_session_details->SetStruct( ConvertQHashToVAStruct( oNewConfig ) );
    	}
    }
    
    void RedstartWindow::on_actionDuplicate_current_session_triggered()
    {
    	RedstartSessionWizardDialog d( this );
    
    	QString sCurrentSessionID = ui->listView_redstart_session_list->GetCurrentSessionID();
    	CVAStruct oCurrentConfig;
    	if( sCurrentSessionID.isEmpty() )
    		return;
    
    	oCurrentConfig = ui->listView_redstart_session_list->GetCurrentConfig();
    	d.SetSession( sCurrentSessionID, ConvertVAStructToQHash( oCurrentConfig ) );
    
    	d.SetDuplicationOptionActivated();
    
    	if( d.exec() )
    	{
    		QVariantHash oNewConfig = d.GetCoreConfig();
    		if( ui->listView_redstart_session_list->SessionNameExists( d.GetSessionName() ) )
    		{
    			// Enforce unique session id if id is already existing
    			QString sNewID = d.GetSessionName();
    			while( ui->listView_redstart_session_list->SessionNameExists( sNewID ) )
    				sNewID += "_copy";
    			ui->listView_redstart_session_list->AddSession( sNewID, oNewConfig ); // In any case save the session so no data is lost
    		}
    		else
    		{
    			ui->listView_redstart_session_list->AddSession( d.GetSessionName(), oNewConfig );
    		}
    
    		ui->treeView_session_details->SetStruct( ConvertQHashToVAStruct( oNewConfig ) );
    	}
    }
    
    void RedstartWindow::CoreChangeInputSignalDecibel( int iLevelDB )
    {
    	emit InputSignalChangedDecibel( iLevelDB );
    	emit InputSignalChangedDecibel( ( double ) iLevelDB );
    }
    
    void RedstartWindow::CoreChangeInputSignalDecibel( double dLevelDB )
    {
    	emit InputSignalChangedDecibel( dLevelDB );
    	emit InputSignalChangedDecibel( ( int ) dLevelDB );
    
    	if( m_pVAInterface )
    	{
    		const double dGain = db20_to_ratio( dLevelDB );
    		m_pVAInterface->SetInputGain( dGain );
    	}
    }
    
    void RedstartWindow::CoreChangeInputIsMuted( int iMuted )
    {
    	emit InputIsMutedChanged( ( bool ) iMuted );
    
    	if( m_pVAInterface )
    		m_pVAInterface->SetInputMuted( ( bool ) iMuted );
    }
    
    void RedstartWindow::CoreChangeOutputSignalDecibel( int iLevelDB )
    {
    	emit OutputSignalChangedDecibel( iLevelDB );
    	emit OutputSignalChangedDecibel( ( double ) iLevelDB );
    }
    
    void RedstartWindow::CoreChangeOutputSignalDecibel( double dLevelDB )
    {
    	emit OutputSignalChangedDecibel( dLevelDB );
    	emit OutputSignalChangedDecibel( ( int ) dLevelDB );
    
    	if( m_pVAInterface )
    	{
    		const double dGain = db20_to_ratio( dLevelDB );
    		m_pVAInterface->SetOutputGain( dGain );
    	}
    }
    
    void RedstartWindow::CoreChangeOutputIsMuted( int iMuted )
    {
    	emit OutputIsMutedChanged( ( bool ) iMuted );
    
    	if( m_pVAInterface )
    		m_pVAInterface->SetOutputMuted( ( bool ) iMuted );
    }
    
    
    void RedstartWindow::on_actionRunSimpleExample_triggered()
    {
    	try
    	{
    		if( !m_pVAInterface )
    			VA_EXCEPT2( INVALID_PARAMETER, "No VA interface available. Please start a session, first." );
    
    		RunSimpleExample( m_pVAInterface );
    	}
    	catch( CVAException& e )
    	{
    		QString sErrorMessage = QString( "Could not run simple example scene: %1" ).arg( QString::fromStdString( e.ToString() ) );
    		QErrorMessage oErrMsg;
    		oErrMsg.showMessage( sErrorMessage );
    		oErrMsg.exec();
    	}
    }
    void RedstartWindow::on_pushButton_core_control_reset_clicked()
    {
    	if( m_pVAInterface )
    		m_pVAInterface->Reset();
    }