audio 2.0.0-0 → 2.0.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/audio.d.ts ADDED
@@ -0,0 +1,232 @@
1
+ /**
2
+ * audio — paged audio instance with declarative ops.
3
+ */
4
+
5
+ /** Time value: seconds as number, or parseable string ('1.5s', '500ms', '1:30') */
6
+ type Time = number | string
7
+
8
+ type AudioSource = AudioInstance | AudioBuffer | Float32Array[] | number
9
+ type FilterType = 'highpass' | 'lowpass' | 'bandpass' | 'notch' | 'eq' | 'lowshelf' | 'highshelf'
10
+
11
+ export interface AudioInstance {
12
+ /** Decoded PCM pages */
13
+ pages: Float32Array[][]
14
+ /** Per-channel, per-block stats (min/max/energy + registered fields) */
15
+ stats: AudioStats
16
+ /** Sample rate in Hz */
17
+ sampleRate: number
18
+ /** Effective channel count (reflects remix edits) */
19
+ readonly channels: number
20
+ /** Effective sample count (reflects structural edits) */
21
+ readonly length: number
22
+ /** Effective duration in seconds */
23
+ readonly duration: number
24
+ /** Original source reference (URL/path string, or null for PCM-backed) */
25
+ source: string | null
26
+ /** Storage mode */
27
+ storage: string
28
+ /** Promise — resolves to true when ready (decoded, mic active, etc.) */
29
+ ready: Promise<true>
30
+ /** Edit list (inspectable) */
31
+ edits: EditOp[]
32
+ /** Monotonic counter, increments on edit/undo */
33
+ version: number
34
+ /** Current position in seconds (read/write, or use seek()) */
35
+ currentTime: number
36
+ /** True when playing */
37
+ playing: boolean
38
+ /** True when paused */
39
+ paused: boolean
40
+ /** Playback volume in dB (0 = unity) */
41
+ volume: number
42
+ /** Whether playback loops */
43
+ loop: boolean
44
+ /** Current playback block for visualization */
45
+ block: Float32Array | null
46
+
47
+ // ── Events ──────────────────────────────────────────────────────
48
+ /** Subscribe to instance event */
49
+ on(event: 'change', fn: () => void): this
50
+ on(event: 'metadata', fn: (event: { sampleRate: number, channels: number }) => void): this
51
+ on(event: 'data', fn: (event: { delta: ProgressDelta, offset: number, sampleRate: number, channels: number }) => void): this
52
+ on(event: 'progress', fn: (event: { offset: number, total: number }) => void): this
53
+ on(event: 'timeupdate', fn: (time: number) => void): this
54
+ on(event: 'ended', fn: () => void): this
55
+ on(event: string, fn: (...args: any[]) => void): this
56
+ /** Unsubscribe from instance event */
57
+ off(event: string, fn: (...args: any[]) => void): this
58
+ /** Dispose — stop playback/recording, clear listeners, release caches */
59
+ dispose(): void
60
+
61
+ // ── Core I/O ────────────────────────────────────────────────────
62
+ /** Move playhead — preloads nearby pages, triggers seek if playing */
63
+ seek(t: number): this
64
+ /** Read audio data. Channel option returns single Float32Array. */
65
+ read(opts?: { at?: Time, duration?: Time, channel?: number, format?: string, meta?: Record<string, any> }): Promise<Float32Array[] | Float32Array | Int16Array[] | Uint8Array[] | Uint8Array>
66
+ /** Async-iterable over materialized blocks. `for await (let block of a)` */
67
+ [Symbol.asyncIterator](): AsyncGenerator<Float32Array[], void, unknown>
68
+ /** Ensure stats are fresh, return stats + block range */
69
+ stat(name: 'db' | 'rms' | 'loudness', opts?: { at?: Time, duration?: Time }): Promise<number>
70
+ stat(name: 'clipping', opts?: { at?: Time, duration?: Time }): Promise<Float32Array>
71
+ stat(name: 'clipping', opts: { bins: number, at?: Time, duration?: Time }): Promise<Float32Array>
72
+ stat(name: 'dc', opts?: { at?: Time, duration?: Time }): Promise<number>
73
+ stat(name: 'min' | 'max', opts?: { at?: Time, duration?: Time }): Promise<number>
74
+ stat(name: 'min' | 'max', opts: { bins: number, at?: Time, duration?: Time, channel?: number }): Promise<Float32Array>
75
+ stat(name: 'min' | 'max', opts: { bins: number, at?: Time, duration?: Time, channel: number[] }): Promise<Float32Array[]>
76
+ stat(name: 'spectrum', opts?: { bins?: number, at?: Time, duration?: Time, fMin?: number, fMax?: number, weight?: boolean }): Promise<Float32Array>
77
+ stat(name: 'cepstrum', opts?: { bins?: number, at?: Time, duration?: Time }): Promise<Float32Array>
78
+ stat(name: 'silence', opts?: { threshold?: number, minDuration?: number, at?: Time, duration?: Time }): Promise<{ at: number, duration: number }[]>
79
+ stat<T extends string[]>(name: T, opts?: { at?: Time, duration?: Time, bins?: number, channel?: number | number[] }): Promise<{ [K in keyof T]: number | Float32Array | Float32Array[] }>
80
+ stat(name: string, opts?: { at?: Time, duration?: Time, bins?: number, channel?: number | number[] }): Promise<number | Float32Array | Float32Array[]>
81
+ spectrum(opts?: { bins?: number, at?: Time, duration?: Time, fMin?: number, fMax?: number, weight?: boolean }): Promise<Float32Array>
82
+ cepstrum(opts?: { bins?: number, at?: Time, duration?: Time }): Promise<Float32Array>
83
+ silence(opts?: { threshold?: number, minDuration?: number, at?: Time, duration?: Time }): Promise<{ at: number, duration: number }[]>
84
+ /** Serialize to JSON */
85
+ toJSON(): { source: string | null, edits: EditOp[], sampleRate: number, channels: number, duration: number }
86
+
87
+ // ── Structural ops ───────────────────────────────────────────
88
+ crop(opts?: { at?: Time, duration?: Time }): this
89
+ insert(other: AudioSource, opts?: { at?: Time }): this
90
+ remove(opts?: { at?: Time, duration?: Time }): this
91
+ repeat(times: number, opts?: { at?: Time, duration?: Time }): this
92
+ pad(before: number, after?: number): this
93
+ speed(rate: number): this
94
+
95
+ // ── Sample ops ──────────────────────────────────────────────
96
+ gain(value: number | ((t: number) => number), opts?: { at?: Time, duration?: Time, channel?: number | number[], unit?: 'db' | 'linear' }): this
97
+ fade(duration: Time, curve?: 'linear' | 'exp' | 'log' | 'cos', opts?: { at?: Time }): this
98
+ reverse(opts?: { at?: Time, duration?: Time }): this
99
+ mix(other: AudioSource, opts?: { at?: Time, duration?: Time }): this
100
+ write(data: Float32Array[] | Float32Array, opts?: { at?: Time }): this
101
+ remix(channels: number | (number | null)[]): this
102
+ pan(value: number | ((t: number) => number), opts?: { at?: Time, duration?: Time, channel?: number | number[] }): this
103
+
104
+ // ── Filters ──────────────────────────────────────────────────
105
+ filter(type: FilterType, ...params: number[]): this
106
+ filter(fn: (data: Float32Array, params: Record<string, unknown>) => Float32Array, opts?: Record<string, unknown>): this
107
+ highpass(freq: number): this
108
+ lowpass(freq: number): this
109
+ bandpass(freq: number, Q?: number): this
110
+ notch(freq: number, Q?: number): this
111
+ eq(freq: number, gain?: number, Q?: number): this
112
+ lowshelf(freq: number, gain?: number, Q?: number): this
113
+ highshelf(freq: number, gain?: number, Q?: number): this
114
+
115
+ // ── Smart ops ───────────────────────────────────────────────
116
+ trim(threshold?: number): this
117
+ normalize(): this
118
+ normalize(preset: 'streaming' | 'podcast' | 'broadcast'): this
119
+ normalize(targetDb: number, opts?: 'lufs' | { mode?: 'peak' | 'lufs' | 'rms', at?: Time, duration?: Time, channel?: number | number[] }): this
120
+ normalize(opts: { target?: number, mode?: 'peak' | 'lufs' | 'rms', at?: Time, duration?: Time, channel?: number | number[], dc?: boolean, ceiling?: number }): this
121
+
122
+ // ── Fns (registered via audio.fn) ───────────────────────────
123
+ clip(opts?: { at?: Time, duration?: Time }): AudioInstance
124
+ split(...offsets: Time[]): AudioInstance[]
125
+ undo(n?: number): EditOp | EditOp[] | null
126
+ run(...edits: EditOp[]): this
127
+ transform(fn: (channels: Float32Array[], ctx: any) => Float32Array[] | false | null): this
128
+ play(opts?: { at?: Time, duration?: Time, volume?: number, loop?: boolean, paused?: boolean }): this
129
+ pause(): void
130
+ resume(): void
131
+ stop(): this
132
+ save(target: string | FileSystemWritableFileStream, opts?: { format?: string, at?: Time, duration?: Time, meta?: Record<string, any> }): Promise<void>
133
+ encode(format?: string, opts?: { at?: Time, duration?: Time, meta?: Record<string, any> }): Promise<Uint8Array>
134
+ encode(opts?: { at?: Time, duration?: Time, meta?: Record<string, any> }): Promise<Uint8Array>
135
+ clone(): AudioInstance
136
+ }
137
+
138
+ export interface AudioStats {
139
+ blockSize: number
140
+ min: Float32Array[]
141
+ max: Float32Array[]
142
+ energy: Float32Array[]
143
+ [field: string]: number | Float32Array[]
144
+ }
145
+
146
+ export interface EditOp {
147
+ type: string
148
+ [key: string]: any
149
+ }
150
+
151
+
152
+ export interface AudioOpts {
153
+ sampleRate?: number
154
+ channels?: number
155
+ storage?: 'memory' | 'persistent' | 'auto'
156
+ decode?: 'worker' | 'main'
157
+ }
158
+
159
+ export interface ProgressDelta {
160
+ fromBlock: number
161
+ min: Float32Array[]
162
+ max: Float32Array[]
163
+ energy: Float32Array[]
164
+ }
165
+
166
+ export interface OpDescriptor {
167
+ process?: (chs: Float32Array[], ctx: Record<string, any>) => Float32Array[] | false | null
168
+ plan?: (segs: any[], ctx: Record<string, any>) => any[]
169
+ resolve?: (args: any[], ctx: Record<string, any>) => EditOp | EditOp[] | false | null
170
+ call?: (std: Function, ...args: any[]) => any
171
+ ch?: Function
172
+ }
173
+
174
+ /** Serialized audio instance (from toJSON) */
175
+ export interface AudioDocument {
176
+ source: string | null
177
+ edits: EditOp[]
178
+ sampleRate: number
179
+ channels: number
180
+ duration: number
181
+ }
182
+
183
+ /** No source — returns pushable instance. Use .push() to feed PCM, .record() for mic, .stop() to finalize. */
184
+ declare function audio(source?: null, opts?: AudioOpts): AudioInstance & {
185
+ push(data: Float32Array[] | Float32Array | ArrayBufferView, format?: string | { format?: string, channels?: number, sampleRate?: number }): AudioInstance
186
+ record(opts?: Record<string, any>): AudioInstance
187
+ recording: boolean
188
+ }
189
+ /** Async entry — decode from file/URL/bytes, wrap PCM/silence, concat from array, or restore from JSON */
190
+ /** Sync entry — returns instance immediately. Thenable: `await audio(src)` waits for full decode. */
191
+ declare function audio(source: string | URL | ArrayBuffer | Uint8Array | AudioBuffer | Float32Array[] | number | AudioDocument | (AudioInstance | string | URL | ArrayBuffer)[], opts?: AudioOpts): AudioInstance & PromiseLike<AudioInstance>
192
+
193
+ declare namespace audio {
194
+ /** Package version */
195
+ const version: string
196
+ /** Samples per PCM page chunk (default 1024 * BLOCK_SIZE). Set before creating instances. */
197
+ let PAGE_SIZE: number
198
+ /** Samples per stat block (default 1024). Set before creating instances. */
199
+ let BLOCK_SIZE: number
200
+ /** OPFS-backed cache backend for large files (browser only) */
201
+ function opfsCache(dirName?: string): Promise<{
202
+ read(i: number): Promise<Float32Array[]>
203
+ write(i: number, data: Float32Array[]): Promise<void>
204
+ has(i: number): Promise<boolean>
205
+ evict(i: number): Promise<void>
206
+ clear(): Promise<void>
207
+ }>
208
+ /** Sync entry — from PCM data, AudioBuffer, audio instance (structural copy), silence, function source, or typed array with format */
209
+ function from(source: Float32Array[] | AudioBuffer | AudioInstance | number, opts?: AudioOpts): AudioInstance
210
+ function from(fn: (t: number, i: number) => number | number[], opts: AudioOpts & { duration: number }): AudioInstance
211
+ function from(source: Int16Array | Int8Array | Uint8Array | Uint16Array, opts: AudioOpts & { format: string }): AudioInstance
212
+ /** Op registration and query */
213
+ function op(): Record<string, OpDescriptor>
214
+ function op(name: string): OpDescriptor | undefined
215
+ function op(name: string, descriptor: OpDescriptor | Function): void
216
+ /** Stat registration and query */
217
+ interface StatDescriptor {
218
+ /** Per-block computation during decode */
219
+ block?: (chs: Float32Array[], ctx: { sampleRate: number, [k: string]: unknown }) => number | number[]
220
+ /** Reducer for scalar/binned queries: (src, from, to) → number */
221
+ reduce?: (src: Float32Array, from: number, to: number) => number
222
+ /** Derived aggregation from block stats */
223
+ query?: (stats: AudioStats, chs: number[], from: number, to: number, sr: number) => any
224
+ }
225
+ function stat(): Record<string, StatDescriptor>
226
+ function stat(name: string): StatDescriptor | undefined
227
+ function stat(name: string, descriptor: StatDescriptor | ((chs: Float32Array[], ctx: { sampleRate: number, [k: string]: unknown }) => number | number[])): void
228
+ /** Audio instance prototype — extensible (like $.fn) */
229
+ const fn: Record<string, any>
230
+ }
231
+
232
+ export default audio
package/audio.js ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * audio — full bundle with all built-in ops, stats, and methods.
3
+ *
4
+ * import audio from 'audio'
5
+ * let a = await audio('file.mp3')
6
+ * a.gain(-3).trim().normalize()
7
+ * await a.save('out.wav')
8
+ */
9
+
10
+ import audio from './core.js'
11
+ export { default } from './core.js'
12
+ export { parseTime } from './core.js'
13
+ export { render } from './plan.js'
14
+
15
+ // ── Infrastructure (self-register on import) ────────────────────────────
16
+
17
+ import './cache.js'
18
+ import './stats.js'
19
+ import './plan.js'
20
+
21
+ // ── Methods ─────────────────────────────────────────────────────────────
22
+
23
+ import './fn/clip.js'
24
+ import './fn/split.js'
25
+ import './fn/play.js'
26
+ import './fn/save.js'
27
+
28
+ // ── Ops ─────────────────────────────────────────────────────────────────
29
+
30
+ import './fn/crop.js'
31
+ import './fn/remove.js'
32
+ import './fn/insert.js'
33
+ import './fn/repeat.js'
34
+ import './fn/gain.js'
35
+ import './fn/fade.js'
36
+ import './fn/reverse.js'
37
+ import './fn/mix.js'
38
+ import './fn/write.js'
39
+ import './fn/remix.js'
40
+ import './fn/trim.js'
41
+ import './fn/normalize.js'
42
+ import './fn/filter.js'
43
+ import './fn/pan.js'
44
+ import './fn/pad.js'
45
+ import './fn/speed.js'
46
+ import './fn/transform.js'
47
+
48
+ // ── Stats ───────────────────────────────────────────────────────────────
49
+
50
+ import './fn/stat.js'
51
+ import './fn/loudness.js'
52
+ import './fn/spectrum.js'
53
+ import './fn/cepstrum.js'
54
+ import './fn/silence.js'