Apologies that the following is an AI-generated report. I had to get help understanding how object positions were treated. It seems that objects can have an initial location for loudspeaker outputs (OLR) but they are moved to their initial positions for binaural (OBR).
Is this correct?
======================================
Object Initialization and Movement in liboar
This document explains how object-based audio elements are initialized and how their positions are updated during the first render call.
There is a key difference in behavior between Loudspeaker Rendering (OLR) and Binaural Rendering (OBR).
Summary
- Loudspeaker Rendering (OLR): Objects can be initialized to their starting position from the first call to render. If
oar_update_audio_element_metadata is called before oar_render, the object starts at the configured position immediately with no transition.
- Binaural Rendering (OBR): Objects will move from a default position to the configured position over the first render call, even if
oar_update_audio_element_metadata is called before oar_render.
- Default Position: The default position is Azimuth:
0.0°, Elevation: 0.0°, Distance: 1.0 (normalized).
Detailed Analysis
1. Loudspeaker Rendering (OLR)
When rendering to loudspeakers (e.g., Stereo, 5.1, 7.1.4), the Open Loudspeaker Renderer (OLR) is used.
Step 1: Element Addition
Calling oar_add_audio_element creates the renderer. For OLR, it does not initialize object positions with defaults in the processing channel. The processor vector remains empty.
- File: audio_element_renderer.c
- File: renderer.c (
impl->processors is initialized empty).
Step 2: Metadata Update (Before Render)
Calling oar_update_audio_element_metadata before render adds the metadata block to the processing channel.
- File: olr.c (
_metadata_update calls object_audio_renderer_add_metadatas).
- File: renderer.c (
renderer_impl_add_metadatas creates the processor if it doesn't exist and adds metadata).
Step 3: First Render
During the first oar_render, the block processor processes the queued metadata.
- File: block_processing_channel.c (
block_processing_channel_process calls _refil_processing_queue).
- File: interpret_object_metadata.c (
interpret_object_metadata_process handles the block).
Because this is the first block, self->last_block_end is UINT64_MAX (initialized in interpret_object_metadata_create at line 38).
if (self->last_block_end != UINT64_MAX &&
start_sample == self->last_block_end) {
interp_from = self->last_block_gains_to;
} else {
target_sample = start_sample;
interp_from = 0;
}
Since it goes to the else block, interp_from is NULL and target_sample equals start_sample.
This causes it to return a fixed_gains block instead of interp_gains:
} else if (target_sample != end_sample) {
return fixed_gains_create(target_sample, end_sample, interp_to, n);
}
- File: processing_block.c (
_fixed_gains_process applies the constant gains calculated from the configured position to the entire block).
Thus, the object starts immediately at the configured position.
2. Binaural Rendering (OBR)
When rendering to binaural (headphones), the Open Binaural Renderer (OBR) is used.
Step 1: Element Addition
Calling oar_add_audio_element triggers OBR to add the element and initialize the DSP.
- File: obr.c (
_set_attribute calls obr_add_audio_element).
- File: obr_impl.cc (
AddAudioElement calls InitializeDsp).
- File: obr_impl.cc (
InitializeDsp calls group.UpdateAmbisonicEncoder).
- File: processing_group.cc (
UpdateAmbisonicEncoder calls ambisonic_encoder_->SetSource with default positions).
The default positions are defined in AudioElementConfig constructor:
if (type == AudioElementType::kObjectMono) {
AudioObjectInputChannel input_channel("kMono", 0.0f, 0.0f, 1.0f);
object_channels_.push_back(input_channel);
}
- File: audio_element_config.cc (Default: Azimuth
0.0f, Elevation 0.0f, Distance 1.0f).
In AmbisonicEncoder::SetSource:
if (sources_.find(input_channel) == sources_.end()) {
SourceProperties source_properties{};
source_properties.current = {gain, azimuth, elevation, distance};
source_properties.target = source_properties.current;
sources_.insert({input_channel, source_properties});
return;
}
- File: ambisonic_encoder.cc
This initializes current and target in sources_ to the default position.
Step 2: Metadata Update (Before Render)
Calling oar_update_audio_element_metadata before render updates the position.
- File: obr_impl.cc (
UpdateObjectChannelPosition updates positions in audio_elements_ and calls UpdateAllAmbisonicEncoders -> UpdateAmbisonicEncoder -> SetSource).
In AmbisonicEncoder::SetSource:
// If the values are unchanged, do nothing.
SourceProperties& source_properties = sources_.at(input_channel);
if (source_properties.target.gain == gain && ... ) { return; }
// Update only the target parameters.
source_properties.target.gain = gain;
source_properties.target.azimuth = azimuth;
...
Since the source already exists in sources_ (from Step 1), it only updates the target parameters to the configured position. The current parameters remain at the default position.
Step 3: First Render
During the first render call, OBR processes the audio.
- File: ambisonic_encoder.cc (
ProcessPlanarAudioData is called).
It checks if interpolation is needed:
if (!params_equal(source_properties.current, source_properties.target)) {
fill_column(source_properties.current, column_start[in_ch]);
needs_interpolation[in_ch] = true;
}
Since current (default) != target (configured), needs_interpolation becomes true.
This forces per-frame interpolation:
for (size_t frame = 0; frame < num_frames; ++frame) {
float alpha = static_cast<float>(frame) / static_cast<float>(num_frames - 1);
// ... interpolate from column_start (default) to column_end (configured)
}
Thus, the object moves from the default position to the configured position over the duration of the first audio block.
After the block is processed, current is caught up to target (line 300), so subsequent blocks start from the configured position.
Conclusion
The behavior depends on the target output layout:
- For Loudspeaker layouts (OLR), objects can be initialized to their starting position from the first call to render by calling
oar_update_audio_element_metadata before oar_render.
- For Binaural layouts (OBR), it is not possible to avoid the initial transition. The object will always transition from the default position (
{0, 0, 1}) to the configured position during the first render block.
Apologies that the following is an AI-generated report. I had to get help understanding how object positions were treated. It seems that objects can have an initial location for loudspeaker outputs (OLR) but they are moved to their initial positions for binaural (OBR).
Is this correct?
======================================
Object Initialization and Movement in liboar
This document explains how object-based audio elements are initialized and how their positions are updated during the first render call.
There is a key difference in behavior between Loudspeaker Rendering (OLR) and Binaural Rendering (OBR).
Summary
oar_update_audio_element_metadatais called beforeoar_render, the object starts at the configured position immediately with no transition.oar_update_audio_element_metadatais called beforeoar_render.0.0°, Elevation:0.0°, Distance:1.0(normalized).Detailed Analysis
1. Loudspeaker Rendering (OLR)
When rendering to loudspeakers (e.g., Stereo, 5.1, 7.1.4), the Open Loudspeaker Renderer (OLR) is used.
Step 1: Element Addition
Calling
oar_add_audio_elementcreates the renderer. For OLR, it does not initialize object positions with defaults in the processing channel. The processor vector remains empty.impl->processorsis initialized empty).Step 2: Metadata Update (Before Render)
Calling
oar_update_audio_element_metadatabefore render adds the metadata block to the processing channel._metadata_updatecallsobject_audio_renderer_add_metadatas).renderer_impl_add_metadatascreates the processor if it doesn't exist and adds metadata).Step 3: First Render
During the first
oar_render, the block processor processes the queued metadata.block_processing_channel_processcalls_refil_processing_queue).interpret_object_metadata_processhandles the block).Because this is the first block,
self->last_block_endisUINT64_MAX(initialized ininterpret_object_metadata_createat line 38).Since it goes to the
elseblock,interp_fromisNULLandtarget_sampleequalsstart_sample.This causes it to return a
fixed_gainsblock instead ofinterp_gains:_fixed_gains_processapplies the constant gains calculated from the configured position to the entire block).Thus, the object starts immediately at the configured position.
2. Binaural Rendering (OBR)
When rendering to binaural (headphones), the Open Binaural Renderer (OBR) is used.
Step 1: Element Addition
Calling
oar_add_audio_elementtriggers OBR to add the element and initialize the DSP._set_attributecallsobr_add_audio_element).AddAudioElementcallsInitializeDsp).InitializeDspcallsgroup.UpdateAmbisonicEncoder).UpdateAmbisonicEncodercallsambisonic_encoder_->SetSourcewith default positions).The default positions are defined in
AudioElementConfigconstructor:0.0f, Elevation0.0f, Distance1.0f).In
AmbisonicEncoder::SetSource:This initializes
currentandtargetinsources_to the default position.Step 2: Metadata Update (Before Render)
Calling
oar_update_audio_element_metadatabefore render updates the position.UpdateObjectChannelPositionupdates positions inaudio_elements_and callsUpdateAllAmbisonicEncoders->UpdateAmbisonicEncoder->SetSource).In
AmbisonicEncoder::SetSource:Since the source already exists in
sources_(from Step 1), it only updates thetargetparameters to the configured position. Thecurrentparameters remain at the default position.Step 3: First Render
During the first render call, OBR processes the audio.
ProcessPlanarAudioDatais called).It checks if interpolation is needed:
Since
current(default) !=target(configured),needs_interpolationbecomestrue.This forces per-frame interpolation:
Thus, the object moves from the default position to the configured position over the duration of the first audio block.
After the block is processed,
currentis caught up totarget(line 300), so subsequent blocks start from the configured position.Conclusion
The behavior depends on the target output layout:
oar_update_audio_element_metadatabeforeoar_render.{0, 0, 1}) to the configured position during the first render block.