diff --git a/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioElementMetadata.cs b/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioElementMetadata.cs
index 78c3145c..987d8f9e 100644
--- a/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioElementMetadata.cs
+++ b/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioElementMetadata.cs
@@ -73,7 +73,7 @@ public void Read(BitExtractor extractor, bool alternateObjectPresent, int object
if (elementIndex == objectElementIndex) {
ObjectElement(extractor, objectCount, bedOrISFObjects);
} else { // Other elements are unused by encoders
- blockOffsetFactor = new short[] { -1 };
+ blockOffsetFactor = new short[] { (short)(-1 - elementIndex) };
}
extractor.Position = endPos; // Padding
}
diff --git a/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioElementMetadataMetadata.cs b/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioElementMetadataMetadata.cs
index b80475b3..cefbf346 100644
--- a/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioElementMetadataMetadata.cs
+++ b/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioElementMetadataMetadata.cs
@@ -1,21 +1,35 @@
using System.Collections.Generic;
+using System.Linq;
using Cavern.Format.Common;
namespace Cavern.Format.Decoders.EnhancedAC3 {
partial class OAElementMD : IMetadataSupplier {
+ ///
public ReadableMetadata GetMetadata() {
+ if (blockOffsetFactor[0] < 0) {
+ return new ReadableMetadata(new[] {
+ new ReadableMetadataHeader("Object Audio Element Metadata (Unknown Element)", new[] {
+ new ReadableMetadataField("oa_element_id_idx", "Type of the Object Audio Element", -1 - blockOffsetFactor[0]),
+ })
+ });
+ }
+
List headers = new List {
- new ReadableMetadataHeader("Object Audio Element Metadata", new[] {
+ new ReadableMetadataHeader("Object Audio Element Metadata (Object Element)", new[] {
new ReadableMetadataField("sample_offset", "Offset from the frame beginning in samples", sampleOffset),
new ReadableMetadataField("num_obj_info_blocks", "Number of block update info blocks", blockOffsetFactor.Length)
})
};
- if (infoBlocks != null) {
- for (int obj = 0; obj < updateLast.Length; ++obj) {
- for (int blk = 0; blk < infoBlocks[obj].Length; ++blk) {
- headers.AddRange(infoBlocks[obj][blk].GetMetadata().Headers);
- }
+
+ int channels = 0;
+ for (int obj = 0; obj < updateLast.Length; ++obj) {
+ for (int blk = 0; blk < infoBlocks[obj].Length; ++blk) {
+ ObjectInfoBlock block = infoBlocks[obj][blk];
+ string title = block.IsBed ?
+ $"Bed {++channels} Info Block {blk + 1}" :
+ $"Object {obj - channels + 1} Info Block {blk + 1}";
+ headers.AddRange(block.GetMetadata().Headers.Select(x => new ReadableMetadataHeader(title, x.Fields)));
}
}
return new ReadableMetadata(headers);
diff --git a/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioMetadata.cs b/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioMetadata.cs
index 40193fb5..1b2be676 100644
--- a/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioMetadata.cs
+++ b/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioMetadata.cs
@@ -28,7 +28,7 @@ partial class ObjectAudioMetadata {
/// Bed channels used. The first dimension is the element ID, the second is one bit for each channel,
/// in the order of .
///
- bool[][] bedAssignment = new bool[0][];
+ bool[][] bedAssignment;
///
/// Use intermediate spatial format (ISF), which has a few fixed layouts.
@@ -163,6 +163,8 @@ void ProgramAssignment(BitExtractor extractor) {
bedAssignment = new bool[1][];
bedAssignment[0] = new bool[(int)NonStandardBedChannel.Max];
bedAssignment[0][(int)NonStandardBedChannel.LowFrequencyEffects] = true;
+ } else {
+ bedAssignment = new bool[0][];
}
} else {
int contentDescription = extractor.Read(4);
diff --git a/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioMetadataMetadata.cs b/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioMetadataMetadata.cs
index 44163f34..240cac6f 100644
--- a/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioMetadataMetadata.cs
+++ b/Cavern.Format/Decoders/EnhancedAC3/ObjectAudioMetadataMetadata.cs
@@ -8,10 +8,16 @@ partial class ObjectAudioMetadata : IMetadataSupplier {
/// Gets the metadata for this codec in a human-readable format.
///
public ReadableMetadata GetMetadata() {
+ bool hasLFE = bedAssignment.Length == 1 && bedAssignment[0][(int)NonStandardBedChannel.LowFrequencyEffects];
List headers = new List {
new ReadableMetadataHeader("Object Audio MetaData header", new[] {
- new ReadableMetadataField("object_count", "Number of rendered dynamic objects", ObjectCount),
- new ReadableMetadataField("oa_element_count", "Number of Object Audio Element blocks", elements.Length)
+ new ReadableMetadataField("object_count", "Total number of audio objects, including static and dynamic", ObjectCount),
+ new ReadableMetadataField("oa_element_count", "Number of Object Audio Element blocks", elements.Length),
+ new ReadableMetadataField("b_dyn_object_only_program", "The program only contains dynamic objects other than the LFE",
+ bedAssignment.Length == 0 || hasLFE),
+ new ReadableMetadataField("b_lfe_present", "The LFE channel is present in an object-only program", hasLFE),
+ new ReadableMetadataField("num_bed_instances", "Number of bed channels or channel pairs", bedAssignment.Length),
+ new ReadableMetadataField("num_dynamic_objects", "Number of dynamic objects", ObjectCount - bedAssignment.Length),
})
};
for (int i = 0; i < elements.Length; i++) {
diff --git a/Cavern.Format/Decoders/EnhancedAC3/ObjectInfoBlock.cs b/Cavern.Format/Decoders/EnhancedAC3/ObjectInfoBlock.cs
index b78dfe64..6ddcba18 100644
--- a/Cavern.Format/Decoders/EnhancedAC3/ObjectInfoBlock.cs
+++ b/Cavern.Format/Decoders/EnhancedAC3/ObjectInfoBlock.cs
@@ -11,6 +11,11 @@ partial class ObjectInfoBlock {
///
public bool ValidPosition { get; private set; }
+ ///
+ /// This object is not dynamic, but used as a bed channel.
+ ///
+ public bool IsBed => anchor == ObjectAnchor.Speaker;
+
///
/// This frame contains the difference from the last object position instead of an exact position.
///
diff --git a/Cavern.Format/Decoders/EnhancedAC3/ObjectInfoBlockMetadata.cs b/Cavern.Format/Decoders/EnhancedAC3/ObjectInfoBlockMetadata.cs
index 987d9f9b..14d9af44 100644
--- a/Cavern.Format/Decoders/EnhancedAC3/ObjectInfoBlockMetadata.cs
+++ b/Cavern.Format/Decoders/EnhancedAC3/ObjectInfoBlockMetadata.cs
@@ -5,6 +5,7 @@
namespace Cavern.Format.Decoders.EnhancedAC3 {
partial class ObjectInfoBlock : IMetadataSupplier {
+ ///
public ReadableMetadata GetMetadata() => new ReadableMetadata(new List {
new ReadableMetadataHeader("Object Info Block", new[] {
new ReadableMetadataField("object_gain", "Object gain", gain < 0 ? "reuse" : QMath.GainToDb(gain).ToString("0 dB")),