music-metadata 10.4.0 → 10.5.0

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/README.md CHANGED
@@ -48,6 +48,7 @@ If you find this project useful and would like to support its development, consi
48
48
  | ------------- |---------------------------------| -------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------:|
49
49
  | AIFF / AIFF-C | Audio Interchange File Format | [:link:](https://wikipedia.org/wiki/Audio_Interchange_File_Format) | <img src="https://upload.wikimedia.org/wikipedia/commons/8/84/Apple_Computer_Logo_rainbow.svg" width="40" alt="Apple rainbow logo"> |
50
50
  | AAC | ADTS / Advanced Audio Coding | [:link:](https://en.wikipedia.org/wiki/Advanced_Audio_Coding) | <img src="https://svgshare.com/i/UT8.svg" width="40" alt="AAC logo"> |
51
+ | AMR | Adaptive Multi-Rate audio codec | [:link:](https://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec) | <img src="https://foreverhits.files.wordpress.com/2015/05/ape_audio.jpg" width="40" alt="Monkey's Audio logo"> |
51
52
  | APE | Monkey's Audio | [:link:](https://wikipedia.org/wiki/Monkey's_Audio) | <img src="https://foreverhits.files.wordpress.com/2015/05/ape_audio.jpg" width="40" alt="Monkey's Audio logo"> |
52
53
  | ASF | Advanced Systems Format | [:link:](https://wikipedia.org/wiki/Advanced_Systems_Format) | |
53
54
  | BWF | Broadcast Wave Format | [:link:](https://en.wikipedia.org/wiki/Broadcast_Wave_Format) | |
@@ -17,6 +17,7 @@ import { musepackParserLoader } from './musepack/MusepackLoader.js';
17
17
  import { oggParserLoader } from './ogg/OggLoader.js';
18
18
  import { wavpackParserLoader } from './wavpack/WavPackLoader.js';
19
19
  import { riffParserLoader } from './wav/WaveLoader.js';
20
+ import { amrParserLoader } from './amr/AmrLoader.js';
20
21
  const debug = initDebug('music-metadata:parser:factory');
21
22
  export function parseHttpContentType(contentType) {
22
23
  const type = ContentType.parse(contentType);
@@ -44,7 +45,8 @@ export class ParserFactory {
44
45
  wavpackParserLoader,
45
46
  musepackParserLoader,
46
47
  dsfParserLoader,
47
- dsdiffParserLoader
48
+ dsdiffParserLoader,
49
+ amrParserLoader
48
50
  ].forEach(parser => this.registerParser(parser));
49
51
  }
50
52
  registerParser(parser) {
@@ -158,6 +160,8 @@ function getParserIdForMimeType(httpContentType) {
158
160
  return 'matroska';
159
161
  case 'dsf':
160
162
  return 'dsf';
163
+ case 'amr':
164
+ return 'amr';
161
165
  }
162
166
  break;
163
167
  case 'video':
@@ -0,0 +1,2 @@
1
+ import type { IParserLoader } from '../ParserFactory.js';
2
+ export declare const amrParserLoader: IParserLoader;
@@ -0,0 +1,8 @@
1
+ export const amrParserLoader = {
2
+ parserType: 'amr',
3
+ extensions: ['.amr'],
4
+ async load(metadata, tokenizer, options) {
5
+ return new (await import('./AmrParser.js')).AmrParser(metadata, tokenizer, options);
6
+ }
7
+ };
8
+ //# sourceMappingURL=AmrLoader.js.map
@@ -0,0 +1,7 @@
1
+ import { BasicParser } from '../common/BasicParser.js';
2
+ /**
3
+ * Adaptive Multi-Rate audio codec
4
+ */
5
+ export declare class AmrParser extends BasicParser {
6
+ parse(): Promise<void>;
7
+ }
@@ -0,0 +1,49 @@
1
+ import { BasicParser } from '../common/BasicParser.js';
2
+ import { AnsiStringType } from 'token-types';
3
+ import initDebug from 'debug';
4
+ import { FrameHeader } from './AmrToken.js';
5
+ const debug = initDebug('music-metadata:parser:AMR');
6
+ /**
7
+ * There are 8 varying levels of compression. First byte of the frame specifies CMR
8
+ * (codec mode request), values 0-7 are valid for AMR. Each mode have different frame size.
9
+ * This table reflects that fact.
10
+ */
11
+ const m_block_size = [12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0];
12
+ /**
13
+ * Adaptive Multi-Rate audio codec
14
+ */
15
+ export class AmrParser extends BasicParser {
16
+ async parse() {
17
+ const magicNr = await this.tokenizer.readToken(new AnsiStringType(5));
18
+ if (magicNr !== '#!AMR') {
19
+ throw new Error('Invalid AMR file: invalid MAGIC number');
20
+ }
21
+ this.metadata.setFormat('container', 'AMR');
22
+ this.metadata.setFormat('codec', 'AMR');
23
+ this.metadata.setFormat('sampleRate', 8000);
24
+ this.metadata.setFormat('bitrate', 64000);
25
+ this.metadata.setFormat('numberOfChannels', 1);
26
+ let total_size = 0;
27
+ let frames = 0;
28
+ const assumedFileLength = this.tokenizer.fileInfo?.size ?? Number.MAX_SAFE_INTEGER;
29
+ if (this.options.duration) {
30
+ while (this.tokenizer.position < assumedFileLength) {
31
+ const header = await this.tokenizer.readToken(FrameHeader);
32
+ /* first byte is rate mode. each rate mode has frame of given length. look it up. */
33
+ const size = m_block_size[header.frameType];
34
+ if (size > 0) {
35
+ total_size += size + 1;
36
+ if (total_size > assumedFileLength)
37
+ break;
38
+ await this.tokenizer.ignore(size);
39
+ ++frames;
40
+ }
41
+ else {
42
+ debug(`Found no-data frame, frame-type: ${header.frameType}. Skipping`);
43
+ }
44
+ }
45
+ this.metadata.setFormat('duration', frames * 0.02);
46
+ }
47
+ }
48
+ }
49
+ //# sourceMappingURL=AmrParser.js.map
@@ -0,0 +1,11 @@
1
+ import type { IGetToken } from 'strtok3';
2
+ interface IFrameHeader {
3
+ frameType: number;
4
+ }
5
+ /**
6
+ * ID3v2 header
7
+ * Ref: http://id3.org/id3v2.3.0#ID3v2_header
8
+ * ToDo
9
+ */
10
+ export declare const FrameHeader: IGetToken<IFrameHeader>;
11
+ export {};
@@ -0,0 +1,15 @@
1
+ import { getBitAllignedNumber } from '../common/Util.js';
2
+ /**
3
+ * ID3v2 header
4
+ * Ref: http://id3.org/id3v2.3.0#ID3v2_header
5
+ * ToDo
6
+ */
7
+ export const FrameHeader = {
8
+ len: 1,
9
+ get: (buf, off) => {
10
+ return {
11
+ frameType: getBitAllignedNumber(buf, off, 1, 4)
12
+ };
13
+ }
14
+ };
15
+ //# sourceMappingURL=AmrToken.js.map
@@ -10,7 +10,13 @@ declare const AsfContentParseError_base: {
10
10
  stack?: string;
11
11
  };
12
12
  captureStackTrace(targetObject: object, constructorOpt?: Function): void;
13
- prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
13
+ prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite /**
14
+ * Specifies the amount of time to buffer data before starting to play the file, in millisecond units.
15
+ * If this value is nonzero, the Play Duration field and all of the payload Presentation Time fields have been offset
16
+ * by this amount. Therefore, player software must subtract the value in the preroll field from the play duration and
17
+ * presentation times to calculate their actual values. It follows that all payload Presentation Time fields need to
18
+ * be at least this value.
19
+ */[]) => any) | undefined;
14
20
  stackTraceLimit: number;
15
21
  };
16
22
  export declare class AsfContentParseError extends AsfContentParseError_base {
package/lib/type.d.ts CHANGED
@@ -521,7 +521,7 @@ export interface IAudioMetadata extends INativeAudioMetadata {
521
521
  /**
522
522
  * Corresponds with parser module name
523
523
  */
524
- export type ParserType = 'mpeg' | 'apev2' | 'mp4' | 'asf' | 'flac' | 'ogg' | 'aiff' | 'wavpack' | 'riff' | 'musepack' | 'dsf' | 'dsdiff' | 'adts' | 'matroska';
524
+ export type ParserType = 'mpeg' | 'apev2' | 'mp4' | 'asf' | 'flac' | 'ogg' | 'aiff' | 'wavpack' | 'riff' | 'musepack' | 'dsf' | 'dsdiff' | 'adts' | 'matroska' | 'amr';
525
525
  export interface IOptions {
526
526
  /**
527
527
  * default: `false`, if set to `true`, it will parse the whole media file if required to determine the duration.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "music-metadata",
3
3
  "description": "Music metadata parser for Node.js, supporting virtual any audio and tag format.",
4
- "version": "10.4.0",
4
+ "version": "10.5.0",
5
5
  "author": {
6
6
  "name": "Borewit",
7
7
  "url": "https://github.com/Borewit"
@@ -105,8 +105,8 @@
105
105
  "dependencies": {
106
106
  "@tokenizer/token": "^0.3.0",
107
107
  "content-type": "^1.0.5",
108
- "debug": "^4.3.4",
109
- "file-type": "^19.4.1",
108
+ "debug": "^4.3.7",
109
+ "file-type": "^19.5.0",
110
110
  "media-typer": "^1.1.0",
111
111
  "strtok3": "^9.0.0",
112
112
  "token-types": "^6.0.0",