-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAudioDome_Module.py
More file actions
353 lines (305 loc) · 14.2 KB
/
AudioDome_Module.py
File metadata and controls
353 lines (305 loc) · 14.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
"""
The AudioDome Module
================
Description: This module provides classes and functions for rendering spatial audio stimuli using the AudioDome system in Python.
Author info: Nima Zargarnezhad (please contact nzargarn@uwo.ca for any queries)
License: MIT / CC BY 4.0
Citation: If you use this module in your work, please cite the following paper:
Nima Zargarnezhad, Bruno Mesquita, Ewan A Macpherson, Ingrid Johnsrude;
Focality of sound source placement by higher (ninth) order ambisonics and perceptual effects of spectral reproduction errors.
J. Acoust. Soc. Am. 1 April 2025; 157 (4): 2802–2818. https://doi.org/10.1121/10.0036226
"""
# Setting up the client
from osc4py3.as_eventloop import *
from osc4py3 import oscbuildparse
from AudioDome_Communication_Setup import *
# Command functions in practice
#Check if a input value is float or not
def check_float(value):
try:
float(value)
return True
except ValueError:
return False
#-------- Scene Commands
#Play a scene
def play_scene(sceneID):
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
command = "/scene/{}/play".format(sceneID)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
#Stop a scene
def stop_scene(sceneID):
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
command = "/scene/{}/stop".format(sceneID)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
#-------- Object Commands
#Play an object
def play_object(sceneID, objectID):
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
# objectID: string variable refering to the object number in the scene specified with sceneID
command = "/scene/{}/object/{}/play".format(sceneID, objectID)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
#Stop an object
def stop_object(sceneID, objectID):
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
# objectID: string variable refering to the object number in the scene specified with sceneID
command = "/scene/{}/object/{}/stop".format(sceneID, objectID)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
#Set the gain of an object
def set_object_gain(sceneID, objectID, objectGain):
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
# objectID: string variable refering to the object number in the scene specified with sceneID
# objectGain: string variable refering to the object's gain in dB (between -40 to 40)
if check_float(objectGain) is False:
objectGain = "0"
command = "/scene/{0}/object/{1}/gain/{2}".format(sceneID, objectID, objectGain)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
#Set the azimuth angle of an object
def set_object_azimuth(sceneID, objectID, objectAzimuth):
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
# objectID: string variable refering to the object number in the scene specified with sceneID
# objectAzimuth: string variable refering to the object's azimuth angle in degrees (between -180 and 180)
command = "/scene/{0}/object/{1}/azi/{2}".format(sceneID, objectID, objectAzimuth)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
#Set the elevation angle of an object
def set_object_elevation(sceneID, objectID, objectElevation):
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
# objectID: string variable refering to the object number in the scene specified with sceneID
# objectElevation: string variable refering to the object's elevation angle in degrees (between -90 and 90)
command = "/scene/{0}/object/{1}/ele/{2}".format(sceneID, objectID, objectElevation)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
#Set the speaker channel of an object
def set_object_channel(sceneID, objectID, objectChannel):
# Note 1: For audio to come from just the set speaker channel you must switch the panning method to "nearest" with the 'set_object_panning' command.
# Note 2: This command will change the object's position (the set azimuth and elevation angles are cleared after running this command).
# Note 3: The change in position with this command is not overwritten on azimuth and elevation levels in the spatial audio creator GUI. For compatibality reasons it's also avoided here.
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
# objectID: string variable refering to the object number in the scene specified with sceneID
# objectChannel: string variable refering to the channel number of interest (between 1 to 91)
command = "/scene/{0}/object/{1}/channeldir/{2}".format(sceneID, objectID, objectChannel)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
#Set the panning method of an object.
def set_object_panning(sceneID, objectID, objectPanningMethod):
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
# objectID: string variable refering to the object number in the scene specified with sceneID
# objectPanningMethod: string variable refering to object panning method: "ambi"||"vbap"||"nearest"
command = "/scene/{0}/object/{1}/method/{2}".format(sceneID, objectID, objectPanningMethod)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
#Set/unset looping (repeting infinitly) cues of an object
def set_object_loop(sceneID, objectID, loopStatus):
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
# objectID: string variable refering to the object number in the scene specified with sceneID
# loopStatus: string variable turning on or off the object's looping: "on"||"off"
command = "/scene/{0}/object/{1}/loop/{2}".format(sceneID, objectID, loopStatus)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
#Set/unset the room effect of an object
def set_object_room_effect(sceneID, objectID, roomEffectStatus):
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
# objectID: string variable refering to the object number in the scene specified with sceneID
# roomEffectStatus: string variable turning on or off the room effect on an object: "on"||"off"
command = "/scene/{0}/object/{1}/room/{2}".format(sceneID, objectID, roomEffectStatus)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
#-------- Cue Commands
#Play a cue
def play_cue(sceneID, objectID, cueID):
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
# objectID: string variable refering to the object number in the scene specified with sceneID
# cueID: string variable refering to the cue number belonging to the object specified with objectID
command = "/scene/{0}/object/{1}/cue/{2}/play".format(sceneID, objectID, cueID)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
#Stop a cue
def stop_cue(sceneID, objectID, cueID):
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
# objectID: string variable refering to the object number in the scene specified with sceneID
# cueID: string variable refering to the cue number belonging to the object specified with objectID
command = "/scene/{0}/object/{1}/cue/{2}/stop".format(sceneID, objectID, cueID)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
#Select a cue beloning to an object
def set_cue_select(sceneID, objectID, cueID):
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
# objectID: string variable refering to the object number in the scene specified with sceneID
# cueID: string variable refering to the cue number belonging to the object specified with objectID - to be set as for the object
command = "/scene/{0}/object/{1}/cue/{2}/select".format(sceneID, objectID, cueID)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
#Set the gain of a cue (belonging to an object)
def set_cue_gain(sceneID, objectID, cueID, cueGain):
# Inputs:
# sceneID: string variable refering to the scene number on the spatial sound creator
# objectID: string variable refering to the object number in the scene specified with sceneID
# cueID: string variable refering to the cue number belonging to the object specified with objectID
# cueGain: string variable refering to that specific cue's gain in dB (between -40 to 40)
if check_float(cueGain) is False:
cueGain = "0"
command = "/scene/{0}/object/{1}/cue/{2}/gain/{3}".format(sceneID, objectID, cueID, cueGain)
#print("Sending "+command)
msg = oscbuildparse.OSCMessage(command,None,[])
osc_send(msg, clientName)
osc_process()
class cue:
def __init__(self, ID, name, object_ID, scene_ID):
# Cue info
self.ID = ID
self.name = name
self.gain = 0
self.selected = (ID==0)
# Belongingness info
self.object_ID = object_ID
self.scene_ID = scene_ID
# Sending relevant commands to the dome
self.set_gain(self.gain)
# Methods to change atributes and communicate changes to the dome
# Play
def play(self):
play_cue(self.scene_ID, self.object_ID, self.ID)
#Stop
def stop(self):
stop_cue(self.scene_ID, self.object_ID, self.ID)
# Set gain
def set_gain(self, gain):
self.gain = gain
set_cue_gain(self.scene_ID, self.object_ID, self.ID, self.gain)
class auditory_object:
def __init__(self, ID, name, scene_ID, panning_method, room_effect):
# Auditory object info
self.ID = ID
self.name = name
self.gain = 0
self.channel = 1
self.azi = 0
self.ele = 0
self.panning_method = panning_method
self.loop = "off"
self.room_effect = room_effect
self.dist = 0.3 # communication and initiation?
# Belongingness info
self.scene_ID = scene_ID
# Associated Cues
self.cues = [cue(0, "Reserved Cue", self.ID, self.scene_ID)]
self.selected_cue_ID = 0 # initiated with the reserved cue
# Sending relevant commands to the dome
self.set_gain(self.gain)
self.set_channel(self.channel)
self.set_azimuth(self.azi)
self.set_elevation(self.ele)
self.set_panning(self.panning_method)
self.turn_loop(self.loop)
self.turn_roomEffect(self.room_effect)
# Methods to change atributes and communicate changes to the dome
# Play
def play(self):
play_object(self.scene_ID, self.ID)
#Stop
def stop(self):
stop_object(self.scene_ID, self.ID)
# Set gain
def set_gain(self, gain):
self.gain = gain
set_object_gain(self.scene_ID, self.ID, self.gain)
# Set azimuth
def set_azimuth(self, azi):
self.azi = azi
set_object_azimuth(self.scene_ID, self.ID, self.azi)
# Set channel
def set_channel(self, channel):
self.channel = channel
set_object_channel(self.scene_ID, self.ID, self.channel)
# Set elevation
def set_elevation(self, ele):
self.ele = ele
set_object_elevation(self.scene_ID, self.ID, self.ele)
# Set panning method
def set_panning(self, panning_method):
self.panning_method = panning_method
set_object_panning(self.scene_ID, self.ID, self.panning_method)
# Set looping
def turn_loop(self, loop):
self.loop = loop
set_object_loop(self.scene_ID, self.ID, self.loop)
# Set room effect
def turn_roomEffect(self, room_effect):
self.room_effect = room_effect
set_object_room_effect(self.scene_ID, self.ID, self.room_effect)
# The method to add cues to an object
def add_cue(self, cue_ID, cue_name):
self.cues.append(cue(cue_ID, cue_name, self.ID, self.scene_ID))
# The method to select a cue
def select_cue(self, cue_ID):
set_cue_select(self.scene_ID, self.ID, cue_ID)
self.cues[self.selected_cue_ID].selected = False
self.cues[cue_ID].selected = True
self.selected_cue_ID = cue_ID
class scene:
def __init__(self, ID, name):
self.ID = ID
self.name = name
self.gain = 0
self.panning_method = "ambi"
self.room_effect = "off"
self.room_size = 0.50 # communication and initiation?
self.objects = [auditory_object(0, "Reserved Object", self.ID, self.panning_method, self.room_effect)]
# Methods to change atributes and communicate changes to the dome
# Play
def play(self):
play_scene(self.ID)
# Stop
def stop(self):
stop_scene(self.ID)
# The method to add objects to the scene
def add_object(self, object_ID, obejct_name):
self.objects.append(auditory_object(object_ID, obejct_name, self.ID, self.panning_method, self.room_effect))