1.2.0: Add Events#

In AudibleLight, Event objects represent sounds placed within a Scene. There are two types of Event objects:

  • Static Events, which occupy the same point in space;

  • Moving Events, which move through space according to a particular trajectory (e.g., linear, random…)

AudibleLight defines a comprehensive API for adding Event objects to a Scene, as well as controlling parameters relating to the underlying audio file (e.g., duration, offset, any augmentations), how it moves through space (e.g., its velocity and resolution), and how it relates to the whole Scene (e.g., how loud it is versus the noise floor).

Note that the Augmentation API for AudibleLight has its own tutorial.

Adding static Event objects#

[1]:
from audiblelight.core import Scene
from audiblelight import utils
[2]:
scene = Scene(
    duration=60,
    sample_rate=44100,
    backend="rlr",
    backend_kwargs=dict(
        mesh=utils.get_project_root() / "tests/test_resources/meshes/Oyens.glb"
    ),
    fg_path=utils.get_project_root() / "tests/test_resources/soundevents",
)
scene.add_microphone(microphone_type="ambeovr")
2025-11-03 17:13:16.857 | WARNING  | audiblelight.worldstate:load_mesh_navigation_waypoints:1878 - Cannot find waypoints for mesh Oyens inside default location (/home/huw-cheston/Documents/python_projects/AudibleLight/resources/waypoints/gibson). No navigation waypoints will be loaded.
CreateContext: Context created
Warning: initializing context twice. Will destroy old context and create a new one.
CreateContext: Context created

We are now ready to add an Event to our scene. By default, this will start from between 0 and 59 seconds (i.e., scene.duration - 1), with an audio file pulled from our fg_path.

[3]:
added = scene.add_event(event_type="static", alias="my_first_event")
Warning: initializing context twice. Will destroy old context and create a new one.
CreateContext: Context created
2025-11-03 17:13:20.479 | INFO     | audiblelight.core:add_event:972 - Event added successfully: Static 'Event' with alias 'my_first_event', audio file '/home/huw-cheston/Documents/python_projects/AudibleLight/tests/test_resources/soundevents/musicInstrument/8390.wav' (unloaded, 0 augmentations), 1 emitter(s).

Note that the same functionality could be achieved by calling Scene.add_event_static with the same arguments (minus event_type="static").

Using overrides#

To control more parameters of the Event, we can pass in arguments to add_event. These arguments will override any distributions passed to Scene.__init__, allowing for more finegrained placing of events.

[4]:
added2 = scene.add_event(
    event_type="static",
    alias="my_second_event",
    filepath=utils.get_project_root() / "tests/test_resources/soundevents/music/000010.mp3",
    duration=10,
    scene_start=5.0,
    event_start=2.0,
    polar=True,
    position=[-45., 0., 0.5]
)
Warning: initializing context twice. Will destroy old context and create a new one.
CreateContext: Context created
2025-11-03 17:13:20.798 | INFO     | audiblelight.core:add_event:972 - Event added successfully: Static 'Event' with alias 'my_second_event', audio file '/home/huw-cheston/Documents/python_projects/AudibleLight/tests/test_resources/soundevents/music/000010.mp3' (unloaded, 0 augmentations), 1 emitter(s).

This example loads in a music file with an offset at 2 seconds and a duration of 10 seconds (i.e., seconds 2 – 12 will be used). The audio file will start 5 seconds in to the start of the scene. It will be placed 45 degrees to the front-left of the mic, level with the mic, and 0.5 meters away.

Note that, when dealing with multiple microphones added to a single Scene, as well as passing polar=True, we also need to pass the alias of the microphone to mic=..., so the correct offset can be calculated.

[5]:
scene.clear_microphones()
mic1 = scene.add_microphone(microphone_type="monocapsule", alias="mic_a")
mic2 = scene.add_microphone(microphone_type="monocapsule", alias="mic_b")

pol = scene.add_event(
    event_type="static",
    polar=True,
    mic="mic_a",
    alias="pol",
    position=[-45., 0., 0.5],
    duration=1
)
Warning: initializing context twice. Will destroy old context and create a new one.
CreateContext: Context created
Warning: initializing context twice. Will destroy old context and create a new one.
CreateContext: Context created
Warning: initializing context twice. Will destroy old context and create a new one.
CreateContext: Context created
Warning: initializing context twice. Will destroy old context and create a new one.
CreateContext: Context created
2025-11-03 17:13:22.305 | INFO     | audiblelight.core:add_event:972 - Event added successfully: Static 'Event' with alias 'pol', audio file '/home/huw-cheston/Documents/python_projects/AudibleLight/tests/test_resources/soundevents/music/007527.mp3' (unloaded, 0 augmentations), 1 emitter(s).

