@poe-platform/safe-bash 0.1.840 → 0.1.841

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.
@@ -0,0 +1,19 @@
1
+ export declare class Reader {
2
+ readonly bytes: Uint8Array;
3
+ readonly view: DataView;
4
+ constructor(bytes: Uint8Array);
5
+ check(offset: number, size: number): void;
6
+ slice(offset: number, size: number): Uint8Array;
7
+ text(offset: number, size: number): string;
8
+ u8(offset: number): number;
9
+ u16(offset: number, little?: boolean): number;
10
+ u24(offset: number, little?: boolean): number;
11
+ u32(offset: number, little?: boolean): number;
12
+ u64(offset: number, little?: boolean): bigint;
13
+ safe64(offset: number, little?: boolean): number;
14
+ }
15
+ export declare function join(parts: Uint8Array[]): Uint8Array;
16
+ export declare function ascii(text: string): Uint8Array;
17
+ export declare function uint32(value: number, little?: boolean): Uint8Array;
18
+ export declare function cleanText(text: string): string;
19
+ export declare function duration(samples: number, sampleRate: number): number;
@@ -1,3 +1,4 @@
1
+ export { mpegFrame } from "./mpeg.js";
1
2
  export { probeOggStreamSource, type OggCommentSpan } from "./ogg-stream-source.js";
2
3
  export { scanOggPages, type OggPageSpan } from "./ogg-source.js";
3
4
  export { probeMp3Source, type Mp3Tag } from "./mp3-source.js";
@@ -74,6 +74,97 @@ function duration(samples, sampleRate) {
74
74
  return samples / sampleRate;
75
75
  }
76
76
 
77
+ // packages/audio-ast/src/mpeg.ts
78
+ function mpegFrame(header, offset, end) {
79
+ const versionBits = header >>> 19 & 3, layer = header >>> 17 & 3, bitrateIndex = header >>> 12 & 15, rateIndex = header >>> 10 & 3;
80
+ if (header >>> 21 !== 2047 || versionBits === 1 || layer !== 1 || !bitrateIndex || bitrateIndex === 15 || rateIndex === 3)
81
+ throw new Error(`Invalid MPEG Layer III frame at ${offset}`);
82
+ const version = versionBits === 3 ? 1 : versionBits === 2 ? 2 : 2.5;
83
+ const rate = [44100, 48e3, 32e3][rateIndex] / (version === 1 ? 1 : version === 2 ? 2 : 4);
84
+ const bitrate = (version === 1 ? [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320] : [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160])[bitrateIndex] * 1e3;
85
+ const count = version === 1 ? 1152 : 576, frameSize = Math.floor((version === 1 ? 144 : 72) * bitrate / rate) + (header >>> 9 & 1), ch = header >>> 6 & 3;
86
+ if (frameSize > end - offset) throw new Error("Truncated MPEG frame");
87
+ const channels = ch === 3 ? 1 : 2;
88
+ const fields = {
89
+ version,
90
+ layer: 3,
91
+ bitrate,
92
+ sampleRate: rate,
93
+ channels,
94
+ samples: count,
95
+ padding: header >>> 9 & 1
96
+ };
97
+ return { version, rate, count, frameSize, channels, fields };
98
+ }
99
+ function mpegVbr(r, offset, frameSize, header, fields) {
100
+ const version = Number(fields.version), channels = Number(fields.channels);
101
+ const side = version === 1 ? channels === 1 ? 17 : 32 : channels === 1 ? 9 : 17, crc = header & 65536 ? 0 : 2;
102
+ const xing = offset + 4 + crc + side;
103
+ if (xing + 8 <= offset + frameSize && ["Xing", "Info"].includes(r.text(xing, 4))) {
104
+ const flags = r.u32(xing + 4);
105
+ let pos = xing + 8;
106
+ const vbr = { type: r.text(xing, 4), flags };
107
+ if (flags & 1) {
108
+ vbr.frames = r.u32(pos);
109
+ pos += 4;
110
+ }
111
+ if (flags & 2) {
112
+ vbr.bytes = r.u32(pos);
113
+ pos += 4;
114
+ }
115
+ if (flags & 4) {
116
+ vbr.toc = r.slice(pos, 100);
117
+ pos += 100;
118
+ }
119
+ if (flags & 8) {
120
+ vbr.quality = r.u32(pos);
121
+ pos += 4;
122
+ }
123
+ if (pos > offset + frameSize) throw new Error("Xing header exceeds frame");
124
+ fields.vbr = vbr;
125
+ if (pos + 24 <= offset + frameSize && ["LAME", "Lavc", "Lavf"].includes(r.text(pos, 4))) {
126
+ const packed = r.u24(pos + 21);
127
+ fields.encoderDelay = packed >>> 12;
128
+ fields.encoderPadding = packed & 4095;
129
+ }
130
+ }
131
+ const vbri = offset + 36;
132
+ if (vbri + 26 <= offset + frameSize && r.text(vbri, 4) === "VBRI")
133
+ fields.vbr = {
134
+ type: "VBRI",
135
+ version: r.u16(vbri + 4),
136
+ delay: r.u16(vbri + 6),
137
+ quality: r.u16(vbri + 8),
138
+ bytes: r.u32(vbri + 10),
139
+ frames: r.u32(vbri + 14),
140
+ entries: r.u16(vbri + 18),
141
+ scale: r.u16(vbri + 20),
142
+ entryBytes: r.u16(vbri + 22),
143
+ framesPerEntry: r.u16(vbri + 24)
144
+ };
145
+ }
146
+ function mpegStream(state, first) {
147
+ let { samples, seconds: seconds2, audioBytes } = state;
148
+ const { sampleRate, channels, frames } = state;
149
+ if (!frames) throw new Error("MP3 contains no MPEG frames");
150
+ const vbr = first.fields?.vbr;
151
+ const declared = vbr?.frames;
152
+ if (typeof declared === "number" && declared > 0) {
153
+ if (declared !== frames && declared !== frames - 1)
154
+ throw new Error("MPEG VBR frame count mismatch");
155
+ const encodedSamples = declared * (sampleRate >= 32e3 ? 1152 : 576);
156
+ const delay = Number(first.fields?.encoderDelay ?? 0), padding = Number(first.fields?.encoderPadding ?? 0);
157
+ if (delay + padding > encodedSamples) throw new Error("Invalid MPEG encoder delay/padding");
158
+ samples = encodedSamples - delay - padding;
159
+ seconds2 = duration(samples, sampleRate);
160
+ if (declared === frames - 1) audioBytes -= first.size;
161
+ first.fields.encodedSamples = encodedSamples;
162
+ }
163
+ const encodedSeconds = duration(Number(first.fields?.encodedSamples ?? samples), sampleRate);
164
+ const bitrate = encodedSeconds ? audioBytes * 8 / encodedSeconds : 0;
165
+ return { codec: "mp3", sampleRate, channels, samples, duration: seconds2, bitrate };
166
+ }
167
+
77
168
  // packages/audio-ast/src/ogg-stream.ts
