VACore.cpp 12.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 *  --------------------------------------------------------------------------------------------
 *
 *    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
 *
 *  --------------------------------------------------------------------------------------------
 */

14
#include <VAInterface.h>
Jonas Stienen's avatar
Jonas Stienen committed
15

16
#include <VAVersion.h>
Jonas Stienen's avatar
Jonas Stienen committed
17 18 19 20 21 22 23 24 25
#include <VAException.h>
#include <VAStruct.h>

#include <algorithm>
#include <iomanip>
#include <sstream>

const double DECIBEL_MINUS_INFINITY = -1.5E-308;

26
#define VACORE_REGISTER_LITERAL(L) push_back( CVAIntLiteral( "VACore", #L, IVAInterface::L ) )
Jonas Stienen's avatar
Jonas Stienen committed
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

class CVALiteralsTable : public std::vector<CVAIntLiteral>
{
public:
	CVALiteralsTable()
	{
		// Make shure that you always keep this list consistent
		// Lua, Matlab, etc. take their definitions from here.

		VACORE_REGISTER_LITERAL( VA_CORESTATE_CREATED );
		VACORE_REGISTER_LITERAL( VA_CORESTATE_READY );
		VACORE_REGISTER_LITERAL( VA_CORESTATE_FAIL );

		VACORE_REGISTER_LITERAL( VA_PLAYBACK_STATE_PAUSED );
		VACORE_REGISTER_LITERAL( VA_PLAYBACK_STATE_PLAYING );
		VACORE_REGISTER_LITERAL( VA_PLAYBACK_STATE_STOPPED );
43

Jonas Stienen's avatar
Jonas Stienen committed
44 45 46 47 48 49 50 51 52
		VACORE_REGISTER_LITERAL( VA_PLAYBACK_ACTION_NONE );
		VACORE_REGISTER_LITERAL( VA_PLAYBACK_ACTION_STOP );
		VACORE_REGISTER_LITERAL( VA_PLAYBACK_ACTION_PLAY );
		VACORE_REGISTER_LITERAL( VA_PLAYBACK_ACTION_PAUSE );

		VACORE_REGISTER_LITERAL( VA_AURAMODE_NOTHING );
		VACORE_REGISTER_LITERAL( VA_AURAMODE_DIRECT_SOUND );
		VACORE_REGISTER_LITERAL( VA_AURAMODE_EARLY_REFLECTIONS );
		VACORE_REGISTER_LITERAL( VA_AURAMODE_DIFFUSE_DECAY );
53 54
		VACORE_REGISTER_LITERAL( VA_AURAMODE_SOURCE_DIRECTIVITY );
		VACORE_REGISTER_LITERAL( VA_AURAMODE_MEDIUM_ABSORPTION );
Jonas Stienen's avatar
Jonas Stienen committed
55 56 57 58 59
		VACORE_REGISTER_LITERAL( VA_AURAMODE_SCATTERING );
		VACORE_REGISTER_LITERAL( VA_AURAMODE_DIFFRACTION );
		VACORE_REGISTER_LITERAL( VA_AURAMODE_NEARFIELD );
		VACORE_REGISTER_LITERAL( VA_AURAMODE_DOPPLER );
		VACORE_REGISTER_LITERAL( VA_AURAMODE_SPREADING_LOSS );
60
		VACORE_REGISTER_LITERAL( VA_AURAMODE_TRANSMISSION );		
Jonas Stienen's avatar
Jonas Stienen committed
61 62 63 64 65 66 67 68
		VACORE_REGISTER_LITERAL( VA_AURAMODE_DEFAULT );
		VACORE_REGISTER_LITERAL( VA_AURAMODE_ALL );
	};
};

#undef VACORE_REGISTER_LITERAL

// Global literals table
69
CVALiteralsTable g_oVALiterals;
Jonas Stienen's avatar
Jonas Stienen committed
70

71
IVAInterface::IVAInterface() {}
Jonas Stienen's avatar
Jonas Stienen committed
72

73
IVAInterface::~IVAInterface() {}
Jonas Stienen's avatar
Jonas Stienen committed
74

