itaVA_tutorial.m 11.5 KB
Newer Older
fpa's avatar
fpa committed
1
2
3
4
%% Short tutorial for itaVA, a Matlab interface for Virtual Acoustics (VA)
% The tutorial covers basic operations for setting up a simple virtual scene
% (1 receiver, 1 static / 1 moving virtual sound source), and explains how to
% set up a synchronized playback of multiple virtual sound sources.
5
%
fpa's avatar
fpa committed
6
7
% It is recommended to run the tutorial in sections to understand the basic
% concepts and controls!
8
%
fpa's avatar
fpa committed
9
10
11
12
13
14
15
% WARNING: Check the playback level of your sound card to avoid hearing damage!
%
% NOTE: The user needs a running version of VAServer.exe / Redstart.exe (+ dependencies)
% which can be downloaded here: http://www.virtualacoustics.org/ (section Download)
% For a more detailed introduction, the reader is referred to http://www.virtualacoustics.org/start.html
%
% Explore itaVA by typing "doc itaVA" in Matlab's command window.
16
17
%
% Author:  Florian Pausch, fpa@akustik.rwth-aachen.de
fpa's avatar
fpa committed
18
% Version: 2018-03-26 (compatible with VA.v2018a_preview.win32-x64.vc12 (and probably higher))
19
% Revision: Ernesto Accolti 2018-02-20 (update for VA.2018a_preview)
20

21
%% Step 0: Initializations
22
% Select VA environment
fpa's avatar
fpa committed
23
VAsel = 1;  % 0: start VAServer.exe (without GUI for visualization of virtual environment), 
24
            % 1: start Redstart.exe (with graphical user interface)
25
26
27
            
% Set VA root directory containing bin, conf, data folders etc.
if ~exist('deployDir','var')
fpa's avatar
fpa committed
28
    deployDir = uigetdir(pwd, 'Set VA root directory...');
29
end
30

fpa's avatar
fpa committed
31
% Do you use Natural Point's Optitrack motion tracking system?
32
33
34
35
36
37
38
39
40
41
42
43
useTracker = false;

if VAsel==0
    % start VAServer.exe (in Server mode) if not running already
    [~,searchresult]=system('tasklist /FI "imagename eq VAServer.exe" /fo table /nh');
    if ~strcmp(strtrim(searchresult(1:13)),'VAServer.exe')
        % input parameters: deployDir\VAServer.exe localhost:12340 deployDir\VACore.ini &
        system([fullfile(deployDir,'\bin\VAServer.exe localhost:12340 '),fullfile(deployDir,'\conf\VACore.ini &')]);
        pause(1) % start-up may take some time on old PC's, pause() to avoid errors
    end
else
    % start VAGUI.exe if not running already
44
    [~,searchresult]=system('tasklist /FI "imagename eq Redstart.exe" /fo table /nh');
45
46
    if ~strcmp(strtrim(searchresult(1:13)),'Redstart.exe')
        system(fullfile(deployDir,'\bin\Redstart.exe &'));
47
48
49
        pause(1) % start-up may take some time on old PC's, pause() to avoid error
    end
end
50
 
fpa's avatar
fpa committed
51

52
53
54
55
56
57
58
59
60
61
62
63
64
%% Step 1: 
% VAsel = 0: VAServer.exe was started based on the configuration in VAini.exe and currently is running
% VAsel = 1: Create a session under the menu item Redstart and press the start button in Redstart VA GUI

if ~exist('firstStart','var')
    firstStart = true;
end

if VAsel == 1 && firstStart == true
    fprintf('(1) Create a session under the menu item Redstart.\n(2) Press the start button in Redstart VA GUI.\n(3) Press any button in Matlab to continue.\n')
    firstStart = false;
    pause 
end
65

fpa's avatar
fpa committed
66

67
68
69
70
%% Step 2: Create itaVA object and connect to VAServer
a = itaVA;

% Connect to VAServer (must be running and listening to default port on localhost)
71
if ~a.get_connected % only connect if no connection to server is established
72
73
74
75
76
77
    a.connect('localhost')
end

% Reset VA and clear the scene
a.reset()

78
79
80
% Optionally add important data directories (if not specified in the VA setup GUI which pops up the first time you use VA)
a.add_search_path( fullfile( deployDir, 'data' ) );
a.add_search_path( fullfile( deployDir, 'conf' ) );
81

fpa's avatar
fpa committed
82
83

%% Step 3: Set global output gain
84
% set global gain of VA output
85
a.set_output_gain(0.3); % value between 0 (-inf dB) and 1 (0 dB) 
86
87

% % query available reproduction modules (cf. VACore.ini)
88
% modules = a.get_modules;
89
% 
fpa's avatar
fpa committed
90
% Example: receiver dumping for binaural free field renderer
91
92
93
94
% command_struct = struct();
% command_struct.command = 'STARTDUMPLISTENERS';
% command_struct.gain = .1;
% command_struct.FilenameFormat = 'ListenerFuerMeckingjay$(ListenerID).wav';
fpa's avatar
fpa committed
95
% a.call_module( 'BinauralFreeField:MyBinauralRenderer', command_struct )
96
% command_struct.command = 'STOPDUMPLISTENERS';
fpa's avatar
fpa committed
97
% a.call_module( 'BinauralFreeField:MyBinauralRenderer', command_struct )
98
99


