music-metadata 9.0.0 → 9.0.1
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 +519 -508
- package/lib/common/RandomFileReader.d.ts +2 -2
- package/lib/common/RandomFileReader.js +1 -1
- package/lib/id3v1/ID3v1Parser.js +2 -2
- package/lib/lyrics3/Lyrics3.js +4 -4
- package/lib/matroska/MatroskaParser.d.ts +8 -1
- package/lib/matroska/MatroskaParser.js +28 -19
- package/lib/matroska/types.d.ts +13 -13
- package/lib/mp4/AtomToken.d.ts +9 -8
- package/lib/mp4/AtomToken.js +1 -0
- package/lib/mpeg/MpegParser.js +3 -3
- package/lib/mpeg/XingTag.d.ts +1 -1
- package/lib/mpeg/XingTag.js +1 -1
- package/lib/ogg/opus/OpusParser.d.ts +3 -3
- package/lib/ogg/opus/OpusParser.js +1 -1
- package/lib/ogg/speex/SpeexParser.d.ts +2 -2
- package/lib/ogg/speex/SpeexParser.js +1 -1
- package/lib/ogg/theora/TheoraParser.d.ts +2 -2
- package/lib/ogg/vorbis/VorbisParser.d.ts +6 -5
- package/lib/ogg/vorbis/VorbisParser.js +11 -2
- package/lib/wav/WaveChunk.d.ts +1 -1
- package/lib/wavpack/WavPackParser.d.ts +1 -0
- package/lib/wavpack/WavPackParser.js +4 -2
- package/package.json +141 -141
|
@@ -9,13 +9,13 @@ export declare class RandomFileReader implements IRandomReader {
|
|
|
9
9
|
private constructor();
|
|
10
10
|
/**
|
|
11
11
|
* Read from a given position of an abstracted file or buffer.
|
|
12
|
-
* @param buffer {
|
|
12
|
+
* @param buffer {Uint8Array} is the buffer that the data will be written to.
|
|
13
13
|
* @param offset {number} is the offset in the buffer to start writing at.
|
|
14
14
|
* @param length {number}is an integer specifying the number of bytes to read.
|
|
15
15
|
* @param position {number} is an argument specifying where to begin reading from in the file.
|
|
16
16
|
* @return {Promise<number>} bytes read
|
|
17
17
|
*/
|
|
18
|
-
randomRead(buffer:
|
|
18
|
+
randomRead(buffer: Uint8Array, offset: number, length: number, position: number): Promise<number>;
|
|
19
19
|
close(): Promise<void>;
|
|
20
20
|
static init(filePath: string, fileSize: number): Promise<RandomFileReader>;
|
|
21
21
|
}
|
|
@@ -10,7 +10,7 @@ export class RandomFileReader {
|
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* Read from a given position of an abstracted file or buffer.
|
|
13
|
-
* @param buffer {
|
|
13
|
+
* @param buffer {Uint8Array} is the buffer that the data will be written to.
|
|
14
14
|
* @param offset {number} is the offset in the buffer to start writing at.
|
|
15
15
|
* @param length {number}is an integer specifying the number of bytes to read.
|
|
16
16
|
* @param position {number} is an argument specifying where to begin reading from in the file.
|
package/lib/id3v1/ID3v1Parser.js
CHANGED
|
@@ -121,9 +121,9 @@ export class ID3v1Parser extends BasicParser {
|
|
|
121
121
|
}
|
|
122
122
|
export async function hasID3v1Header(reader) {
|
|
123
123
|
if (reader.fileSize >= 128) {
|
|
124
|
-
const tag =
|
|
124
|
+
const tag = new Uint8Array(3);
|
|
125
125
|
await reader.randomRead(tag, 0, tag.length, reader.fileSize - 128);
|
|
126
|
-
return
|
|
126
|
+
return new TextDecoder('latin1').decode(tag) === 'TAG';
|
|
127
127
|
}
|
|
128
128
|
return false;
|
|
129
129
|
}
|
package/lib/lyrics3/Lyrics3.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export const endTag2 = 'LYRICS200';
|
|
2
2
|
export async function getLyricsHeaderLength(reader) {
|
|
3
3
|
if (reader.fileSize >= 143) {
|
|
4
|
-
const buf =
|
|
4
|
+
const buf = new Uint8Array(15);
|
|
5
5
|
await reader.randomRead(buf, 0, buf.length, reader.fileSize - 143);
|
|
6
|
-
const txt =
|
|
7
|
-
const tag = txt.
|
|
6
|
+
const txt = new TextDecoder('latin1').decode(buf);
|
|
7
|
+
const tag = txt.slice(6);
|
|
8
8
|
if (tag === endTag2) {
|
|
9
|
-
return parseInt(txt.
|
|
9
|
+
return parseInt(txt.slice(0, 6), 10) + 15;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
return 0;
|
|
@@ -27,11 +27,18 @@ export declare class MatroskaParser extends BasicParser {
|
|
|
27
27
|
private parseContainer;
|
|
28
28
|
private readVintData;
|
|
29
29
|
private readElement;
|
|
30
|
-
private isMaxValue;
|
|
31
30
|
private readFloat;
|
|
32
31
|
private readFlag;
|
|
33
32
|
private readUint;
|
|
34
33
|
private readString;
|
|
35
34
|
private readBuffer;
|
|
36
35
|
private addTag;
|
|
36
|
+
private static readUIntBE;
|
|
37
|
+
/**
|
|
38
|
+
* Reeds an unsigned integer from a big endian buffer of length `len`
|
|
39
|
+
* @param buf Buffer to decode from
|
|
40
|
+
* @param len Number of bytes
|
|
41
|
+
* @private
|
|
42
|
+
*/
|
|
43
|
+
private static readUIntBeAsBigInt;
|
|
37
44
|
}
|
|
@@ -3,6 +3,7 @@ import initDebug from 'debug';
|
|
|
3
3
|
import { BasicParser } from '../common/BasicParser.js';
|
|
4
4
|
import * as matroskaDtd from './MatroskaDtd.js';
|
|
5
5
|
import { DataType, TargetType, TrackType } from './types.js';
|
|
6
|
+
import * as Token from 'token-types';
|
|
6
7
|
const debug = initDebug('music-metadata:parser:matroska');
|
|
7
8
|
/**
|
|
8
9
|
* Extensible Binary Meta Language (EBML) parser
|
|
@@ -21,7 +22,7 @@ export class MatroskaParser extends BasicParser {
|
|
|
21
22
|
this.parserMap.set(DataType.uint, e => this.readUint(e));
|
|
22
23
|
this.parserMap.set(DataType.string, e => this.readString(e));
|
|
23
24
|
this.parserMap.set(DataType.binary, e => this.readBuffer(e));
|
|
24
|
-
this.parserMap.set(DataType.uid, async (e) =>
|
|
25
|
+
this.parserMap.set(DataType.uid, async (e) => this.readBuffer(e));
|
|
25
26
|
this.parserMap.set(DataType.bool, e => this.readFlag(e));
|
|
26
27
|
this.parserMap.set(DataType.float, e => this.readFloat(e));
|
|
27
28
|
}
|
|
@@ -45,7 +46,7 @@ export class MatroskaParser extends BasicParser {
|
|
|
45
46
|
if (typeof info.duration === 'number') {
|
|
46
47
|
const duration = info.duration * timecodeScale / 1000000000;
|
|
47
48
|
await this.addTag('segment:title', info.title);
|
|
48
|
-
this.metadata.setFormat('duration', duration);
|
|
49
|
+
this.metadata.setFormat('duration', Number(duration));
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
const audioTracks = matroska.segment.tracks;
|
|
@@ -168,7 +169,7 @@ export class MatroskaParser extends BasicParser {
|
|
|
168
169
|
++oc;
|
|
169
170
|
mask >>= 1;
|
|
170
171
|
}
|
|
171
|
-
const id =
|
|
172
|
+
const id = new Uint8Array(oc);
|
|
172
173
|
await this.tokenizer.readBuffer(id);
|
|
173
174
|
return id;
|
|
174
175
|
}
|
|
@@ -176,22 +177,11 @@ export class MatroskaParser extends BasicParser {
|
|
|
176
177
|
const id = await this.readVintData(this.ebmlMaxIDLength);
|
|
177
178
|
const lenField = await this.readVintData(this.ebmlMaxSizeLength);
|
|
178
179
|
lenField[0] ^= 0x80 >> (lenField.length - 1);
|
|
179
|
-
const nrLen = Math.min(6, lenField.length); // JavaScript can max read 6 bytes integer
|
|
180
180
|
return {
|
|
181
|
-
id:
|
|
182
|
-
len:
|
|
181
|
+
id: MatroskaParser.readUIntBE(id, id.length),
|
|
182
|
+
len: MatroskaParser.readUIntBE(lenField, lenField.length)
|
|
183
183
|
};
|
|
184
184
|
}
|
|
185
|
-
isMaxValue(vintData) {
|
|
186
|
-
if (vintData.length === this.ebmlMaxSizeLength) {
|
|
187
|
-
for (let n = 1; n < this.ebmlMaxSizeLength; ++n) {
|
|
188
|
-
if (vintData[n] !== 0xff)
|
|
189
|
-
return false;
|
|
190
|
-
}
|
|
191
|
-
return true;
|
|
192
|
-
}
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
195
185
|
async readFloat(e) {
|
|
196
186
|
switch (e.len) {
|
|
197
187
|
case 0:
|
|
@@ -211,19 +201,38 @@ export class MatroskaParser extends BasicParser {
|
|
|
211
201
|
}
|
|
212
202
|
async readUint(e) {
|
|
213
203
|
const buf = await this.readBuffer(e);
|
|
214
|
-
|
|
215
|
-
return buf.readUIntBE(e.len - nrLen, nrLen);
|
|
204
|
+
return MatroskaParser.readUIntBE(buf, e.len);
|
|
216
205
|
}
|
|
217
206
|
async readString(e) {
|
|
218
207
|
const rawString = await this.tokenizer.readToken(new StringType(e.len, 'utf-8'));
|
|
219
208
|
return rawString.replace(/\x00.*$/g, '');
|
|
220
209
|
}
|
|
221
210
|
async readBuffer(e) {
|
|
222
|
-
const buf =
|
|
211
|
+
const buf = new Uint8Array(e.len);
|
|
223
212
|
await this.tokenizer.readBuffer(buf);
|
|
224
213
|
return buf;
|
|
225
214
|
}
|
|
226
215
|
async addTag(tagId, value) {
|
|
227
216
|
await this.metadata.addTag('matroska', tagId, value);
|
|
228
217
|
}
|
|
218
|
+
static readUIntBE(buf, len) {
|
|
219
|
+
return Number(MatroskaParser.readUIntBeAsBigInt(buf, len));
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Reeds an unsigned integer from a big endian buffer of length `len`
|
|
223
|
+
* @param buf Buffer to decode from
|
|
224
|
+
* @param len Number of bytes
|
|
225
|
+
* @private
|
|
226
|
+
*/
|
|
227
|
+
static readUIntBeAsBigInt(buf, len) {
|
|
228
|
+
const normalizedNumber = new Uint8Array(8);
|
|
229
|
+
const cleanNumber = buf.subarray(0, len);
|
|
230
|
+
try {
|
|
231
|
+
normalizedNumber.set(cleanNumber, 8 - len);
|
|
232
|
+
return Token.UINT64_BE.get(normalizedNumber, 0);
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
return BigInt(-1);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
229
238
|
}
|
package/lib/matroska/types.d.ts
CHANGED
|
@@ -17,20 +17,20 @@ export interface IElementType<T> {
|
|
|
17
17
|
readonly multiple?: boolean;
|
|
18
18
|
}
|
|
19
19
|
export interface IContainerType {
|
|
20
|
-
[id: number]: IElementType<string | number | boolean |
|
|
20
|
+
[id: number]: IElementType<string | number | boolean | Uint8Array>;
|
|
21
21
|
}
|
|
22
22
|
export interface ITree {
|
|
23
|
-
[name: string]: string | number | boolean |
|
|
23
|
+
[name: string]: string | number | boolean | Uint8Array | ITree | ITree[];
|
|
24
24
|
}
|
|
25
25
|
export interface ISeekHead {
|
|
26
|
-
id?:
|
|
26
|
+
id?: Uint8Array;
|
|
27
27
|
position?: number;
|
|
28
28
|
}
|
|
29
29
|
export interface IMetaSeekInformation {
|
|
30
30
|
seekHeads: ISeekHead[];
|
|
31
31
|
}
|
|
32
32
|
export interface ISegmentInformation {
|
|
33
|
-
uid?:
|
|
33
|
+
uid?: Uint8Array;
|
|
34
34
|
timecodeScale?: number;
|
|
35
35
|
duration?: number;
|
|
36
36
|
dateUTC?: number;
|
|
@@ -39,7 +39,7 @@ export interface ISegmentInformation {
|
|
|
39
39
|
writingApp?: string;
|
|
40
40
|
}
|
|
41
41
|
export interface ITrackEntry {
|
|
42
|
-
uid?:
|
|
42
|
+
uid?: Uint8Array;
|
|
43
43
|
trackNumber?: number;
|
|
44
44
|
trackType?: TrackType;
|
|
45
45
|
audio?: ITrackAudio;
|
|
@@ -52,7 +52,7 @@ export interface ITrackEntry {
|
|
|
52
52
|
name?: string;
|
|
53
53
|
language?: string;
|
|
54
54
|
codecID?: string;
|
|
55
|
-
codecPrivate?:
|
|
55
|
+
codecPrivate?: Uint8Array;
|
|
56
56
|
codecName?: string;
|
|
57
57
|
codecSettings?: string;
|
|
58
58
|
codecInfoUrl?: string;
|
|
@@ -69,14 +69,14 @@ export interface ITrackVideo {
|
|
|
69
69
|
displayHeight?: number;
|
|
70
70
|
displayUnit?: number;
|
|
71
71
|
aspectRatioType?: number;
|
|
72
|
-
colourSpace?:
|
|
72
|
+
colourSpace?: Uint8Array;
|
|
73
73
|
gammaValue?: number;
|
|
74
74
|
}
|
|
75
75
|
export interface ITrackAudio {
|
|
76
76
|
samplingFrequency?: number;
|
|
77
77
|
outputSamplingFrequency?: number;
|
|
78
78
|
channels?: number;
|
|
79
|
-
channelPositions?:
|
|
79
|
+
channelPositions?: Uint8Array;
|
|
80
80
|
bitDepth?: number;
|
|
81
81
|
}
|
|
82
82
|
export interface ICuePoint {
|
|
@@ -99,7 +99,7 @@ export interface ICueReference {
|
|
|
99
99
|
export interface ISimpleTag {
|
|
100
100
|
name?: string;
|
|
101
101
|
'string'?: string;
|
|
102
|
-
binary?:
|
|
102
|
+
binary?: Uint8Array;
|
|
103
103
|
language?: string;
|
|
104
104
|
default?: boolean;
|
|
105
105
|
}
|
|
@@ -122,9 +122,9 @@ export declare enum TrackType {
|
|
|
122
122
|
control = 32
|
|
123
123
|
}
|
|
124
124
|
export interface ITarget {
|
|
125
|
-
trackUID?:
|
|
126
|
-
chapterUID?:
|
|
127
|
-
attachmentUID?:
|
|
125
|
+
trackUID?: Uint8Array;
|
|
126
|
+
chapterUID?: Uint8Array;
|
|
127
|
+
attachmentUID?: Uint8Array;
|
|
128
128
|
targetTypeValue?: TargetType;
|
|
129
129
|
targetType?: string;
|
|
130
130
|
}
|
|
@@ -142,7 +142,7 @@ export interface IAttachmedFile {
|
|
|
142
142
|
description?: string;
|
|
143
143
|
name: string;
|
|
144
144
|
mimeType: string;
|
|
145
|
-
data:
|
|
145
|
+
data: Uint8Array;
|
|
146
146
|
uid: string;
|
|
147
147
|
}
|
|
148
148
|
export interface IAttachments {
|
package/lib/mp4/AtomToken.d.ts
CHANGED
|
@@ -123,6 +123,7 @@ export declare abstract class FixedLengthAtom {
|
|
|
123
123
|
*
|
|
124
124
|
* @param {number} len Length as specified in the size field
|
|
125
125
|
* @param {number} expLen Total length of sum of specified fields in the standard
|
|
126
|
+
* @param atomId Atom ID
|
|
126
127
|
*/
|
|
127
128
|
protected constructor(len: number, expLen: number, atomId: string);
|
|
128
129
|
}
|
|
@@ -148,7 +149,7 @@ export interface IAtomMdhd extends IAtomMxhd {
|
|
|
148
149
|
export declare class MdhdAtom extends FixedLengthAtom implements IGetToken<IAtomMdhd> {
|
|
149
150
|
len: number;
|
|
150
151
|
constructor(len: number);
|
|
151
|
-
get(buf:
|
|
152
|
+
get(buf: Uint8Array, off: number): IAtomMdhd;
|
|
152
153
|
}
|
|
153
154
|
/**
|
|
154
155
|
* Token: Movie Header Atom
|
|
@@ -156,7 +157,7 @@ export declare class MdhdAtom extends FixedLengthAtom implements IGetToken<IAtom
|
|
|
156
157
|
export declare class MvhdAtom extends FixedLengthAtom implements IGetToken<IAtomMvhd> {
|
|
157
158
|
len: number;
|
|
158
159
|
constructor(len: number);
|
|
159
|
-
get(buf:
|
|
160
|
+
get(buf: Uint8Array, off: number): IAtomMvhd;
|
|
160
161
|
}
|
|
161
162
|
/**
|
|
162
163
|
* Data Atom Structure ('data')
|
|
@@ -209,7 +210,7 @@ export interface INameAtom extends IVersionAndFlags {
|
|
|
209
210
|
export declare class NameAtom implements IGetToken<INameAtom> {
|
|
210
211
|
len: number;
|
|
211
212
|
constructor(len: number);
|
|
212
|
-
get(buf:
|
|
213
|
+
get(buf: Uint8Array, off: number): INameAtom;
|
|
213
214
|
}
|
|
214
215
|
/**
|
|
215
216
|
* Track Header Atoms interface
|
|
@@ -262,7 +263,7 @@ export interface ITrackHeaderAtom extends IVersionAndFlags {
|
|
|
262
263
|
export declare class TrackHeaderAtom implements IGetToken<ITrackHeaderAtom> {
|
|
263
264
|
len: number;
|
|
264
265
|
constructor(len: number);
|
|
265
|
-
get(buf:
|
|
266
|
+
get(buf: Uint8Array, off: number): ITrackHeaderAtom;
|
|
266
267
|
}
|
|
267
268
|
/**
|
|
268
269
|
* Atom: Sample Description Atom ('stsd')
|
|
@@ -289,7 +290,7 @@ export interface IAtomStsd {
|
|
|
289
290
|
export declare class StsdAtom implements IGetToken<IAtomStsd> {
|
|
290
291
|
len: number;
|
|
291
292
|
constructor(len: number);
|
|
292
|
-
get(buf:
|
|
293
|
+
get(buf: Uint8Array, off: number): IAtomStsd;
|
|
293
294
|
}
|
|
294
295
|
export interface ISoundSampleDescriptionVersion {
|
|
295
296
|
version: number;
|
|
@@ -327,7 +328,7 @@ declare class SimpleTableAtom<T> implements IGetToken<ITableAtom<T>> {
|
|
|
327
328
|
len: number;
|
|
328
329
|
private token;
|
|
329
330
|
constructor(len: number, token: IGetToken<T>);
|
|
330
|
-
get(buf:
|
|
331
|
+
get(buf: Uint8Array, off: number): ITableAtom<T>;
|
|
331
332
|
}
|
|
332
333
|
export interface ITimeToSampleToken {
|
|
333
334
|
count: number;
|
|
@@ -373,7 +374,7 @@ export interface IStszAtom extends ITableAtom<number> {
|
|
|
373
374
|
export declare class StszAtom implements IGetToken<IStszAtom> {
|
|
374
375
|
len: number;
|
|
375
376
|
constructor(len: number);
|
|
376
|
-
get(buf:
|
|
377
|
+
get(buf: Uint8Array, off: number): IStszAtom;
|
|
377
378
|
}
|
|
378
379
|
/**
|
|
379
380
|
* Chunk offset atom, 'stco'
|
|
@@ -389,6 +390,6 @@ export declare class StcoAtom extends SimpleTableAtom<number> {
|
|
|
389
390
|
export declare class ChapterText implements IGetToken<string> {
|
|
390
391
|
len: number;
|
|
391
392
|
constructor(len: number);
|
|
392
|
-
get(buf:
|
|
393
|
+
get(buf: Uint8Array, off: number): string;
|
|
393
394
|
}
|
|
394
395
|
export {};
|
package/lib/mp4/AtomToken.js
CHANGED
|
@@ -61,6 +61,7 @@ export class FixedLengthAtom {
|
|
|
61
61
|
*
|
|
62
62
|
* @param {number} len Length as specified in the size field
|
|
63
63
|
* @param {number} expLen Total length of sum of specified fields in the standard
|
|
64
|
+
* @param atomId Atom ID
|
|
64
65
|
*/
|
|
65
66
|
constructor(len, expLen, atomId) {
|
|
66
67
|
this.len = len;
|
package/lib/mpeg/MpegParser.js
CHANGED
|
@@ -212,9 +212,9 @@ export class MpegParser extends AbstractID3Parser {
|
|
|
212
212
|
this.totalDataLength = 0;
|
|
213
213
|
this.bitrates = [];
|
|
214
214
|
this.calculateEofDuration = false;
|
|
215
|
-
this.buf_frame_header =
|
|
215
|
+
this.buf_frame_header = new Uint8Array(4);
|
|
216
216
|
this.syncPeek = {
|
|
217
|
-
buf:
|
|
217
|
+
buf: new Uint8Array(maxPeekLen),
|
|
218
218
|
len: 0
|
|
219
219
|
};
|
|
220
220
|
}
|
|
@@ -394,7 +394,7 @@ export class MpegParser extends AbstractID3Parser {
|
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
396
|
async parseAdts(header) {
|
|
397
|
-
const buf =
|
|
397
|
+
const buf = new Uint8Array(3);
|
|
398
398
|
await this.tokenizer.readBuffer(buf);
|
|
399
399
|
header.frameLength += common.getBitAllignedNumber(buf, 0, 0, 11);
|
|
400
400
|
this.totalDataLength += header.frameLength;
|
package/lib/mpeg/XingTag.d.ts
CHANGED
package/lib/mpeg/XingTag.js
CHANGED
|
@@ -40,7 +40,7 @@ export async function readXingHeader(tokenizer) {
|
|
|
40
40
|
xingInfoTag.streamSize = await tokenizer.readToken(Token.UINT32_BE);
|
|
41
41
|
}
|
|
42
42
|
if (flags.toc) {
|
|
43
|
-
xingInfoTag.toc =
|
|
43
|
+
xingInfoTag.toc = new Uint8Array(100);
|
|
44
44
|
await tokenizer.readBuffer(xingInfoTag.toc);
|
|
45
45
|
}
|
|
46
46
|
if (flags.vbrScale) {
|
|
@@ -16,9 +16,9 @@ export declare class OpusParser extends VorbisParser {
|
|
|
16
16
|
/**
|
|
17
17
|
* Parse first Opus Ogg page
|
|
18
18
|
* @param {IPageHeader} header
|
|
19
|
-
* @param {
|
|
19
|
+
* @param {Uint8Array} pageData
|
|
20
20
|
*/
|
|
21
|
-
protected parseFirstPage(header: IPageHeader, pageData:
|
|
22
|
-
protected parseFullPage(pageData:
|
|
21
|
+
protected parseFirstPage(header: IPageHeader, pageData: Uint8Array): void;
|
|
22
|
+
protected parseFullPage(pageData: Uint8Array): Promise<void>;
|
|
23
23
|
calculateDuration(header: IPageHeader): void;
|
|
24
24
|
}
|
|
@@ -15,7 +15,7 @@ export class OpusParser extends VorbisParser {
|
|
|
15
15
|
/**
|
|
16
16
|
* Parse first Opus Ogg page
|
|
17
17
|
* @param {IPageHeader} header
|
|
18
|
-
* @param {
|
|
18
|
+
* @param {Uint8Array} pageData
|
|
19
19
|
*/
|
|
20
20
|
parseFirstPage(header, pageData) {
|
|
21
21
|
this.metadata.setFormat('codec', 'Opus');
|
|
@@ -15,7 +15,7 @@ export declare class SpeexParser extends VorbisParser {
|
|
|
15
15
|
/**
|
|
16
16
|
* Parse first Speex Ogg page
|
|
17
17
|
* @param {IPageHeader} header
|
|
18
|
-
* @param {
|
|
18
|
+
* @param {Uint8Array} pageData
|
|
19
19
|
*/
|
|
20
|
-
protected parseFirstPage(header: IPageHeader, pageData:
|
|
20
|
+
protected parseFirstPage(header: IPageHeader, pageData: Uint8Array): void;
|
|
21
21
|
}
|
|
@@ -16,7 +16,7 @@ export class SpeexParser extends VorbisParser {
|
|
|
16
16
|
/**
|
|
17
17
|
* Parse first Speex Ogg page
|
|
18
18
|
* @param {IPageHeader} header
|
|
19
|
-
* @param {
|
|
19
|
+
* @param {Uint8Array} pageData
|
|
20
20
|
*/
|
|
21
21
|
parseFirstPage(header, pageData) {
|
|
22
22
|
debug('First Ogg/Speex page');
|
|
@@ -15,7 +15,7 @@ export declare class TheoraParser implements Ogg.IPageConsumer {
|
|
|
15
15
|
* @param header Ogg Page Header
|
|
16
16
|
* @param pageData Page data
|
|
17
17
|
*/
|
|
18
|
-
parsePage(header: Ogg.IPageHeader, pageData:
|
|
18
|
+
parsePage(header: Ogg.IPageHeader, pageData: Uint8Array): Promise<void>;
|
|
19
19
|
flush(): Promise<void>;
|
|
20
20
|
calculateDuration(header: Ogg.IPageHeader): void;
|
|
21
21
|
/**
|
|
@@ -23,5 +23,5 @@ export declare class TheoraParser implements Ogg.IPageConsumer {
|
|
|
23
23
|
* @param {IPageHeader} header
|
|
24
24
|
* @param {Buffer} pageData
|
|
25
25
|
*/
|
|
26
|
-
protected parseFirstPage(header: Ogg.IPageHeader, pageData:
|
|
26
|
+
protected parseFirstPage(header: Ogg.IPageHeader, pageData: Uint8Array): Promise<void>;
|
|
27
27
|
}
|
|
@@ -16,9 +16,10 @@ export declare class VorbisParser implements IPageConsumer {
|
|
|
16
16
|
* @param header Ogg Page Header
|
|
17
17
|
* @param pageData Page data
|
|
18
18
|
*/
|
|
19
|
-
parsePage(header: IPageHeader, pageData:
|
|
19
|
+
parsePage(header: IPageHeader, pageData: Uint8Array): Promise<void>;
|
|
20
|
+
private static mergeUint8Arrays;
|
|
20
21
|
flush(): Promise<void>;
|
|
21
|
-
parseUserComment(pageData:
|
|
22
|
+
parseUserComment(pageData: Uint8Array, offset: number): Promise<number>;
|
|
22
23
|
addTag(id: string, value: string | IVorbisPicture): Promise<void>;
|
|
23
24
|
calculateDuration(header: IPageHeader): void;
|
|
24
25
|
/**
|
|
@@ -26,10 +27,10 @@ export declare class VorbisParser implements IPageConsumer {
|
|
|
26
27
|
* @param header
|
|
27
28
|
* @param pageData
|
|
28
29
|
*/
|
|
29
|
-
protected parseFirstPage(header: IPageHeader, pageData:
|
|
30
|
-
protected parseFullPage(pageData:
|
|
30
|
+
protected parseFirstPage(header: IPageHeader, pageData: Uint8Array): void;
|
|
31
|
+
protected parseFullPage(pageData: Uint8Array): Promise<void>;
|
|
31
32
|
/**
|
|
32
33
|
* Ref: https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-840005.2
|
|
33
34
|
*/
|
|
34
|
-
protected parseUserCommentList(pageData:
|
|
35
|
+
protected parseUserCommentList(pageData: Uint8Array, offset: number): Promise<void>;
|
|
35
36
|
}
|
|
@@ -32,7 +32,7 @@ export class VorbisParser {
|
|
|
32
32
|
if (header.headerType.lastPage || !header.headerType.continued) {
|
|
33
33
|
// Flush page segments
|
|
34
34
|
if (this.pageSegments.length > 0) {
|
|
35
|
-
const fullPage =
|
|
35
|
+
const fullPage = VorbisParser.mergeUint8Arrays(this.pageSegments);
|
|
36
36
|
await this.parseFullPage(fullPage);
|
|
37
37
|
}
|
|
38
38
|
// Reset page segments
|
|
@@ -43,8 +43,17 @@ export class VorbisParser {
|
|
|
43
43
|
this.calculateDuration(header);
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
+
static mergeUint8Arrays(arrays) {
|
|
47
|
+
const totalSize = arrays.reduce((acc, e) => acc + e.length, 0);
|
|
48
|
+
const merged = new Uint8Array(totalSize);
|
|
49
|
+
arrays.forEach((array, i, _arrays) => {
|
|
50
|
+
const offset = _arrays.slice(0, i).reduce((acc, e) => acc + e.length, 0);
|
|
51
|
+
merged.set(array, offset);
|
|
52
|
+
});
|
|
53
|
+
return merged;
|
|
54
|
+
}
|
|
46
55
|
async flush() {
|
|
47
|
-
await this.parseFullPage(
|
|
56
|
+
await this.parseFullPage(VorbisParser.mergeUint8Arrays(this.pageSegments));
|
|
48
57
|
}
|
|
49
58
|
async parseUserComment(pageData, offset) {
|
|
50
59
|
const decoder = new VorbisDecoder(pageData, offset);
|
package/lib/wav/WaveChunk.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare class WavPackParser extends BasicParser {
|
|
|
8
8
|
parseWavPackBlocks(): Promise<void>;
|
|
9
9
|
/**
|
|
10
10
|
* Ref: http://www.wavpack.com/WavPack5FileFormat.pdf, 3.0 Metadata Sub-blocks
|
|
11
|
+
* @param header Header
|
|
11
12
|
* @param remainingLength
|
|
12
13
|
*/
|
|
13
14
|
private parseMetadataSubBlock;
|
|
@@ -4,6 +4,7 @@ import { FourCcToken } from '../common/FourCC.js';
|
|
|
4
4
|
import { BasicParser } from '../common/BasicParser.js';
|
|
5
5
|
import { WavPack } from './WavPackToken.js';
|
|
6
6
|
import initDebug from 'debug';
|
|
7
|
+
import { uint8ArrayToHex } from 'uint8array-extras';
|
|
7
8
|
const debug = initDebug('music-metadata:parser:WavPack');
|
|
8
9
|
/**
|
|
9
10
|
* WavPack Parser
|
|
@@ -49,13 +50,14 @@ export class WavPackParser extends BasicParser {
|
|
|
49
50
|
}
|
|
50
51
|
/**
|
|
51
52
|
* Ref: http://www.wavpack.com/WavPack5FileFormat.pdf, 3.0 Metadata Sub-blocks
|
|
53
|
+
* @param header Header
|
|
52
54
|
* @param remainingLength
|
|
53
55
|
*/
|
|
54
56
|
async parseMetadataSubBlock(header, remainingLength) {
|
|
55
57
|
while (remainingLength > WavPack.MetadataIdToken.len) {
|
|
56
58
|
const id = await this.tokenizer.readToken(WavPack.MetadataIdToken);
|
|
57
59
|
const dataSizeInWords = await this.tokenizer.readNumber(id.largeBlock ? Token.UINT24_LE : Token.UINT8);
|
|
58
|
-
const data =
|
|
60
|
+
const data = new Uint8Array(dataSizeInWords * 2 - (id.isOddSize ? 1 : 0));
|
|
59
61
|
await this.tokenizer.readBuffer(data);
|
|
60
62
|
debug(`Metadata Sub-Blocks functionId=0x${id.functionId.toString(16)}, id.largeBlock=${id.largeBlock},data-size=${data.length}`);
|
|
61
63
|
switch (id.functionId) {
|
|
@@ -78,7 +80,7 @@ export class WavPackParser extends BasicParser {
|
|
|
78
80
|
this.metadata.setFormat('audioMD5', data);
|
|
79
81
|
break;
|
|
80
82
|
case 0x2f: // ID_BLOCK_CHECKSUM
|
|
81
|
-
debug(`ID_BLOCK_CHECKSUM: checksum=${data
|
|
83
|
+
debug(`ID_BLOCK_CHECKSUM: checksum=${uint8ArrayToHex(data)}`);
|
|
82
84
|
break;
|
|
83
85
|
default:
|
|
84
86
|
debug(`Ignore unsupported meta-sub-block-id functionId=0x${id.functionId.toString(16)}`);
|