75
bool IVAInterface::AddSearchPath( const std::string& sPath )
Jonas Stienen's avatar
Jonas Stienen committed
76
{
77 78 79 80
	CVAStruct oArg;
	oArg[ "addsearchpath" ] = sPath;
	CVAStruct oRet = CallModule( "VACore", oArg );
	const bool bPathFound = oRet[ "pathvalid" ];
Jonas Stienen's avatar
Jonas Stienen committed
81 82 83
	return bPathFound;
}

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
84
/* moved to base
85
bool IVAInterface::IsValidAuralizationMode( const int iAuralizationMode )
Jonas Stienen's avatar
Jonas Stienen committed
86 87 88 89
{
	return ( iAuralizationMode >= 0 ) && ( iAuralizationMode <= 2047 );
}

90
bool IVAInterface::IsValidVolume( const double dVolume )
91 92
{
	return ( dVolume >= 0 );
Jonas Stienen's avatar
Jonas Stienen committed
93 94
}

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
95
bool IVAInterface::GetBufferSignalSourcePlaybackActionValid( const int iAction )
Jonas Stienen's avatar
Jonas Stienen committed
96
{
97
	if( iAction == IVAInterface::VA_PLAYBACK_ACTION_PAUSE )
Jonas Stienen's avatar
Jonas Stienen committed
98
		return true;
99
	if( iAction == IVAInterface::VA_PLAYBACK_ACTION_PLAY )
Jonas Stienen's avatar
Jonas Stienen committed
100
		return true;
101
	if( iAction == IVAInterface::VA_PLAYBACK_ACTION_STOP )
Jonas Stienen's avatar
Jonas Stienen committed
102
		return true;
103

Jonas Stienen's avatar
Jonas Stienen committed
104 105
	return false;
}
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
106
*/
Jonas Stienen's avatar
Jonas Stienen committed
107

108
std::string IVAInterface::GetLogLevelStr( const int iLogLevel )
Jonas Stienen's avatar
Jonas Stienen committed
109
{
110 111 112 113 114 115
	if( iLogLevel == IVAInterface::VA_LOG_LEVEL_QUIET ) return "QUIET";
	if( iLogLevel == IVAInterface::VA_LOG_LEVEL_ERROR ) return "ERRORS";
	if( iLogLevel == IVAInterface::VA_LOG_LEVEL_WARNING ) return "WARNINGS";
	if( iLogLevel == IVAInterface::VA_LOG_LEVEL_INFO ) return "INFOS";
	if( iLogLevel == IVAInterface::VA_LOG_LEVEL_VERBOSE ) return "VERBOSE";
	if( iLogLevel == IVAInterface::VA_LOG_LEVEL_TRACE ) return "TRACE";
Jonas Stienen's avatar
Jonas Stienen committed
116 117 118
	return "UNDEFINED";
}

Jonas Stienen's avatar
Jonas Stienen committed
119
// Parses a token of an auralization mode part (must be uppercase, used below)
Jonas Stienen's avatar
Jonas Stienen committed
120 121
int ParseAuralizationModeToken( const std::string& t )
{
122 123 124 125 126 127 128 129 130 131 132 133 134
	if( t == "DS" ) return IVAInterface::VA_AURAMODE_DIRECT_SOUND;
	if( t == "ER" ) return IVAInterface::VA_AURAMODE_EARLY_REFLECTIONS;
	if( t == "DD" ) return IVAInterface::VA_AURAMODE_DIFFUSE_DECAY;
	if( t == "SD" ) return IVAInterface::VA_AURAMODE_SOURCE_DIRECTIVITY;
	if( t == "MA" ) return IVAInterface::VA_AURAMODE_MEDIUM_ABSORPTION;
	if( t == "TV" ) return IVAInterface::VA_AURAMODE_TEMP_VAR;
	if( t == "SC" ) return IVAInterface::VA_AURAMODE_SCATTERING;
	if( t == "DF" ) return IVAInterface::VA_AURAMODE_DIFFRACTION;
	if( t == "NF" ) return IVAInterface::VA_AURAMODE_NEARFIELD;
	if( t == "DP" ) return IVAInterface::VA_AURAMODE_DOPPLER;
	if( t == "SL" ) return IVAInterface::VA_AURAMODE_SPREADING_LOSS;
	if( t == "TR" ) return IVAInterface::VA_AURAMODE_TRANSMISSION;
	if( t == "AB" ) return IVAInterface::VA_AURAMODE_ABSORPTION;
Jonas Stienen's avatar
Jonas Stienen committed
135 136 137
	return -1;
}

