-
-
Notifications
You must be signed in to change notification settings - Fork 88
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
225 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
import * as Token from 'token-types'; | ||
import {FourCcToken} from '../common/FourCC'; | ||
|
||
/** | ||
* Common interface for the common chunk DSD header | ||
*/ | ||
export interface IChunkHeader { | ||
|
||
/** | ||
* Chunk ID | ||
*/ | ||
id: string; | ||
|
||
/** | ||
* Chunk size | ||
*/ | ||
size: number; | ||
} | ||
|
||
/** | ||
* Common chunk DSD header: the 'chunk name (Four-CC)' & chunk size | ||
*/ | ||
export const ChunkHeader: Token.IGetToken<IChunkHeader> = { | ||
len: 12, | ||
|
||
get: (buf: Buffer, off: number): IChunkHeader => { | ||
return {id: FourCcToken.get(buf, off), size: Token.UINT64_LE.get(buf, off + 4)}; | ||
} | ||
}; | ||
|
||
/** | ||
* Interface to DSD payload chunk | ||
*/ | ||
export interface IDsdChunk { | ||
|
||
/** | ||
* Total file size | ||
*/ | ||
fileSize: number; | ||
|
||
/** | ||
* If Metadata doesn’t 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: number; | ||
} | ||
|
||
/** | ||
* Common chunk DSD header: the 'chunk name (Four-CC)' & chunk size | ||
*/ | ||
export const DsdChunk: Token.IGetToken<IDsdChunk> = { | ||
len: 16, | ||
|
||
get: (buf: Buffer, off: number): IDsdChunk => { | ||
return { | ||
fileSize: Token.INT64_LE.get(buf, off), | ||
metadataPointer: Token.INT64_LE.get(buf, off + 8) | ||
} | ||
; | ||
} | ||
}; | ||
|
||
export 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: number; | ||
|
||
/** | ||
* Block size per channel | ||
*/ | ||
blockSizePerChannel: number; | ||
} | ||
|
||
/** | ||
* Common chunk DSD header: the 'chunk name (Four-CC)' & chunk size | ||
*/ | ||
export const FormatChunk: Token.IGetToken<IFormatChunk> = { | ||
len: 44, | ||
|
||
get: (buf: Buffer, off: number): IFormatChunk => { | ||
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) | ||
}; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
'use strict'; | ||
|
||
import { AbstractID3Parser } from '../id3v2/AbstractID3Parser'; | ||
import * as assert from 'assert'; | ||
|
||
import * as _debug from 'debug'; | ||
import {ChunkHeader, DsdChunk, FormatChunk, IChunkHeader, IDsdChunk} from "./DsfChunk"; | ||
import {ID3v2Parser} from "../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 | ||
*/ | ||
export class DsfParser extends AbstractID3Parser { | ||
|
||
public async _parse(): Promise<void> { | ||
|
||
const chunkHeader = await this.tokenizer.readToken<IChunkHeader>(ChunkHeader); | ||
assert.strictEqual(chunkHeader.id, 'DSD '); | ||
this.metadata.setFormat('dataformat', 'DSF'); | ||
const dsdChunk = await this.tokenizer.readToken<IDsdChunk>(DsdChunk); | ||
if (dsdChunk.metadataPointer === 0) { | ||
debug(`No ID3v2 tag present`); | ||
} else { | ||
debug(`expect ID3v2 at offset=${dsdChunk.metadataPointer}`); | ||
await this.parseChunks(); | ||
// Jump to ID3 header | ||
this.tokenizer.ignore(dsdChunk.metadataPointer - this.tokenizer.position); | ||
return new ID3v2Parser().parse(this.metadata, this.tokenizer, this.options); | ||
} | ||
} | ||
|
||
private async parseChunks() { | ||
const chunkHeader = await this.tokenizer.readToken<IChunkHeader>(ChunkHeader); | ||
debug(`Parsing chunk name=${chunkHeader.id} size=${chunkHeader.size}`); | ||
switch (chunkHeader.id) { | ||
case 'fmt ': | ||
const formatChunk = await this.tokenizer.readToken(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', formatChunk.sampleCount / formatChunk.samplingFrequency); | ||
return; | ||
default: | ||
this.tokenizer.ignore(chunkHeader.size - ChunkHeader.len); | ||
break; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import {assert} from 'chai'; | ||
import * as mm from '../src'; | ||
import * as path from 'path'; | ||
|
||
describe('Parse DSF (dsd stream file)', () => { | ||
|
||
const dsfSamplePath = path.join(__dirname, 'samples', 'dsf'); | ||
|
||
it('parse: 2L-110_stereo-5644k-1b_04.dsf', async () => { | ||
|
||
const dsfFilePath = path.join(dsfSamplePath, '2L-110_stereo-5644k-1b_04_0.1-sec.dsf'); | ||
|
||
const metadata = await mm.parseFile(dsfFilePath, {duration: false}); | ||
assert.strictEqual(metadata.format.dataformat, 'DSF'); | ||
assert.deepEqual(metadata.format.tagTypes, ['ID3v2.3']); | ||
|
||
// format chunk information | ||
assert.deepEqual(metadata.format.numberOfChannels, 2); | ||
assert.deepEqual(metadata.format.bitsPerSample, 1); | ||
assert.deepEqual(metadata.format.sampleRate, 5644800); | ||
assert.deepEqual(metadata.format.numberOfSamples, 564480); | ||
assert.deepEqual(metadata.format.duration, 0.1); | ||
|
||
// ID3v2 chunk information | ||
assert.strictEqual(metadata.common.title, 'Kyrie'); | ||
assert.strictEqual(metadata.common.artist, 'CANTUS (Tove Ramlo-Ystad) & Frode Fjellheim'); | ||
assert.deepEqual(metadata.common.track, {no: 4, of: 12}); | ||
}); | ||
|
||
}); |