itaVA_tutorial.m 12.4 KB
Newer Older
1
2
%% Short tutorial for itaVA (Virtual Acoustics (VA) Matlab client)
% covers basic operations for setting up a simple example of a virtual scene
3
% (binaural synthesis for 1 receiver, 1 static / 1 moving virtual sound source)
4
5
6
7
8
9
10
11
12
13
14
15
% as well as synchronized playback of multiple virtual sound sources
%
% NOTE: The user needs a running version of VAServer.exe / VAGUI.exe (+ dependencies)
% ( please contact {jst, fpa}@akustik.rwth-aachen.de ).
% Set up the (absolute) path of the VA deploy dir (see below).
% Configuration settings are based on VACore.ini / VAGUI.ini files (located in conf directory).
% Additionally, it is necessary to select the correct audio driver backend 
% (e.g. Portaudio, ASIO4All)
%
% Explore itaVA by typing "doc itaVA" in Matlab command window
%
% Author:  Florian Pausch, fpa@akustik.rwth-aachen.de
16
% Version: 2018-03-12 (compatible with VA.v2018a_preview.win32-x64.vc12 (and probably higher))
17
% Revision: Ernesto Accolti 2018-02-20 (update for VA.2018a_preview)
18

19
%% Step 0: Initializations
20
% Select VA environment
21
VAsel = 0;  % 0: start VAServer.exe (without GUI for visualization of virtual environment), 
22
            % 1: start Redstart.exe (with graphical user interface)
23
24
25
26
27
            
% Set VA root directory containing bin, conf, data folders etc.
if ~exist('deployDir','var')
    deployDir = uigetdir(pwd);
end
28
29
30
31
32
33
34
35
36
37
38
39
40
41

% Do you use Natural Point's Optitrack tracking system?
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
42
    [~,searchresult]=system('tasklist /FI "imagename eq Redstart.exe" /fo table /nh');
43
44
    if ~strcmp(strtrim(searchresult(1:13)),'Redstart.exe')
        system(fullfile(deployDir,'\bin\Redstart.exe &'));
45
46
47
        pause(1) % start-up may take some time on old PC's, pause() to avoid error
    end
end
48
 
49
50
51
52
53
54
55
56
57
58
59
60
61
%% 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
62
63
64
65
66

%% Step 2: Create itaVA object and connect to VAServer
a = itaVA;

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

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

74
75
76
% Optionally add important data directories (if not speciefied 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' ) );
77
78
79

%% Step 3: Set global output gain (optionally set reproduction module)
% set global gain of VA output
80
a.set_output_gain(0.3); % value between 0 (-inf dB) and 1 (0 dB) 
81
82

% % query available reproduction modules (cf. VACore.ini)
83
% modules = a.get_modules;
84
85
86
87
88
89
% 
% Example 1: set reproduction module for binaural synthesis, e.g. 'hprep' for a
% binaural synthesis played back over headphones and set HPEQ file
% command_struct = struct();
% command_struct.hpirinv = '$(VADataDir)/HPEQ/HD600_all_eq_128_stereo.wav';
% command_struct.gain = 0.1;
90
% a.call_module( 'Headphones:MyHD600', command_struct )
91

92
% Example 2: receiver dumping for binaural freefield renderer
93
94
95
96
% command_struct = struct();
% command_struct.command = 'STARTDUMPLISTENERS';
% command_struct.gain = .1;
% command_struct.FilenameFormat = 'ListenerFuerMeckingjay$(ListenerID).wav';
97
% a.call_module( 'BinauralFreefield:MyBinauralFreefield', command_struct )
98
% command_struct.command = 'STOPDUMPLISTENERS';
99
% a.call_module( 'BinauralFreefield:MyBinauralFreefield', command_struct )
100
101


102
%% Step 4: Create a receiver and assign a HRIR set
103
104
% load HRTF set stored in VADataDir\HRIR

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

107
% create a receiver and assign the HRTF set
108
109
110
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 );

111
LHeight = 1.2; % height of receiver's interaural axis [m]
112

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

124
125
a.set_sound_receiver_position(L, [0 LHeight 0])

126
127
128
129
130
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
131
132
133
134

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

% For further information, please refer to the documentation of the class itaOrientation
139
140

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

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

if useTracker
148
149
    a.set_tracked_sound_receiver(L)
    a.connect_tracker()
150
151
end

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


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

a.set_sound_source_position(S1,[-2 LHeightTracked 0])
162
163
164
165
166
167
S1ori = ita_rpy2quat(0,0,-90); % calculate quaternion orientation based on roll/pitch/yaw input
S1ori_quat = S1ori.e;  % access quaternion coefficients 
a.set_sound_source_orientation(S1,S1ori_quat)
% The virtual sound source is now positioned on the left side of the receiver, 
% 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
168
169

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

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

