Task 416: .MPA File Format
Task 416: .MPA File Format
The .MPA file format is an audio file format for raw MPEG-1 or MPEG-2 Audio Layer II streams, as defined in the ISO/IEC 11172-3 and ISO/IEC 13818-3 standards.
- The properties intrinsic to the .MPA file format are the following frame header fields (the file is a sequence of audio frames, each with this structure, and no overall file header beyond the concatenated frames):
- Sync word (11 bits): Always 11111111111 to mark the start of a frame.
- Version (2 bits): The MPEG version (11 for MPEG-1, 10 for MPEG-2, 00 for MPEG-2.5, 01 reserved).
- Layer (2 bits): The audio layer (10 for Layer II).
- Protection bit (1 bit): 0 if the frame has a 16-bit CRC, 1 if no CRC.
- Bitrate index (4 bits): Index to the bitrate (values 0-15 mapping to specific kbit/s rates, depending on version and layer; e.g., for MPEG-1 Layer II, 0001 = 32 kbit/s, 1010 = 192 kbit/s).
- Sampling rate index (2 bits): Index to the sampling rate (depending on version; e.g., for MPEG-1, 00 = 44.1 kHz, 01 = 48 kHz, 10 = 32 kHz, 11 reserved).
- Padding bit (1 bit): 0 if no padding, 1 if an extra byte is added to the frame.
- Private bit (1 bit): Reserved for application-specific use (0 or 1).
- Channel mode (2 bits): The channel configuration (00 = stereo, 01 = joint stereo, 10 = dual channel, 11 = mono).
- Mode extension (2 bits): Additional details for joint stereo mode (specifies bands for intensity stereo or MS stereo).
- Copyright bit (1 bit): 0 if not copyrighted, 1 if copyrighted.
- Original bit (1 bit): 0 if copy, 1 if original.
- Emphasis (2 bits): Pre-emphasis applied (00 = none, 01 = 50/15 µs, 10 reserved, 11 = CCITT J.17).
Derived properties per frame include the actual bitrate (kbit/s), sampling rate (Hz), number of channels (1 or 2), and frame length (bytes, calculated as (144 * bitrate) / sampling_rate + padding for Layer II).
- Two direct download links for .MPA format files (note: the format is identical to .MP2 files, which are more commonly available for samples; these can be renamed to .MPA if needed):
- https://filesamples.com/samples/audio/mp2/sample1.mp2
- https://filesamples.com/samples/audio/mp2/sample2.mp2
- Here is the embedded HTML/JavaScript for a Ghost blog post that allows drag-and-drop of a .MPA file and dumps the properties to the screen (it parses the first frame header and displays the properties; assumes the file is valid and starts with a frame):
Drag and drop .MPA file here
- Python class:
import struct
import os
class MPAParsing:
def __init__(self, filepath):
self.filepath = filepath
self.properties = {}
self.data = None
def decode_read(self):
with open(self.filepath, 'rb') as f:
self.data = f.read()
# Find first sync
offset = 0
while offset < len(self.data) - 4:
if self.data[offset] == 0xFF and (self.data[offset+1] & 0xE0) == 0xE0:
break
offset += 1
if offset >= len(self.data) - 4:
print("No valid MPA frame found.")
return
header = struct.unpack('>I', self.data[offset:offset+4])[0]
version_index = (header >> 19) & 3
layer_index = (header >> 17) & 3
crc = (header >> 16) & 1
bitrate_index = (header >> 12) & 15
sampling_index = (header >> 10) & 3
padding = (header >> 9) & 1
private_bit = (header >> 8) & 1
channel_index = (header >> 6) & 3
mode_ext = (header >> 4) & 3
copyright = (header >> 3) & 1
original = (header >> 2) & 1
emphasis = header & 3
self.properties = {
'Version index': version_index,
'Layer index': layer_index,
'Protection bit': crc,
'Bitrate index': bitrate_index,
'Sampling rate index': sampling_index,
'Padding bit': padding,
'Private bit': private_bit,
'Channel mode index': channel_index,
'Mode extension': mode_ext,
'Copyright bit': copyright,
'Original bit': original,
'Emphasis': emphasis
}
def print_properties(self):
if not self.properties:
print("No properties decoded.")
return
for key, value in self.properties.items():
print(f"{key}: {value}")
def write(self, new_filepath):
if not self.data:
# Create a dummy file if no data
# Use example values for MPEG-1 Layer II, 192 kbit/s, 44.1 kHz, stereo, no padding, no CRC
version = 3 # 11
layer = 2 # 10
crc = 1 # no CRC
bitrate_index = 10 # 192 kbit/s for M1L2
sampling_index = 0 # 44.1
padding = 0
private = 0
channel = 0 # stereo
mode_ext = 0
copyright = 0
original = 1
emphasis = 0
header_int = (0xFFF << 21) | (version << 19) | (layer << 17) | (crc << 16) | (bitrate_index << 12) | (sampling_index << 10) | (padding << 9) | (private << 8) | (channel << 6) | (mode_ext << 4) | (copyright << 3) | (original << 2) | emphasis
header = struct.pack('>I', header_int)
bitrate = 192000 # bps
sampling = 44100
frame_size = (144 * bitrate // sampling) + padding
dummy_data = b'\x00' * (frame_size - 4)
self.data = header + dummy_data
with open(new_filepath, 'wb') as f:
f.write(self.data)
# Example usage:
# parser = MPAParsing('example.mpa')
# parser.decode_read()
# parser.print_properties()
# parser.write('new.mpa')
- Java class:
import java.io.*;
import java.nio.*;
public class MPAParsing {
private String filepath;
private byte[] data;
private int[] properties = new int[12]; // For the 12 fields
public MPAParsing(String filepath) {
this.filepath = filepath;
}
public void decodeRead() throws IOException {
File file = new File(filepath);
data = new byte[(int) file.length()];
try (FileInputStream fis = new FileInputStream(file)) {
fis.read(data);
}
// Find first sync
int offset = 0;
while (offset < data.length - 4) {
if ((data[offset] & 0xFF) == 0xFF && (data[offset + 1] & 0xE0) == 0xE0) {
break;
}
offset++;
}
if (offset >= data.length - 4) {
System.out.println("No valid MPA frame found.");
return;
}
ByteBuffer bb = ByteBuffer.wrap(data, offset, 4).order(ByteOrder.BIG_ENDIAN);
int header = bb.getInt();
properties[0] = (header >> 19) & 3; // version
properties[1] = (header >> 17) & 3; // layer
properties[2] = (header >> 16) & 1; // crc
properties[3] = (header >> 12) & 15; // bitrate index
properties[4] = (header >> 10) & 3; // sampling index
properties[5] = (header >> 9) & 1; // padding
properties[6] = (header >> 8) & 1; // private
properties[7] = (header >> 6) & 3; // channel
properties[8] = (header >> 4) & 3; // mode ext
properties[9] = (header >> 3) & 1; // copyright
properties[10] = (header >> 2) & 1; // original
properties[11] = header & 3; // emphasis
}
public void printProperties() {
String[] keys = {"Version index", "Layer index", "Protection bit", "Bitrate index", "Sampling rate index", "Padding bit", "Private bit", "Channel mode index", "Mode extension", "Copyright bit", "Original bit", "Emphasis"};
for (int i = 0; i < keys.length; i++) {
System.out.println(keys[i] + ": " + properties[i]);
}
}
public void write(String newFilepath) throws IOException {
if (data == null) {
// Create dummy
int version = 3;
int layer = 2;
int crc = 1;
int bitrateIndex = 10;
int samplingIndex = 0;
int padding = 0;
int privateBit = 0;
int channel = 0;
int modeExt = 0;
int copyright = 0;
int original = 1;
int emphasis = 0;
int header = (0xFFF << 21) | (version << 19) | (layer << 17) | (crc << 16) | (bitrateIndex << 12) | (samplingIndex << 10) | (padding << 9) | (privateBit << 8) | (channel << 6) | (modeExt << 4) | (copyright << 3) | (original << 2) | emphasis;
ByteBuffer bb = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
bb.putInt(header);
byte[] headerBytes = bb.array();
int bitrate = 192000;
int sampling = 44100;
int frameSize = (144 * bitrate / sampling) + padding;
data = new byte[frameSize];
System.arraycopy(headerBytes, 0, data, 0, 4);
// Dummy data already zeros
}
try (FileOutputStream fos = new FileOutputStream(newFilepath)) {
fos.write(data);
}
}
// Example usage:
// public static void main(String[] args) throws IOException {
// MPAParsing parser = new MPAParsing("example.mpa");
// parser.decodeRead();
// parser.printProperties();
// parser.write("new.mpa");
// }
}
- JavaScript class:
class MPAParsing {
constructor(filepath) {
this.filepath = filepath;
this.properties = {};
this.data = null;
}
async decodeRead() {
// Note: In Node.js, use fs module
const fs = require('fs');
this.data = fs.readFileSync(this.filepath);
let offset = 0;
while (offset < this.data.length - 4) {
if (this.data[offset] === 0xFF && (this.data[offset + 1] & 0xE0) === 0xE0) {
break;
}
offset++;
}
if (offset >= this.data.length - 4) {
console.log('No valid MPA frame found.');
return;
}
const header = (this.data[offset] << 24) | (this.data[offset + 1] << 16) | (this.data[offset + 2] << 8) | this.data[offset + 3];
this.properties = {
versionIndex: (header >> 19) & 3,
layerIndex: (header >> 17) & 3,
protectionBit: (header >> 16) & 1,
bitrateIndex: (header >> 12) & 15,
samplingIndex: (header >> 10) & 3,
paddingBit: (header >> 9) & 1,
privateBit: (header >> 8) & 1,
channelModeIndex: (header >> 6) & 3,
modeExtension: (header >> 4) & 3,
copyrightBit: (header >> 3) & 1,
originalBit: (header >> 2) & 1,
emphasis: header & 3
};
}
printProperties() {
if (Object.keys(this.properties).length === 0) {
console.log('No properties decoded.');
return;
}
for (const [key, value] of Object.entries(this.properties)) {
console.log(`${key}: ${value}`);
}
}
write(newFilepath) {
if (!this.data) {
// Create dummy
const version = 3;
const layer = 2;
const crc = 1;
const bitrateIndex = 10;
const samplingIndex = 0;
const padding = 0;
const privateBit = 0;
const channel = 0;
const modeExt = 0;
const copyright = 0;
const original = 1;
const emphasis = 0;
const header = (0xFFF << 21) | (version << 19) | (layer << 17) | (crc << 16) | (bitrateIndex << 12) | (samplingIndex << 10) | (padding << 9) | (privateBit << 8) | (channel << 6) | (modeExt << 4) | (copyright << 3) | (original << 2) | emphasis;
const headerBuffer = new Uint32Array([header]);
const headerBytes = new Uint8Array(headerBuffer.buffer).reverse(); // Big endian
const bitrate = 192000;
const sampling = 44100;
const frameSize = (144 * bitrate / sampling) + padding;
this.data = new Uint8Array(frameSize);
this.data.set(headerBytes, 0);
// Dummy data zeros
}
const fs = require('fs');
fs.writeFileSync(newFilepath, this.data);
}
}
// Example usage:
// const parser = new MPAParsing('example.mpa');
// await parser.decodeRead();
// parser.printProperties();
// parser.write('new.mpa');
- C class (struct-based, with functions; compile with std=c99 or later):
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
typedef struct {
char* filepath;
uint8_t* data;
size_t size;
int properties[12];
} MPAParsing;
MPAParsing* mpa_create(const char* filepath) {
MPAParsing* parser = malloc(sizeof(MPAParsing));
parser->filepath = strdup(filepath);
parser->data = NULL;
parser->size = 0;
memset(parser->properties, 0, sizeof(parser->properties));
return parser;
}
void mpa_decode_read(MPAParsing* parser) {
FILE* f = fopen(parser->filepath, "rb");
if (!f) return;
fseek(f, 0, SEEK_END);
parser->size = ftell(f);
fseek(f, 0, SEEK_SET);
parser->data = malloc(parser->size);
fread(parser->data, 1, parser->size, f);
fclose(f);
size_t offset = 0;
while (offset < parser->size - 4) {
if (parser->data[offset] == 0xFF && (parser->data[offset + 1] & 0xE0) == 0xE0) {
break;
}
offset++;
}
if (offset >= parser->size - 4) {
printf("No valid MPA frame found.\n");
return;
}
uint32_t header = (parser->data[offset] << 24) | (parser->data[offset + 1] << 16) | (parser->data[offset + 2] << 8) | parser->data[offset + 3];
parser->properties[0] = (header >> 19) & 3;
parser->properties[1] = (header >> 17) & 3;
parser->properties[2] = (header >> 16) & 1;
parser->properties[3] = (header >> 12) & 15;
parser->properties[4] = (header >> 10) & 3;
parser->properties[5] = (header >> 9) & 1;
parser->properties[6] = (header >> 8) & 1;
parser->properties[7] = (header >> 6) & 3;
parser->properties[8] = (header >> 4) & 3;
parser->properties[9] = (header >> 3) & 1;
parser->properties[10] = (header >> 2) & 1;
parser->properties[11] = header & 3;
}
void mpa_print_properties(MPAParsing* parser) {
const char* keys[12] = {"Version index", "Layer index", "Protection bit", "Bitrate index", "Sampling rate index", "Padding bit", "Private bit", "Channel mode index", "Mode extension", "Copyright bit", "Original bit", "Emphasis"};
for (int i = 0; i < 12; i++) {
printf("%s: %d\n", keys[i], parser->properties[i]);
}
}
void mpa_write(MPAParsing* parser, const char* new_filepath) {
if (!parser->data) {
// Create dummy
uint32_t version = 3;
uint32_t layer = 2;
uint32_t crc = 1;
uint32_t bitrate_index = 10;
uint32_t sampling_index = 0;
uint32_t padding = 0;
uint32_t private_bit = 0;
uint32_t channel = 0;
uint32_t mode_ext = 0;
uint32_t copyright = 0;
uint32_t original = 1;
uint32_t emphasis = 0;
uint32_t header = (0xFFF << 21) | (version << 19) | (layer << 17) | (crc << 16) | (bitrate_index << 12) | (sampling_index << 10) | (padding << 9) | (private_bit << 8) | (channel << 6) | (mode_ext << 4) | (copyright << 3) | (original << 2) | emphasis;
uint32_t bitrate = 192000;
uint32_t sampling = 44100;
uint32_t frame_size = (144 * bitrate / sampling) + padding;
parser->data = calloc(frame_size, 1);
parser->data[0] = (header >> 24) & 0xFF;
parser->data[1] = (header >> 16) & 0xFF;
parser->data[2] = (header >> 8) & 0xFF;
parser->data[3] = header & 0xFF;
parser->size = frame_size;
}
FILE* f = fopen(new_filepath, "wb");
if (f) {
fwrite(parser->data, 1, parser->size, f);
fclose(f);
}
}
void mpa_destroy(MPAParsing* parser) {
free(parser->filepath);
free(parser->data);
free(parser);
}
// Example usage:
// int main() {
// MPAParsing* parser = mpa_create("example.mpa");
// mpa_decode_read(parser);
// mpa_print_properties(parser);
// mpa_write(parser, "new.mpa");
// mpa_destroy(parser);
// return 0;
// }