music-metadata 7.12.1 → 7.12.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +9 -9
- package/README.md +434 -434
- package/lib/ParserFactory.d.ts +48 -48
- package/lib/ParserFactory.js +252 -252
- package/lib/aiff/AiffParser.d.ts +14 -14
- package/lib/aiff/AiffParser.js +84 -84
- package/lib/aiff/AiffToken.d.ts +22 -22
- package/lib/aiff/AiffToken.js +43 -43
- package/lib/apev2/APEv2Parser.d.ts +30 -30
- package/lib/apev2/APEv2Parser.js +164 -161
- package/lib/apev2/APEv2TagMapper.d.ts +4 -4
- package/lib/apev2/APEv2TagMapper.js +86 -86
- package/lib/apev2/APEv2Token.d.ts +100 -100
- package/lib/apev2/APEv2Token.js +126 -126
- package/lib/asf/AsfObject.d.ts +319 -319
- package/lib/asf/AsfObject.js +381 -381
- package/lib/asf/AsfParser.d.ts +17 -17
- package/lib/asf/AsfParser.js +135 -135
- package/lib/asf/AsfTagMapper.d.ts +7 -7
- package/lib/asf/AsfTagMapper.js +95 -95
- package/lib/asf/AsfUtil.d.ts +13 -13
- package/lib/asf/AsfUtil.js +38 -38
- package/lib/asf/GUID.d.ts +84 -84
- package/lib/asf/GUID.js +121 -121
- package/lib/common/BasicParser.d.ts +17 -17
- package/lib/common/BasicParser.js +18 -18
- package/lib/common/CaseInsensitiveTagMap.d.ts +10 -10
- package/lib/common/CaseInsensitiveTagMap.js +21 -21
- package/lib/common/CombinedTagMapper.d.ts +19 -19
- package/lib/common/CombinedTagMapper.js +51 -51
- package/lib/common/FourCC.d.ts +6 -6
- package/lib/common/FourCC.js +28 -28
- package/lib/common/GenericTagMapper.d.ts +51 -51
- package/lib/common/GenericTagMapper.js +55 -55
- package/lib/common/GenericTagTypes.d.ts +33 -33
- package/lib/common/GenericTagTypes.js +131 -131
- package/lib/common/MetadataCollector.d.ts +76 -76
- package/lib/common/MetadataCollector.js +275 -275
- package/lib/common/RandomFileReader.d.ts +22 -22
- package/lib/common/RandomFileReader.js +34 -34
- package/lib/common/RandomUint8ArrayReader.d.ts +18 -18
- package/lib/common/RandomUint8ArrayReader.js +25 -25
- package/lib/common/Util.d.ts +57 -57
- package/lib/common/Util.js +157 -157
- package/lib/core.d.ts +48 -48
- package/lib/core.js +90 -90
- package/lib/dsdiff/DsdiffParser.d.ts +14 -14
- package/lib/dsdiff/DsdiffParser.js +143 -143
- package/lib/dsdiff/DsdiffToken.d.ts +9 -9
- package/lib/dsdiff/DsdiffToken.js +21 -21
- package/lib/dsf/DsfChunk.d.ts +86 -86
- package/lib/dsf/DsfChunk.js +54 -54
- package/lib/dsf/DsfParser.d.ts +9 -9
- package/lib/dsf/DsfParser.js +56 -56
- package/lib/flac/FlacParser.d.ts +28 -28
- package/lib/flac/FlacParser.js +175 -175
- package/lib/id3v1/ID3v1Parser.d.ts +13 -13
- package/lib/id3v1/ID3v1Parser.js +134 -134
- package/lib/id3v1/ID3v1TagMap.d.ts +4 -4
- package/lib/id3v1/ID3v1TagMap.js +22 -22
- package/lib/id3v2/AbstractID3Parser.d.ts +17 -17
- package/lib/id3v2/AbstractID3Parser.js +60 -60
- package/lib/id3v2/FrameParser.d.ts +31 -31
- package/lib/id3v2/FrameParser.js +329 -329
- package/lib/id3v2/ID3v22TagMapper.d.ts +9 -9
- package/lib/id3v2/ID3v22TagMapper.js +55 -55
- package/lib/id3v2/ID3v24TagMapper.d.ts +14 -14
- package/lib/id3v2/ID3v24TagMapper.js +193 -193
- package/lib/id3v2/ID3v2Parser.d.ts +28 -28
- package/lib/id3v2/ID3v2Parser.js +182 -182
- package/lib/id3v2/ID3v2Token.d.ts +73 -73
- package/lib/id3v2/ID3v2Token.js +106 -106
- package/lib/iff/index.d.ts +33 -33
- package/lib/iff/index.js +19 -19
- package/lib/index.d.ts +45 -45
- package/lib/index.js +74 -74
- package/lib/lyrics3/Lyrics3.d.ts +3 -3
- package/lib/lyrics3/Lyrics3.js +17 -17
- package/lib/matroska/MatroskaDtd.d.ts +8 -8
- package/lib/matroska/MatroskaDtd.js +279 -279
- package/lib/matroska/MatroskaParser.d.ts +37 -37
- package/lib/matroska/MatroskaParser.js +235 -235
- package/lib/matroska/MatroskaTagMapper.d.ts +4 -4
- package/lib/matroska/MatroskaTagMapper.js +35 -35
- package/lib/matroska/types.d.ts +175 -175
- package/lib/matroska/types.js +32 -32
- package/lib/mp4/Atom.d.ts +16 -16
- package/lib/mp4/Atom.js +70 -70
- package/lib/mp4/AtomToken.d.ts +395 -395
- package/lib/mp4/AtomToken.js +406 -406
- package/lib/mp4/MP4Parser.d.ts +30 -30
- package/lib/mp4/MP4Parser.js +511 -511
- package/lib/mp4/MP4TagMapper.d.ts +5 -5
- package/lib/mp4/MP4TagMapper.js +115 -115
- package/lib/mpeg/ExtendedLameHeader.d.ts +27 -27
- package/lib/mpeg/ExtendedLameHeader.js +31 -31
- package/lib/mpeg/MpegParser.d.ts +49 -49
- package/lib/mpeg/MpegParser.js +524 -524
- package/lib/mpeg/ReplayGainDataFormat.d.ts +55 -55
- package/lib/mpeg/ReplayGainDataFormat.js +69 -69
- package/lib/mpeg/XingTag.d.ts +45 -45
- package/lib/mpeg/XingTag.js +69 -69
- package/lib/musepack/index.d.ts +5 -5
- package/lib/musepack/index.js +32 -32
- package/lib/musepack/sv7/BitReader.d.ts +13 -13
- package/lib/musepack/sv7/BitReader.js +54 -54
- package/lib/musepack/sv7/MpcSv7Parser.d.ts +8 -8
- package/lib/musepack/sv7/MpcSv7Parser.js +46 -46
- package/lib/musepack/sv7/StreamVersion7.d.ts +28 -28
- package/lib/musepack/sv7/StreamVersion7.js +41 -41
- package/lib/musepack/sv8/MpcSv8Parser.d.ts +6 -6
- package/lib/musepack/sv8/MpcSv8Parser.js +55 -55
- package/lib/musepack/sv8/StreamVersion8.d.ts +40 -40
- package/lib/musepack/sv8/StreamVersion8.js +80 -80
- package/lib/ogg/Ogg.d.ts +72 -72
- package/lib/ogg/Ogg.js +2 -2
- package/lib/ogg/OggParser.d.ts +23 -23
- package/lib/ogg/OggParser.js +126 -126
- package/lib/ogg/opus/Opus.d.ts +48 -48
- package/lib/ogg/opus/Opus.js +28 -28
- package/lib/ogg/opus/OpusParser.d.ts +25 -25
- package/lib/ogg/opus/OpusParser.js +56 -56
- package/lib/ogg/speex/Speex.d.ts +36 -36
- package/lib/ogg/speex/Speex.js +31 -31
- package/lib/ogg/speex/SpeexParser.d.ts +22 -22
- package/lib/ogg/speex/SpeexParser.js +35 -35
- package/lib/ogg/theora/Theora.d.ts +20 -20
- package/lib/ogg/theora/Theora.js +23 -23
- package/lib/ogg/theora/TheoraParser.d.ts +28 -28
- package/lib/ogg/theora/TheoraParser.js +44 -44
- package/lib/ogg/vorbis/Vorbis.d.ts +69 -69
- package/lib/ogg/vorbis/Vorbis.js +78 -78
- package/lib/ogg/vorbis/VorbisDecoder.d.ts +12 -12
- package/lib/ogg/vorbis/VorbisDecoder.js +32 -32
- package/lib/ogg/vorbis/VorbisParser.d.ts +36 -36
- package/lib/ogg/vorbis/VorbisParser.js +128 -128
- package/lib/ogg/vorbis/VorbisTagMapper.d.ts +7 -7
- package/lib/ogg/vorbis/VorbisTagMapper.js +132 -132
- package/lib/riff/RiffChunk.d.ts +16 -16
- package/lib/riff/RiffChunk.js +32 -32
- package/lib/riff/RiffInfoTagMap.d.ts +10 -10
- package/lib/riff/RiffInfoTagMap.js +37 -37
- package/lib/type.d.ts +592 -592
- package/lib/type.js +5 -5
- package/lib/wav/BwfChunk.d.ts +17 -17
- package/lib/wav/BwfChunk.js +29 -28
- package/lib/wav/WaveChunk.d.ts +64 -64
- package/lib/wav/WaveChunk.js +65 -65
- package/lib/wav/WaveParser.d.ts +24 -24
- package/lib/wav/WaveParser.js +158 -156
- package/lib/wavpack/WavPackParser.d.ts +14 -14
- package/lib/wavpack/WavPackParser.js +99 -99
- package/lib/wavpack/WavPackToken.d.ts +64 -64
- package/lib/wavpack/WavPackToken.js +76 -76
- package/package.json +150 -150
package/lib/flac/FlacParser.js
CHANGED
|
@@ -1,175 +1,175 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FlacParser = void 0;
|
|
4
|
-
const token_types_1 = require("token-types");
|
|
5
|
-
const
|
|
6
|
-
const util = require("../common/Util");
|
|
7
|
-
const Vorbis_1 = require("../ogg/vorbis/Vorbis");
|
|
8
|
-
const AbstractID3Parser_1 = require("../id3v2/AbstractID3Parser");
|
|
9
|
-
const FourCC_1 = require("../common/FourCC");
|
|
10
|
-
const VorbisParser_1 = require("../ogg/vorbis/VorbisParser");
|
|
11
|
-
const VorbisDecoder_1 = require("../ogg/vorbis/VorbisDecoder");
|
|
12
|
-
const debug =
|
|
13
|
-
/**
|
|
14
|
-
* FLAC supports up to 128 kinds of metadata blocks; currently the following are defined:
|
|
15
|
-
* ref: https://xiph.org/flac/format.html#metadata_block
|
|
16
|
-
*/
|
|
17
|
-
var BlockType;
|
|
18
|
-
(function (BlockType) {
|
|
19
|
-
BlockType[BlockType["STREAMINFO"] = 0] = "STREAMINFO";
|
|
20
|
-
BlockType[BlockType["PADDING"] = 1] = "PADDING";
|
|
21
|
-
BlockType[BlockType["APPLICATION"] = 2] = "APPLICATION";
|
|
22
|
-
BlockType[BlockType["SEEKTABLE"] = 3] = "SEEKTABLE";
|
|
23
|
-
BlockType[BlockType["VORBIS_COMMENT"] = 4] = "VORBIS_COMMENT";
|
|
24
|
-
BlockType[BlockType["CUESHEET"] = 5] = "CUESHEET";
|
|
25
|
-
BlockType[BlockType["PICTURE"] = 6] = "PICTURE";
|
|
26
|
-
})(BlockType || (BlockType = {}));
|
|
27
|
-
class FlacParser extends AbstractID3Parser_1.AbstractID3Parser {
|
|
28
|
-
constructor() {
|
|
29
|
-
super(...arguments);
|
|
30
|
-
this.padding = 0;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Initialize parser with output (metadata), input (tokenizer) & parsing options (options).
|
|
34
|
-
* @param {INativeMetadataCollector} metadata Output
|
|
35
|
-
* @param {ITokenizer} tokenizer Input
|
|
36
|
-
* @param {IOptions} options Parsing options
|
|
37
|
-
*/
|
|
38
|
-
init(metadata, tokenizer, options) {
|
|
39
|
-
super.init(metadata, tokenizer, options);
|
|
40
|
-
this.vorbisParser = new VorbisParser_1.VorbisParser(metadata, options);
|
|
41
|
-
return this;
|
|
42
|
-
}
|
|
43
|
-
async postId3v2Parse() {
|
|
44
|
-
const fourCC = await this.tokenizer.readToken(FourCC_1.FourCcToken);
|
|
45
|
-
if (fourCC.toString() !== 'fLaC') {
|
|
46
|
-
throw new Error('Invalid FLAC preamble');
|
|
47
|
-
}
|
|
48
|
-
let blockHeader;
|
|
49
|
-
do {
|
|
50
|
-
// Read block header
|
|
51
|
-
blockHeader = await this.tokenizer.readToken(Metadata.BlockHeader);
|
|
52
|
-
// Parse block data
|
|
53
|
-
await this.parseDataBlock(blockHeader);
|
|
54
|
-
} while (!blockHeader.lastBlock);
|
|
55
|
-
if (this.tokenizer.fileInfo.size && this.metadata.format.duration) {
|
|
56
|
-
const dataSize = this.tokenizer.fileInfo.size - this.tokenizer.position;
|
|
57
|
-
this.metadata.setFormat('bitrate', 8 * dataSize / this.metadata.format.duration);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
parseDataBlock(blockHeader) {
|
|
61
|
-
debug(`blockHeader type=${blockHeader.type}, length=${blockHeader.length}`);
|
|
62
|
-
switch (blockHeader.type) {
|
|
63
|
-
case BlockType.STREAMINFO:
|
|
64
|
-
return this.parseBlockStreamInfo(blockHeader.length);
|
|
65
|
-
case BlockType.PADDING:
|
|
66
|
-
this.padding += blockHeader.length;
|
|
67
|
-
break;
|
|
68
|
-
case BlockType.APPLICATION:
|
|
69
|
-
break;
|
|
70
|
-
case BlockType.SEEKTABLE:
|
|
71
|
-
break;
|
|
72
|
-
case BlockType.VORBIS_COMMENT:
|
|
73
|
-
return this.parseComment(blockHeader.length);
|
|
74
|
-
case BlockType.CUESHEET:
|
|
75
|
-
break;
|
|
76
|
-
case BlockType.PICTURE:
|
|
77
|
-
return this.parsePicture(blockHeader.length).then();
|
|
78
|
-
default:
|
|
79
|
-
this.metadata.addWarning('Unknown block type: ' + blockHeader.type);
|
|
80
|
-
}
|
|
81
|
-
// Ignore data block
|
|
82
|
-
return this.tokenizer.ignore(blockHeader.length).then();
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Parse STREAMINFO
|
|
86
|
-
*/
|
|
87
|
-
async parseBlockStreamInfo(dataLen) {
|
|
88
|
-
if (dataLen !== Metadata.BlockStreamInfo.len)
|
|
89
|
-
throw new Error('Unexpected block-stream-info length');
|
|
90
|
-
const streamInfo = await this.tokenizer.readToken(Metadata.BlockStreamInfo);
|
|
91
|
-
this.metadata.setFormat('container', 'FLAC');
|
|
92
|
-
this.metadata.setFormat('codec', 'FLAC');
|
|
93
|
-
this.metadata.setFormat('lossless', true);
|
|
94
|
-
this.metadata.setFormat('numberOfChannels', streamInfo.channels);
|
|
95
|
-
this.metadata.setFormat('bitsPerSample', streamInfo.bitsPerSample);
|
|
96
|
-
this.metadata.setFormat('sampleRate', streamInfo.sampleRate);
|
|
97
|
-
if (streamInfo.totalSamples > 0) {
|
|
98
|
-
this.metadata.setFormat('duration', streamInfo.totalSamples / streamInfo.sampleRate);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Parse VORBIS_COMMENT
|
|
103
|
-
* Ref: https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-640004.2.3
|
|
104
|
-
*/
|
|
105
|
-
async parseComment(dataLen) {
|
|
106
|
-
const data = await this.tokenizer.readToken(new token_types_1.Uint8ArrayType(dataLen));
|
|
107
|
-
const decoder = new VorbisDecoder_1.VorbisDecoder(data, 0);
|
|
108
|
-
decoder.readStringUtf8(); // vendor (skip)
|
|
109
|
-
const commentListLength = decoder.readInt32();
|
|
110
|
-
for (let i = 0; i < commentListLength; i++) {
|
|
111
|
-
const tag = decoder.parseUserComment();
|
|
112
|
-
this.vorbisParser.addTag(tag.key, tag.value);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
async parsePicture(dataLen) {
|
|
116
|
-
if (this.options.skipCovers) {
|
|
117
|
-
return this.tokenizer.ignore(dataLen);
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
const picture = await this.tokenizer.readToken(new Vorbis_1.VorbisPictureToken(dataLen));
|
|
121
|
-
this.vorbisParser.addTag('METADATA_BLOCK_PICTURE', picture);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
exports.FlacParser = FlacParser;
|
|
126
|
-
class Metadata {
|
|
127
|
-
}
|
|
128
|
-
Metadata.BlockHeader = {
|
|
129
|
-
len: 4,
|
|
130
|
-
get: (buf, off) => {
|
|
131
|
-
return {
|
|
132
|
-
lastBlock: util.getBit(buf, off, 7),
|
|
133
|
-
type: util.getBitAllignedNumber(buf, off, 1, 7),
|
|
134
|
-
length: token_types_1.UINT24_BE.get(buf, off + 1)
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
/**
|
|
139
|
-
* METADATA_BLOCK_DATA
|
|
140
|
-
* Ref: https://xiph.org/flac/format.html#metadata_block_streaminfo
|
|
141
|
-
*/
|
|
142
|
-
Metadata.BlockStreamInfo = {
|
|
143
|
-
len: 34,
|
|
144
|
-
get: (buf, off) => {
|
|
145
|
-
return {
|
|
146
|
-
// The minimum block size (in samples) used in the stream.
|
|
147
|
-
minimumBlockSize: token_types_1.UINT16_BE.get(buf, off),
|
|
148
|
-
// The maximum block size (in samples) used in the stream.
|
|
149
|
-
// (Minimum blocksize == maximum blocksize) implies a fixed-blocksize stream.
|
|
150
|
-
maximumBlockSize: token_types_1.UINT16_BE.get(buf, off + 2) / 1000,
|
|
151
|
-
// The minimum frame size (in bytes) used in the stream.
|
|
152
|
-
// May be 0 to imply the value is not known.
|
|
153
|
-
minimumFrameSize: token_types_1.UINT24_BE.get(buf, off + 4),
|
|
154
|
-
// The maximum frame size (in bytes) used in the stream.
|
|
155
|
-
// May be 0 to imply the value is not known.
|
|
156
|
-
maximumFrameSize: token_types_1.UINT24_BE.get(buf, off + 7),
|
|
157
|
-
// Sample rate in Hz. Though 20 bits are available,
|
|
158
|
-
// the maximum sample rate is limited by the structure of frame headers to 655350Hz.
|
|
159
|
-
// Also, a value of 0 is invalid.
|
|
160
|
-
sampleRate: token_types_1.UINT24_BE.get(buf, off + 10) >> 4,
|
|
161
|
-
// probably slower: sampleRate: common.getBitAllignedNumber(buf, off + 10, 0, 20),
|
|
162
|
-
// (number of channels)-1. FLAC supports from 1 to 8 channels
|
|
163
|
-
channels: util.getBitAllignedNumber(buf, off + 12, 4, 3) + 1,
|
|
164
|
-
// bits per sample)-1.
|
|
165
|
-
// FLAC supports from 4 to 32 bits per sample. Currently the reference encoder and decoders only support up to 24 bits per sample.
|
|
166
|
-
bitsPerSample: util.getBitAllignedNumber(buf, off + 12, 7, 5) + 1,
|
|
167
|
-
// Total samples in stream.
|
|
168
|
-
// 'Samples' means inter-channel sample, i.e. one second of 44.1Khz audio will have 44100 samples regardless of the number of channels.
|
|
169
|
-
// A value of zero here means the number of total samples is unknown.
|
|
170
|
-
totalSamples: util.getBitAllignedNumber(buf, off + 13, 4, 36),
|
|
171
|
-
// the MD5 hash of the file (see notes for usage... it's a littly tricky)
|
|
172
|
-
fileMD5: new token_types_1.Uint8ArrayType(16).get(buf, off + 18)
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
};
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FlacParser = void 0;
|
|
4
|
+
const token_types_1 = require("token-types");
|
|
5
|
+
const debug_1 = require("debug");
|
|
6
|
+
const util = require("../common/Util");
|
|
7
|
+
const Vorbis_1 = require("../ogg/vorbis/Vorbis");
|
|
8
|
+
const AbstractID3Parser_1 = require("../id3v2/AbstractID3Parser");
|
|
9
|
+
const FourCC_1 = require("../common/FourCC");
|
|
10
|
+
const VorbisParser_1 = require("../ogg/vorbis/VorbisParser");
|
|
11
|
+
const VorbisDecoder_1 = require("../ogg/vorbis/VorbisDecoder");
|
|
12
|
+
const debug = (0, debug_1.default)('music-metadata:parser:FLAC');
|
|
13
|
+
/**
|
|
14
|
+
* FLAC supports up to 128 kinds of metadata blocks; currently the following are defined:
|
|
15
|
+
* ref: https://xiph.org/flac/format.html#metadata_block
|
|
16
|
+
*/
|
|
17
|
+
var BlockType;
|
|
18
|
+
(function (BlockType) {
|
|
19
|
+
BlockType[BlockType["STREAMINFO"] = 0] = "STREAMINFO";
|
|
20
|
+
BlockType[BlockType["PADDING"] = 1] = "PADDING";
|
|
21
|
+
BlockType[BlockType["APPLICATION"] = 2] = "APPLICATION";
|
|
22
|
+
BlockType[BlockType["SEEKTABLE"] = 3] = "SEEKTABLE";
|
|
23
|
+
BlockType[BlockType["VORBIS_COMMENT"] = 4] = "VORBIS_COMMENT";
|
|
24
|
+
BlockType[BlockType["CUESHEET"] = 5] = "CUESHEET";
|
|
25
|
+
BlockType[BlockType["PICTURE"] = 6] = "PICTURE";
|
|
26
|
+
})(BlockType || (BlockType = {}));
|
|
27
|
+
class FlacParser extends AbstractID3Parser_1.AbstractID3Parser {
|
|
28
|
+
constructor() {
|
|
29
|
+
super(...arguments);
|
|
30
|
+
this.padding = 0;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Initialize parser with output (metadata), input (tokenizer) & parsing options (options).
|
|
34
|
+
* @param {INativeMetadataCollector} metadata Output
|
|
35
|
+
* @param {ITokenizer} tokenizer Input
|
|
36
|
+
* @param {IOptions} options Parsing options
|
|
37
|
+
*/
|
|
38
|
+
init(metadata, tokenizer, options) {
|
|
39
|
+
super.init(metadata, tokenizer, options);
|
|
40
|
+
this.vorbisParser = new VorbisParser_1.VorbisParser(metadata, options);
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
async postId3v2Parse() {
|
|
44
|
+
const fourCC = await this.tokenizer.readToken(FourCC_1.FourCcToken);
|
|
45
|
+
if (fourCC.toString() !== 'fLaC') {
|
|
46
|
+
throw new Error('Invalid FLAC preamble');
|
|
47
|
+
}
|
|
48
|
+
let blockHeader;
|
|
49
|
+
do {
|
|
50
|
+
// Read block header
|
|
51
|
+
blockHeader = await this.tokenizer.readToken(Metadata.BlockHeader);
|
|
52
|
+
// Parse block data
|
|
53
|
+
await this.parseDataBlock(blockHeader);
|
|
54
|
+
} while (!blockHeader.lastBlock);
|
|
55
|
+
if (this.tokenizer.fileInfo.size && this.metadata.format.duration) {
|
|
56
|
+
const dataSize = this.tokenizer.fileInfo.size - this.tokenizer.position;
|
|
57
|
+
this.metadata.setFormat('bitrate', 8 * dataSize / this.metadata.format.duration);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
parseDataBlock(blockHeader) {
|
|
61
|
+
debug(`blockHeader type=${blockHeader.type}, length=${blockHeader.length}`);
|
|
62
|
+
switch (blockHeader.type) {
|
|
63
|
+
case BlockType.STREAMINFO:
|
|
64
|
+
return this.parseBlockStreamInfo(blockHeader.length);
|
|
65
|
+
case BlockType.PADDING:
|
|
66
|
+
this.padding += blockHeader.length;
|
|
67
|
+
break;
|
|
68
|
+
case BlockType.APPLICATION:
|
|
69
|
+
break;
|
|
70
|
+
case BlockType.SEEKTABLE:
|
|
71
|
+
break;
|
|
72
|
+
case BlockType.VORBIS_COMMENT:
|
|
73
|
+
return this.parseComment(blockHeader.length);
|
|
74
|
+
case BlockType.CUESHEET:
|
|
75
|
+
break;
|
|
76
|
+
case BlockType.PICTURE:
|
|
77
|
+
return this.parsePicture(blockHeader.length).then();
|
|
78
|
+
default:
|
|
79
|
+
this.metadata.addWarning('Unknown block type: ' + blockHeader.type);
|
|
80
|
+
}
|
|
81
|
+
// Ignore data block
|
|
82
|
+
return this.tokenizer.ignore(blockHeader.length).then();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Parse STREAMINFO
|
|
86
|
+
*/
|
|
87
|
+
async parseBlockStreamInfo(dataLen) {
|
|
88
|
+
if (dataLen !== Metadata.BlockStreamInfo.len)
|
|
89
|
+
throw new Error('Unexpected block-stream-info length');
|
|
90
|
+
const streamInfo = await this.tokenizer.readToken(Metadata.BlockStreamInfo);
|
|
91
|
+
this.metadata.setFormat('container', 'FLAC');
|
|
92
|
+
this.metadata.setFormat('codec', 'FLAC');
|
|
93
|
+
this.metadata.setFormat('lossless', true);
|
|
94
|
+
this.metadata.setFormat('numberOfChannels', streamInfo.channels);
|
|
95
|
+
this.metadata.setFormat('bitsPerSample', streamInfo.bitsPerSample);
|
|
96
|
+
this.metadata.setFormat('sampleRate', streamInfo.sampleRate);
|
|
97
|
+
if (streamInfo.totalSamples > 0) {
|
|
98
|
+
this.metadata.setFormat('duration', streamInfo.totalSamples / streamInfo.sampleRate);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Parse VORBIS_COMMENT
|
|
103
|
+
* Ref: https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-640004.2.3
|
|
104
|
+
*/
|
|
105
|
+
async parseComment(dataLen) {
|
|
106
|
+
const data = await this.tokenizer.readToken(new token_types_1.Uint8ArrayType(dataLen));
|
|
107
|
+
const decoder = new VorbisDecoder_1.VorbisDecoder(data, 0);
|
|
108
|
+
decoder.readStringUtf8(); // vendor (skip)
|
|
109
|
+
const commentListLength = decoder.readInt32();
|
|
110
|
+
for (let i = 0; i < commentListLength; i++) {
|
|
111
|
+
const tag = decoder.parseUserComment();
|
|
112
|
+
this.vorbisParser.addTag(tag.key, tag.value);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async parsePicture(dataLen) {
|
|
116
|
+
if (this.options.skipCovers) {
|
|
117
|
+
return this.tokenizer.ignore(dataLen);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
const picture = await this.tokenizer.readToken(new Vorbis_1.VorbisPictureToken(dataLen));
|
|
121
|
+
this.vorbisParser.addTag('METADATA_BLOCK_PICTURE', picture);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.FlacParser = FlacParser;
|
|
126
|
+
class Metadata {
|
|
127
|
+
}
|
|
128
|
+
Metadata.BlockHeader = {
|
|
129
|
+
len: 4,
|
|
130
|
+
get: (buf, off) => {
|
|
131
|
+
return {
|
|
132
|
+
lastBlock: util.getBit(buf, off, 7),
|
|
133
|
+
type: util.getBitAllignedNumber(buf, off, 1, 7),
|
|
134
|
+
length: token_types_1.UINT24_BE.get(buf, off + 1)
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* METADATA_BLOCK_DATA
|
|
140
|
+
* Ref: https://xiph.org/flac/format.html#metadata_block_streaminfo
|
|
141
|
+
*/
|
|
142
|
+
Metadata.BlockStreamInfo = {
|
|
143
|
+
len: 34,
|
|
144
|
+
get: (buf, off) => {
|
|
145
|
+
return {
|
|
146
|
+
// The minimum block size (in samples) used in the stream.
|
|
147
|
+
minimumBlockSize: token_types_1.UINT16_BE.get(buf, off),
|
|
148
|
+
// The maximum block size (in samples) used in the stream.
|
|
149
|
+
// (Minimum blocksize == maximum blocksize) implies a fixed-blocksize stream.
|
|
150
|
+
maximumBlockSize: token_types_1.UINT16_BE.get(buf, off + 2) / 1000,
|
|
151
|
+
// The minimum frame size (in bytes) used in the stream.
|
|
152
|
+
// May be 0 to imply the value is not known.
|
|
153
|
+
minimumFrameSize: token_types_1.UINT24_BE.get(buf, off + 4),
|
|
154
|
+
// The maximum frame size (in bytes) used in the stream.
|
|
155
|
+
// May be 0 to imply the value is not known.
|
|
156
|
+
maximumFrameSize: token_types_1.UINT24_BE.get(buf, off + 7),
|
|
157
|
+
// Sample rate in Hz. Though 20 bits are available,
|
|
158
|
+
// the maximum sample rate is limited by the structure of frame headers to 655350Hz.
|
|
159
|
+
// Also, a value of 0 is invalid.
|
|
160
|
+
sampleRate: token_types_1.UINT24_BE.get(buf, off + 10) >> 4,
|
|
161
|
+
// probably slower: sampleRate: common.getBitAllignedNumber(buf, off + 10, 0, 20),
|
|
162
|
+
// (number of channels)-1. FLAC supports from 1 to 8 channels
|
|
163
|
+
channels: util.getBitAllignedNumber(buf, off + 12, 4, 3) + 1,
|
|
164
|
+
// bits per sample)-1.
|
|
165
|
+
// FLAC supports from 4 to 32 bits per sample. Currently the reference encoder and decoders only support up to 24 bits per sample.
|
|
166
|
+
bitsPerSample: util.getBitAllignedNumber(buf, off + 12, 7, 5) + 1,
|
|
167
|
+
// Total samples in stream.
|
|
168
|
+
// 'Samples' means inter-channel sample, i.e. one second of 44.1Khz audio will have 44100 samples regardless of the number of channels.
|
|
169
|
+
// A value of zero here means the number of total samples is unknown.
|
|
170
|
+
totalSamples: util.getBitAllignedNumber(buf, off + 13, 4, 36),
|
|
171
|
+
// the MD5 hash of the file (see notes for usage... it's a littly tricky)
|
|
172
|
+
fileMD5: new token_types_1.Uint8ArrayType(16).get(buf, off + 18)
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { BasicParser } from '../common/BasicParser';
|
|
2
|
-
import { IRandomReader } from '../type';
|
|
3
|
-
/**
|
|
4
|
-
* ID3v1 Genre mappings
|
|
5
|
-
* Ref: https://de.wikipedia.org/wiki/Liste_der_ID3v1-Genres
|
|
6
|
-
*/
|
|
7
|
-
export declare const Genres: string[];
|
|
8
|
-
export declare class ID3v1Parser extends BasicParser {
|
|
9
|
-
private static getGenre;
|
|
10
|
-
parse(): Promise<void>;
|
|
11
|
-
private addTag;
|
|
12
|
-
}
|
|
13
|
-
export declare function hasID3v1Header(reader: IRandomReader): Promise<boolean>;
|
|
1
|
+
import { BasicParser } from '../common/BasicParser';
|
|
2
|
+
import { IRandomReader } from '../type';
|
|
3
|
+
/**
|
|
4
|
+
* ID3v1 Genre mappings
|
|
5
|
+
* Ref: https://de.wikipedia.org/wiki/Liste_der_ID3v1-Genres
|
|
6
|
+
*/
|
|
7
|
+
export declare const Genres: string[];
|
|
8
|
+
export declare class ID3v1Parser extends BasicParser {
|
|
9
|
+
private static getGenre;
|
|
10
|
+
parse(): Promise<void>;
|
|
11
|
+
private addTag;
|
|
12
|
+
}
|
|
13
|
+
export declare function hasID3v1Header(reader: IRandomReader): Promise<boolean>;
|