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
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.StreamReader = void 0;
|
|
4
|
-
const Token = require("token-types");
|
|
5
|
-
const
|
|
6
|
-
const util = require("../../common/Util");
|
|
7
|
-
const debug =
|
|
8
|
-
const PacketKey = new Token.StringType(2, 'binary');
|
|
9
|
-
/**
|
|
10
|
-
* Stream Header Packet part 1
|
|
11
|
-
* Ref: http://trac.musepack.net/musepack/wiki/SV8Specification#StreamHeaderPacket
|
|
12
|
-
*/
|
|
13
|
-
const SH_part1 = {
|
|
14
|
-
len: 5,
|
|
15
|
-
get: (buf, off) => {
|
|
16
|
-
return {
|
|
17
|
-
crc: Token.UINT32_LE.get(buf, off),
|
|
18
|
-
streamVersion: Token.UINT8.get(buf, off + 4)
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* Stream Header Packet part 3
|
|
24
|
-
* Ref: http://trac.musepack.net/musepack/wiki/SV8Specification#StreamHeaderPacket
|
|
25
|
-
*/
|
|
26
|
-
const SH_part3 = {
|
|
27
|
-
len: 2,
|
|
28
|
-
get: (buf, off) => {
|
|
29
|
-
return {
|
|
30
|
-
sampleFrequency: [44100, 48000, 37800, 32000][util.getBitAllignedNumber(buf, off, 0, 3)],
|
|
31
|
-
maxUsedBands: util.getBitAllignedNumber(buf, off, 3, 5),
|
|
32
|
-
channelCount: util.getBitAllignedNumber(buf, off + 1, 0, 4) + 1,
|
|
33
|
-
msUsed: util.isBitSet(buf, off + 1, 4),
|
|
34
|
-
audioBlockFrames: util.getBitAllignedNumber(buf, off + 1, 5, 3)
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
class StreamReader {
|
|
39
|
-
constructor(tokenizer) {
|
|
40
|
-
this.tokenizer = tokenizer;
|
|
41
|
-
}
|
|
42
|
-
async readPacketHeader() {
|
|
43
|
-
const key = await this.tokenizer.readToken(PacketKey);
|
|
44
|
-
const size = await this.readVariableSizeField();
|
|
45
|
-
return {
|
|
46
|
-
key,
|
|
47
|
-
payloadLength: size.value - 2 - size.len
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
async readStreamHeader(size) {
|
|
51
|
-
const streamHeader = {};
|
|
52
|
-
debug(`Reading SH at offset=${this.tokenizer.position}`);
|
|
53
|
-
const part1 = await this.tokenizer.readToken(SH_part1);
|
|
54
|
-
size -= SH_part1.len;
|
|
55
|
-
Object.assign(streamHeader, part1);
|
|
56
|
-
debug(`SH.streamVersion = ${part1.streamVersion}`);
|
|
57
|
-
const sampleCount = await this.readVariableSizeField();
|
|
58
|
-
size -= sampleCount.len;
|
|
59
|
-
streamHeader.sampleCount = sampleCount.value;
|
|
60
|
-
const bs = await this.readVariableSizeField();
|
|
61
|
-
size -= bs.len;
|
|
62
|
-
streamHeader.beginningOfSilence = bs.value;
|
|
63
|
-
const part3 = await this.tokenizer.readToken(SH_part3);
|
|
64
|
-
size -= SH_part3.len;
|
|
65
|
-
Object.assign(streamHeader, part3);
|
|
66
|
-
// assert.equal(size, 0);
|
|
67
|
-
await this.tokenizer.ignore(size);
|
|
68
|
-
return streamHeader;
|
|
69
|
-
}
|
|
70
|
-
async readVariableSizeField(len = 1, hb = 0) {
|
|
71
|
-
let n = await this.tokenizer.readNumber(Token.UINT8);
|
|
72
|
-
if ((n & 0x80) === 0) {
|
|
73
|
-
return { len, value: hb + n };
|
|
74
|
-
}
|
|
75
|
-
n &= 0x7F;
|
|
76
|
-
n += hb;
|
|
77
|
-
return this.readVariableSizeField(len + 1, n << 7);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
exports.StreamReader = StreamReader;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StreamReader = void 0;
|
|
4
|
+
const Token = require("token-types");
|
|
5
|
+
const debug_1 = require("debug");
|
|
6
|
+
const util = require("../../common/Util");
|
|
7
|
+
const debug = (0, debug_1.default)('music-metadata:parser:musepack:sv8');
|
|
8
|
+
const PacketKey = new Token.StringType(2, 'binary');
|
|
9
|
+
/**
|
|
10
|
+
* Stream Header Packet part 1
|
|
11
|
+
* Ref: http://trac.musepack.net/musepack/wiki/SV8Specification#StreamHeaderPacket
|
|
12
|
+
*/
|
|
13
|
+
const SH_part1 = {
|
|
14
|
+
len: 5,
|
|
15
|
+
get: (buf, off) => {
|
|
16
|
+
return {
|
|
17
|
+
crc: Token.UINT32_LE.get(buf, off),
|
|
18
|
+
streamVersion: Token.UINT8.get(buf, off + 4)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Stream Header Packet part 3
|
|
24
|
+
* Ref: http://trac.musepack.net/musepack/wiki/SV8Specification#StreamHeaderPacket
|
|
25
|
+
*/
|
|
26
|
+
const SH_part3 = {
|
|
27
|
+
len: 2,
|
|
28
|
+
get: (buf, off) => {
|
|
29
|
+
return {
|
|
30
|
+
sampleFrequency: [44100, 48000, 37800, 32000][util.getBitAllignedNumber(buf, off, 0, 3)],
|
|
31
|
+
maxUsedBands: util.getBitAllignedNumber(buf, off, 3, 5),
|
|
32
|
+
channelCount: util.getBitAllignedNumber(buf, off + 1, 0, 4) + 1,
|
|
33
|
+
msUsed: util.isBitSet(buf, off + 1, 4),
|
|
34
|
+
audioBlockFrames: util.getBitAllignedNumber(buf, off + 1, 5, 3)
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
class StreamReader {
|
|
39
|
+
constructor(tokenizer) {
|
|
40
|
+
this.tokenizer = tokenizer;
|
|
41
|
+
}
|
|
42
|
+
async readPacketHeader() {
|
|
43
|
+
const key = await this.tokenizer.readToken(PacketKey);
|
|
44
|
+
const size = await this.readVariableSizeField();
|
|
45
|
+
return {
|
|
46
|
+
key,
|
|
47
|
+
payloadLength: size.value - 2 - size.len
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
async readStreamHeader(size) {
|
|
51
|
+
const streamHeader = {};
|
|
52
|
+
debug(`Reading SH at offset=${this.tokenizer.position}`);
|
|
53
|
+
const part1 = await this.tokenizer.readToken(SH_part1);
|
|
54
|
+
size -= SH_part1.len;
|
|
55
|
+
Object.assign(streamHeader, part1);
|
|
56
|
+
debug(`SH.streamVersion = ${part1.streamVersion}`);
|
|
57
|
+
const sampleCount = await this.readVariableSizeField();
|
|
58
|
+
size -= sampleCount.len;
|
|
59
|
+
streamHeader.sampleCount = sampleCount.value;
|
|
60
|
+
const bs = await this.readVariableSizeField();
|
|
61
|
+
size -= bs.len;
|
|
62
|
+
streamHeader.beginningOfSilence = bs.value;
|
|
63
|
+
const part3 = await this.tokenizer.readToken(SH_part3);
|
|
64
|
+
size -= SH_part3.len;
|
|
65
|
+
Object.assign(streamHeader, part3);
|
|
66
|
+
// assert.equal(size, 0);
|
|
67
|
+
await this.tokenizer.ignore(size);
|
|
68
|
+
return streamHeader;
|
|
69
|
+
}
|
|
70
|
+
async readVariableSizeField(len = 1, hb = 0) {
|
|
71
|
+
let n = await this.tokenizer.readNumber(Token.UINT8);
|
|
72
|
+
if ((n & 0x80) === 0) {
|
|
73
|
+
return { len, value: hb + n };
|
|
74
|
+
}
|
|
75
|
+
n &= 0x7F;
|
|
76
|
+
n += hb;
|
|
77
|
+
return this.readVariableSizeField(len + 1, n << 7);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.StreamReader = StreamReader;
|
package/lib/ogg/Ogg.d.ts
CHANGED
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Page header
|
|
3
|
-
* Ref: https://www.xiph.org/ogg/doc/framing.html#page_header
|
|
4
|
-
*/
|
|
5
|
-
export interface IPageHeader {
|
|
6
|
-
/**
|
|
7
|
-
* capture_pattern
|
|
8
|
-
* A header begins with a capture pattern that simplifies identifying pages;
|
|
9
|
-
* once the decoder has found the capture pattern it can do a more intensive job of verifying that it has in fact found a page boundary (as opposed to an inadvertent coincidence in the byte stream).
|
|
10
|
-
*/
|
|
11
|
-
capturePattern: string;
|
|
12
|
-
/**
|
|
13
|
-
* stream_structure_version
|
|
14
|
-
*/
|
|
15
|
-
version: number;
|
|
16
|
-
/**
|
|
17
|
-
* header_type_flag
|
|
18
|
-
*/
|
|
19
|
-
headerType: {
|
|
20
|
-
/**
|
|
21
|
-
* True: continued packet;
|
|
22
|
-
* False: fresh packet
|
|
23
|
-
*/
|
|
24
|
-
continued: boolean;
|
|
25
|
-
/**
|
|
26
|
-
* True: first page of logical bitstream (bos)
|
|
27
|
-
* False: not first page of logical bitstream
|
|
28
|
-
*/
|
|
29
|
-
firstPage: boolean;
|
|
30
|
-
/**
|
|
31
|
-
* True: last page of logical bitstream (eos)
|
|
32
|
-
* False: not last page of logical bitstream
|
|
33
|
-
*/
|
|
34
|
-
lastPage: boolean;
|
|
35
|
-
};
|
|
36
|
-
/**
|
|
37
|
-
* The total samples encoded after including all packets finished on this page
|
|
38
|
-
* The position specified in the frame header of the last page tells how long the data coded by the bitstream is.
|
|
39
|
-
*/
|
|
40
|
-
absoluteGranulePosition: number;
|
|
41
|
-
streamSerialNumber: number;
|
|
42
|
-
pageSequenceNo: number;
|
|
43
|
-
pageChecksum: number;
|
|
44
|
-
/**
|
|
45
|
-
* The number of segment entries to appear in the segment table.
|
|
46
|
-
* The maximum number of 255 segments (255 bytes each) sets the maximum possible physical page size at 65307 bytes or
|
|
47
|
-
* just under 64kB (thus we know that a header corrupted so as destroy sizing/alignment information will not cause a
|
|
48
|
-
* runaway bitstream. We'll read in the page according to the corrupted size information that's guaranteed to be a
|
|
49
|
-
* reasonable size regardless, notice the checksum mismatch, drop sync and then look for recapture).
|
|
50
|
-
*/
|
|
51
|
-
page_segments: number;
|
|
52
|
-
}
|
|
53
|
-
export interface ISegmentTable {
|
|
54
|
-
totalPageSize: number;
|
|
55
|
-
}
|
|
56
|
-
export interface IPageConsumer {
|
|
57
|
-
/**
|
|
58
|
-
* Parse Ogg page
|
|
59
|
-
* @param {IPageHeader} header Ogg page header
|
|
60
|
-
* @param {Buffer} pageData Ogg page data
|
|
61
|
-
*/
|
|
62
|
-
parsePage(header: IPageHeader, pageData: Uint8Array): any;
|
|
63
|
-
/**
|
|
64
|
-
* Calculate duration of provided header
|
|
65
|
-
* @param header Ogg header
|
|
66
|
-
*/
|
|
67
|
-
calculateDuration(header: IPageHeader): any;
|
|
68
|
-
/**
|
|
69
|
-
* Force to parse pending segments
|
|
70
|
-
*/
|
|
71
|
-
flush(): any;
|
|
72
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Page header
|
|
3
|
+
* Ref: https://www.xiph.org/ogg/doc/framing.html#page_header
|
|
4
|
+
*/
|
|
5
|
+
export interface IPageHeader {
|
|
6
|
+
/**
|
|
7
|
+
* capture_pattern
|
|
8
|
+
* A header begins with a capture pattern that simplifies identifying pages;
|
|
9
|
+
* once the decoder has found the capture pattern it can do a more intensive job of verifying that it has in fact found a page boundary (as opposed to an inadvertent coincidence in the byte stream).
|
|
10
|
+
*/
|
|
11
|
+
capturePattern: string;
|
|
12
|
+
/**
|
|
13
|
+
* stream_structure_version
|
|
14
|
+
*/
|
|
15
|
+
version: number;
|
|
16
|
+
/**
|
|
17
|
+
* header_type_flag
|
|
18
|
+
*/
|
|
19
|
+
headerType: {
|
|
20
|
+
/**
|
|
21
|
+
* True: continued packet;
|
|
22
|
+
* False: fresh packet
|
|
23
|
+
*/
|
|
24
|
+
continued: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* True: first page of logical bitstream (bos)
|
|
27
|
+
* False: not first page of logical bitstream
|
|
28
|
+
*/
|
|
29
|
+
firstPage: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* True: last page of logical bitstream (eos)
|
|
32
|
+
* False: not last page of logical bitstream
|
|
33
|
+
*/
|
|
34
|
+
lastPage: boolean;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* The total samples encoded after including all packets finished on this page
|
|
38
|
+
* The position specified in the frame header of the last page tells how long the data coded by the bitstream is.
|
|
39
|
+
*/
|
|
40
|
+
absoluteGranulePosition: number;
|
|
41
|
+
streamSerialNumber: number;
|
|
42
|
+
pageSequenceNo: number;
|
|
43
|
+
pageChecksum: number;
|
|
44
|
+
/**
|
|
45
|
+
* The number of segment entries to appear in the segment table.
|
|
46
|
+
* The maximum number of 255 segments (255 bytes each) sets the maximum possible physical page size at 65307 bytes or
|
|
47
|
+
* just under 64kB (thus we know that a header corrupted so as destroy sizing/alignment information will not cause a
|
|
48
|
+
* runaway bitstream. We'll read in the page according to the corrupted size information that's guaranteed to be a
|
|
49
|
+
* reasonable size regardless, notice the checksum mismatch, drop sync and then look for recapture).
|
|
50
|
+
*/
|
|
51
|
+
page_segments: number;
|
|
52
|
+
}
|
|
53
|
+
export interface ISegmentTable {
|
|
54
|
+
totalPageSize: number;
|
|
55
|
+
}
|
|
56
|
+
export interface IPageConsumer {
|
|
57
|
+
/**
|
|
58
|
+
* Parse Ogg page
|
|
59
|
+
* @param {IPageHeader} header Ogg page header
|
|
60
|
+
* @param {Buffer} pageData Ogg page data
|
|
61
|
+
*/
|
|
62
|
+
parsePage(header: IPageHeader, pageData: Uint8Array): any;
|
|
63
|
+
/**
|
|
64
|
+
* Calculate duration of provided header
|
|
65
|
+
* @param header Ogg header
|
|
66
|
+
*/
|
|
67
|
+
calculateDuration(header: IPageHeader): any;
|
|
68
|
+
/**
|
|
69
|
+
* Force to parse pending segments
|
|
70
|
+
*/
|
|
71
|
+
flush(): any;
|
|
72
|
+
}
|
package/lib/ogg/Ogg.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
package/lib/ogg/OggParser.d.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { IGetToken } from 'strtok3/lib/core';
|
|
2
|
-
import { BasicParser } from '../common/BasicParser';
|
|
3
|
-
import * as Ogg from './Ogg';
|
|
4
|
-
export declare class SegmentTable implements IGetToken<Ogg.ISegmentTable> {
|
|
5
|
-
private static sum;
|
|
6
|
-
len: number;
|
|
7
|
-
constructor(header: Ogg.IPageHeader);
|
|
8
|
-
get(buf: any, off: any): Ogg.ISegmentTable;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Parser for Ogg logical bitstream framing
|
|
12
|
-
*/
|
|
13
|
-
export declare class OggParser extends BasicParser {
|
|
14
|
-
private static Header;
|
|
15
|
-
private header;
|
|
16
|
-
private pageNumber;
|
|
17
|
-
private pageConsumer;
|
|
18
|
-
/**
|
|
19
|
-
* Parse page
|
|
20
|
-
* @returns {Promise<void>}
|
|
21
|
-
*/
|
|
22
|
-
parse(): Promise<void>;
|
|
23
|
-
}
|
|
1
|
+
import { IGetToken } from 'strtok3/lib/core';
|
|
2
|
+
import { BasicParser } from '../common/BasicParser';
|
|
3
|
+
import * as Ogg from './Ogg';
|
|
4
|
+
export declare class SegmentTable implements IGetToken<Ogg.ISegmentTable> {
|
|
5
|
+
private static sum;
|
|
6
|
+
len: number;
|
|
7
|
+
constructor(header: Ogg.IPageHeader);
|
|
8
|
+
get(buf: any, off: any): Ogg.ISegmentTable;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Parser for Ogg logical bitstream framing
|
|
12
|
+
*/
|
|
13
|
+
export declare class OggParser extends BasicParser {
|
|
14
|
+
private static Header;
|
|
15
|
+
private header;
|
|
16
|
+
private pageNumber;
|
|
17
|
+
private pageConsumer;
|
|
18
|
+
/**
|
|
19
|
+
* Parse page
|
|
20
|
+
* @returns {Promise<void>}
|
|
21
|
+
*/
|
|
22
|
+
parse(): Promise<void>;
|
|
23
|
+
}
|
package/lib/ogg/OggParser.js
CHANGED
|
@@ -1,126 +1,126 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OggParser = exports.SegmentTable = void 0;
|
|
4
|
-
const Token = require("token-types");
|
|
5
|
-
const core_1 = require("strtok3/lib/core");
|
|
6
|
-
const
|
|
7
|
-
const util = require("../common/Util");
|
|
8
|
-
const FourCC_1 = require("../common/FourCC");
|
|
9
|
-
const BasicParser_1 = require("../common/BasicParser");
|
|
10
|
-
const VorbisParser_1 = require("./vorbis/VorbisParser");
|
|
11
|
-
const OpusParser_1 = require("./opus/OpusParser");
|
|
12
|
-
const SpeexParser_1 = require("./speex/SpeexParser");
|
|
13
|
-
const TheoraParser_1 = require("./theora/TheoraParser");
|
|
14
|
-
const debug =
|
|
15
|
-
class SegmentTable {
|
|
16
|
-
constructor(header) {
|
|
17
|
-
this.len = header.page_segments;
|
|
18
|
-
}
|
|
19
|
-
static sum(buf, off, len) {
|
|
20
|
-
let s = 0;
|
|
21
|
-
for (let i = off; i < off + len; ++i) {
|
|
22
|
-
s += buf[i];
|
|
23
|
-
}
|
|
24
|
-
return s;
|
|
25
|
-
}
|
|
26
|
-
get(buf, off) {
|
|
27
|
-
return {
|
|
28
|
-
totalPageSize: SegmentTable.sum(buf, off, this.len)
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
exports.SegmentTable = SegmentTable;
|
|
33
|
-
/**
|
|
34
|
-
* Parser for Ogg logical bitstream framing
|
|
35
|
-
*/
|
|
36
|
-
class OggParser extends BasicParser_1.BasicParser {
|
|
37
|
-
/**
|
|
38
|
-
* Parse page
|
|
39
|
-
* @returns {Promise<void>}
|
|
40
|
-
*/
|
|
41
|
-
async parse() {
|
|
42
|
-
debug('pos=%s, parsePage()', this.tokenizer.position);
|
|
43
|
-
try {
|
|
44
|
-
let header;
|
|
45
|
-
do {
|
|
46
|
-
header = await this.tokenizer.readToken(OggParser.Header);
|
|
47
|
-
if (header.capturePattern !== 'OggS')
|
|
48
|
-
throw new Error('Invalid Ogg capture pattern');
|
|
49
|
-
this.metadata.setFormat('container', 'Ogg');
|
|
50
|
-
this.header = header;
|
|
51
|
-
this.pageNumber = header.pageSequenceNo;
|
|
52
|
-
debug('page#=%s, Ogg.id=%s', header.pageSequenceNo, header.capturePattern);
|
|
53
|
-
const segmentTable = await this.tokenizer.readToken(new SegmentTable(header));
|
|
54
|
-
debug('totalPageSize=%s', segmentTable.totalPageSize);
|
|
55
|
-
const pageData = await this.tokenizer.readToken(new Token.Uint8ArrayType(segmentTable.totalPageSize));
|
|
56
|
-
debug('firstPage=%s, lastPage=%s, continued=%s', header.headerType.firstPage, header.headerType.lastPage, header.headerType.continued);
|
|
57
|
-
if (header.headerType.firstPage) {
|
|
58
|
-
const id = new Token.StringType(7, 'ascii').get(Buffer.from(pageData), 0);
|
|
59
|
-
switch (id) {
|
|
60
|
-
case '\x01vorbis': // Ogg/Vorbis
|
|
61
|
-
debug('Set page consumer to Ogg/Vorbis');
|
|
62
|
-
this.pageConsumer = new VorbisParser_1.VorbisParser(this.metadata, this.options);
|
|
63
|
-
break;
|
|
64
|
-
case 'OpusHea': // Ogg/Opus
|
|
65
|
-
debug('Set page consumer to Ogg/Opus');
|
|
66
|
-
this.pageConsumer = new OpusParser_1.OpusParser(this.metadata, this.options, this.tokenizer);
|
|
67
|
-
break;
|
|
68
|
-
case 'Speex ': // Ogg/Speex
|
|
69
|
-
debug('Set page consumer to Ogg/Speex');
|
|
70
|
-
this.pageConsumer = new SpeexParser_1.SpeexParser(this.metadata, this.options, this.tokenizer);
|
|
71
|
-
break;
|
|
72
|
-
case 'fishead':
|
|
73
|
-
case '\x00theora': // Ogg/Theora
|
|
74
|
-
debug('Set page consumer to Ogg/Theora');
|
|
75
|
-
this.pageConsumer = new TheoraParser_1.TheoraParser(this.metadata, this.options, this.tokenizer);
|
|
76
|
-
break;
|
|
77
|
-
default:
|
|
78
|
-
throw new Error('gg audio-codec not recognized (id=' + id + ')');
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
this.pageConsumer.parsePage(header, pageData);
|
|
82
|
-
} while (!header.headerType.lastPage);
|
|
83
|
-
}
|
|
84
|
-
catch (err) {
|
|
85
|
-
if (err instanceof core_1.EndOfStreamError) {
|
|
86
|
-
this.metadata.addWarning('Last OGG-page is not marked with last-page flag');
|
|
87
|
-
debug(`End-of-stream`);
|
|
88
|
-
this.metadata.addWarning('Last OGG-page is not marked with last-page flag');
|
|
89
|
-
if (this.header) {
|
|
90
|
-
this.pageConsumer.calculateDuration(this.header);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
else if (err.message.startsWith('FourCC')) {
|
|
94
|
-
if (this.pageNumber > 0) {
|
|
95
|
-
// ignore this error: work-around if last OGG-page is not marked with last-page flag
|
|
96
|
-
this.metadata.addWarning('Invalid FourCC ID, maybe last OGG-page is not marked with last-page flag');
|
|
97
|
-
this.pageConsumer.flush();
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
throw err;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
exports.OggParser = OggParser;
|
|
107
|
-
OggParser.Header = {
|
|
108
|
-
len: 27,
|
|
109
|
-
get: (buf, off) => {
|
|
110
|
-
return {
|
|
111
|
-
capturePattern: FourCC_1.FourCcToken.get(buf, off),
|
|
112
|
-
version: Token.UINT8.get(buf, off + 4),
|
|
113
|
-
headerType: {
|
|
114
|
-
continued: util.getBit(buf, off + 5, 0),
|
|
115
|
-
firstPage: util.getBit(buf, off + 5, 1),
|
|
116
|
-
lastPage: util.getBit(buf, off + 5, 2)
|
|
117
|
-
},
|
|
118
|
-
// packet_flag: buf.readUInt8(off + 5),
|
|
119
|
-
absoluteGranulePosition: Number(Token.UINT64_LE.get(buf, off + 6)),
|
|
120
|
-
streamSerialNumber: Token.UINT32_LE.get(buf, off + 14),
|
|
121
|
-
pageSequenceNo: Token.UINT32_LE.get(buf, off + 18),
|
|
122
|
-
pageChecksum: Token.UINT32_LE.get(buf, off + 22),
|
|
123
|
-
page_segments: Token.UINT8.get(buf, off + 26)
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
};
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OggParser = exports.SegmentTable = void 0;
|
|
4
|
+
const Token = require("token-types");
|
|
5
|
+
const core_1 = require("strtok3/lib/core");
|
|
6
|
+
const debug_1 = require("debug");
|
|
7
|
+
const util = require("../common/Util");
|
|
8
|
+
const FourCC_1 = require("../common/FourCC");
|
|
9
|
+
const BasicParser_1 = require("../common/BasicParser");
|
|
10
|
+
const VorbisParser_1 = require("./vorbis/VorbisParser");
|
|
11
|
+
const OpusParser_1 = require("./opus/OpusParser");
|
|
12
|
+
const SpeexParser_1 = require("./speex/SpeexParser");
|
|
13
|
+
const TheoraParser_1 = require("./theora/TheoraParser");
|
|
14
|
+
const debug = (0, debug_1.default)('music-metadata:parser:ogg');
|
|
15
|
+
class SegmentTable {
|
|
16
|
+
constructor(header) {
|
|
17
|
+
this.len = header.page_segments;
|
|
18
|
+
}
|
|
19
|
+
static sum(buf, off, len) {
|
|
20
|
+
let s = 0;
|
|
21
|
+
for (let i = off; i < off + len; ++i) {
|
|
22
|
+
s += buf[i];
|
|
23
|
+
}
|
|
24
|
+
return s;
|
|
25
|
+
}
|
|
26
|
+
get(buf, off) {
|
|
27
|
+
return {
|
|
28
|
+
totalPageSize: SegmentTable.sum(buf, off, this.len)
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.SegmentTable = SegmentTable;
|
|
33
|
+
/**
|
|
34
|
+
* Parser for Ogg logical bitstream framing
|
|
35
|
+
*/
|
|
36
|
+
class OggParser extends BasicParser_1.BasicParser {
|
|
37
|
+
/**
|
|
38
|
+
* Parse page
|
|
39
|
+
* @returns {Promise<void>}
|
|
40
|
+
*/
|
|
41
|
+
async parse() {
|
|
42
|
+
debug('pos=%s, parsePage()', this.tokenizer.position);
|
|
43
|
+
try {
|
|
44
|
+
let header;
|
|
45
|
+
do {
|
|
46
|
+
header = await this.tokenizer.readToken(OggParser.Header);
|
|
47
|
+
if (header.capturePattern !== 'OggS')
|
|
48
|
+
throw new Error('Invalid Ogg capture pattern');
|
|
49
|
+
this.metadata.setFormat('container', 'Ogg');
|
|
50
|
+
this.header = header;
|
|
51
|
+
this.pageNumber = header.pageSequenceNo;
|
|
52
|
+
debug('page#=%s, Ogg.id=%s', header.pageSequenceNo, header.capturePattern);
|
|
53
|
+
const segmentTable = await this.tokenizer.readToken(new SegmentTable(header));
|
|
54
|
+
debug('totalPageSize=%s', segmentTable.totalPageSize);
|
|
55
|
+
const pageData = await this.tokenizer.readToken(new Token.Uint8ArrayType(segmentTable.totalPageSize));
|
|
56
|
+
debug('firstPage=%s, lastPage=%s, continued=%s', header.headerType.firstPage, header.headerType.lastPage, header.headerType.continued);
|
|
57
|
+
if (header.headerType.firstPage) {
|
|
58
|
+
const id = new Token.StringType(7, 'ascii').get(Buffer.from(pageData), 0);
|
|
59
|
+
switch (id) {
|
|
60
|
+
case '\x01vorbis': // Ogg/Vorbis
|
|
61
|
+
debug('Set page consumer to Ogg/Vorbis');
|
|
62
|
+
this.pageConsumer = new VorbisParser_1.VorbisParser(this.metadata, this.options);
|
|
63
|
+
break;
|
|
64
|
+
case 'OpusHea': // Ogg/Opus
|
|
65
|
+
debug('Set page consumer to Ogg/Opus');
|
|
66
|
+
this.pageConsumer = new OpusParser_1.OpusParser(this.metadata, this.options, this.tokenizer);
|
|
67
|
+
break;
|
|
68
|
+
case 'Speex ': // Ogg/Speex
|
|
69
|
+
debug('Set page consumer to Ogg/Speex');
|
|
70
|
+
this.pageConsumer = new SpeexParser_1.SpeexParser(this.metadata, this.options, this.tokenizer);
|
|
71
|
+
break;
|
|
72
|
+
case 'fishead':
|
|
73
|
+
case '\x00theora': // Ogg/Theora
|
|
74
|
+
debug('Set page consumer to Ogg/Theora');
|
|
75
|
+
this.pageConsumer = new TheoraParser_1.TheoraParser(this.metadata, this.options, this.tokenizer);
|
|
76
|
+
break;
|
|
77
|
+
default:
|
|
78
|
+
throw new Error('gg audio-codec not recognized (id=' + id + ')');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
this.pageConsumer.parsePage(header, pageData);
|
|
82
|
+
} while (!header.headerType.lastPage);
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
if (err instanceof core_1.EndOfStreamError) {
|
|
86
|
+
this.metadata.addWarning('Last OGG-page is not marked with last-page flag');
|
|
87
|
+
debug(`End-of-stream`);
|
|
88
|
+
this.metadata.addWarning('Last OGG-page is not marked with last-page flag');
|
|
89
|
+
if (this.header) {
|
|
90
|
+
this.pageConsumer.calculateDuration(this.header);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else if (err.message.startsWith('FourCC')) {
|
|
94
|
+
if (this.pageNumber > 0) {
|
|
95
|
+
// ignore this error: work-around if last OGG-page is not marked with last-page flag
|
|
96
|
+
this.metadata.addWarning('Invalid FourCC ID, maybe last OGG-page is not marked with last-page flag');
|
|
97
|
+
this.pageConsumer.flush();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.OggParser = OggParser;
|
|
107
|
+
OggParser.Header = {
|
|
108
|
+
len: 27,
|
|
109
|
+
get: (buf, off) => {
|
|
110
|
+
return {
|
|
111
|
+
capturePattern: FourCC_1.FourCcToken.get(buf, off),
|
|
112
|
+
version: Token.UINT8.get(buf, off + 4),
|
|
113
|
+
headerType: {
|
|
114
|
+
continued: util.getBit(buf, off + 5, 0),
|
|
115
|
+
firstPage: util.getBit(buf, off + 5, 1),
|
|
116
|
+
lastPage: util.getBit(buf, off + 5, 2)
|
|
117
|
+
},
|
|
118
|
+
// packet_flag: buf.readUInt8(off + 5),
|
|
119
|
+
absoluteGranulePosition: Number(Token.UINT64_LE.get(buf, off + 6)),
|
|
120
|
+
streamSerialNumber: Token.UINT32_LE.get(buf, off + 14),
|
|
121
|
+
pageSequenceNo: Token.UINT32_LE.get(buf, off + 18),
|
|
122
|
+
pageChecksum: Token.UINT32_LE.get(buf, off + 22),
|
|
123
|
+
page_segments: Token.UINT8.get(buf, off + 26)
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
};
|