Now, the pol Event is placed so that it is -45 degrees from the mic_a MicArray.

[ ]:
scene.clear_microphone("mic_b")

Controlling duplicate audio files#

By default, we allow a single unique audio file to appear numerous times in a Scene. In practice, this is usually not a problem as we would expect fg_dir to contain many audio files, and therefore duplicates (especially overlapping duplicates) are in reality very rare.

If this behaviour is undesirable, the argument allow_duplicate_audios=False can be passed when initialising a Scene:

[ ]:
no_dupes_allowed = Scene(
    duration=60,
    sample_rate=44100,
    backend="rlr",
    backend_kwargs=dict(
        mesh=utils.get_project_root() / "tests/test_resources/meshes/Oyens.glb"
    ),
    fg_path=utils.get_project_root() / "tests/test_resources/soundevents/music",
    allow_duplicate_audios=False
)

# Add in some music files
for _ in range(2):
    no_dupes_allowed.add_event(event_type="static")

# Print the filepaths
events = no_dupes_allowed.get_events()
for ev in events:
    print(ev.filename)

Controlling same class Event objects#

We also allow multiple appearances of the same class by default. For instance, if we have a “waterTap” class and allow_duplicate_audios=False, we may have multiple instances of “waterTap” Events, but each will use a different audio file.

We can control this behaviour by setting allow_same_class_events=False when initialising a Scene. This will ensure that every Event added to the Scene has a unique class:

[5]:
no_same_class_events_allowed = Scene(
    duration=60,
    sample_rate=44100,
    backend="rlr",
    backend_kwargs=dict(
        mesh=utils.get_project_root() / "tests/test_resources/meshes/Oyens.glb"
    ),
    fg_path=utils.get_project_root() / "tests/test_resources/soundevents",
    allow_duplicate_audios=False,
    allow_same_class_events=False
)

# Add in a waterTap event
tap1 = utils.get_project_root() / "tests/test_resources/soundevents/waterTap/95709.wav"
no_same_class_events_allowed.add_event(
    event_type="static",
    filepath=tap1,
)

# If we try and add another waterTap object, we'll get an error
tap2 = utils.get_project_root() / "tests/test_resources/soundevents/waterTap/205695.wav"
try:
    no_same_class_events_allowed.add_event(
        event_type="static",
        filepath=tap2
    )
except ValueError as err:
    print(f"Raised error: {err}")
2025-11-04 15:39:44.303 | WARNING  | audiblelight.worldstate:load_mesh_navigation_waypoints:1878 - Cannot find waypoints for mesh Oyens inside default location (/home/huw-cheston/Documents/python_projects/AudibleLight/resources/waypoints/gibson). No navigation waypoints will be loaded.
CreateContext: Context created
Warning: initializing context twice. Will destroy old context and create a new one.
2025-11-04 15:39:46.087 | INFO     | audiblelight.core:add_event:1002 - Event added successfully: Static 'Event' with alias 'event000', audio file '/home/huw-cheston/Documents/python_projects/AudibleLight/tests/test_resources/soundevents/waterTap/95709.wav' (unloaded, 0 augmentations), 1 emitter(s).
CreateContext: Context created
Raised error: Audio file /home/huw-cheston/Documents/python_projects/AudibleLight/tests/test_resources/soundevents/waterTap/205695.wav uses a class that has already been added to the Scene (10). Either choose a different audio file, or set `Scene.allow_duplicate_audios=False`.

Inspecting Event objects#

For more information on the Event, we can use its alias to grab it from the Scene

[7]:
event2 = scene.get_event("pol")
print(event2)
Static 'Event' with alias 'pol', audio file '/home/huw-cheston/Documents/python_projects/AudibleLight/tests/test_resources/soundevents/music/007527.mp3' (unloaded, 0 augmentations), 1 emitter(s).

We can also load the audio file with Event.load_audio.

Note that this will happen automatically whenever scene.generate is called, so you don’t need to worry about making this part of your data generation code.

[8]:
audio = event2.load_audio(ignore_cache=True, normalize=True)
print(event2.is_audio_loaded)
True

Adding moving events#

Simple moving Events can be added in the same way as simple static Events.