% optionally set volume of sound source
176
a.set_sound_source_sound_power(S1,0.05); % value between 0 (-inf dB) and 1 (0 dB) 
177
178

% set playback state of audiofile signal source 
179
180
181
182
183
184
a.set_signal_source_buffer_looping( X1, true );          % looping yes/no?
a.set_signal_source_buffer_playback_action( X1, 'play' ) % e.g., plays the audiofile signal source

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

185
a.set_signal_source_buffer_playback_action( X1, 'stop' ) % stop playback
186
187
188
189
190


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

191
S2  = a.create_sound_source('Source 2');    % name of the sound source as string
192
193

% Create an audiofile signal source for the sound source (based on a mono wave file)
194
X2  = a.create_signal_source_buffer_from_file( 'WelcomeToVA.wav' );
195
196

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

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

% increase sound source power due to energy loss (directivity)
a.set_sound_source_sound_power(S2,0.15)
206
207

% define a simple trajectory: the virtual sound source S2 shall move on a
208
% circle on the horizontal plane with constant radius from pi/2 to -pi/2 (counter-clockwise rotation)
209
% Note: for the definition of phi/theta, the local coordinate system of the
210
211
212
%       receiver is used (view/up direction: -z/y axis), i.e. phi=0 is in look
%       direction of the receiver and increases counterclockwise, and the
%       zenith angle starts at north pole (0) and ends at south pole (pi)
213
214
215

circleR     = 2;        % radius of trajectory [m]
nlegs       = 200;      % number of equidistant trajectory legs
216
217
218
219
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]
220

221
phi = linspace(phi_start,phi_end,nlegs);
222

223
224
225
traj_cart(:,1) = circleR*sin(phi); 
traj_cart(:,2) = circleR*cos(phi);
traj_cart(:,3) = LHeight + circleR*cos(theta);
226

227
% set initial position of S2 (use first position of trajectory)
228
229
a.set_sound_source_position(S2, [traj_cart(1,1) traj_cart(1,2) traj_cart(1,3)]);

230
231
232
233
% ... and the initial orientation
S2ori = ita_rpy2quat(0,0,0); % alternatively use ita_vu2quat
a.set_sound_source_orientation(S2,S2ori.e); % access quaternion coefficients by .e
a.set_signal_source_buffer_looping( X2, true );         % looping yes/no?
234
235

% set period of high-precision timer [s] (for precise position updates in the following update loop)
236
a.set_timer(Tvel/nlegs); 
237
238
for idx = 1:nlegs
    if idx==1 % start playback during first loop cycle
239
       a.set_signal_source_buffer_playback_action(X2, 'play')
240
241
242
    end
    
    % wait for a signal of the high-precision timer
243
    a.wait_for_timer();
244
    
245
    % update source position and view/up direction of S2 (virtual sound source always points at receiver)
246
247
    a.set_sound_source_position(S2, [traj_cart(idx,1), traj_cart(idx,2), traj_cart(idx,3)]);
   
248
    if idx==nlegs % optionally: stop playback during last loop cycle
249
       a.set_signal_source_buffer_playback_action(X2, 'STOP') 
250
251
252
253
254
    end
end


%% Step 7: Use synchronized scene actions
255
256
257
258
259
260
261
262
263
264
265
%  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) 

% set initial position of S2 (use first position of trajectory)
a.set_sound_source_position(S2, [traj_cart(1,1) traj_cart(1,2) traj_cart(1,3)]);
% ... and the initial orientation
a.set_sound_source_orientation(S2,S2ori.e); % access quaternion coefficients by .e

% shift buffer playback position of signal source
a.set_signal_source_buffer_playback_position(X1,0.5)
266

267
% everything between .lock_update and .unlock_update will be triggered in
268
% one cycle to allow for synchronized scene events
269
270
271
272
a.lock_update;
a.set_signal_source_buffer_playback_action(X1, 'PLAY')
a.set_signal_source_buffer_playback_action(X2, 'PLAY')
a.unlock_update;
273
274
275

% wait until longer signal source is played back completely
java.util.concurrent.locks.LockSupport.parkNanos(6.5*10^9); 
276

277
278
279
280
a.lock_update;
a.set_signal_source_buffer_playback_action(X1, 'STOP')
a.set_signal_source_buffer_playback_action(X2, 'STOP')
a.unlock_update;
281
282


283
%% Step 8: Clean up (optionally), reset, and disconnect from VAServer
284

285
286
287
% delete sound sources
a.delete_sound_source(S1);
a.delete_sound_source(S2);
288

289
290
% delete receiver
a.delete_sound_receiver(L);
291
292
293
294
295
296

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

if useTracker
    % disconnect from tracker
297
    a.disconnect_tracker
298
299
300
end

% disconnect itaVA object from server
301
a.disconnect()
302
303