138
int IVAInterface::ParseAuralizationModeStr( const std::string& sModeStr, const int iBaseMode )
139
{
Jonas Stienen's avatar
Jonas Stienen committed
140 141
	// Remove all whitespaces, valid chars: Alphabetic + *+-,
	std::string s;
142 143 144 145
	for( size_t k = 0; k < sModeStr.size(); k++ )
	{
		if( isspace( sModeStr[ k ] ) )
			continue;
Jonas Stienen's avatar
Jonas Stienen committed
146

147 148
		if( isalpha( sModeStr[ k ] ) )
		{
149
			s += char( toupper( sModeStr[ k ] ) );
Jonas Stienen's avatar
Jonas Stienen committed
150 151
			continue;
		}
152 153 154 155 156 157

		if( ( sModeStr[ k ] == '*' ) ||
			( sModeStr[ k ] == '+' ) ||
			( sModeStr[ k ] == '-' ) ||
			( sModeStr[ k ] == ',' ) )
		{
158
			s += char( toupper( sModeStr[ k ] ) );
Jonas Stienen's avatar
Jonas Stienen committed
159 160 161
			continue;
		}

162
		VA_EXCEPT2( INVALID_PARAMETER, "Auralization mode specification contains invalid characters" );
Jonas Stienen's avatar
Jonas Stienen committed
163 164 165
	}

	// Trivial cases: Empty string, "null", "none", "default", "all"
166 167 168 169
	if( s.empty() ) return VA_AURAMODE_NOTHING;
	if( ( s == "NULL" ) || ( s == "NONE" ) ) return VA_AURAMODE_NOTHING;
	if( s == "DEFAULT" ) return VA_AURAMODE_DEFAULT;
	if( ( s == "ALL" ) || ( s == "*" ) ) return VA_AURAMODE_ALL;
Jonas Stienen's avatar
Jonas Stienen committed
170 171 172

	// Format: List of tokens seperated by commas (possibly whitespaces)
	// [fwe] For not adding PCRE this is implemented by hand here
173 174 175 176
	size_t i = 0, j = 0, op = 0;
	bool err = false;
	int m = 0; // Scanning modes: 0 => none, 1 => token
	int def = 0, plus = 0, minus = 0;
Jonas Stienen's avatar
Jonas Stienen committed
177 178
	std::string sErrorMsg;

179 180 181 182 183 184 185 186 187 188 189 190 191
	for( i; i < s.length(); i++ )
	{
		if( isalpha( s[ i ] ) )
		{
			if( m == 0 )
			{
				// None => Begin token
				j = i;
				m = 1;
			}
			else
			{ 
				// Token => extend
Jonas Stienen's avatar
Jonas Stienen committed
192 193 194 195
				continue;
			}
		}

196 197 198 199
		if( s[ i ] == '+' )
		{
			if( ( m == 1 ) || ( op != 0 ) )
			{ // Scanning toking || multiple operands => Error
Jonas Stienen's avatar
Jonas Stienen committed
200 201 202 203 204
				err = true;
				sErrorMsg = "Multiple plus operand found in auralisation mode";
				break;
			}

205
			op = 1;
Jonas Stienen's avatar
Jonas Stienen committed
206 207
		}

208 209 210 211
		if( s[ i ] == '-' )
		{
			if( ( m == 1 ) || ( op != 0 ) )
			{ // Scanning toking || multiple operands => Error
Jonas Stienen's avatar
Jonas Stienen committed
212 213 214 215 216
				err = true;
				sErrorMsg = "Multiple minus operand found in auralisation mode";
				break;
			}

217
			op = 2;
Jonas Stienen's avatar
Jonas Stienen committed
218 219
		}

220 221 222 223
		if( s[ i ] == ',' )
		{
			if( m == 0 ) 
			{ // No token => Error
Jonas Stienen's avatar
Jonas Stienen committed
224 225 226
				err = true;
				sErrorMsg = "No token in auralisation mode found";
				break;
227 228 229 230 231 232
			}
			else
			{ // Finished token
				std::string t = s.substr( j, i - j );
				int p = ParseAuralizationModeToken( t );
				if( p == -1 ) {
Jonas Stienen's avatar
Jonas Stienen committed
233
					// Invalid token
234
					sErrorMsg = "Invalid token '" + t + "' found in auralisation mode";
Jonas Stienen's avatar
Jonas Stienen committed
235 236 237 238
					err = true;
					break;
				}

239 240 241
				if( op == 0 ) def |= p;	// No operator
				if( op == 1 ) plus |= p;	// Plus operator
				if( op == 2 ) minus |= p;	// Minus operator
Jonas Stienen's avatar
Jonas Stienen committed
242

243 244 245
				op = 0;
				j = 0;
				m = 0;
Jonas Stienen's avatar
Jonas Stienen committed
246 247 248 249 250
			}
		}
	}

	// Unfinished token?
251 252 253 254 255 256
	if( m != 0 )
	{
		std::string t = s.substr( j, i - j );
		int p = ParseAuralizationModeToken( t );
		if( p == -1 )
		{
Jonas Stienen's avatar
Jonas Stienen committed
257
			// Invalid token
258
			sErrorMsg = "Invalid token '" + t + "' found in auralisation mode";
Jonas Stienen's avatar
Jonas Stienen committed
259 260 261
			err = true;
		}

262 263 264
		if( op == 0 ) def |= p;	// No operator
		if( op == 1 ) plus |= p;	// Plus operator
		if( op == 2 ) minus |= p;	// Minus operator
Jonas Stienen's avatar
Jonas Stienen committed
265 266
	}

267 268 269
	if( err )
		VA_EXCEPT2( INVALID_PARAMETER, "Invalid auralization mode specification, " + sErrorMsg );

Jonas Stienen's avatar
Jonas Stienen committed
270 271

	// Combine modes:
272 273
	int result = ( iBaseMode & VA_AURAMODE_ALL );
	if( def != 0 ) // Assignment => Forget about the base
Jonas Stienen's avatar
Jonas Stienen committed
274 275 276 277 278 279 280 281 282 283 284
		result = def;

	// Plus flags
	result |= plus;

	// Minus flags (stronger than plus)
	result &= ~minus;

	return result;
}

