Task 046: .AU File Type
Task 046: .AU File Type
.AU File Format Specifications
The .AU file format, also known as the Sun audio format, is a simple audio container introduced by Sun Microsystems. It is primarily associated with Unix-based systems and supports various audio encodings, with a focus on big-endian byte order. The format consists of a fixed 24-byte header, followed by an optional variable-length information (annotation) chunk, and then the audio data. All integer values in the header are 32-bit unsigned integers stored in big-endian format.
1. List of Properties Intrinsic to the .AU File Format
The properties refer to the structural elements defined in the file header and associated metadata, which are essential to interpreting the file's content. These include:
- Magic Number: A 4-byte identifier, always set to the ASCII string ".snd" (hexadecimal: 2E 73 6E 64), confirming the file type.
- Data Offset: A 4-byte unsigned integer indicating the byte offset from the start of the file to the beginning of the audio data section. This value is at least 24 (the minimum header size) and accounts for the optional information chunk.
- Data Size: A 4-byte unsigned integer specifying the length of the audio data in bytes. If unknown, this is set to 0xFFFFFFFF (all bits set).
- Encoding: A 4-byte unsigned integer defining the audio data encoding format. Common values include:
- 1: 8-bit μ-law (ISDN).
- 2: 8-bit linear PCM.
- 3: 16-bit linear PCM.
- 4: 24-bit linear PCM.
- 5: 32-bit linear PCM.
- 6: 32-bit IEEE floating-point.
- 7: 64-bit IEEE floating-point.
- Other values may include ADPCM variants (e.g., 23 for G.722 ADPCM).
- Sample Rate: A 4-byte unsigned integer representing the sampling frequency in Hertz (samples per second), such as 8000, 11025, or 44100.
- Channels: A 4-byte unsigned integer indicating the number of audio channels (e.g., 1 for mono, 2 for stereo).
- Information Chunk (Annotation): A variable-length string (length = Data Offset - 24 bytes), typically a NULL-terminated ASCII description or metadata about the audio content. This is optional but always present if the data offset exceeds 24.
These properties are derived directly from the file's binary structure and are independent of external file system attributes.
2. Two Direct Download Links for .AU Files
- https://filesamples.com/samples/audio/au/sample3.au
- https://filesamples.com/samples/audio/au/sample4.au
These links provide sample .AU audio files suitable for testing.
3. HTML/JavaScript for Drag-and-Drop .AU File Property Dump
The following is a self-contained HTML page with embedded JavaScript that enables a user to drag and drop a .AU file. Upon dropping, it reads the file, decodes the header, and displays the properties on the screen.
4. Python Class for .AU File Handling
The following Python class can open a .AU file, decode its header, read and print the properties, and write a new .AU file with specified properties and dummy audio data (for demonstration).
import struct
import os
class AUFileHandler:
def __init__(self, filename=None):
self.filename = filename
self.magic = b''
self.data_offset = 0
self.data_size = 0
self.encoding = 0
self.sample_rate = 0
self.channels = 0
self.info = b''
if filename and os.path.exists(filename):
self.read()
def read(self):
with open(self.filename, 'rb') as f:
# Read header (24 bytes)
header = f.read(24)
if len(header) < 24:
raise ValueError("Invalid .AU file: Header too short")
self.magic, self.data_offset, self.data_size, self.encoding, self.sample_rate, self.channels = struct.unpack('>4sIIIII', header)
if self.magic != b'.snd':
raise ValueError("Invalid .AU file: Magic number mismatch")
# Read info chunk
info_length = self.data_offset - 24
self.info = f.read(info_length).split(b'\x00', 1)[0].decode('ascii', errors='ignore')
def print_properties(self):
print(f"Magic Number: {self.magic.decode('ascii')}")
print(f"Data Offset: {self.data_offset}")
print(f"Data Size: {self.data_size if self.data_size != 0xFFFFFFFF else 'Unknown (0xFFFFFFFF)'}")
print(f"Encoding: {self.encoding}")
print(f"Sample Rate: {self.sample_rate} Hz")
print(f"Channels: {self.channels}")
print(f"Information Chunk: {self.info or 'None'}")
def write(self, output_filename, audio_data=b'', info='Sample AU File', data_size=0xFFFFFFFF):
info_bytes = info.encode('ascii') + b'\x00' # NULL-terminated
info_length = len(info_bytes)
self.data_offset = 24 + info_length
self.data_size = len(audio_data) if data_size == 0xFFFFFFFF else data_size
header = struct.pack('>4sIIIII', b'.snd', self.data_offset, self.data_size, self.encoding, self.sample_rate, self.channels)
with open(output_filename, 'wb') as f:
f.write(header)
f.write(info_bytes)
f.write(audio_data)
# Example usage:
# handler = AUFileHandler('sample.au')
# handler.print_properties()
# handler.write('output.au', audio_data=b'\x00' * 1024, encoding=3, sample_rate=44100, channels=2)
5. Java Class for .AU File Handling
The following Java class can open a .AU file, decode its header, read and print the properties to the console, and write a new .AU file with specified properties and dummy audio data.
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
public class AUFileHandler {
private String filename;
private String magic;
private int dataOffset;
private int dataSize;
private int encoding;
private int sampleRate;
private int channels;
private String info;
public AUFileHandler(String filename) {
this.filename = filename;
if (filename != null && new File(filename).exists()) {
read();
}
}
public void read() {
try (FileInputStream fis = new FileInputStream(filename);
DataInputStream dis = new DataInputStream(fis)) {
byte[] magicBytes = new byte[4];
dis.readFully(magicBytes);
magic = new String(magicBytes, StandardCharsets.US_ASCII);
if (!magic.equals(".snd")) {
throw new IOException("Invalid .AU file: Magic number mismatch");
}
dataOffset = dis.readInt();
dataSize = dis.readInt();
encoding = dis.readInt();
sampleRate = dis.readInt();
channels = dis.readInt();
int infoLength = dataOffset - 24;
byte[] infoBytes = new byte[infoLength];
dis.readFully(infoBytes);
int nullIndex = 0;
while (nullIndex < infoLength && infoBytes[nullIndex] != 0) nullIndex++;
info = new String(infoBytes, 0, nullIndex, StandardCharsets.US_ASCII);
} catch (IOException e) {
System.err.println("Error reading .AU file: " + e.getMessage());
}
}
public void printProperties() {
System.out.println("Magic Number: " + magic);
System.out.println("Data Offset: " + dataOffset);
System.out.println("Data Size: " + (dataSize == -1 ? "Unknown (0xFFFFFFFF)" : dataSize));
System.out.println("Encoding: " + encoding);
System.out.println("Sample Rate: " + sampleRate + " Hz");
System.out.println("Channels: " + channels);
System.out.println("Information Chunk: " + (info.isEmpty() ? "None" : info));
}
public void write(String outputFilename, byte[] audioData, String infoStr, int dataSizeParam) throws IOException {
byte[] infoBytes = (infoStr + "\0").getBytes(StandardCharsets.US_ASCII);
int infoLength = infoBytes.length;
this.dataOffset = 24 + infoLength;
this.dataSize = (dataSizeParam == -1) ? audioData.length : dataSizeParam;
try (FileOutputStream fos = new FileOutputStream(outputFilename);
DataOutputStream dos = new DataOutputStream(fos)) {
dos.writeBytes(".snd");
dos.writeInt(dataOffset);
dos.writeInt(this.dataSize);
dos.writeInt(encoding);
dos.writeInt(sampleRate);
dos.writeInt(channels);
dos.write(infoBytes);
dos.write(audioData);
}
}
// Example usage:
// public static void main(String[] args) {
// AUFileHandler handler = new AUFileHandler("sample.au");
// handler.printProperties();
// byte[] dummyData = new byte[1024];
// handler.write("output.au", dummyData, "Sample AU File", -1);
// }
}
6. JavaScript Class for .AU File Handling
The following JavaScript class (for Node.js) can open a .AU file, decode its header, read and print the properties to the console, and write a new .AU file with specified properties and dummy audio data.
const fs = require('fs');
class AUFileHandler {
constructor(filename = null) {
this.filename = filename;
this.magic = '';
this.dataOffset = 0;
this.dataSize = 0;
this.encoding = 0;
this.sampleRate = 0;
this.channels = 0;
this.info = '';
if (filename && fs.existsSync(filename)) {
this.read();
}
}
read() {
const buffer = fs.readFileSync(this.filename);
const dataView = new DataView(buffer.buffer);
this.magic = String.fromCharCode(dataView.getUint8(0), dataView.getUint8(1), dataView.getUint8(2), dataView.getUint8(3));
if (this.magic !== '.snd') {
throw new Error('Invalid .AU file: Magic number mismatch');
}
this.dataOffset = dataView.getUint32(4, false); // Big-endian
this.dataSize = dataView.getUint32(8, false);
this.encoding = dataView.getUint32(12, false);
this.sampleRate = dataView.getUint32(16, false);
this.channels = dataView.getUint32(20, false);
const infoLength = this.dataOffset - 24;
let infoBuffer = buffer.slice(24, 24 + infoLength);
const nullIndex = infoBuffer.indexOf(0);
this.info = infoBuffer.slice(0, nullIndex >= 0 ? nullIndex : infoLength).toString('ascii');
}
printProperties() {
console.log(`Magic Number: ${this.magic}`);
console.log(`Data Offset: ${this.dataOffset}`);
console.log(`Data Size: ${this.dataSize === 0xFFFFFFFF ? 'Unknown (0xFFFFFFFF)' : this.dataSize}`);
console.log(`Encoding: ${this.encoding}`);
console.log(`Sample Rate: ${this.sampleRate} Hz`);
console.log(`Channels: ${this.channels}`);
console.log(`Information Chunk: ${this.info || 'None'}`);
}
write(outputFilename, audioData = Buffer.alloc(0), info = 'Sample AU File', dataSize = 0xFFFFFFFF) {
const infoBuffer = Buffer.from(info + '\0', 'ascii');
const infoLength = infoBuffer.length;
this.dataOffset = 24 + infoLength;
this.dataSize = (dataSize === 0xFFFFFFFF) ? audioData.length : dataSize;
const header = Buffer.alloc(24);
header.write('.snd', 0, 4);
header.writeUInt32BE(this.dataOffset, 4);
header.writeUInt32BE(this.dataSize, 8);
header.writeUInt32BE(this.encoding, 12);
header.writeUInt32BE(this.sampleRate, 16);
header.writeUInt32BE(this.channels, 20);
const outputBuffer = Buffer.concat([header, infoBuffer, audioData]);
fs.writeFileSync(outputFilename, outputBuffer);
}
}
// Example usage:
// const handler = new AUFileHandler('sample.au');
// handler.printProperties();
// handler.write('output.au', Buffer.alloc(1024), 'Sample AU File', 0xFFFFFFFF);
7. C++ Class for .AU File Handling
The following C++ class can open a .AU file, decode its header, read and print the properties to the console, and write a new .AU file with specified properties and dummy audio data.
#include <iostream>
#include <fstream>
#include <vector>
#include <cstring>
#include <cstdint>
#include <algorithm>
class AUFileHandler {
private:
std::string filename;
std::string magic;
uint32_t dataOffset;
uint32_t dataSize;
uint32_t encoding;
uint32_t sampleRate;
uint32_t channels;
std::string info;
uint32_t readBigEndianUInt32(std::ifstream& file) {
uint32_t value;
file.read(reinterpret_cast<char*>(&value), sizeof(value));
return __builtin_bswap32(value); // Assuming little-endian host
}
public:
AUFileHandler(const std::string& fname = "") : filename(fname), dataOffset(0), dataSize(0), encoding(0), sampleRate(0), channels(0) {
if (!fname.empty()) {
read();
}
}
void read() {
std::ifstream file(filename, std::ios::binary);
if (!file) {
std::cerr << "Error opening file: " << filename << std::endl;
return;
}
char magicBytes[4];
file.read(magicBytes, 4);
magic = std::string(magicBytes, 4);
if (magic != ".snd") {
throw std::runtime_error("Invalid .AU file: Magic number mismatch");
}
dataOffset = readBigEndianUInt32(file);
dataSize = readBigEndianUInt32(file);
encoding = readBigEndianUInt32(file);
sampleRate = readBigEndianUInt32(file);
channels = readBigEndianUInt32(file);
uint32_t infoLength = dataOffset - 24;
std::vector<char> infoBytes(infoLength);
file.read(infoBytes.data(), infoLength);
auto nullIt = std::find(infoBytes.begin(), infoBytes.end(), '\0');
info = std::string(infoBytes.begin(), nullIt);
}
void printProperties() const {
std::cout << "Magic Number: " << magic << std::endl;
std::cout << "Data Offset: " << dataOffset << std::endl;
std::cout << "Data Size: " << (dataSize == 0xFFFFFFFF ? "Unknown (0xFFFFFFFF)" : std::to_string(dataSize)) << std::endl;
std::cout << "Encoding: " << encoding << std::endl;
std::cout << "Sample Rate: " << sampleRate << " Hz" << std::endl;
std::cout << "Channels: " << channels << std::endl;
std::cout << "Information Chunk: " << (info.empty() ? "None" : info) << std::endl;
}
void write(const std::string& outputFilename, const std::vector<uint8_t>& audioData, const std::string& infoStr, uint32_t dataSizeParam = 0xFFFFFFFF) {
std::string infoWithNull = infoStr + '\0';
uint32_t infoLength = infoWithNull.size();
dataOffset = 24 + infoLength;
dataSize = (dataSizeParam == 0xFFFFFFFF) ? audioData.size() : dataSizeParam;
std::ofstream file(outputFilename, std::ios::binary);
if (!file) {
std::cerr << "Error opening output file: " << outputFilename << std::endl;
return;
}
file.write(".snd", 4);
uint32_t beDataOffset = __builtin_bswap32(dataOffset);
file.write(reinterpret_cast<const char*>(&beDataOffset), sizeof(beDataOffset));
uint32_t beDataSize = __builtin_bswap32(dataSize);
file.write(reinterpret_cast<const char*>(&beDataSize), sizeof(beDataSize));
uint32_t beEncoding = __builtin_bswap32(encoding);
file.write(reinterpret_cast<const char*>(&beEncoding), sizeof(beEncoding));
uint32_t beSampleRate = __builtin_bswap32(sampleRate);
file.write(reinterpret_cast<const char*>(&beSampleRate), sizeof(beSampleRate));
uint32_t beChannels = __builtin_bswap32(channels);
file.write(reinterpret_cast<const char*>(&beChannels), sizeof(beChannels));
file.write(infoWithNull.c_str(), infoLength);
file.write(reinterpret_cast<const char*>(audioData.data()), audioData.size());
}
};
// Example usage:
// int main() {
// AUFileHandler handler("sample.au");
// handler.printProperties();
// std::vector<uint8_t> dummyData(1024, 0);
// handler.write("output.au", dummyData, "Sample AU File");
// return 0;
// }