aboutsummaryrefslogtreecommitdiff
path: root/Src/replicant/nsmp3/MPEGHeader.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/replicant/nsmp3/MPEGHeader.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/replicant/nsmp3/MPEGHeader.cpp')
-rw-r--r--Src/replicant/nsmp3/MPEGHeader.cpp170
1 files changed, 170 insertions, 0 deletions
diff --git a/Src/replicant/nsmp3/MPEGHeader.cpp b/Src/replicant/nsmp3/MPEGHeader.cpp
new file mode 100644
index 00000000..1971577e
--- /dev/null
+++ b/Src/replicant/nsmp3/MPEGHeader.cpp
@@ -0,0 +1,170 @@
+#include "MPEGHeader.h"
+#include <math.h>
+
+// [mpeg_version][layer][index]
+static const int bitrates[4][4][15] =
+{
+ {
+ // MPEG-2.5
+ { 0,},
+ { 0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000}, // Layer 3
+ { 0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000}, // Layer 2
+ { 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000}, // Layer 1
+ },
+
+ {
+ // invalid
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, },
+ },
+
+ {
+ // MPEG-2
+ { 0,},
+ { 0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000}, // Layer 3
+ { 0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000}, // Layer 2
+ { 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000}, // Layer 1
+ },
+
+ {
+ // MPEG-1
+ { 0,},
+ { 0, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000}, // Layer 3
+ { 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000}, // Layer 2
+ { 0, 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000}, // Layer 1
+ },
+};
+
+// [mpeg_version][index]
+static const int sample_rates[4][4] =
+{
+ {11025, 12000, 8000, 0}, // MPEG-2.5
+ {0, },
+ {22050, 24000, 16000, 0}, // MPEG-2
+ {44100, 48000, 32000, 0}, // MPEG-1
+};
+
+// [mpeg_version][layer]
+static const int samples_per_frame[4][4] =
+{
+ // Layer 3, Layer 2, Layer 1
+ { 0, 576, 1152, 384}, // MPEG2.5
+ { 0, },
+ { 0, 576, 1152, 384}, // MPEG2
+ { 0, 1152, 1152, 384}, // MPEG1
+};
+
+// [layer]
+static const int bits_per_slot[4] = { 0, 8, 8, 32 };
+
+void MPEGHeader::ReadBuffer(const uint8_t *buffer)
+{
+ sync = ((uint16_t)buffer[0] << 3) | (buffer[1] >> 5);
+ mpeg_version = (buffer[1] >> 3) & 3;
+ layer = (buffer[1] >> 1) & 3;
+ protection = (buffer[1]) & 1;
+ bitrate_index = (buffer[2] >> 4) & 0xF;
+ sample_rate_index = (buffer[2] >> 2) & 3;
+ padding_bit = (buffer[2] >> 1) & 1;
+ private_bit = buffer[2] & 1;
+ channel_mode = (buffer[3] >> 6) & 3;
+ mode_extension = (buffer[3] >> 4) & 3;
+ copyright = (buffer[3] >> 3) & 1;
+ original = (buffer[3] >> 2) & 1;
+ emphasis = (buffer[3]) & 3;
+}
+
+bool MPEGHeader::IsSync() const
+{
+ return sync == 0x07FF
+ && layer != LayerError
+ && mpeg_version != MPEG_Error
+ && bitrate_index != 15
+ && bitrate_index != 0
+ && sample_rate_index != 3
+ && !(mpeg_version == MPEG2 && layer != Layer3)
+ && !(mpeg_version == MPEG2_5 && layer != Layer3);
+}
+
+int MPEGHeader::GetBitrate() const
+{
+ return bitrates[mpeg_version][layer][bitrate_index];
+}
+
+int MPEGHeader::HeaderSize() const
+{
+ if (protection == CRC)
+ return 4 + 2; // 32bits frame header, 16bits CRC
+ else
+ return 4; // 32bits frame ehader
+}
+
+int MPEGHeader::GetSampleRate() const
+{
+ return sample_rates[mpeg_version][sample_rate_index];
+}
+
+bool MPEGHeader::IsCopyright() const
+{
+ return copyright == 1;
+}
+bool MPEGHeader::IsCRC() const
+{
+ return protection == CRC;
+}
+
+bool MPEGHeader::IsOriginal() const
+{
+ return original == 1;
+}
+
+int MPEGHeader::GetSamplesPerFrame() const
+{
+ return samples_per_frame[mpeg_version][layer];
+}
+
+int MPEGHeader::FrameSize() const
+{
+ int nBitsPerSlot;
+ int nAvgSlotsPerFrame;
+
+ nBitsPerSlot = bits_per_slot[layer];
+
+ nAvgSlotsPerFrame = (GetSamplesPerFrame() * (bitrates[mpeg_version][layer][bitrate_index] / nBitsPerSlot)) / sample_rates[mpeg_version][sample_rate_index];
+
+ return (nAvgSlotsPerFrame + padding_bit) * nBitsPerSlot / 8;
+}
+
+int MPEGHeader::GetLayer() const
+{
+ switch(layer)
+ {
+ case Layer1:
+ return 1;
+ case Layer2:
+ return 2;
+ case Layer3:
+ return 3;
+ default:
+ return 0;
+ }
+}
+
+int MPEGHeader::GetNumChannels() const
+{
+ switch(channel_mode)
+ {
+ case Stereo:
+ return 2;
+ case JointStereo:
+ return 2;
+ case DualChannel:
+ return 2;
+ case Mono:
+ return 1;
+ default:
+ return 0;
+ }
+}