"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AIFFParser = void 0; const Token = require("token-types"); const initDebug = require("debug"); const strtok3 = require("strtok3/lib/core"); const ID3v2Parser_1 = require("../id3v2/ID3v2Parser"); const FourCC_1 = require("../common/FourCC"); const BasicParser_1 = require("../common/BasicParser"); const AiffToken = require("./AiffToken"); const iff = require("../iff"); const debug = initDebug('music-metadata:parser:aiff'); /** * AIFF - Audio Interchange File Format * * Ref: * http://www.onicos.com/staff/iz/formats/aiff.html * http://muratnkonar.com/aiff/index.html * http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/AIFF/AIFF.html */ class AIFFParser extends BasicParser_1.BasicParser { async parse() { const header = await this.tokenizer.readToken(iff.Header); if (header.chunkID !== 'FORM') throw new Error('Invalid Chunk-ID, expected \'FORM\''); // Not AIFF format const type = await this.tokenizer.readToken(FourCC_1.FourCcToken); switch (type) { case 'AIFF': this.metadata.setFormat('container', type); this.isCompressed = false; break; case 'AIFC': this.metadata.setFormat('container', 'AIFF-C'); this.isCompressed = true; break; default: throw Error('Unsupported AIFF type: ' + type); } this.metadata.setFormat('lossless', !this.isCompressed); try { while (!this.tokenizer.fileInfo.size || this.tokenizer.fileInfo.size - this.tokenizer.position >= iff.Header.len) { debug('Reading AIFF chunk at offset=' + this.tokenizer.position); const chunkHeader = await this.tokenizer.readToken(iff.Header); debug(`Chunk id=${chunkHeader.chunkID}`); const nextChunk = 2 * Math.round(chunkHeader.chunkSize / 2); const bytesRead = await this.readData(chunkHeader); await this.tokenizer.ignore(nextChunk - bytesRead); } } catch (err) { if (err instanceof strtok3.EndOfStreamError) { debug(`End-of-stream`); } else { throw err; } } } async readData(header) { switch (header.chunkID) { case 'COMM': // The Common Chunk const common = await this.tokenizer.readToken(new AiffToken.Common(header, this.isCompressed)); this.metadata.setFormat('bitsPerSample', common.sampleSize); this.metadata.setFormat('sampleRate', common.sampleRate); this.metadata.setFormat('numberOfChannels', common.numChannels); this.metadata.setFormat('numberOfSamples', common.numSampleFrames); this.metadata.setFormat('duration', common.numSampleFrames / common.sampleRate); this.metadata.setFormat('codec', common.compressionName); return header.chunkSize; case 'ID3 ': // ID3-meta-data const id3_data = await this.tokenizer.readToken(new Token.Uint8ArrayType(header.chunkSize)); const rst = strtok3.fromBuffer(id3_data); await new ID3v2Parser_1.ID3v2Parser().parse(this.metadata, rst, this.options); return header.chunkSize; case 'SSND': // Sound Data Chunk if (this.metadata.format.duration) { this.metadata.setFormat('bitrate', 8 * header.chunkSize / this.metadata.format.duration); } return 0; default: return 0; } } } exports.AIFFParser = AIFFParser;