78
169
  function oggIdentification(head, size = head.length) {
79
170
  const r = new Reader(head);
@@ -883,97 +974,6 @@ async function probeId3Source(source, options = {}) {
883
974
  return { size, version, tags };
884
975
  }
885
976
 
886
- // packages/audio-ast/src/mpeg.ts
887
- function mpegFrame(header, offset, end) {
888
- const versionBits = header >>> 19 & 3, layer = header >>> 17 & 3, bitrateIndex = header >>> 12 & 15, rateIndex = header >>> 10 & 3;
889
- if (header >>> 21 !== 2047 || versionBits === 1 || layer !== 1 || !bitrateIndex || bitrateIndex === 15 || rateIndex === 3)
890
- throw new Error(`Invalid MPEG Layer III frame at ${offset}`);
891
- const version = versionBits === 3 ? 1 : versionBits === 2 ? 2 : 2.5;
892
- const rate = [44100, 48e3, 32e3][rateIndex] / (version === 1 ? 1 : version === 2 ? 2 : 4);
893
- const bitrate = (version === 1 ? [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320] : [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160])[bitrateIndex] * 1e3;
894
- const count = version === 1 ? 1152 : 576, frameSize = Math.floor((version === 1 ? 144 : 72) * bitrate / rate) + (header >>> 9 & 1), ch = header >>> 6 & 3;
895
- if (frameSize > end - offset) throw new Error("Truncated MPEG frame");
896
- const channels = ch === 3 ? 1 : 2;
897
- const fields = {
898
- version,
899
- layer: 3,
900
- bitrate,
901
- sampleRate: rate,
902
- channels,
903
- samples: count,
904
- padding: header >>> 9 & 1
905
- };
906
- return { version, rate, count, frameSize, channels, fields };
907
- }
908
- function mpegVbr(r, offset, frameSize, header, fields) {
909
- const version = Number(fields.version), channels = Number(fields.channels);
910
- const side = version === 1 ? channels === 1 ? 17 : 32 : channels === 1 ? 9 : 17, crc = header & 65536 ? 0 : 2;
911
- const xing = offset + 4 + crc + side;
912
- if (xing + 8 <= offset + frameSize && ["Xing", "Info"].includes(r.text(xing, 4))) {
913
- const flags = r.u32(xing + 4);
914
- let pos = xing + 8;
915
- const vbr = { type: r.text(xing, 4), flags };
916
- if (flags & 1) {
917
- vbr.frames = r.u32(pos);
918
- pos += 4;
919
- }
920
- if (flags & 2) {
921
- vbr.bytes = r.u32(pos);
922
- pos += 4;
923
- }
924
- if (flags & 4) {
925
- vbr.toc = r.slice(pos, 100);
926
- pos += 100;
927
- }
928
- if (flags & 8) {
929
- vbr.quality = r.u32(pos);
930
- pos += 4;
931
- }
932
- if (pos > offset + frameSize) throw new Error("Xing header exceeds frame");
933
- fields.vbr = vbr;
934
- if (pos + 24 <= offset + frameSize && ["LAME", "Lavc", "Lavf"].includes(r.text(pos, 4))) {
935
- const packed = r.u24(pos + 21);
936
- fields.encoderDelay = packed >>> 12;
937
- fields.encoderPadding = packed & 4095;
938
- }
939
- }
940
- const vbri = offset + 36;
941
- if (vbri + 26 <= offset + frameSize && r.text(vbri, 4) === "VBRI")
942
- fields.vbr = {
943
- type: "VBRI",
944
- version: r.u16(vbri + 4),
945
- delay: r.u16(vbri + 6),
946
- quality: r.u16(vbri + 8),
947
- bytes: r.u32(vbri + 10),
948
- frames: r.u32(vbri + 14),
949
- entries: r.u16(vbri + 18),
950
- scale: r.u16(vbri + 20),
951
- entryBytes: r.u16(vbri + 22),
952
- framesPerEntry: r.u16(vbri + 24)
953
- };
954
- }
955
- function mpegStream(state, first) {
956
- let { samples, seconds: seconds2, audioBytes } = state;
957
- const { sampleRate, channels, frames } = state;
958
- if (!frames) throw new Error("MP3 contains no MPEG frames");
959
- const vbr = first.fields?.vbr;
960
- const declared = vbr?.frames;
961
- if (typeof declared === "number" && declared > 0) {
962
- if (declared !== frames && declared !== frames - 1)
963
- throw new Error("MPEG VBR frame count mismatch");
964
- const encodedSamples = declared * (sampleRate >= 32e3 ? 1152 : 576);
965
- const delay = Number(first.fields?.encoderDelay ?? 0), padding = Number(first.fields?.encoderPadding ?? 0);
966
- if (delay + padding > encodedSamples) throw new Error("Invalid MPEG encoder delay/padding");
967
- samples = encodedSamples - delay - padding;
968
- seconds2 = duration(samples, sampleRate);
969
- if (declared === frames - 1) audioBytes -= first.size;
970
- first.fields.encodedSamples = encodedSamples;
971
- }
972
- const encodedSeconds = duration(Number(first.fields?.encodedSamples ?? samples), sampleRate);
973
- const bitrate = encodedSeconds ? audioBytes * 8 / encodedSeconds : 0;
974
- return { codec: "mp3", sampleRate, channels, samples, duration: seconds2, bitrate };
975
- }
976
-
977
977
  // packages/audio-ast/src/mp3-source.ts
978
978
  async function probeMp3Source(source, options = {}) {
979
979
  const read = async (offset2, length) => {
@@ -2092,6 +2092,7 @@ export {
2092
2092
  encodeWav,
2093
2093
  extractChannels,
2094
2094
  fade,
2095
+ mpegFrame,
2095
2096
  normalize,
2096
2097
  normalizeVorbisCommentKey,
2097
2098
  pad,
@@ -0,0 +1,23 @@
1
+ import { Reader } from "./binary.js";
2
+ import type { AudioStream } from "./types.js";
3
+ /** Shared strict frame validation for resident parsing and bounded source probing. */
4
+ export declare function mpegFrame(header: number, offset: number, end: number): {
5
+ version: number;
6
+ rate: number;
7
+ count: number;
8
+ frameSize: number;
9
+ channels: number;
10
+ fields: Record<string, unknown>;
11
+ };
12
+ export declare function mpegVbr(r: Reader, offset: number, frameSize: number, header: number, fields: Record<string, unknown>): void;
13
+ export declare function mpegStream(state: {
14
+ samples: number;
15
+ seconds: number;
16
+ audioBytes: number;
17
+ sampleRate: number;
18
+ channels: number;
19
+ frames: number;
20
+ }, first: {
21
+ size: number;
22
+ fields: Record<string, unknown>;
23
+ }): AudioStream;
@@ -9,6 +9,7 @@ export declare function parseAacAdts(bytes: Uint8Array): MediaDocument;
9
9
  export declare function serializeAacAdts(doc: MediaDocument): Uint8Array;
10
10
  export declare function aacAst(): MediaAstPlugin;
11
11
  export declare function isWavSignature(bytes: Uint8Array): boolean;
12
+ export declare function wavPacketFrames(sampleRate: number, block: number): number;
12
13
  export declare function parseWav(bytes: Uint8Array, options?: ParseMediaOptions): MediaDocument;
13
14
  export declare function serializeWav(doc: MediaDocument): Uint8Array;
14
15
  type WavMetadataOnlyOptions = MediaSourceProbeOptions & {
@@ -84,6 +84,8 @@ export interface MediaAudioData {
84
84
  readonly startSeconds?: number | undefined;
85
85
  }
86
86
  export interface MediaSample {
87
+ /** Absolute source file offset when the sample was parsed from a container. */
88
+ readonly offset?: number;
87
89
  readonly data: Uint8Array;
88
90
  readonly dts: number;
89
91
  readonly pts: number;
@@ -305,6 +307,8 @@ export interface MediaProbeStream {
305
307
  readonly duration: string;
306
308
  readonly bit_rate?: string | undefined;
307
309
  readonly nb_frames?: string | undefined;
310
+ readonly nb_read_packets?: string | undefined;
311
+ readonly nb_read_frames?: string | undefined;
308
312
  readonly disposition: Readonly<Record<string, number>>;
309
313
  readonly tags?: Readonly<Record<string, string>> | undefined;
310
314
  readonly side_data_list?: readonly Readonly<Record<string, unknown>>[] | undefined;
@@ -1,11 +1,12 @@
1
1
  // packages/safe-bash/src/audio-ast.ts
2
- import { concat, decodePcm, encodeWav, extractChannels, fade, normalize, normalizeVorbisCommentKey, pad, parseAudio, probeAudio, probeFlacSource, probeId3Source, probeMp3Source, probeOggStreamSource, probeWavSource, readId3Text, remix, resample, scanOggPages, stats, transformAudio, trim, writeAudioMetadata } from "../audio-ast/index.js";
2
+ import { concat, decodePcm, encodeWav, extractChannels, fade, mpegFrame, normalize, normalizeVorbisCommentKey, pad, parseAudio, probeAudio, probeFlacSource, probeId3Source, probeMp3Source, probeOggStreamSource, probeWavSource, readId3Text, remix, resample, scanOggPages, stats, transformAudio, trim, writeAudioMetadata } from "../audio-ast/index.js";
3
3
  export {
4
4
  concat,
5
5
  decodePcm,
6
6
  encodeWav,
7
7
  extractChannels,
8
8
  fade,
9
+ mpegFrame,
9
10
  normalize,
10
11
  normalizeVorbisCommentKey,
11
12
  pad,
@@ -1,2 +1,2 @@
1
- export { "concat", "decodePcm", "encodeWav", "extractChannels", "fade", "normalize", "normalizeVorbisCommentKey", "pad", "parseAudio", "probeAudio", "probeFlacSource", "probeId3Source", "probeMp3Source", "probeOggStreamSource", "probeWavSource", "readId3Text", "remix", "resample", "scanOggPages", "stats", "transformAudio", "trim", "writeAudioMetadata" } from "../audio-ast/index.js";
1
+ export { "concat", "decodePcm", "encodeWav", "extractChannels", "fade", "mpegFrame", "normalize", "normalizeVorbisCommentKey", "pad", "parseAudio", "probeAudio", "probeFlacSource", "probeId3Source", "probeMp3Source", "probeOggStreamSource", "probeWavSource", "readId3Text", "remix", "resample", "scanOggPages", "stats", "transformAudio", "trim", "writeAudioMetadata" } from "../audio-ast/index.js";
2
2
  //# sourceMappingURL=audio-ast.js.map