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")),