fpa's avatar
fpa committed
100
%% Step 4: Create a receiver and assign an HRIR set
101
102
% load HRTF set stored in VADataDir\HRIR

103
HRIRSet = a.create_directivity( 'ITA_Artificial_Head_5x5_44kHz_128.v17.ir.daff' ); % $(DefaultHRIR) macro would work, too
104

105
% create a receiver and assign the HRTF set
106
107
108
L       = a.create_sound_receiver('Listener'); % input parameters: (displayed) name (in VAGUI) / auralization mode / ID of HRIR data set
a.set_sound_receiver_directivity( L, HRIRSet );

109
LHeight = 1.2; % height of receiver's interaural axis [m]
110

111
% set position/orientation of receiver L in virtual world in VA world coordinates / openGL coordinates [m]:
112
%       center of coordinate system: (x,y,z)=(0,0,0), right-handed coordinate system
113
%       receiver is looking into -z direction (default) 
114
115
116
117
%       (positive) offset to the right  -> +x
%       (positive) offset in height     -> +y
%
% use a.setListenerPositionOrientationYPR() to specify 
118
% the receiver's orientation in the virtual world in yaw-pitch-roll coordinates, or
119
% a.setListenerPositionOrientationVelocityVU() to specify 
120
% the receiver's orientation in the virtual world by view-up vectors
121

122
123
a.set_sound_receiver_position(L, [0 LHeight 0])

124
125
126
127
128
ori_initial = ita_rpy2quat(0,0,0); % calculate quaternion orientation based on roll/pitch/yaw input
ori_initial_quat = ori_initial.e;  % access quaternion coefficients 
a.set_sound_receiver_orientation(L, ori_initial_quat)  % the midpoint of the receiver's interaural axis is now at a height of LHeight metres, 
%                                                        no additional lateral offset,
%                                                        the receiver is facing into -z direction
129
130
131
132

% Infos for orientation commands:
% A positive rotation is always applied clockwise wrt. the respective axis [deg]
% Roll:  rotation wrt. -z axis, tilting 
133
134
135
136
% Pitch: rotation wrt. x axis, nodding
% Yaw:   rotation wrt. y axis, turning

% For further information, please refer to the documentation of the class itaOrientation
137
138

% NOTE: When using CTC reproduction module, additionally set the real-world
139
140
%       position and orientation of the receiver (wrt. loudspeaker positions) 
%       by using the method set_sound_receiver_real_world_position_orientation_view_up()
141

142
% activate the receiver to listen to sound sources in playback status 'play' 
143
a.set_active_sound_receiver(L)
144
145

if useTracker
146
147
    a.set_tracked_sound_receiver(L)
    a.connect_tracker()
148
149
end

150
% query the receiver position
151
LPosTracked = a.get_sound_receiver_position(L);
152
153
154
155
LHeightTracked = LPosTracked(2);


%%  Step 5: Create a static virtual sound source:
156
157
%   S1: static sound source at a defined position
S1 = a.create_sound_source('Source 1');      % name of the sound source as string
158

fpa's avatar
fpa committed
159
160
a.set_sound_source_position(S1,[2 LHeightTracked 0])
S1ori = ita_rpy2quat(0,0,90); % calculate quaternion orientation based on roll/pitch/yaw input
161
162
S1ori_quat = S1ori.e;  % access quaternion coefficients 
a.set_sound_source_orientation(S1,S1ori_quat)
fpa's avatar
fpa committed
163
% The virtual sound source is now positioned on the right side of the receiver, 
164
165
% at a height of LHeightTracked metres, at a distance of 2 metres relative to 
% the midpoint of the interaural axis and facing to +x direction
166
167

% Create an audiofile signal source for the sound source (based on a mono wave file)
fpa's avatar
fpa committed
168
X1 = a.create_signal_source_buffer_from_file( 'WelcomeToVA.wav' ); % Macro $(DemoSound) would also work here
169
170

% ...and link the signal source to the sound source
171
a.set_sound_source_signal_source(S1,X1)
172
173

% optionally set volume of sound source
fpa's avatar
fpa committed
174
a.set_sound_source_sound_power(S1,3e-2); % value between 0 (-inf dB) and 1 (0 dB) 
175
176

% set playback state of audiofile signal source 
177
a.set_signal_source_buffer_looping( X1, true );          % looping yes/no?
fpa's avatar
fpa committed
178
a.set_signal_source_buffer_playback_action( X1, 'PLAY' ) % e.g., plays the audiofile signal source
179
180
181
182

% listen to the virtual scene for 3 seconds
pause(3)

