import type { IGetToken } from 'strtok3'; import * as util from '../common/Util.js'; import { UINT16_BE, UINT24_BE, Uint8ArrayType } from 'token-types'; /** * FLAC supports up to 128 kinds of metadata blocks; currently the following are defined: * ref: https://xiph.org/flac/format.html#metadata_block */ export const BlockType = { STREAMINFO: 0, // STREAMINFO PADDING: 1, // PADDING APPLICATION: 2, // APPLICATION SEEKTABLE: 3, // SEEKTABLE VORBIS_COMMENT: 4, // VORBIS_COMMENT CUESHEET: 5, // CUESHEET PICTURE: 6 // PICTURE }; export type BlockType = typeof BlockType[keyof typeof BlockType]; /** * METADATA_BLOCK_DATA * Ref: https://xiph.org/flac/format.html#metadata_block_streaminfo */ export interface IBlockHeader { // Last-metadata-block flag: '1' if this block is the last metadata block before the audio blocks, '0' otherwise. lastBlock: boolean, // BLOCK_TYPE type: BlockType, // Length (in bytes) of metadata to follow (does not include the size of the METADATA_BLOCK_HEADER) length: number; } export const BlockHeader: IGetToken = { len: 4, get: (buf: Uint8Array, off: number): IBlockHeader => { return { lastBlock: util.getBit(buf, off, 7), type: util.getBitAllignedNumber(buf, off, 1, 7), length: UINT24_BE.get(buf, off + 1) }; } }; /** * METADATA_BLOCK_DATA * Ref: https://xiph.org/flac/format.html#metadata_block_streaminfo */ export interface IBlockStreamInfo { minimumBlockSize: number, // The maximum block size (in samples) used in the stream. // (Minimum blocksize == maximum blocksize) implies a fixed-blocksize stream. maximumBlockSize: number, // The minimum frame size (in bytes) used in the stream. // May be 0 to imply the value is not known. minimumFrameSize: number, // The maximum frame size (in bytes) used in the stream. // May be 0 to imply the value is not known. maximumFrameSize: number, // Sample rate in Hz. Though 20 bits are available, // the maximum sample rate is limited by the structure of frame headers to 655350Hz. // Also, a value of 0 is invalid. sampleRate: number, // probably slower: sampleRate: common.getBitAllignedNumber(buf, off + 10, 0, 20), // (number of channels)-1. FLAC supports from 1 to 8 channels channels: number, // bits per sample)-1. // FLAC supports from 4 to 32 bits per sample. Currently the reference encoder and decoders only support up to 24 bits per sample. bitsPerSample: number, // Total samples in stream. // 'Samples' means inter-channel sample, i.e. one second of 44.1Khz audio will have 44100 samples regardless of the number of channels. // A value of zero here means the number of total samples is unknown. totalSamples: number, // the MD5 hash of the file (see notes for usage... it's a littly tricky) fileMD5: Uint8Array; } /** * METADATA_BLOCK_DATA * Ref: https://xiph.org/flac/format.html#metadata_block_streaminfo */ export const BlockStreamInfo: IGetToken = { len: 34, get: (buf: Uint8Array, off: number): IBlockStreamInfo => { return { // The minimum block size (in samples) used in the stream. minimumBlockSize: UINT16_BE.get(buf, off), // The maximum block size (in samples) used in the stream. // (Minimum blocksize == maximum blocksize) implies a fixed-blocksize stream. maximumBlockSize: UINT16_BE.get(buf, off + 2) / 1000, // The minimum frame size (in bytes) used in the stream. // May be 0 to imply the value is not known. minimumFrameSize: UINT24_BE.get(buf, off + 4), // The maximum frame size (in bytes) used in the stream. // May be 0 to imply the value is not known. maximumFrameSize: UINT24_BE.get(buf, off + 7), // Sample rate in Hz. Though 20 bits are available, // the maximum sample rate is limited by the structure of frame headers to 655350Hz. // Also, a value of 0 is invalid. sampleRate: UINT24_BE.get(buf, off + 10) >> 4, // probably slower: sampleRate: common.getBitAllignedNumber(buf, off + 10, 0, 20), // (number of channels)-1. FLAC supports from 1 to 8 channels channels: util.getBitAllignedNumber(buf, off + 12, 4, 3) + 1, // bits per sample)-1. // FLAC supports from 4 to 32 bits per sample. Currently the reference encoder and decoders only support up to 24 bits per sample. bitsPerSample: util.getBitAllignedNumber(buf, off + 12, 7, 5) + 1, // Total samples in stream. // 'Samples' means inter-channel sample, i.e. one second of 44.1Khz audio will have 44100 samples regardless of the number of channels. // A value of zero here means the number of total samples is unknown. totalSamples: util.getBitAllignedNumber(buf, off + 13, 4, 36), // the MD5 hash of the file (see notes for usage... it's a littly tricky) fileMD5: new Uint8ArrayType(16).get(buf, off + 18) }; } };