Initial working version

This commit is contained in:
Samuel Kent
2022-12-22 20:22:22 +11:00
parent ce9675a1cc
commit ced7fa5092
902 changed files with 150252 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
import { IGetToken } from 'strtok3/lib/core';
/**
* Common interface for the common chunk DSD header
*/
export interface IChunkHeader {
/**
* Chunk ID
*/
id: string;
/**
* Chunk size
*/
size: bigint;
}
/**
* Common chunk DSD header: the 'chunk name (Four-CC)' & chunk size
*/
export declare const ChunkHeader: IGetToken<IChunkHeader>;
/**
* Interface to DSD payload chunk
*/
export interface IDsdChunk {
/**
* Total file size
*/
fileSize: bigint;
/**
* If Metadata doesnt exist, set 0. If the file has ID3v2 tag, then set the pointer to it.
* ID3v2 tag should be located in the end of the file.
*/
metadataPointer: bigint;
}
/**
* Common chunk DSD header: the 'chunk name (Four-CC)' & chunk size
*/
export declare const DsdChunk: IGetToken<IDsdChunk>;
export declare enum ChannelType {
mono = 1,
stereo = 2,
channels = 3,
quad = 4,
'4 channels' = 5,
'5 channels' = 6,
'5.1 channels' = 7
}
/**
* Interface to format chunk payload chunk
*/
export interface IFormatChunk {
/**
* Version of this file format
*/
formatVersion: number;
/**
* Format ID
*/
formatID: number;
/**
* Channel Type
*/
channelType: ChannelType;
/**
* Channel num
*/
channelNum: number;
/**
* Sampling frequency
*/
samplingFrequency: number;
/**
* Bits per sample
*/
bitsPerSample: number;
/**
* Sample count
*/
sampleCount: bigint;
/**
* Block size per channel
*/
blockSizePerChannel: number;
}
/**
* Common chunk DSD header: the 'chunk name (Four-CC)' & chunk size
*/
export declare const FormatChunk: IGetToken<IFormatChunk>;
+54
View File
@@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FormatChunk = exports.ChannelType = exports.DsdChunk = exports.ChunkHeader = void 0;
const Token = require("token-types");
const FourCC_1 = require("../common/FourCC");
/**
* Common chunk DSD header: the 'chunk name (Four-CC)' & chunk size
*/
exports.ChunkHeader = {
len: 12,
get: (buf, off) => {
return { id: FourCC_1.FourCcToken.get(buf, off), size: Token.UINT64_LE.get(buf, off + 4) };
}
};
/**
* Common chunk DSD header: the 'chunk name (Four-CC)' & chunk size
*/
exports.DsdChunk = {
len: 16,
get: (buf, off) => {
return {
fileSize: Token.INT64_LE.get(buf, off),
metadataPointer: Token.INT64_LE.get(buf, off + 8)
};
}
};
var ChannelType;
(function (ChannelType) {
ChannelType[ChannelType["mono"] = 1] = "mono";
ChannelType[ChannelType["stereo"] = 2] = "stereo";
ChannelType[ChannelType["channels"] = 3] = "channels";
ChannelType[ChannelType["quad"] = 4] = "quad";
ChannelType[ChannelType["4 channels"] = 5] = "4 channels";
ChannelType[ChannelType["5 channels"] = 6] = "5 channels";
ChannelType[ChannelType["5.1 channels"] = 7] = "5.1 channels";
})(ChannelType = exports.ChannelType || (exports.ChannelType = {}));
/**
* Common chunk DSD header: the 'chunk name (Four-CC)' & chunk size
*/
exports.FormatChunk = {
len: 40,
get: (buf, off) => {
return {
formatVersion: Token.INT32_LE.get(buf, off),
formatID: Token.INT32_LE.get(buf, off + 4),
channelType: Token.INT32_LE.get(buf, off + 8),
channelNum: Token.INT32_LE.get(buf, off + 12),
samplingFrequency: Token.INT32_LE.get(buf, off + 16),
bitsPerSample: Token.INT32_LE.get(buf, off + 20),
sampleCount: Token.INT64_LE.get(buf, off + 24),
blockSizePerChannel: Token.INT32_LE.get(buf, off + 32)
};
}
};
+9
View File
@@ -0,0 +1,9 @@
import { AbstractID3Parser } from '../id3v2/AbstractID3Parser';
/**
* DSF (dsd stream file) File Parser
* Ref: https://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
*/
export declare class DsfParser extends AbstractID3Parser {
_parse(): Promise<void>;
private parseChunks;
}
+56
View File
@@ -0,0 +1,56 @@
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
exports.DsfParser = void 0;
const AbstractID3Parser_1 = require("../id3v2/AbstractID3Parser");
const _debug = require("debug");
const DsfChunk_1 = require("./DsfChunk");
const ID3v2Parser_1 = require("../id3v2/ID3v2Parser");
const debug = _debug('music-metadata:parser:DSF');
/**
* DSF (dsd stream file) File Parser
* Ref: https://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
*/
class DsfParser extends AbstractID3Parser_1.AbstractID3Parser {
async _parse() {
const p0 = this.tokenizer.position; // mark start position, normally 0
const chunkHeader = await this.tokenizer.readToken(DsfChunk_1.ChunkHeader);
if (chunkHeader.id !== 'DSD ')
throw new Error('Invalid chunk signature');
this.metadata.setFormat('container', 'DSF');
this.metadata.setFormat('lossless', true);
const dsdChunk = await this.tokenizer.readToken(DsfChunk_1.DsdChunk);
if (dsdChunk.metadataPointer === BigInt(0)) {
debug(`No ID3v2 tag present`);
}
else {
debug(`expect ID3v2 at offset=${dsdChunk.metadataPointer}`);
await this.parseChunks(dsdChunk.fileSize - chunkHeader.size);
// Jump to ID3 header
await this.tokenizer.ignore(Number(dsdChunk.metadataPointer) - this.tokenizer.position - p0);
return new ID3v2Parser_1.ID3v2Parser().parse(this.metadata, this.tokenizer, this.options);
}
}
async parseChunks(bytesRemaining) {
while (bytesRemaining >= DsfChunk_1.ChunkHeader.len) {
const chunkHeader = await this.tokenizer.readToken(DsfChunk_1.ChunkHeader);
debug(`Parsing chunk name=${chunkHeader.id} size=${chunkHeader.size}`);
switch (chunkHeader.id) {
case 'fmt ':
const formatChunk = await this.tokenizer.readToken(DsfChunk_1.FormatChunk);
this.metadata.setFormat('numberOfChannels', formatChunk.channelNum);
this.metadata.setFormat('sampleRate', formatChunk.samplingFrequency);
this.metadata.setFormat('bitsPerSample', formatChunk.bitsPerSample);
this.metadata.setFormat('numberOfSamples', formatChunk.sampleCount);
this.metadata.setFormat('duration', Number(formatChunk.sampleCount) / formatChunk.samplingFrequency);
const bitrate = formatChunk.bitsPerSample * formatChunk.samplingFrequency * formatChunk.channelNum;
this.metadata.setFormat('bitrate', bitrate);
return; // We got what we want, stop further processing of chunks
default:
this.tokenizer.ignore(Number(chunkHeader.size) - DsfChunk_1.ChunkHeader.len);
break;
}
bytesRemaining -= chunkHeader.size;
}
}
}
exports.DsfParser = DsfParser;