fpa's avatar
fpa committed
183
a.set_signal_source_buffer_playback_action( X1, 'STOP' ) % stop playback
184
185
186
187
188


%%  Step 6: Create a moving virtual sound source (with directivity):
%   S2: moving virtual sound source (on a pre-defined trajectory)

fpa's avatar
fpa committed
189
S2 = a.create_sound_source('Source 2');    % name of the sound source as string
190
191

% Create an audiofile signal source for the sound source (based on a mono wave file)
fpa's avatar
fpa committed
192
X2 = a.create_signal_source_buffer_from_file( 'WelcomeToVA.wav' );
193
194

% ...and link the signal source to the sound source
195
a.set_sound_source_signal_source(S2,X2);
196
197

% load a directivity file in *.daff file format (e.g. directivity of a trumpet)
198
S2dir = a.create_directivity( 'Singer.v17.ms.daff' );
199
% set directivity of S2
200
201
202
a.set_sound_source_directivity(S2,S2dir);

% increase sound source power due to energy loss (directivity)
fpa's avatar
fpa committed
203
a.set_sound_source_sound_power(S2,0.1)
204
205

% define a simple trajectory: the virtual sound source S2 shall move on a
206
% circle on the horizontal plane with constant radius from pi/2 to -pi/2 (counter-clockwise rotation)
fpa's avatar
fpa committed
207
208
% Note: Please refer to itaOrientation to get more information about the used
%       openGL coordinate system!
209
210
211

circleR     = 2;        % radius of trajectory [m]
nlegs       = 200;      % number of equidistant trajectory legs
212
213
214
215
Tvel        = 10;       % time to pass nlegs points
phi_start   = pi/2;     % start azimuth angle in [rad]
phi_end     = -pi/2;    % end azimuth angle in [rad]
theta       = pi/2;     % zenith angle in [rad]
216

fpa's avatar
fpa committed
217
% define the position trajectory
218
phi = linspace(phi_start,phi_end,nlegs);
fpa's avatar
fpa committed
219
S2pos_traj = ([circleR*sin(phi)', repmat(LHeight,nlegs,1), -circleR*cos(phi)']);
220

fpa's avatar
fpa committed
221
222
223
% ... and the orientation trajectory
S2ori_traj = ita_rpy2quat(zeros(nlegs,1),zeros(nlegs,1),linspace(90,-90,nlegs)'); % alternatively use ita_vu2quat
a.set_signal_source_buffer_looping( X2, true ); % looping yes/no?
224
225

% set period of high-precision timer [s] (for precise position updates in the following update loop)
226
a.set_timer(Tvel/nlegs); 
227
228
for idx = 1:nlegs
    if idx==1 % start playback during first loop cycle
fpa's avatar
fpa committed
229
       a.set_signal_source_buffer_playback_action(X2, 'PLAY')
230
231
232
    end
    
    % wait for a signal of the high-precision timer
233
    a.wait_for_timer();
234
    
fpa's avatar
fpa committed
235
236
237
238
    % update source position and orientation of S2 (virtual sound source always points at receiver)
    a.set_sound_source_position(S2, [S2pos_traj(idx,1), S2pos_traj(idx,2), S2pos_traj(idx,3)]);
    a.set_sound_source_orientation(S2, S2ori_traj(idx).e); % access quaternion coefficients by .e

239
    if idx==nlegs % optionally: stop playback during last loop cycle
240
       a.set_signal_source_buffer_playback_action(X2, 'STOP') 
241
242
243
244
245
    end
end


%% Step 7: Use synchronized scene actions
246
247
248
249
250
%  Set set_signal_source_buffer_playback_action for the two existing sources
%  simultaneously (Note: no spatial separation if same signal source from buffer is used 
%  for both sound sources) 

% shift buffer playback position of signal source
fpa's avatar
fpa committed
251
a.set_signal_source_buffer_playback_position(X2,0.5)
252

253
% everything between .lock_update and .unlock_update will be triggered in
254
% one cycle to allow for synchronized scene events
255
256
257
258
a.lock_update;
a.set_signal_source_buffer_playback_action(X1, 'PLAY')
a.set_signal_source_buffer_playback_action(X2, 'PLAY')
a.unlock_update;
259

fpa's avatar
fpa committed
260
% listen to the scene
261
java.util.concurrent.locks.LockSupport.parkNanos(6.5*10^9); 
262

263
264
265
266
a.lock_update;
a.set_signal_source_buffer_playback_action(X1, 'STOP')
a.set_signal_source_buffer_playback_action(X2, 'STOP')
a.unlock_update;
267
268


269
%% Step 8: Clean up (optionally), reset, and disconnect from VAServer
270

271
272
273
% delete sound sources
a.delete_sound_source(S1);
a.delete_sound_source(S2);
274

275
276
277
278
279
% reset VA and clear the scene
a.reset()

if useTracker
    % disconnect from tracker
280
    a.disconnect_tracker
281
282
283
end

% disconnect itaVA object from server
284
a.disconnect()
285
286