/// <summary> /// Returns the calculated frame length (including header /// and CRC) /// </summary> /// <returns></returns> /// <exception cref="InvalidOperationException"> /// CanCalculateFrameLength is false /// </exception> public static int CalculateFrameLength(Mp3FrameHeader fh) { if (null == fh) { throw new ArgumentNullException("fh"); } if (fh.Version == MpegVersion.Reserved) { throw new InvalidOperationException("This frame has a reserved version"); } int scaleFactor; int slotSize; switch (fh.Layer) { case MpegLayer.Layer1: scaleFactor = L1_SCALE; slotSize = L1_SLOTSIZE; break; case MpegLayer.Layer2: case MpegLayer.Layer3: scaleFactor = L23_SCALE; slotSize = L23_SLOTSIZE; break; case MpegLayer.Reserved: throw new InvalidOperationException("This frame has a reserved layer"); default: Debug.Fail(UnexpectedException.Message); throw new UnexpectedException(); } try { int paddingSlots = fh.HasPadding ? 1 : 0; int crcSize = fh.HasCRC ? Mp3Frame.CRC_SIZE : 0; int numSlots = scaleFactor * CalculateBitrate(fh) / CalculateSamplerate(fh) + paddingSlots; int dataSize = numSlots * slotSize; return dataSize + crcSize; } catch (InvalidOperationException e) { // I know this is brittle. Fortunately I've got unit test power if (e.Message.Contains("bitrate")) { throw new InvalidOperationException("Cannot calculate bitrate"); } else { throw new InvalidOperationException("Cannot calculate samplerate"); } } catch { Debug.Fail(UnexpectedException.Message); throw new UnexpectedException(); } }
/// <summary> /// Bitrate /// </summary> /// <exception cref="InvalidOperationException"> /// Bitrate is free or invalid, or the version or layer is reserved /// </exception> public static int CalculateBitrate(Mp3FrameHeader fh) { if (null == fh) { throw new ArgumentNullException("fh"); } if (fh.HasFreeBitrate) { throw new InvalidOperationException("This frame has a free bitrate"); } if (fh.HasInvalidBitrate) { throw new InvalidOperationException("This frame has an invalid bitrate"); } return BITRATE_TABLE[GetBitrateTableIndex(fh), fh.BitrateIndex]; }
public void CalculateBitrate_HasFreeTest() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_BR_FREE]); Mp3FrameHeaderRules.CalculateBitrate(h); }
/// <summary> /// True if this represents a valid MPEG frame /// </summary> /// <remarks> /// This does not indicate a valid MP3 frame /// </remarks> public static bool IsValid(Mp3FrameHeader fh) { if (null == fh) { throw new ArgumentNullException("fh"); } bool isInvalid = !fh.HasFrameSync || fh.Version == MpegVersion.Reserved || fh.Layer == MpegLayer.Reserved || fh.HasInvalidBitrate || fh.HasReservedSamplerate || fh.Emphasis == MpegEmphasis.Reserved || HasInvalidBitrateForChannelMode(fh); return !isInvalid; }
/// <summary> /// The samplerate for this frame is known, if the /// sample rate is not reserved and the mpeg version is not reserved /// </summary> public static bool CanCalculateSamplerate(Mp3FrameHeader fh) { if (null == fh) { throw new ArgumentNullException("fh"); } return !(fh.HasReservedSamplerate || fh.Version == MpegVersion.Reserved); }
/// <summary> /// If a bitrate can be calculated from the frame header /// (i.e. if CalculateBitrate won't throw) /// </summary> public static bool CanCalculateBitrate(Mp3FrameHeader fh) { if (null == fh) { throw new ArgumentNullException("fh"); } return !( fh.HasFreeBitrate || fh.HasInvalidBitrate || fh.Version == MpegVersion.Reserved || fh.Layer == MpegLayer.Reserved); }
public static int CalculatePayloadLength(Mp3FrameHeader fh) { return CalculateFrameLength(fh) - Mp3FrameHeader.HEADER_SIZE - (fh.HasCRC ? Mp3Frame.CRC_SIZE : 0); }
public void HasInvalidBitrateForChannelMode_Test() { h = new Mp3FrameHeader(TEST_HEADER[0]); Assert.That(Mp3FrameHeaderRules.HasInvalidBitrateForChannelMode(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[1]); Assert.That(Mp3FrameHeaderRules.HasInvalidBitrateForChannelMode(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[2]); Assert.That(Mp3FrameHeaderRules.HasInvalidBitrateForChannelMode(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[3]); Assert.That(Mp3FrameHeaderRules.HasInvalidBitrateForChannelMode(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[4]); Assert.That(Mp3FrameHeaderRules.HasInvalidBitrateForChannelMode(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[5]); Assert.That(Mp3FrameHeaderRules.HasInvalidBitrateForChannelMode(h), Is.True); }
public void CalculateFrameLength_ReservedVersionTest() { h = new Mp3FrameHeader(TEST_HEADER[3]); Mp3FrameHeaderRules.CalculateFrameLength(h); }
public void CalculateFrameLength_ReservedLayerTest() { h = new Mp3FrameHeader(TEST_HEADER[4]); Mp3FrameHeaderRules.CalculateFrameLength(h); }
public void CalculateFrameLength_NoSamplerateTest() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_SR_RESERVED]); Mp3FrameHeaderRules.CalculateFrameLength(h); }
public void CalculateFrameLength_NoBitrateTest() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_BR_FREE]); Mp3FrameHeaderRules.CalculateFrameLength(h); }
public void CalculateBitrate_Test() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_BR_128]); Assert.That(Mp3FrameHeaderRules.CalculateBitrate(h), Is.EqualTo(128000)); }
public void CalculateBitrate_ReservedLayerTest() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_BR_LR]); Mp3FrameHeaderRules.CalculateBitrate(h); }
public void CalculateBitrate_HasInvalidTest() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_BR_INVALID]); Mp3FrameHeaderRules.CalculateBitrate(h); }
public void CanCalculateFrameLength_Test() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_OK]); Assert.That(Mp3FrameHeaderRules.CanCalculateFrameLength(h), Is.True); h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_LR]); Assert.That(Mp3FrameHeaderRules.CanCalculateFrameLength(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_BR_INVALID]); Assert.That(Mp3FrameHeaderRules.CanCalculateFrameLength(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_BR_FREE]); Assert.That(Mp3FrameHeaderRules.CanCalculateFrameLength(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_SR_RESERVED]); Assert.That(Mp3FrameHeaderRules.CanCalculateFrameLength(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_VR]); Assert.That(Mp3FrameHeaderRules.CanCalculateFrameLength(h), Is.False); }
public void CanCalculateSamplerate_Test() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_SR_RESERVED]); Assert.That(Mp3FrameHeaderRules.CanCalculateSamplerate(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[THIDX_BR_VR]); Assert.That(Mp3FrameHeaderRules.CanCalculateSamplerate(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[THIDX_SMOKE]); Assert.That(Mp3FrameHeaderRules.CanCalculateSamplerate(h), Is.True); }
public void CalculateFrameLength_Test() { // V25, Layer 1, no padding h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_V25L1_NO_PADDING]); Assert.That(Mp3FrameHeaderRules.CalculateFrameLength(h), Is.EqualTo(624)); // V25, Layer 1, padding h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_V25L1_PADDING]); Assert.That(Mp3FrameHeaderRules.CalculateFrameLength(h), Is.EqualTo(132)); // V2, Layer 2, no padding h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_V2L2_NO_PADDING]); Assert.That(Mp3FrameHeaderRules.CalculateFrameLength(h), Is.EqualTo(1296)); // V2, Layer 2, padding h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_V2L2_PADDING]); Assert.That(Mp3FrameHeaderRules.CalculateFrameLength(h), Is.EqualTo(145)); // V1, Layer 3, no padding h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_V1L3_NO_PADDING]); Assert.AreEqual(112000, Mp3FrameHeaderRules.CalculateBitrate(h)); Assert.AreEqual(32000, Mp3FrameHeaderRules.CalculateSamplerate(h)); Assert.That(Mp3FrameHeaderRules.CalculateFrameLength(h), Is.EqualTo(504)); // V1, Layer 3, padding h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_V1L3_PADDING]); Assert.That(Mp3FrameHeaderRules.CalculateFrameLength(h), Is.EqualTo(169)); // Add a CRC h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_WITH_CRC]); Assert.That(Mp3FrameHeaderRules.CalculateFrameLength(h), Is.EqualTo(171)); }
public void IsValid_Test() { h = new Mp3FrameHeader(TEST_HEADER[0]); Assert.That(Mp3FrameHeaderRules.IsValid(h), Is.True); h = new Mp3FrameHeader(TEST_HEADER[1]); Assert.That(Mp3FrameHeaderRules.IsValid(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[2]); Assert.That(Mp3FrameHeaderRules.IsValid(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[3]); Assert.That(Mp3FrameHeaderRules.IsValid(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[4]); Assert.That(Mp3FrameHeaderRules.IsValid(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[5]); Assert.That(Mp3FrameHeaderRules.IsValid(h), Is.False); }
public void CalculatePayloadLength_CantCalculateTest() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_BR_FREE]); Mp3FrameHeaderRules.CalculatePayloadLength(h); }
/// <summary> /// Get the samplerate /// </summary> /// <exception cref="InvalidOperationException"> /// HasReservedSamplerate is true or mpeg version is reserved /// </exception> public static int CalculateSamplerate(Mp3FrameHeader fh) { if (null == fh) { throw new ArgumentNullException("fh"); } if (fh.HasReservedSamplerate) { throw new InvalidOperationException("This frame has a reserved samplerate"); } if (fh.Version == MpegVersion.Reserved) { throw new InvalidOperationException("This frame has a reserved version"); } switch (fh.Version) { case MpegVersion.V1: return SAMPLERATE_TABLE[SRIDX_V1, fh.SamplerateIndex]; case MpegVersion.V2: return SAMPLERATE_TABLE[SRIDX_V2, fh.SamplerateIndex]; case MpegVersion.V25: return SAMPLERATE_TABLE[SRIDX_V25, fh.SamplerateIndex]; default: Debug.Fail(UnexpectedException.Message); throw new UnexpectedException(); } }
public void CalculatePayloadLength_Test() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_V1L3_PADDING]); Assert.That(Mp3FrameHeaderRules.CalculatePayloadLength(h), Is.EqualTo(169 - 4)); h = new Mp3FrameHeader(TEST_HEADER[THIDX_LEN_WITH_CRC]); Assert.That(Mp3FrameHeaderRules.CalculatePayloadLength(h), Is.EqualTo(171 - 6)); }
/// <summary> /// The frame length can be calculated /// </summary> /// <remarks> The frame length depends on the bitrate, /// samplerate, and layer. /// /// Header is invalid if false</remarks> /// <returns></returns> public static bool CanCalculateFrameLength(Mp3FrameHeader fh) { // Layer is also needed in the calculation, but // that's taken into account by CanCalculateBitrate return CanCalculateBitrate(fh) && CanCalculateSamplerate(fh); }
public void CalculateSamplerate_HasReservedTest() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_SR_RESERVED]); Mp3FrameHeaderRules.CalculateSamplerate(h); }
/// <summary> /// Determines if the header claims a valid /// combination of bitrate and channel mode /// </summary> /// <remarks> /// Frame is invalid if true /// </remarks> public static bool HasInvalidBitrateForChannelMode(Mp3FrameHeader fh) { if (null == fh) { throw new ArgumentNullException("fh"); } if (fh.Layer != MpegLayer.Layer2) { return false; } if (fh.HasFreeBitrate || fh.HasInvalidBitrate) { return false; } switch (CalculateBitrate(fh)) { case 32000: case 48000: case 56000: case 80000: if (fh.ChannelMode == MpegChannelMode.SingleChannel) { return false; } else { return true; } case 224000: case 256000: case 320000: case 384000: if (fh.ChannelMode != MpegChannelMode.SingleChannel) { return false; } else { return true; } default: return false; } }
public void CalculateSamplerate_ReservedVersionTest() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_BR_VR]); Mp3FrameHeaderRules.CalculateSamplerate(h); }
private static int GetBitrateTableIndex(Mp3FrameHeader fh) { // This is gorgeous // Could also be done using more tables switch (fh.Version) { case MpegVersion.V1: switch (fh.Layer) { case MpegLayer.Layer1: return BRIDX_V1L1; case MpegLayer.Layer2: return BRIDX_V1L2; case MpegLayer.Layer3: return BRIDX_V1L3; case MpegLayer.Reserved: break; default: Debug.Fail(UnexpectedException.Message); throw new UnexpectedException(); } break; case MpegVersion.V2: case MpegVersion.V25: switch (fh.Layer) { case MpegLayer.Layer1: return BRIDX_V2L1; case MpegLayer.Layer2: return BRIDX_V2L2; case MpegLayer.Layer3: return BRIDX_V2L3; case MpegLayer.Reserved: break; default: Debug.Fail(UnexpectedException.Message); throw new UnexpectedException(); } break; case MpegVersion.Reserved: throw new InvalidOperationException("This frame does not specify a version"); default: Debug.Fail(UnexpectedException.Message); throw new UnexpectedException(); } throw new InvalidOperationException("This frame does not specify a layer"); }
public void CalculateSamplerate_Test() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_SMOKE]); Assert.That(Mp3FrameHeaderRules.CalculateSamplerate(h), Is.EqualTo(44100)); h = new Mp3FrameHeader(TEST_HEADER[THIDX_SR00_V25]); Assert.That(Mp3FrameHeaderRules.CalculateSamplerate(h), Is.EqualTo(11025)); }
public void CanCalculateBitrate_Test() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_BR_128]); Assert.That(Mp3FrameHeaderRules.CanCalculateBitrate(h), Is.True); h = new Mp3FrameHeader(TEST_HEADER[THIDX_BR_FREE]); Assert.That(Mp3FrameHeaderRules.CanCalculateBitrate(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[THIDX_BR_INVALID]); Assert.That(Mp3FrameHeaderRules.CanCalculateBitrate(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[THIDX_BR_VR]); Assert.That(Mp3FrameHeaderRules.CanCalculateBitrate(h), Is.False); h = new Mp3FrameHeader(TEST_HEADER[THIDX_BR_LR]); Assert.That(Mp3FrameHeaderRules.CanCalculateBitrate(h), Is.False); }
public void ChannelMode_Test() { h = new Mp3FrameHeader(TEST_HEADER[THIDX_CM_STEREO]); Assert.That(h.ChannelMode, Is.EqualTo(MpegChannelMode.Stereo)); h = new Mp3FrameHeader(TEST_HEADER[THIDX_CM_JS]); Assert.That(h.ChannelMode, Is.EqualTo(MpegChannelMode.JointStereo)); h = new Mp3FrameHeader(TEST_HEADER[THIDX_CM_DUAL]); Assert.That(h.ChannelMode, Is.EqualTo(MpegChannelMode.DualChannel)); h = new Mp3FrameHeader(TEST_HEADER[THIDX_CM_MONO]); Assert.That(h.ChannelMode, Is.EqualTo(MpegChannelMode.SingleChannel)); }