API reference¶
Every public class and function is importable from compas_acoustics.
Scene and model¶
Scene
¶
Bases: _PackageDtype, Data
The acoustic model of a room: its surfaces with materials, sources, receivers, and the impulse responses simulated for them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
|
required |
description
|
str
|
|
''
|
sampling_rate
|
int
|
The sample rate every simulation method runs at; default 48000. |
None
|
Examples:
>>> import compas_acoustics as ca
>>> scene = ca.Scene("office")
>>> scene.add_acoustic_objects(ca.AcousticObjectsLibrary.shoebox_room(6, 5, 3, materials=ca.AcousticMaterial("wall", 0.2, 0.1)))
>>> scene.add_source(ca.Source("talker", 1.5, 1.5, 1.6))
>>> scene.add_receiver(ca.Receiver("listener", 4.0, 3.0, 1.2))
>>> len(scene.acoustic_objects), len(scene.sources), len(scene.receivers)
(6, 1, 1)
>>> scene.sampling_rate
48000
acoustic_materials
property
writable
¶
The unique acoustic materials of the scene, keyed by name (as scene_materials).
scene_materials
property
¶
The unique acoustic materials used in the scene, keyed by material name.
add_impulse_response
¶
add_impulse_response(source: Source, receiver: Receiver, ir: ImpulseResponse, attribute: str = 'data') -> None
Store ir on the source-receiver edge under attribute.
Each method stores its responses under its name ('mono', 'binaural', 'ambisonics');
'data' holds the latest mono response.
impulse_responses
¶
Every response stored under attribute, keyed '<receiver guid>_<source guid>'.
populate_ir_graph
¶
populate_ir_graph(impulse_responses: Union[dict, Iterable[ImpulseResponse]], attribute: str = 'data') -> None
Replace every response stored under attribute; other attributes are kept.
simulate
¶
simulate(method) -> dict
Run a simulation method at sampling_rate and store its responses on the IR graph under method.name.
A mono method's responses also go under 'data', which analysis and auralisation read by default.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
method
|
[`SimulationMethod`][compas_acoustics.simulation_methods.base.SimulationMethod]
|
E.g. |
required |
Returns:
| Type | Description |
|---|---|
Dict[str, ImpulseResponse]
|
One per source-receiver pair inside the room, keyed |
AcousticObject
¶
AcousticObject(acoustic_geometry: Mesh, material: AcousticMaterial, x: float = 0, y: float = 0, z: float = 0, name: str = None, role: str = 'boundary', group: str = None)
Bases: _PackageDtype, Data
A surface of the scene with its material.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
acoustic_geometry
|
[`compas.datastructures.Mesh`][compas.datastructures.Mesh]
|
|
required |
material
|
[`compas_acoustics.AcousticMaterial`][compas_acoustics.materials.AcousticMaterial]
|
|
required |
x
|
float
|
The geometry's reference point. |
0
|
y
|
float
|
The geometry's reference point. |
0
|
z
|
float
|
The geometry's reference point. |
0
|
name
|
str
|
Default: the class name. |
None
|
role
|
str
|
|
'boundary'
|
group
|
str
|
The OBJ group the object was read from, for |
None
|
assign_materials_by_group
staticmethod
¶
Set the material of every object read from the named OBJ groups.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
objects
|
list of [`AcousticObject`][compas_acoustics.acoustic_object.AcousticObject]
|
From |
required |
materials
|
dict
|
|
required |
Returns:
| Type | Description |
|---|---|
list of [`AcousticObject`][compas_acoustics.acoustic_object.AcousticObject]
|
|
Examples:
assign_roles_by_group
staticmethod
¶
Set the role of every object read from the named OBJ groups.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
objects
|
list of [`AcousticObject`][compas_acoustics.acoustic_object.AcousticObject]
|
From |
required |
roles
|
dict
|
|
required |
Returns:
| Type | Description |
|---|---|
list of [`AcousticObject`][compas_acoustics.acoustic_object.AcousticObject]
|
|
Examples:
from_obj
classmethod
¶
One acoustic object per g group of a Wavefront OBJ file.
Faces before any g line are in 'default'; a file without g lines is grouped by
its o lines. A group that recurs is merged into the first. Objects are named
'<name>_<group>'. Coordinates are metres, not rounded (RoomGeometry welds them).
Faces may use i, i/j, i//k or i/j/k indices, negative ones relative; faces
with fewer than three distinct vertices are dropped. Every object is a boundary; mark
furniture with assign_roles_by_group.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filepath
|
str
|
|
required |
materials
|
[`AcousticMaterial`][compas_acoustics.materials.AcousticMaterial] or dict
|
One material for every group, or one per group name as |
None
|
name
|
str
|
The prefix of the objects' names; defaults to the file name. |
None
|
Returns:
| Type | Description |
|---|---|
list of [`AcousticObject`][compas_acoustics.acoustic_object.AcousticObject]
|
|
AcousticObjectsLibrary
¶
Factories of commonly used acoustic objects.
shoebox_room
classmethod
¶
shoebox_room(length: float, width: float, height: float, materials=None, sources: list = None, name: str = None)
A shoebox room as six surfaces, each its own AcousticObject.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
length
|
float
|
|
required |
width
|
float
|
|
required |
height
|
float
|
|
required |
materials
|
dict or [`AcousticMaterial`][compas_acoustics.materials.AcousticMaterial]
|
One material for every surface, or one per surface name ( |
None
|
sources
|
list
|
Sources attached to the floor. |
None
|
name
|
str
|
The prefix of the surfaces' names; default from the dimensions. |
None
|
Returns:
| Type | Description |
|---|---|
list of [`AcousticObject`][compas_acoustics.acoustic_object.AcousticObject]
|
Floor, right, front, left and back wall, ceiling. Facing +x from the centre, |
RoomGeometry
dataclass
¶
RoomGeometry(vertices: ndarray, faces: Tuple[Tuple[int, ...], ...], face_materials: Tuple[str, ...], face_names: Tuple[str, ...], face_roles: Tuple[str, ...], materials: Dict[str, SurfaceMaterial], is_closed: bool, open_edge: Optional[Tuple[Tuple[float, ...], Tuple[float, ...]]] = None, obstacle_faces: Tuple[Tuple[int, ...], ...] = (), obstacle_face_materials: Tuple[str, ...] = (), mergeable_faces: int = 0)
Every surface of a scene as one room: welded, oriented, materials on SYNTHESIS_BANDS.
Faces are listed boundary first, then the front and then the back copy of every obstacle face.
is_closed says whether the boundary faces close a volume; open_edge holds the end points of the
first edge that prevents it.
surface_area
property
¶
surface_area: float
Total area exposed to the air: Sabine's and Eyring's S, and the S of the mean free path 4 V / S.
surfaces
property
¶
(area, material) per material over the faces exposed to the air (see _exposed_faces).
volume
property
¶
volume: float
The air volume: the boundary's, less the volume each closed obstacle encloses. Defined only for a closed room.
area_normals
¶
The unit normal of every exposed face scaled by its area, shape (n_exposed, 3); the boundary faces come first.
faces_with_materials
¶
Every face as (vertices (k, 3), material name), obstacle copies included.
from_mesh
classmethod
¶
from_mesh(vertices, faces, face_materials, materials, obstacles=(), merge_coplanar: bool = False, weld_tolerance: float = 0.001) -> RoomGeometry
A room from shared vertices and faces; materials maps names to SurfaceMaterial, those in obstacles are obstacles.
from_scene
classmethod
¶
from_scene(scene, merge_coplanar: bool = True, weld_tolerance: float = 0.001) -> RoomGeometry
Collect, weld, orient and validate every surface of scene.
Boundary faces that close a volume are wound outward; otherwise they are kept as drawn, with a
UserWarning. Obstacle faces are stored twice, OBSTACLE_OFFSET either side and wound opposite,
since a wall reflects off one side only. merge_coplanar joins coplanar faces of one object and
material into larger walls (a triangulated CAD mesh); False keeps them and warns where it could.
weld_tolerance, in metres, is a CAD model's usual absolute tolerance.
is_inside
¶
is_inside(point) -> bool
Whether point is in the air: inside a closed boundary (anywhere in an open scene), outside every closed obstacle.
Decided by generalised winding numbers over the drawn faces, so the obstacle copies play no part.
to_pra
¶
to_pra(fs: int, max_order: int, ray_tracing: bool = False, air_absorption: bool = False, enclosure_only: bool = False, air: Optional[AirConditions] = None) -> Room
The pyroomacoustics room, one wall per face, materials resampled to its octave grid (nine bands at 48 kHz).
Bands above 8 kHz hold the 8 kHz value, where linear extrapolation could pass 1. A material without
scattering scatters DEFAULT_SCATTERING. enclosure_only leaves the obstacles out. The room
answers is_inside with is_inside. air (default AirConditions()) sets the speed of
sound (Cramer) and, with air_absorption, the ISO 9613-1 absorption, in place of pyroomacoustics'
own 343 m/s and absorption table.
Source
¶
Source(name: str, x: float, y: float, z: float, directivity: str = None, direction: Vector = None, sound_file: str = None)
Bases: _PackageDtype, Point
A sound source: position, directivity and facing, an optional sound file, and its level.
spl is the free-field level on its axis at 1 m per octave band, 125 Hz to 8 kHz, in dB re 20 uPa (the
voice presets give the talker levels of ANSI S3.5-1997). On the package scale the direct sound is
1 / (4 pi r) with gain 1 on axis, so Lp = spl + G - 20 dB (Analyser.sound_pressure_level).
Receiver
¶
Receiver(name: str, x: float, y: float, z: float, direction: Vector = None, radius=0.5, up: Vector = None)
Bases: _PackageDtype, Point
A receiver with an orientation, the frame of its ambisonic responses: x is direction, y its left, z up.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Lowercase, without spaces. |
required |
x
|
float
|
|
required |
y
|
float
|
|
required |
z
|
float
|
|
required |
direction
|
[`compas.geometry.Vector`][compas.geometry.Vector]
|
Where it faces; default +x. |
None
|
radius
|
float
|
In metres. |
0.5
|
up
|
[`compas.geometry.Vector`][compas.geometry.Vector]
|
Default +z; only its component orthogonal to |
None
|
frame
property
writable
¶
compas.geometry.Frame : The position and the axes of rotation; setting it sets direction and up.
rotation
property
¶
The orientation, a 3x3 proper rotation whose columns are the facing, left and up axes in world coordinates.
Its transpose takes a world vector to the receiver frame.
AirConditions
dataclass
¶
Air at a temperature (deg C), relative humidity (%) and static pressure (Pa), within Cramer's 0 to 30 deg C and 75 to 102 kPa.
Materials¶
AcousticMaterial
¶
AcousticMaterial(name: str, absorption_coefficients, scattering_coefficients: list = None, transmission_coefficients: list = None, description: str = None, category=None, data_origin: str = None)
Bases: _PackageDtype, Data
Absorption, scattering and transmission coefficients per octave band of Defaults.DEFAULT_FREQUENCY_BANDS.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
|
required |
absorption_coefficients
|
float or list of float
|
One per band, or one for every band. |
required |
scattering_coefficients
|
float or list of float
|
|
None
|
transmission_coefficients
|
float or list of float
|
|
None
|
description
|
str
|
|
None
|
category
|
[`MaterialCategory`][compas_acoustics.materials.MaterialCategory] or str
|
Default |
None
|
data_origin
|
str
|
Default |
None
|
scattering_coefficients_from_depth
¶
Set the scattering coefficients from a surface depth: s = s_max (1 - exp(-(k d)^2)) per band.
After Dalenbaeck (1995), Room acoustic prediction and auralization - how close can we get to reality?, ICA Trondheim; and Paetynen and Lokki (2010), Acta Acust. united Ac. 96(1).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
depth
|
float
|
The surface's characteristic depth, in metres. |
required |
s_max
|
float
|
Default 0.8. |
0.8
|
c
|
float
|
Speed of sound in m/s; default that of |
DEFAULT_SPEED_OF_SOUND
|
Returns:
| Type | Description |
|---|---|
list of float
|
|
MaterialCategory
¶
MaterialsLibrary
¶
MaterialsLibrary(library_path: str = None)
The materials of a folder of JSON files, one per material, looked up by name.
materials_by_category
property
¶
materials_by_category: dict
dict : Sorted material names per MaterialCategory that has any, in the categories' order.
Simulation methods¶
Binaural and Ambisonics need Python 3.11 or newer.
SimulationMethod
¶
Mono
¶
Mono(image_source_order: int = 3, ray_tracing: bool = True, air_absorption: bool = True, n_rays: Optional[int] = 20000, energy_thres: float = 1e-07, duration: Optional[float] = None, receiver_radius: float = 0.5, seed: Union[bool, int] = True, normalize: bool = True, air: Optional[AirConditions] = None)
Bases: SimulationMethod
Image sources up to image_source_order, and the stochastic ray tracer past it if ray_tracing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
image_source_order
|
int
|
Last specular order; with |
3
|
ray_tracing
|
bool
|
Materials without scattering coefficients scatter 0.05 in every band. |
True
|
air_absorption
|
bool
|
|
True
|
n_rays
|
int or None
|
Per source; None: a heuristic of at least 50000. |
20000
|
energy_thres
|
float
|
The product of its reflections in its least absorbed band at which a ray stops; the logged energy is that over the squared distance (Schroeder 2011, eq. 5.54), so the tail has decayed much further. |
1e-7
|
duration
|
float
|
Of the ray-traced responses, in seconds; default 1.5 times the longest Eyring reverberation time, within 0.5 to 12 s (10 s for a scene that closes no volume), with a warning at the cap. Without ray tracing the responses have their natural length. |
None
|
receiver_radius
|
float
|
In metres. |
0.5
|
seed
|
bool or int
|
True seeds with 42, an int with that value, False or None leaves the run unseeded
( |
True
|
normalize
|
bool
|
Whether the responses are peak-normalized views. |
True
|
air
|
AirConditions
|
Its speed of sound and, with |
None
|
Notes
Ray-tracing settings (n_rays to seed) changed with ray_tracing=False raise ValueError.
Examples:
>>> import compas_acoustics as ca
>>> scene = ca.Scene("office")
>>> scene.add_acoustic_objects(ca.AcousticObjectsLibrary.shoebox_room(6, 5, 3, materials=ca.AcousticMaterial("wall", 0.2, 0.1)))
>>> scene.add_source(ca.Source("talker", 1.5, 1.5, 1.6))
>>> scene.add_receiver(ca.Receiver("listener", 4.0, 3.0, 1.2))
>>> responses = scene.simulate(ca.Mono(image_source_order=2, ray_tracing=False))
>>> ir = next(iter(responses.values()))
>>> ir.sampling_rate, ir.n_channels, ir.generation["method"]
(48000, 1, 'mono')
Ray tracing, on by default, adds the late reflections; the seed makes a run repeatable.
>>> responses = scene.simulate(ca.Mono(n_rays=2000, duration=0.5))
>>> ir = next(iter(responses.values()))
>>> ir.ir.shape, ir.generation["seed"]
((24000,), 42)
Binaural
¶
Binaural(reference=None, hrtf=None, *, tail=None, image_source_order=3, n_slopes=1, decay_db=30.0, duration=None, directional_absorption=True, late_envelope=None, diffraction=False, air_absorption=None, seed=True, normalize=True, air=None, scattering=False)
Bases: _HybridMethod
Binaural room impulse responses: image sources, optional edge diffraction, a directional FDN.
The early field is the image sources up to image_source_order (and, with diffraction, edge
diffraction). The last order drives a feedback delay network of 96 lines, one per direction, whose decay
follows a target (Wendt et al. 2014), the count Kirsch et al. (2023) use offline. Every early path and
delay line is filtered with the HRIR measured nearest its direction. Needs Python >= 3.11 and a closed
room. Responses are ears left then right, stored under 'binaural'; generation["hrtf"] names the set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reference
|
(str, dict, Mono or None)
|
A package-scale mono response per pair for the decay target and the late envelope: a method's name on
the IR graph ( |
None
|
hrtf
|
str or path
|
|
None
|
Examples:
>>> import compas_acoustics as ca
>>> scene = ca.Scene("office")
>>> scene.add_acoustic_objects(ca.AcousticObjectsLibrary.shoebox_room(6, 5, 3, materials=ca.AcousticMaterial("wall", 0.2, 0.1)))
>>> scene.add_source(ca.Source("talker", 1.5, 1.5, 1.6))
>>> scene.add_receiver(ca.Receiver("listener", 4.0, 3.0, 1.2))
>>> ir = next(iter(scene.simulate(ca.Binaural(tail="eyring")).values()))
>>> ir.n_channels, ir.generation["hrtf"]
(2, 'KEMAR_FreeFieldComp_48kHz.sofa')
With a ray-traced reference the decay is fitted to a response you already have.
>>> reference = scene.simulate(ca.Mono(ray_tracing=True))
>>> responses = scene.simulate(ca.Binaural(reference="mono"))
Ambisonics
¶
Ambisonics(reference=None, sh_order=1, normalization='SN3D', *, tail=None, image_source_order=3, n_slopes=1, decay_db=30.0, duration=None, directional_absorption=True, late_envelope=None, diffraction=False, air_absorption=None, seed=True, normalize=True, air=None, scattering=False)
Bases: _HybridMethod
Ambisonic room impulse responses: image sources, optional edge diffraction, a directional FDN.
As Binaural, with every early path encoded at its direction and every delay line projected from
its direction at sh_order. Responses are ACN in normalization, stored under 'ambisonics'.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reference
|
(str, dict, Mono or None)
|
As |
None
|
sh_order
|
int
|
The network has 96 delay lines up to third order (Kirsch et al. 2023), above that the smallest
equal-area grid supporting the order. The input gain |
1
|
normalization
|
('SN3D', 'N3D')
|
ACN channel order, W = 1 for a unit plane wave. |
"SN3D"
|
Examples:
>>> import compas_acoustics as ca
>>> scene = ca.Scene("office")
>>> scene.add_acoustic_objects(ca.AcousticObjectsLibrary.shoebox_room(6, 5, 3, materials=ca.AcousticMaterial("wall", 0.2, 0.1)))
>>> scene.add_source(ca.Source("talker", 1.5, 1.5, 1.6))
>>> scene.add_receiver(ca.Receiver("listener", 4.0, 3.0, 1.2))
>>> ir = next(iter(scene.simulate(ca.Ambisonics(tail="eyring", sh_order=2)).values()))
>>> ir.n_channels, ir.ambisonic_order
(9, 2)
Results and analysis¶
ImpulseResponse
¶
ImpulseResponse(name: str, source: Source, receiver: Receiver, ir: ndarray, sampling_rate: int, normalized: bool = True, generation: dict = None, ambisonic_order: int = None, normalization: str = None, channel_order: str = None)
Bases: _PackageDtype, Data
An impulse response between a source and a receiver.
Stored at its raw level with its normalization factor, the peak of all channels. ir
is peak-normalized by default; denormalized and denormalize_group give the raw
level, which keeps distance and level differences between responses.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
|
required |
source
|
Source
|
|
required |
receiver
|
Receiver
|
|
required |
ir
|
ndarray
|
The raw response, (samples,) or (samples, channels). |
required |
sampling_rate
|
int
|
|
required |
normalized
|
bool
|
Whether |
True
|
generation
|
dict
|
The method and its settings; written to the JSON metadata on export. |
None
|
ambisonic_order
|
int
|
None for a mono or binaural response. |
None
|
normalization
|
str
|
|
None
|
channel_order
|
str
|
|
None
|
format
property
¶
str : 'mono', 'binaural' (two channels, no ambisonic order) or 'ambisonic'.
ir
property
writable
¶
np.ndarray : Peak-normalized when normalized; setting it sets the raw response.
metadata
property
¶
dict : The response and how it was generated, as written next to it on export.
normalization_factor
property
¶
float : Peak absolute value of the raw impulse response across all channels.
denormalize_group
staticmethod
¶
Raw impulse responses scaled together so the loudest peaks at 1.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
impulse_responses
|
list or dict of ImpulseResponse
|
|
required |
Returns:
| Type | Description |
|---|---|
list or dict of np.ndarray
|
In the container type of the input. |
direct_sound_index
¶
Sample of the direct sound.
On the package scale (generation['scale'] == 'package') the geometric one, distance / c,
even when early ray-traced bins are louder or an obstacle blocks it; otherwise the largest
sample of the omnidirectional channel.
from_wav
classmethod
¶
Read a WAV written by to_wav, restoring the raw level from its JSON metadata.
Without metadata the WAV is taken as the raw response.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filepath
|
str
|
|
required |
source
|
(Source, Receiver)
|
Used instead of the ones in the metadata. |
None
|
receiver
|
(Source, Receiver)
|
Used instead of the ones in the metadata. |
None
|
normalized
|
bool
|
Whether |
True
|
Returns:
| Type | Description |
|---|---|
ImpulseResponse
|
|
Analyser
¶
Room acoustic parameters of an impulse response.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ir
|
(list, ndarray or ImpulseResponse)
|
Shaped (samples,) or (samples, channels). Only channel 0 (the omnidirectional component of an
ambisonic response) is analysed. An |
required |
Examples:
>>> import compas_acoustics as ca
>>> scene = ca.Scene("office")
>>> scene.add_acoustic_objects(ca.AcousticObjectsLibrary.shoebox_room(6, 5, 3, materials=ca.AcousticMaterial("wall", 0.2, 0.1)))
>>> scene.add_source(ca.Source("talker", 1.5, 1.5, 1.6))
>>> scene.add_receiver(ca.Receiver("listener", 4.0, 3.0, 1.2))
>>> responses = scene.simulate(ca.Mono(ray_tracing=True, n_rays=2000, duration=0.5))
>>> analyser = ca.Analyser(next(iter(responses.values())))
>>> results = analyser.analyse()
>>> results["freqs"]
[125, 250, 500, 1000, 2000, 4000, 8000]
>>> results["T30_overall"] > 0
True
analyse
¶
analyse(ir=None) -> dict
Every parameter of _PARAM_NAMES per band and as '<name>_overall'.
The overall values of EDT, T20, T30, C50, C80, D50 and Ts average 500 and 1000 Hz (ISO 3382-1:2009 Table A.1); the others have their own.
center_time
¶
center_time(impulse_response=None) -> dict
Centre time Ts per band, in seconds from the broadband direct sound (ISO 3382-1), of the zero-phase bands.
clarity_definition
¶
clarity_definition(impulse_response=None) -> dict
C50, C80 and D50 per band (ISO 3382-1).
Early and late parts are cut from the broadband response before band filtering, so filter delay and ringing stay with the part they belong to.
direct_to_reverberant_ratio
¶
direct_to_reverberant_ratio(impulse_response=None) -> dict
DRR per band and in 700-4000 Hz.
The energy of the first 5 ms from the direct sound over the energy after it, in dB. The window
opens 1 ms early so that a band-limited arrival is held whole. 'DRR_overall' is theirs: a
second-order Butterworth band-pass of 700-4000 Hz, since 5 ms does not resolve the low octaves.
Per band the parts are cut before filtering, as for C50.
Returns:
| Type | Description |
|---|---|
dict
|
|
lateral_fraction
¶
lateral_fraction(impulse_response=None) -> dict
Early lateral energy fractions J_LF and J_LFC per band (ISO 3382-1:2009 Annex A).
J_LF: the figure-of-eight energy 5-80 ms after the direct sound over the omnidirectional energy
0-80 ms. J_LFC takes |p_L p| for p_L^2 (Kleiner 1989), a cosine instead of a cosine-squared
weighting of lateral arrivals (Bradley 1994). The figure-of-eight is the first-order dipole of an
ambisonic response, horizontal and perpendicular to the source direction, which is the geometric
one when the response carries its source and receiver, else the direct sound's first-order
intensity. Windows are cut before band filtering, as for C80.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
impulse_response
|
ImpulseResponse
|
An ambisonic response, ACN, SN3D or N3D. Default is the analyser's own. |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
|
plot_frequency_response
¶
Plot the magnitude response, with a 1/smooth octave smoothed one over it unless smooth is None.
print_table
¶
reverberation_times
¶
reverberation_times(impulse_response=None) -> dict
EDT, T20 and T30 per band (ISO 3382-1).
Schroeder (1965) backward integration of the zero-phase band (_band_from_onset),
from the direct sound to the last non-zero sample, normalized to 0 dB at its start, then
linear regression. No noise compensation, since a simulated response has no noise floor:
truncate a measured response at its noise floor first.
sound_pressure_level
¶
sound_pressure_level(source_spl=None, impulse_response=None, strength=None) -> dict
Sound pressure level per band from the source's level at 1 m and G.
Lp = spl + G - 20 dB: on the package scale G's reference, the free field at 10 m, is 20 dB
below the free field at 1 m, where spl is given (compas_acoustics.Source.spl).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_spl
|
float or list of float
|
The source's on-axis level at 1 m, per band of |
None
|
impulse_response
|
ImpulseResponse
|
A package-scale response; default is the analyser's own. |
None
|
strength
|
dict
|
G as |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
|
sound_strength
¶
sound_strength(reference_ir=None, impulse_response=None) -> dict
Strength G per band (ISO 3382-1): the response's energy over that of the free field at 10 m.
Both responses at their raw level: ImpulseResponse objects (used denormalized) or
raw arrays. The single number averages 500 and 1000 Hz.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reference_ir
|
ImpulseResponse or ndarray
|
The source's free-field response at 10 m, at the same sample rate. Default: the
package-scale free field |
None
|
impulse_response
|
ImpulseResponse or ndarray
|
Default is |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
|
speech_transmission_index
¶
speech_transmission_index(impulse_response=None, snr=inf) -> dict
STI and the modulation transfer index per octave band (IEC 60268-16:2020, indirect method).
Responses shorter than the 1.6 s of Section 6.2 are zero-padded, which assumes a full decay.
snr is the signal-to-noise ratio in dB, one value or one per octave band 125-8000 Hz.
Returns:
| Type | Description |
|---|---|
dict
|
|
stage_support
¶
stage_support(impulse_response=None) -> dict
ST_early and ST_late per band (Gade; ISO 3382-1:2009 Annex C), for source and receiver 1 m apart.
The energy 20-100 ms (ST_early) or 100-1000 ms (ST_late) after the direct sound over the energy of the first 10 ms, in dB; the windows are cut before band filtering. Single numbers average 250-2000 Hz.
Returns:
| Type | Description |
|---|---|
dict
|
|
EnergyMap
¶
Bases: _PackageDtype, Data
The energy of a scene's sources at many points, per octave band and time bin, in Pa^2 s / p0^2.
10 log10 of the sum over the bins is the sound pressure level in dB re 20 uPa (spl).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
array - like
|
The points, (n, 3). |
required |
inside
|
array - like
|
Whether each point is in the air of the room, (n,); the others hold no energy and read NaN. |
required |
bands
|
array - like
|
The octave bands' centres in Hz, (b,). |
required |
bin_size
|
float
|
The length of a time bin in seconds; bin |
required |
energy
|
array - like
|
(n, b, bins). |
required |
name
|
str
|
|
None
|
frames
¶
frames(frame_s: float = 0.012)
The broadband level per point in frames of frame_s seconds, for an animation of the energy arriving.
A frame is a whole number of bins: frame_s is rounded up to one.
Returns:
| Type | Description |
|---|---|
tuple of (np.ndarray, np.ndarray)
|
The frames' start times (k,), in seconds, and the levels (n, k) in dB: -inf before any energy arrives, NaN outside the room. |
from_scene
classmethod
¶
from_scene(scene, points, source_index=None, n_rays=None, image_source_order=1, duration=None, air_absorption=True, seed=True, ray_spacing=1.0) -> 'EnergyMap'
The energy map of scene's sources at points.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene
|
[`compas_acoustics.Scene`][compas_acoustics.scene.Scene]
|
|
required |
points
|
iterable of xyz
|
The points, in the room's coordinates. |
required |
source_index
|
int
|
One source by its index in |
None
|
n_rays
|
int
|
Rays per source; by default |
None
|
image_source_order
|
int
|
Image sources up to this order for every point, the rays past it. At least 1: at order 0 the ray tracer logs the direct path too, which would count it twice. |
1
|
duration
|
float
|
Seconds after the emission; by default 1.5 times the longest Eyring reverberation time, as the Mono method. |
None
|
air_absorption
|
bool
|
|
True
|
seed
|
bool or int
|
The rays' seed: True seeds with 42, an int with that value, False leaves them unseeded. |
True
|
ray_spacing
|
float
|
Default 1 m. The rays are traced to one receiver per cell of this size, the point of the cell nearest its centre, and their energy is interpolated to the other points; None traces them to every point. A run costs rays times receivers, the late energy varies slowly and a 0.5 m receiver sphere resolves nothing finer; the image sources stay exact at every point. |
1.0
|
Notes
Points outside the room, or inside a closed obstacle, are left out with one UserWarning.
spl
¶
The sound pressure level per point and band, (n, b), in dB; NaN outside the room.
spl_a
¶
The A-weighted total of the bands per point, (n,), in dB(A) (IEC 61672-1 weights at the band centres).
regularized_fitness
¶
Rays and reflection paths¶
Ray
¶
Ray(points, source=None, source_index: Optional[int] = None, ray_index: Optional[int] = None, direction=None, distance_offset: float = 0.0, name: Optional[str] = None)
Bases: _PackageDtype, Polyline
A ray traced through a scene, the polyline [source_position, hit_1, hit_2, ...].
Times are distances at Defaults().DEFAULT_SPEED_OF_SOUND.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
list
|
|
required |
source
|
[`compas_acoustics.Source`][compas_acoustics.source.Source]
|
|
None
|
source_index
|
int
|
The source's index in the scene. |
None
|
ray_index
|
int
|
The ray's index among those of its source. |
None
|
direction
|
[`compas.geometry.Vector`][compas.geometry.Vector] or list
|
The initial direction; default that of the first segment. |
None
|
distance_offset
|
float
|
The distance travelled before |
0.0
|
name
|
str
|
|
None
|
cumulative_distances
property
¶
The travelled distance from the ray origin at each vertex, including distance_offset.
total_distance
property
¶
total_distance: float
The total distance travelled by the ray, including distance_offset.
is_in_cone
¶
Whether the ray's direction is within half_angle_deg of axis, a cone with its apex at the origin.
up_to_distance
¶
A copy of the ray cut at distance from the source (distance_offset included); None: all.
Returns None if the ray has not emerged yet at distance.
up_to_reflection_order
¶
A copy of the ray with its first order segments; None: all.
ScatteredRay
¶
ScatteredRay(points, parent_ray_index: Optional[int] = None, energy: Optional[float] = None, origin_reflection_order: int = 0, **kwargs)
Bases: Ray
A scattered ray born at a reflection point of a specular ray.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
list
|
From the reflection point it scattered from. |
required |
parent_ray_index
|
int
|
|
None
|
energy
|
float
|
The scattered energy it carries. |
None
|
origin_reflection_order
|
int
|
The parent's segments up to that reflection point. |
0
|
**kwargs
|
{}
|
RayField
¶
Bases: _PackageDtype, Data
Traced rays, with filters and display.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rays
|
list of [`compas_acoustics.Ray`][compas_acoustics.rays.Ray]
|
The specular rays, each with its scattered rays in |
None
|
name
|
str
|
|
None
|
duration_ms
property
¶
duration_ms: float
The largest travel time of the specular rays in milliseconds, 0.0 when empty.
scattered_rays
property
¶
scattered_rays: List[ScatteredRay]
All scattered rays across every ray in the field.
display_in_viewer
¶
display_in_viewer(scene=None, reflection_order: Optional[int] = None, travel_time_ms: Optional[float] = None, show_specular: bool = True, show_scattered: bool = False, color=None, scattered_color=None, linewidth: float = 1.0, show: bool = True)
Display the rays, and the scene's geometry, sources and receivers when given, in a viewer.
reflection_order and travel_time_ms are those of truncated. With show=False
the viewer is returned without being opened.
filter
¶
A new field of the rays of source (object or index) and of ray_index (one or several).
from_scene
classmethod
¶
from_scene(scene, n_rays: int = 500, max_reflection_order: int = 10, direction=None, angle: Optional[float] = None, duration: Optional[float] = None, energy_thres: Optional[float] = None, sources=None, include_scattering: bool = False, scatter_density: int = 10, scatter_max_bounces: int = 1, scatter_band: Optional[int] = None, random_seed: Union[bool, int] = True)
Trace rays through the scene for display.
Each source emits with the density of its radiated energy, the square of its first-order pattern
p + (1 - p) cos(theta) about its direction; with a cone (direction and angle) all
n_rays go into the cone, with the same density. With include_scattering each hit spawns
scattered rays, their number and spread set by the scattering coefficient.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene
|
[`compas_acoustics.Scene`][compas_acoustics.scene.Scene]
|
|
required |
n_rays
|
int
|
Per source. |
500
|
max_reflection_order
|
int
|
|
10
|
direction
|
[`compas.geometry.Vector`][compas.geometry.Vector] or list
|
The axis of a cone to emit into, apex at each source. Requires |
None
|
angle
|
float
|
The cone's half angle in degrees. Requires |
None
|
duration
|
float
|
In seconds: a ray stops at the first reflection past the distance sound travels in it. |
None
|
energy_thres
|
float
|
A ray stops when the energy its reflections leave it, by the band mean of each wall's
absorption (and scattering, with |
None
|
sources
|
list of [`compas_acoustics.Source`][compas_acoustics.source.Source]
|
Default: all of the scene's. |
None
|
include_scattering
|
bool
|
|
False
|
scatter_density
|
int
|
Scattered rays per hit at scattering coefficient 1. |
10
|
scatter_max_bounces
|
int
|
Reflections traced for each scattered ray. |
1
|
scatter_band
|
int
|
The band whose scattering coefficient is used; default the mean of all. |
None
|
random_seed
|
bool or int
|
True seeds with 42, an int with that value, False or None leaves the scattering unseeded. |
True
|
Returns:
| Type | Description |
|---|---|
[`compas_acoustics.RayField`][compas_acoustics.rays.RayField]
|
|
particles
¶
particles(time_ms: float)
The position of every specular ray at time_ms (clamped to [0, duration_ms]), for a billiard view.
Returns:
| Type | Description |
|---|---|
tuple of (list of [`compas.geometry.Point`][compas.geometry.Point], list of int, list of int)
|
The positions, their rays' |
SpecularPath
¶
Bases: Ray
An image-source path [source_position, hit_1, ..., hit_order, receiver_position].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
list
|
|
required |
order
|
int
|
The number of reflections. |
required |
walls
|
list of int
|
The wall of each reflection, in path order: indices into |
required |
image
|
[`compas.geometry.Point`][compas.geometry.Point] or list
|
|
required |
receiver_index
|
int
|
The receiver's index in the scene. |
required |
**kwargs
|
{}
|
SpecularReflections
¶
SpecularReflections(paths: Optional[List[SpecularPath]] = None, name: Optional[str] = None)
Bases: RayField
The image-source paths between sources and receivers: a RayField of SpecularPath.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paths
|
list of [`SpecularPath`][compas_acoustics.rays.SpecularPath]
|
|
None
|
name
|
str
|
|
None
|
filter
¶
filter(source=None, ray_index: Optional[Union[int, List[int]]] = None, receiver_index: Optional[int] = None, order: Optional[Union[int, List[int]]] = None) -> SpecularReflections
As RayField.filter, and the paths to receiver_index of order (one or several).
from_scene
classmethod
¶
from_scene(scene, max_order: int = 3) -> SpecularReflections
The paths of the visible image sources, orders 0 to max_order, from every source to every receiver.
Only the last wall of each image is recorded, so each path is traced back from the receiver: through
that wall to the parent image, and on through whichever wall leads back to the source. An image found
twice (through an edge, from both wall orderings) is kept once. Sources and receivers outside the room
are left out with a UserWarning.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene
|
[`compas_acoustics.Scene`][compas_acoustics.scene.Scene]
|
|
required |
max_order
|
int
|
|
3
|
Returns:
| Type | Description |
|---|---|
[`SpecularReflections`][compas_acoustics.rays.SpecularReflections]
|
|
Audio¶
Auraliser
¶
Auraliser(name: str, impulse_responses, anechoic_sounds=None, description: str = None, sampling_rate: int = None, level: str = 'relative', headroom_db: float = -1.0)
Convolves impulse responses with their anechoic sounds and sums them.
The signal keeps the format of its responses (format): 'mono', 'binaural'
(two ears), or 'ambisonic' (ACN/SN3D, (order + 1)**2 channels at the highest order present;
N3D is converted). Responses of different formats cannot be mixed: there is no decoding.
Responses are used at their raw level, so their level differences are kept; level
sets the output level on export:
'relative': one gain for a group of renders, the loudest peaking atheadroom_db.'individual': each render peaks atheadroom_db.'none': no gain; warns above 0 dBFS.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Lowercase, without spaces. |
required |
impulse_responses
|
dict or list
|
A list of |
required |
anechoic_sounds
|
dict or list
|
File paths, or a dict of ids to dicts with |
None
|
description
|
str
|
|
None
|
sampling_rate
|
int
|
Responses and sounds are resampled to it. Default: that of the first response. |
None
|
level
|
str
|
|
'relative'
|
headroom_db
|
float
|
Target peak in dBFS for |
-1.0
|
Examples:
>>> import compas_acoustics as ca
>>> sound = ca.Defaults().ANECHOIC_SOUNDFILES_LIBRARY_PATH + "/female_speech.wav"
>>> scene = ca.Scene("office")
>>> scene.add_acoustic_objects(ca.AcousticObjectsLibrary.shoebox_room(6, 5, 3, materials=ca.AcousticMaterial("wall", 0.2, 0.1)))
>>> scene.add_source(ca.Source("talker", 1.5, 1.5, 1.6, sound_file=sound))
>>> scene.add_receiver(ca.Receiver("listener", 4.0, 3.0, 1.2))
>>> responses = scene.simulate(ca.Mono(ray_tracing=True, n_rays=2000, duration=0.5))
>>> auraliser = ca.Auraliser("office", list(responses.values()))
>>> auraliser.format, auraliser.convolve().shape[1]
('mono', 1)
format
property
¶
str : 'mono', 'binaural' or 'ambisonic', the format of the impulse responses and of the signal.
impulse_responses
property
writable
¶
dict : Impulse responses as (samples, channels) arrays at sampling_rate, ambisonic ones in ACN/SN3D.
output_channels
property
¶
int : Number of channels of the auralised signal: 1, 2, or (order + 1)**2 for ambisonics.
convolve
¶
Convolve each impulse response with its anechoic sound and sum, in format.
Responses that share a sound are summed first, so each sound is read and convolved once. Lower-order ambisonic responses are padded with zero channels to the highest order.
Returns:
| Type | Description |
|---|---|
ndarray
|
The auralised signal, shaped (samples, |
export_convolved_sound
¶
Write an auralised signal at its output level as a 32-bit float audio file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filepath
|
str
|
|
required |
convolved_sound
|
ndarray
|
None
|
|
gain
|
float
|
E.g. from |
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
The written signal, shaped (samples, channels), as float32. |
import_anechoic_sound
¶
An audio file as a mono (samples,) array at sampling_rate, multichannel files mixed down.
peak_dbfs
staticmethod
¶
Peak absolute value of a signal in dBFS (-inf for silence).
render_gains
staticmethod
¶
Gains that set the output level of a group of auralised signals.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
signals
|
list of np.ndarray
|
From |
required |
level
|
str
|
As |
'relative'
|
headroom_db
|
float
|
Target peak in dBFS; default -1. |
-1.0
|
Returns:
| Type | Description |
|---|---|
list of float
|
One gain per signal. |
AudioPlayer
¶
Plays a sound file or an array, on Windows and macOS.
Attributes:
| Name | Type | Description |
|---|---|---|
system |
str
|
|
sound_type |
str
|
|
duration
property
¶
The length of the array last played, in seconds; 0 for a file or nothing.
position
property
¶
Where the array's playback is, in seconds: it runs with the clock while playing, and holds when paused.
play
¶
Play a file path or an array; the other arguments are those of play_array, a file plays whole at its level.
play_array
¶
Play an array.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array
|
ndarray
|
(samples,) or (samples, channels). A mono signal plays on both channels. |
required |
sampling_rate
|
int
|
Default: |
required |
normalize
|
bool
|
Scale to a peak of 0.99; disable to play an auralisation at its rendered level. |
True
|
gain_db
|
float
|
Applied after the normalisation. |
0.0
|
start
|
float
|
In seconds from the beginning. |
0.0
|
Settings¶
Defaults
¶
DEFAULT_SPEED_OF_SOUND
property
¶
The speed of sound of AirConditions() (20 deg C, 50 %, 101325 Pa), in m/s.
Worker¶
The Python process the Grasshopper components compute in; a script can use it too.
client
¶
This session's worker, started on first use; None if no worker interpreter is configured.