285
std::string IVAInterface::GetAuralizationModeStr( const int iAuralizationMode, const bool bShortFormat )
Jonas Stienen's avatar
Jonas Stienen committed
286 287 288
{
	std::stringstream ss;

289 290
	if( !IsValidAuralizationMode( iAuralizationMode ) )
	{
Jonas Stienen's avatar
Jonas Stienen committed
291
		ss << "Invalid auralization mode (" << iAuralizationMode << ")";
292
		VA_EXCEPT2( INVALID_PARAMETER, ss.str() );
Jonas Stienen's avatar
Jonas Stienen committed
293 294
	}

295 296 297 298 299 300 301
	if( bShortFormat )
	{
		if( iAuralizationMode == 0 ) return "NULL";

		if( iAuralizationMode & VA_AURAMODE_DIRECT_SOUND )      ss << "DS, ";
		if( iAuralizationMode & VA_AURAMODE_EARLY_REFLECTIONS ) ss << "ER, ";
		if( iAuralizationMode & VA_AURAMODE_DIFFUSE_DECAY )     ss << "DD, ";
302 303 304
		if( iAuralizationMode & VA_AURAMODE_SOURCE_DIRECTIVITY )       ss << "DIR, ";
		if( iAuralizationMode & VA_AURAMODE_MEDIUM_ABSORPTION )    ss << "AA, ";
		if( iAuralizationMode & VA_AURAMODE_TEMP_VAR )    ss << "TV, ";
305 306 307 308
		if( iAuralizationMode & VA_AURAMODE_SCATTERING )        ss << "SC, ";
		if( iAuralizationMode & VA_AURAMODE_DIFFRACTION )       ss << "DIF, ";
		if( iAuralizationMode & VA_AURAMODE_NEARFIELD )         ss << "NF, ";
		if( iAuralizationMode & VA_AURAMODE_DOPPLER )           ss << "DP, ";
Jonas Stienen's avatar
Jonas Stienen committed
309
		if( iAuralizationMode & VA_AURAMODE_SPREADING_LOSS )	ss << "SL, ";
310 311
		if( iAuralizationMode & VA_AURAMODE_TRANSMISSION )		ss << "TR, ";
		if( iAuralizationMode & VA_AURAMODE_ABSORPTION )		ss << "AB, ";
312 313 314 315 316 317 318 319
	}
	else
	{
		if( iAuralizationMode == 0 ) return "None (0)";

		if( iAuralizationMode & VA_AURAMODE_DIRECT_SOUND )      ss << "direct sound, ";
		if( iAuralizationMode & VA_AURAMODE_EARLY_REFLECTIONS ) ss << "early reflections, ";
		if( iAuralizationMode & VA_AURAMODE_DIFFUSE_DECAY )     ss << "diffuse decay, ";
320 321 322
		if( iAuralizationMode & VA_AURAMODE_SOURCE_DIRECTIVITY )       ss << "source directivity, ";
		if( iAuralizationMode & VA_AURAMODE_MEDIUM_ABSORPTION )    ss << "air absorption, ";
		if( iAuralizationMode & VA_AURAMODE_TEMP_VAR )    ss << "atmospheric temporal variations, ";
323 324 325 326
		if( iAuralizationMode & VA_AURAMODE_SCATTERING )        ss << "scattering, ";
		if( iAuralizationMode & VA_AURAMODE_DIFFRACTION )       ss << "diffraction, ";
		if( iAuralizationMode & VA_AURAMODE_NEARFIELD )         ss << "near-field effects, ";
		if( iAuralizationMode & VA_AURAMODE_DOPPLER )           ss << "doppler shifts, ";
Jonas Stienen's avatar
Jonas Stienen committed
327
		if( iAuralizationMode & VA_AURAMODE_SPREADING_LOSS )	ss << "spherical spreading loss, ";
328
		if( iAuralizationMode & VA_AURAMODE_TRANSMISSION )		ss << "transmission, ";
329
		if( iAuralizationMode & VA_AURAMODE_ABSORPTION )		ss << "absorption, ";
Jonas Stienen's avatar
Jonas Stienen committed
330 331 332
	}

	// Remove last ,_
333 334
	std::string s( ss.str() );
	s[ 0 ] = char( toupper( s[ 0 ] ) );
335
	return s.substr( 0, s.length() - 2 );
Jonas Stienen's avatar
Jonas Stienen committed
336 337
}

