From cfc6a442defbfcc46ec6faeb07b7b2d85cd605be Mon Sep 17 00:00:00 2001 From: Nik Date: Wed, 7 Sep 2022 09:42:51 +0200 Subject: [PATCH] patterns: Added basic FLAC metadata pattern --- README.md | 1 + patterns/flac.hexpat | 321 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 322 insertions(+) create mode 100644 patterns/flac.hexpat diff --git a/README.md b/README.md index 7eb6adf..89615f4 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ Hex patterns, include patterns and magic files for the use with the ImHex Hex Ed | NTAG | | `patterns/ntag.hexpat` | NTAG213/NTAG215/NTAG216, NFC Forum Type 2 Tag compliant IC | | Shell Link | `application/x-ms-shortcut` | `patterns/lnk.hexpat` | Windows Shell Link file format | | Xilinx BIT | | `patterns/xilinx_bit.hexpat` | Xilinx FPGA Bitstreams | +| FLAC | `audio/flac` | `patterns/flac.hexpat` | Free Lossless Audio Codec, FLAC Audio Format | ### Scripts diff --git a/patterns/flac.hexpat b/patterns/flac.hexpat new file mode 100644 index 0000000..9a7cac8 --- /dev/null +++ b/patterns/flac.hexpat @@ -0,0 +1,321 @@ +#include +#include +#include + +#pragma endian big + +u32 sampleSize; +u32 bitsPerSample; + +// METADATA + +enum BLOCK_TYPE : u8 { + STREAMINFO = 0, + PADDING = 1, + APPLICATION = 2, + SEEKTABLE = 3, + VORBIS_COMMENT = 4, + CUESHEET = 5, + PICTURE = 6, + + INVALID = 127 +}; + +bitfield METADATA_BLOCK_HEADER { + lastMetadataBlock : 1; + blockType : 7; + length : 24; +} [[left_to_right]]; + +bitfield STREAMINFO_FLAGS { + sampleRate : 20; + numChannels : 3 [[format("format_channels")]]; + bitsPerSample : 5; + numSamplesInStream : 36; +} [[inline, left_to_right]]; + +fn format_channels(u8 value) { + return value + 1; +}; + +struct METADATA_BLOCK_STREAMINFO { + u16 minBlockSize, maxBlockSize; + u24 minFrameSize, maxFrameSize; + STREAMINFO_FLAGS flags; + u128 md5Signature; + + bitsPerSample = flags.bitsPerSample; +}; + +struct METADATA_BLOCK_PADDING { + padding[parent.header.length]; +}; + +struct METADATA_BLOCK_APPLICATION { + char applicationID[4]; + u8 applicationData[parent.header.length - sizeof(applicationID)]; +}; + +struct SEEKPOINT { + u64 sampleNumber; + u64 byteOffset; + u16 numSamples; +}; + +struct METADATA_BLOCK_SEEKTABLE { + SEEKPOINT seekPoints[parent.header.length / 18]; +}; + +struct VORBIS_USER_COMMENT { + le u32 length; + char comment[length]; +}; + +struct METADATA_BLOCK_VORBIS_COMMENT { + le u32 vendorLength; + u8 vendor[vendorLength]; + + le u32 userCommentListLength; + VORBIS_USER_COMMENT userCommentList[userCommentListLength]; +}; + +bitfield TRACK_FLAGS { + audioTrack : 1; + preEmphasis : 1; + padding : 6; +} [[inline]]; + +struct CUESHEET_TRACK_INDEX { + u64 sampleOffset; + u8 indexPointNumber; + padding[3]; +}; + +struct CUESHEET_TRACK { + u64 trackOffset; + u8 trackNumber; + char trackISRC[12]; + TRACK_FLAGS flags; + padding[13]; + u8 numTrackIndexPoints; + CUESHEET_TRACK_INDEX indexes[numTrackIndexPoints]; +}; + +struct METADATA_BLOCK_CUESHEET { + char mediaCatalogNumber[128]; + u64 numLeadInSamples; + bool isCD; + padding[258]; + u8 numTracks; + CUESHEET_TRACK tracks[numTracks]; +}; + +enum PICTURE_TYPE : u32 { + Other = 0, + FileIcon = 1, + OtherFileIcon = 2, + CoverFront = 3, + CoverBack = 4, + LeafletPage = 5, + Media = 6, + LeadArtist = 7, + Artist = 8, + Conductor = 9, + Band = 10, + Composer = 11, + Lyricist = 12, + RecordingLocation = 13, + DuringRecording = 14, + DuringPerformance = 15, + MovieScreenCapture = 16, + ABrightColoredFish = 17, + Illustration = 18, + BandLogoType = 19, + PublisherLogoType = 20 +}; + +struct METADATA_BLOCK_PICTURE { + PICTURE_TYPE pictureType; + u32 mimeTypeLength; + char mimeType[mineTypeLength]; + u32 descriptionLength; + char description[descriptionLength]; + u32 width, height; + u32 colorDepth; + u32 colorCount; + u32 pictureDataLength; + u8 pictureData[pictureDataLength]; +}; + + + +// FRAME DATA +// TODO: THIS IS INCOMPLETE / NOT WORKING CURRENTLY + +bitfield FRAME_HEADER_FLAGS { + syncCode : 14; + padding : 1; + blockingStrategy : 1; + blockSize : 4; + sampleRate : 4; + channelAssignment : 4; + sampleSize : 3; + padding : 1; +} [[inline]]; + +struct FRAME_HEADER { + FRAME_HEADER_FLAGS flags; + + sampleSize = flags.sampleSize; + + if (flags.blockingStrategy) + char16 sampleNumber[7]; + else + char16 frameNumber[6]; + + if (flags.blockSize == 0b0110) + u8 blockSize; + else if (flags.blockSize == 0b0111) + u16 blockSize; + + if (flags.sampleRate == 0b1100) + u8 sampleRate; + else if (flags.sampleRate == 0b1101 || flags.sampleRate == 0b1110) + u16 sampleRate; + + u8 crc8; +}; + +struct FRAME_FOOTER { + u16 crc16; +}; + +bitfield SUBFRAME_HEADER { + padding : 1; + type : 6; + wastedBits : 1; +}; + +fn getBitsPerSample() { + if (sampleSize == 0b000) + return bitsPerSample; + else if (sampleSize == 0b001) + return 8; + else if (sampleSize == 0b010) + return 12; + else if (sampleSize == 0b100) + return 16; + else if (sampleSize == 0b101) + return 20; + else if (sampleSize == 0b110) + return 24; +}; + +bitfield SUBFRAME_CONSTANT { + value : getBitsPerSample(); +}; + +bitfield SUBFRAME_VERBATIM { + value : getBitsPerSample() * parent.parent.header.flags.blockSize; +}; + +bitfield SUBFRAME_FIXED_VALUE { + value : getBitsPerSample() * (parent.parent.header.type & 0b111); + codingMethod : 2; +} [[inline]]; + +bitfield RESIDUAL_CODING_METHOD_PARTITIONED_RICE { + partitionOrder : 4; + riceParameter : 4; + if (riceParameter == 0b1111) + bitsPerSample : 5; +} [[right_to_left]]; + +bitfield RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 { + partitionOrder : 4; + riceParameter : 5; + if (riceParameter == 0b11111) + bitsPerSample : 5; +} [[right_to_left]]; + +struct RESIDUAL { + if (parent.value.codingMethod == 0b00) + RESIDUAL_CODING_METHOD_PARTITIONED_RICE rice; + else if (parent.value.codingMethod == 0b01) + RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 rice; + + + if ((parent.parent.header.type & 0b111) == 0b000) + u8 samples[(getBitsPerSample() * (parent.parent.parent.header.flags.blockSize - (parent.parent.header.type & 0b111))) / 8]; + else if (std::core::array_index() != 0) + u8 samples[(getBitsPerSample() * (parent.parent.parent.header.flags.blockSize / (1 << rice.partitionOrder))) / 8]; + else + u8 samples[(getBitsPerSample() * ((parent.parent.parent.header.flags.blockSize / (1 << rice.partitionOrder)) - (parent.parent.header.type & 0b111))) / 8]; +}; + +struct SUBFRAME_FIXED { + SUBFRAME_FIXED_VALUE value; + RESIDUAL residual; +}; + +bitfield SUBFRAME_LPC_VALUE { + warmUpSamples : getBitsPerSample() * ((parent.header.type & 0b011111) + 1); + quantizedLinearPredictorCoefficient : 4; + quantizedLinearPredictorCoefficientShift : 5; + predictorCoefficients : quantizedLinearPredictorCoefficient * ((parent.header.type & 0b011111) + 1); +} [[inline]]; + +struct SUBFRAME_LPC { + SUBFRAME_LPC_VALUE value; + RESIDUAL residual; +}; + + +struct SUBFRAME { + SUBFRAME_HEADER header; + + if (header.type == 0b00000) + SUBFRAME_CONSTANT constant; + else if (header.type == 0b000001) + SUBFRAME_VERBATIM verbatim; + else if ((header.type >> 3) == 0b001 && (header.type & 0b111) <= 4) + SUBFRAME_FIXED fixed; + else if (header.type == 0b100000) + SUBFRAME_LPC lpc; +}; + +struct FRAME { + FRAME_HEADER header; + SUBFRAME subframes[parent.metadata[0].data.flags.numChannels + 1]; + FRAME_FOOTER footer; +}; + + +struct METADATA_BLOCK { + METADATA_BLOCK_HEADER header; + if (header.lastMetadataBlock) + break; + + if (header.blockType == BLOCK_TYPE::STREAMINFO) + METADATA_BLOCK_STREAMINFO data; + else if (header.blockType == BLOCK_TYPE::PADDING) + METADATA_BLOCK_PADDING data; + else if (header.blockType == BLOCK_TYPE::APPLICATION) + METADATA_BLOCK_APPLICATION data; + else if (header.blockType == BLOCK_TYPE::VORBIS_COMMENT) + METADATA_BLOCK_VORBIS_COMMENT data; + else if (header.blockType == BLOCK_TYPE::CUESHEET) + METADATA_BLOCK_CUESHEET data; + else if (header.blockType == BLOCK_TYPE::PICTURE) + METADATA_BLOCK_PICTURE data; + else + std::error("Invalid metadata block type!"); +}; + +struct STREAM { + char magic[4]; + METADATA_BLOCK metadata[while(true)]; + //FRAME frames[while(!std::mem::eof())]; +}; + +STREAM stream @ 0x00; \ No newline at end of file