VACore.cpp 12.1 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
 *
 *  --------------------------------------------------------------------------------------------
 */

Jonas Stienen's avatar
Jonas Stienen committed
14
15
16
17
18
19
20
21
22
23
24
25
#include <VACore.h>

#include <VACoreVersion.h>
#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, IVACore::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
53
54
55
56
57
58
59
		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 );
		VACORE_REGISTER_LITERAL( VA_AURAMODE_DIRECTIVITY );
		VACORE_REGISTER_LITERAL( VA_AURAMODE_AIR_ABSORPTION );
		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
69
70
71
72
73
74
75
76
		VACORE_REGISTER_LITERAL( VA_AURAMODE_DEFAULT );
		VACORE_REGISTER_LITERAL( VA_AURAMODE_ALL );
	};
};

#undef VACORE_REGISTER_LITERAL

// Global literals table
CVALiteralsTable g_oCoreLiterals;

IVACore::IVACore() {}

IVACore::~IVACore() {}

bool IVACore::AddSearchPath( const std::string& sPath )
{
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;
}

84
bool IVACore::IsValidAuralizationMode( const int iAuralizationMode )
Jonas Stienen's avatar
Jonas Stienen committed
85
86
87
88
{
	return ( iAuralizationMode >= 0 ) && ( iAuralizationMode <= 2047 );
}

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

94
bool IVACore::IsValidAudiofileSignalSourcePlaybackAction( const int iAction )
Jonas Stienen's avatar
Jonas Stienen committed
95
96
97
98
99
100
101
{
	if( iAction == IVACore::VA_PLAYBACK_ACTION_PAUSE )
		return true;
	if( iAction == IVACore::VA_PLAYBACK_ACTION_PLAY )
		return true;
	if( iAction == IVACore::VA_PLAYBACK_ACTION_STOP )
		return true;
102

Jonas Stienen's avatar
Jonas Stienen committed
103
104
105
	return false;
}

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

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

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

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

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

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

	// Trivial cases: Empty string, "null", "none", "default", "all"
164
165
166
167
	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
168
169
170

	// Format: List of tokens seperated by commas (possibly whitespaces)
	// [fwe] For not adding PCRE this is implemented by hand here
171
172
173
174
	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
175
176
	std::string sErrorMsg;

177
178
179
180
181
182
183
184
185
186
187
188
189
	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
190
191
192
193
				continue;
			}
		}

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

203
			op = 1;
Jonas Stienen's avatar
Jonas Stienen committed
204
205
		}

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

215
			op = 2;
Jonas Stienen's avatar
Jonas Stienen committed
216
217
		}

218
219
220
221
		if( s[ i ] == ',' )
		{
			if( m == 0 ) 
			{ // No token => Error
Jonas Stienen's avatar
Jonas Stienen committed
222
223
224
				err = true;
				sErrorMsg = "No token in auralisation mode found";
				break;
225
226
227
228
229
230
			}
			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
231
					// Invalid token
232
					sErrorMsg = "Invalid token '" + t + "' found in auralisation mode";
Jonas Stienen's avatar
Jonas Stienen committed
233
234
235
236
					err = true;
					break;
				}

237
238
239
				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
240

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

	// Unfinished token?
249
250
251
252
253
254
	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
255
			// Invalid token
256
			sErrorMsg = "Invalid token '" + t + "' found in auralisation mode";
Jonas Stienen's avatar
Jonas Stienen committed
257
258
259
			err = true;
		}

260
261
262
		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
263
264
	}

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

Jonas Stienen's avatar
Jonas Stienen committed
268
269

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

	// Plus flags
	result |= plus;

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

	return result;
}

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

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

293
294
295
296
297
298
299
300
301
302
303
304
305
306
	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, ";
		if( iAuralizationMode & VA_AURAMODE_DIRECTIVITY )       ss << "DIR, ";
		if( iAuralizationMode & VA_AURAMODE_AIR_ABSORPTION )    ss << "AA, ";
		if( iAuralizationMode & VA_AURAMODE_ATMOS_TEMP_VAR )    ss << "TV, ";
		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
307
		if( iAuralizationMode & VA_AURAMODE_SPREADING_LOSS )	ss << "SL, ";
308
309
		if( iAuralizationMode & VA_AURAMODE_TRANSMISSION )		ss << "TR, ";
		if( iAuralizationMode & VA_AURAMODE_ABSORPTION )		ss << "AB, ";
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
	}
	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, ";
		if( iAuralizationMode & VA_AURAMODE_DIRECTIVITY )       ss << "source directivity, ";
		if( iAuralizationMode & VA_AURAMODE_AIR_ABSORPTION )    ss << "air absorption, ";
		if( iAuralizationMode & VA_AURAMODE_ATMOS_TEMP_VAR )    ss << "atmospheric temporal variations, ";
		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
325
		if( iAuralizationMode & VA_AURAMODE_SPREADING_LOSS )	ss << "spherical spreading loss, ";
326
		if( iAuralizationMode & VA_AURAMODE_TRANSMISSION )		ss << "transmission, ";
327
		if( iAuralizationMode & VA_AURAMODE_ABSORPTION )		ss << "absorption, ";
Jonas Stienen's avatar
Jonas Stienen committed
328
329
330
	}

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

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

	std::stringstream ss;
342
343
344
345
346
347
348
349
	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
350
351
352
353
354
355
356
357
	}

	return ss.str();
}

int IVACore::ParsePlaybackState( const std::string& t )
{
	std::string T = t;
358
359
	for( size_t i = 0; i < t.size(); i++ )
		T[ i ] = char( toupper( t[ i ] ) );
360
361
362
363
364
365
366

	if( T == "PLAYING" )
		return IVACore::VA_PLAYBACK_STATE_PLAYING;
	if( T == "STOPPED" )
		return IVACore::VA_PLAYBACK_STATE_STOPPED;
	if( T == "PAUSED" )
		return IVACore::VA_PLAYBACK_STATE_PAUSED;
Jonas Stienen's avatar
Jonas Stienen committed
367
368
369

	return -1;
}
370

Jonas Stienen's avatar
Jonas Stienen committed
371
372
373
374
375
376
377
378
379
380
381
std::string IVACore::GetPlaybackStateStr( int iPlayState )
{
	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";
}

int IVACore::ParsePlaybackAction( const std::string& t )
{
	std::string T = t;
382
383
	for( size_t i = 0; i < t.size(); i++ )
		T[ i ] = char( toupper( t[ i ] ) );
Jonas Stienen's avatar
Jonas Stienen committed
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403

	if( T == "PLAY" ) return IVACore::VA_PLAYBACK_ACTION_PLAY;
	if( T == "STOP" ) return IVACore::VA_PLAYBACK_ACTION_STOP;
	if( T == "PAUSE" ) return IVACore::VA_PLAYBACK_ACTION_PAUSE;
	return -1;
}

std::string IVACore::GetPlaybackActionStr( int iPlaybackAction )
{
	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";
}

const std::vector<CVAIntLiteral>& IVACore::GetLiterals()
{
	return g_oCoreLiterals;
}