338
std::string IVAInterface::GetVolumeStrDecibel( const double dVolume )
339 340 341
{
	if( !IsValidVolume( dVolume ) )
		return "Invalid";
Jonas Stienen's avatar
Jonas Stienen committed
342 343

	std::stringstream ss;
344 345 346 347 348 349 350 351
	if( dVolume > 0.0f )
	{
		double dVolume_dB = ( ( dVolume == 0 ) ? DECIBEL_MINUS_INFINITY : 20.0f*log10( dVolume ) );
		ss << std::fixed << std::setprecision( 3 ) << dVolume << " (" << dVolume_dB << " dB)";
	}
	else
	{
		ss << std::fixed << std::setprecision( 3 ) << 0.0f << " (-Inf dB)";
Jonas Stienen's avatar
Jonas Stienen committed
352 353 354 355 356
	}

	return ss.str();
}

357
int IVAInterface::ParsePlaybackState( const std::string& t )
Jonas Stienen's avatar
Jonas Stienen committed
358 359
{
	std::string T = t;
360 361
	for( size_t i = 0; i < t.size(); i++ )
		T[ i ] = char( toupper( t[ i ] ) );
362 363

	if( T == "PLAYING" )
364
		return IVAInterface::VA_PLAYBACK_STATE_PLAYING;
365
	if( T == "STOPPED" )
366
		return IVAInterface::VA_PLAYBACK_STATE_STOPPED;
367
	if( T == "PAUSED" )
368
		return IVAInterface::VA_PLAYBACK_STATE_PAUSED;
Jonas Stienen's avatar
Jonas Stienen committed
369 370 371

	return -1;
}
372

373
std::string IVAInterface::GetPlaybackStateStr( int iPlayState )
Jonas Stienen's avatar
Jonas Stienen committed
374 375 376 377 378 379 380
{
	if( iPlayState == VA_PLAYBACK_STATE_PAUSED ) return "PAUSED";
	if( iPlayState == VA_PLAYBACK_STATE_PLAYING ) return "PLAYING";
	if( iPlayState == VA_PLAYBACK_STATE_STOPPED ) return "STOPPED";
	return "UNKOWN PLAYBACK STATE";
}

381
int IVAInterface::ParsePlaybackAction( const std::string& t )
Jonas Stienen's avatar
Jonas Stienen committed
382 383
{
	std::string T = t;
384 385
	for( size_t i = 0; i < t.size(); i++ )
		T[ i ] = char( toupper( t[ i ] ) );
Jonas Stienen's avatar
Jonas Stienen committed
386

387 388 389
	if( T == "PLAY" ) return IVAInterface::VA_PLAYBACK_ACTION_PLAY;
	if( T == "STOP" ) return IVAInterface::VA_PLAYBACK_ACTION_STOP;
	if( T == "PAUSE" ) return IVAInterface::VA_PLAYBACK_ACTION_PAUSE;
Jonas Stienen's avatar
Jonas Stienen committed
390 391 392
	return -1;
}

393
std::string IVAInterface::GetPlaybackActionStr( int iPlaybackAction )
Jonas Stienen's avatar
Jonas Stienen committed
394 395 396 397 398 399 400
{
	if( iPlaybackAction == VA_PLAYBACK_ACTION_PLAY ) return "PLAY";
	if( iPlaybackAction == VA_PLAYBACK_ACTION_STOP ) return "STOP";
	if( iPlaybackAction == VA_PLAYBACK_ACTION_PAUSE ) return "PAUSE";
	return "UNKOWN PLAYBACK ACTION";
}

401
const std::vector<CVAIntLiteral>& IVAInterface::GetLiterals()
Jonas Stienen's avatar
Jonas Stienen committed
402
{
403
	return g_oVALiterals;
Jonas Stienen's avatar
Jonas Stienen committed
404 405
}