[9]:
scene.clear_events()
moving1 = scene.add_event(event_type="moving", alias="my_first_moving_event")
CreateContext: Context created
Warning: initializing context twice. Will destroy old context and create a new one.
Placing trajectory...:   0%|          | 0/1 [00:00<?, ?it/s]
Warning: initializing context twice. Will destroy old context and create a new one.
2025-11-03 17:13:23.991 | INFO     | audiblelight.core:add_event:972 - Event added successfully: Moving 'Event' with alias 'my_first_moving_event', audio file '/home/huw-cheston/Documents/python_projects/AudibleLight/tests/test_resources/soundevents/maleSpeech/93856.wav' (unloaded, 0 augmentations), 2 emitter(s).
CreateContext: Context created

Moving Events expose the same parameters involved when creating a static Event (e.g., duration, offset), along with some new ones.

In particular, we can control:

  • the spatial velocity: how fast the event moves, in metres-per-second

  • the spatial resolution: how many IRs are created per second, in Hz

  • the trajectory: either linear, circular, or random

  • the starting position of the event.

[10]:
added2 = scene.add_event(
    event_type="moving",
    alias="my_second_moving_event",
    spatial_velocity=1.,
    spatial_resolution=0.5,
    shape="linear",
)
Placing trajectory...: 100%|██████████| 1/1 [00:00<00:00,  5.34it/s]
Placing trajectory...: 100%|██████████| 1/1 [00:00<00:00,  6.76it/s]
Placing trajectory...: 100%|██████████| 1/1 [00:00<00:00,  7.27it/s]
2025-11-03 17:13:24.501 | WARNING  | audiblelight.worldstate:define_trajectory:1966 - Number of points in trajectory (2) is smaller than 2, so it is being clamped to 2 internally. If this is happening frequently, consider increasing `resolution` (currently 0.500).
Placing trajectory...:   0%|          | 0/1 [00:00<?, ?it/s]
Warning: initializing context twice. Will destroy old context and create a new one.
CreateContext: Context created
2025-11-03 17:13:25.021 | INFO     | audiblelight.core:add_event:972 - Event added successfully: Moving 'Event' with alias 'my_second_moving_event', audio file '/home/huw-cheston/Documents/python_projects/AudibleLight/tests/test_resources/soundevents/femaleSpeech/236657.wav' (unloaded, 0 augmentations), 2 emitter(s).

A note on class labels#

By default, Event objects will try and define a class_id and class_label attribute using the 13 classes of the DCASE 2023 task 3. AudibleLight will attempt to extract these attributes from the filepath of the audio file if they are not passed when creating an Event.

To show what we mean, let’s try adding in a “femaleSpeech” audio event (class index 0 for this DCASE challenge)

[11]:
scene.clear_events()
female_speech = scene.add_event(
    filepath=utils.get_project_root() / "tests/test_resources/soundevents/femaleSpeech/236385.wav",
    event_type="static"
)

print(female_speech.class_id)
print(female_speech.class_label)
Warning: initializing context twice. Will destroy old context and create a new one.
CreateContext: Context created
Warning: initializing context twice. Will destroy old context and create a new one.
2025-11-03 17:13:25.636 | INFO     | audiblelight.core:add_event:972 - Event added successfully: Static 'Event' with alias 'event000', audio file '/home/huw-cheston/Documents/python_projects/AudibleLight/tests/test_resources/soundevents/femaleSpeech/236385.wav' (unloaded, 0 augmentations), 1 emitter(s).
CreateContext: Context created
0
femaleSpeech

Alternatively, if only one parameter is passed (e.g., just class_label), the missing attribute will be inferred from this using these DCASE classes.

[12]:
scene.clear_events()
female_speech = scene.add_event(
    filepath=utils.get_project_root() / "tests/test_resources/soundevents/femaleSpeech/236385.wav",
    event_type="static",
    class_id=0
)

print(female_speech.class_id)
print(female_speech.class_label)
Warning: initializing context twice. Will destroy old context and create a new one.
CreateContext: Context created
Warning: initializing context twice. Will destroy old context and create a new one.
CreateContext: Context created
2025-11-03 17:13:26.298 | INFO     | audiblelight.core:add_event:972 - Event added successfully: Static 'Event' with alias 'event000', audio file '/home/huw-cheston/Documents/python_projects/AudibleLight/tests/test_resources/soundevents/femaleSpeech/236385.wav' (unloaded, 0 augmentations), 1 emitter(s).
0
femaleSpeech

Of course, these IDs and labels can also be overridden:

[13]:
scene.clear_events()
custom_event = scene.add_event(
    event_type="static",
    alias="my_custom_event",
    class_id=100,
    class_label="customClass",
    filepath=utils.get_project_root() / "tests/test_resources/soundevents/femaleSpeech/236385.wav",
)
print(custom_event.class_id)
print(custom_event.class_label)
Warning: initializing context twice. Will destroy old context and create a new one.
CreateContext: Context created
Warning: initializing context twice. Will destroy old context and create a new one.
CreateContext: Context created
2025-11-03 17:13:26.904 | INFO     | audiblelight.core:add_event:972 - Event added successfully: Static 'Event' with alias 'my_custom_event', audio file '/home/huw-cheston/Documents/python_projects/AudibleLight/tests/test_resources/soundevents/femaleSpeech/236385.wav' (unloaded, 0 augmentations), 1 emitter(s).
100
customClass

Any metadata generated from the scene (e.g., generate_dcase2024_metadata) will adhere to the custom IDs.

But what if we want to use a different class mapping?#

It’s quite likely that you might want to use a different class mapping than the one defined in DCASE2023, task 3.

To solve this, you can pass in a custom mapping when creating a Scene. Let’s try a custom mapping that maps “femaleSpeech” to class index 2, this time:

[14]:
custom_scene = Scene(
    duration=60,
    sample_rate=44100,
    backend="rlr",
    backend_kwargs=dict(
        mesh=utils.get_project_root() / "tests/test_resources/meshes/Oyens.glb"
    ),
    fg_path=utils.get_project_root() / "tests/test_resources/soundevents",
    class_mapping=dict(
        femaleSpeech=2
    )
)
custom_scene.add_microphone(microphone_type="ambeovr")
2025-11-03 17:13:26.954 | WARNING  | audiblelight.worldstate:load_mesh_navigation_waypoints:1878 - Cannot find waypoints for mesh Oyens inside default location (/home/huw-cheston/Documents/python_projects/AudibleLight/resources/waypoints/gibson). No navigation waypoints will be loaded.
CreateContext: Context created
CreateContext: Context created
Warning: initializing context twice. Will destroy old context and create a new one.
[15]:
female_speech_custom = custom_scene.add_event(
    filepath=utils.get_project_root() / "tests/test_resources/soundevents/femaleSpeech/236385.wav",
    event_type="static"
)

print(female_speech_custom.class_id)
print(female_speech_custom.class_label)
CreateContext: Context created
Warning: initializing context twice. Will destroy old context and create a new one.
2025-11-03 17:13:29.257 | INFO     | audiblelight.core:add_event:972 - Event added successfully: Static 'Event' with alias 'event000', audio file '/home/huw-cheston/Documents/python_projects/AudibleLight/tests/test_resources/soundevents/femaleSpeech/236385.wav' (unloaded, 0 augmentations), 1 emitter(s).
2
femaleSpeech

You can also pass in the name of a particular task (e.g., DCASE 2025, task 4) and use the mapping directly, without having to define a dictionary.

Hint: to see which mappings can be used in this way, check out audiblelight.class_mappings.py

[16]:
dcase2025 = Scene(
    duration=60,
    sample_rate=44100,
    backend="rlr",
    backend_kwargs=dict(
        mesh=utils.get_project_root() / "tests/test_resources/meshes/Oyens.glb"
    ),
    fg_path=utils.get_project_root() / "tests/test_resources/soundevents",
    class_mapping="dcase2025task4"
)
2025-11-03 17:13:29.315 | WARNING  | audiblelight.worldstate:load_mesh_navigation_waypoints:1878 - Cannot find waypoints for mesh Oyens inside default location (/home/huw-cheston/Documents/python_projects/AudibleLight/resources/waypoints/gibson). No navigation waypoints will be loaded.
CreateContext: Context created

We can also use Scene.get_class_mapping to check the current class mapping:

[17]:
# Compare with https://dcase.community/challenge2025/task-spatial-semantic-segmentation-of-sound-scenes#audio-dataset
dcase2025.get_class_mapping()
[17]:
{'AlarmClock': 0,
 'BicycleBell': 1,
 'Blender': 2,
 'Buzzer': 3,
 'Clapping': 4,
 'Cough': 5,
 'CupboardOpenClose': 6,
 'Dishes': 7,
 'Doorbell': 8,
 'FootSteps': 9,
 'HairDryer': 10,
 'MechanicalFans': 11,
 'MusicalKeyboard': 12,
 'Percussion': 13,
 'Pour': 14,
 'Speech': 15,
 'Typing': 16,
 'VacuumCleaner': 17}