decibri 0.0.1 → 1.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.
@@ -0,0 +1,21 @@
1
+ #import <AVFoundation/AVFoundation.h>
2
+
3
+ // CheckMicrophonePermission — macOS only (compiled via binding.gyp OS=='mac').
4
+ //
5
+ // Returns nullptr if the process may proceed (Authorized or NotDetermined).
6
+ // Returns a static error string if permission is Denied or Restricted.
7
+ //
8
+ // NotDetermined: PortAudio will trigger the OS permission dialog on first
9
+ // access naturally. After the user denies, status becomes Denied and the
10
+ // next call returns the error string.
11
+ extern "C" const char* CheckMicrophonePermission() {
12
+ AVAuthorizationStatus status =
13
+ [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
14
+
15
+ if (status == AVAuthorizationStatusDenied ||
16
+ status == AVAuthorizationStatusRestricted) {
17
+ return "Microphone access denied. "
18
+ "Enable access in System Settings \xe2\x86\x92 Privacy & Security \xe2\x86\x92 Microphone.";
19
+ }
20
+ return nullptr; // Authorized or NotDetermined — proceed
21
+ }
@@ -0,0 +1,273 @@
1
+ /// <reference types="node" />
2
+
3
+ import { Readable, ReadableOptions } from 'stream';
4
+
5
+ // ─── Interfaces ───────────────────────────────────────────────────────────────
6
+
7
+ /** Describes a single audio input device returned by `Decibri.devices()`. */
8
+ export interface DeviceInfo {
9
+ /** PortAudio device index — pass as `options.device` to target this device. */
10
+ index: number;
11
+ /** Human-readable device name reported by the OS. */
12
+ name: string;
13
+ /** Maximum number of input channels supported by this device. */
14
+ maxInputChannels: number;
15
+ /** Device's native/preferred sample rate in Hz. */
16
+ defaultSampleRate: number;
17
+ /** Whether this is the current system default input device. */
18
+ isDefault: boolean;
19
+ }
20
+
21
+ /** Version strings returned by `Decibri.version()`. */
22
+ export interface VersionInfo {
23
+ /** decibri package version (e.g. `"1.0.0"`). */
24
+ decibri: string;
25
+ /** Bundled PortAudio version string (e.g. `"PortAudio V19.7.0-devel..."`). */
26
+ portaudio: string;
27
+ }
28
+
29
+ /**
30
+ * Constructor options for `Decibri`.
31
+ * All standard Node.js `ReadableOptions` (e.g. `highWaterMark`) are also accepted.
32
+ */
33
+ export interface DecibriOptions extends ReadableOptions {
34
+ /**
35
+ * Samples per second.
36
+ * @default 16000
37
+ * @minimum 1000
38
+ * @maximum 384000
39
+ */
40
+ sampleRate?: number;
41
+
42
+ /**
43
+ * Number of input channels.
44
+ * @default 1
45
+ * @minimum 1
46
+ * @maximum 32
47
+ */
48
+ channels?: number;
49
+
50
+ /**
51
+ * Frames delivered per audio callback — controls chunk size and latency.
52
+ * At 16 kHz the default of 1600 produces 100 ms chunks.
53
+ * @default 1600
54
+ * @minimum 64
55
+ * @maximum 65536
56
+ */
57
+ framesPerBuffer?: number;
58
+
59
+ /**
60
+ * Device to capture from. Pass a numeric index from `Decibri.devices()`,
61
+ * or a case-insensitive substring of the device name.
62
+ * Omit to use the system default input device.
63
+ * Throws `TypeError` if a name string matches zero or multiple devices.
64
+ */
65
+ device?: number | string;
66
+
67
+ /**
68
+ * Enable voice activity detection. When `true`, emits `'speech'` when RMS
69
+ * energy crosses `vadThreshold` and `'silence'` after `vadHoldoff` ms of
70
+ * sub-threshold audio.
71
+ * @default false
72
+ */
73
+ vad?: boolean;
74
+
75
+ /**
76
+ * RMS energy threshold for speech detection (0–1 normalised scale).
77
+ * Tune upward in noisy environments.
78
+ * @default 0.01
79
+ * @minimum 0
80
+ * @maximum 1
81
+ */
82
+ vadThreshold?: number;
83
+
84
+ /**
85
+ * Milliseconds of sub-threshold audio before `'silence'` is emitted.
86
+ * Prevents rapid toggling on natural speech pauses.
87
+ * @default 300
88
+ * @minimum 0
89
+ */
90
+ vadHoldoff?: number;
91
+
92
+ /**
93
+ * Sample encoding format.
94
+ * - `'int16'` — 16-bit signed integer, little-endian (default)
95
+ * - `'float32'` — 32-bit IEEE 754 float, little-endian
96
+ *
97
+ * Both formats emit a `Buffer`. For zero-copy typed array access:
98
+ * ```ts
99
+ * // int16 (default)
100
+ * const samples = new Int16Array(chunk.buffer, chunk.byteOffset, chunk.length / 2);
101
+ * // float32
102
+ * const samples = new Float32Array(chunk.buffer, chunk.byteOffset, chunk.length / 4);
103
+ * ```
104
+ * @default 'int16'
105
+ */
106
+ format?: 'int16' | 'float32';
107
+ }
108
+
109
+ // ─── Decibri ─────────────────────────────────────────────────────────────────
110
+
111
+ /**
112
+ * A Node.js `Readable` stream that captures raw PCM audio from the microphone.
113
+ *
114
+ * **Audio format** (default):
115
+ * - Encoding: 16-bit signed integer (Int16), little-endian
116
+ * - Sample rate: 16 000 Hz
117
+ * - Channels: 1 (mono)
118
+ *
119
+ * Each `'data'` event emits a `Buffer` of Int16 samples. To view as a typed
120
+ * array without copying:
121
+ * ```ts
122
+ * mic.on('data', (chunk: Buffer) => {
123
+ * const samples = new Int16Array(chunk.buffer, chunk.byteOffset, chunk.length / 2);
124
+ * });
125
+ * ```
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * import Decibri from 'decibri';
130
+ *
131
+ * const mic = new Decibri({ sampleRate: 16000, channels: 1 });
132
+ *
133
+ * mic.on('data', (chunk) => {
134
+ * // chunk is a Buffer of Int16 PCM samples
135
+ * });
136
+ * mic.on('error', (err) => console.error(err));
137
+ * mic.on('backpressure', () => console.warn('Consumer too slow — consider dropping frames'));
138
+ *
139
+ * setTimeout(() => mic.stop(), 5000);
140
+ * ```
141
+ */
142
+ declare class Decibri extends Readable {
143
+ constructor(options?: DecibriOptions);
144
+
145
+ /**
146
+ * Stop microphone capture and end the stream cleanly.
147
+ * Safe to call multiple times — subsequent calls are no-ops.
148
+ */
149
+ stop(): void;
150
+
151
+ /**
152
+ * `true` while the microphone is actively capturing audio.
153
+ */
154
+ readonly isOpen: boolean;
155
+
156
+ /**
157
+ * Returns all available audio input devices on the system.
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * const devices = Decibri.devices();
162
+ * // [
163
+ * // { index: 0, name: 'Built-in Microphone', maxInputChannels: 1,
164
+ * // defaultSampleRate: 44100, isDefault: true },
165
+ * // ...
166
+ * // ]
167
+ * ```
168
+ */
169
+ static devices(): DeviceInfo[];
170
+
171
+ /**
172
+ * Returns version information for decibri and the bundled PortAudio library.
173
+ *
174
+ * @example
175
+ * ```ts
176
+ * Decibri.version();
177
+ * // { decibri: '1.0.0', portaudio: 'PortAudio V19.7.0-devel...' }
178
+ * ```
179
+ */
180
+ static version(): VersionInfo;
181
+
182
+ // ── Event overloads ─────────────────────────────────────────────────────────
183
+ //
184
+ // The 'backpressure' event is added to all listener methods below.
185
+ // It fires when push() returns false — the mic cannot be paused, so the
186
+ // consumer should drain the stream or drop frames.
187
+
188
+ addListener(event: 'close', listener: () => void): this;
189
+ addListener(event: 'data', listener: (chunk: Buffer) => void): this;
190
+ addListener(event: 'end', listener: () => void): this;
191
+ addListener(event: 'error', listener: (err: Error) => void): this;
192
+ addListener(event: 'pause', listener: () => void): this;
193
+ addListener(event: 'readable', listener: () => void): this;
194
+ addListener(event: 'resume', listener: () => void): this;
195
+ addListener(event: 'backpressure', listener: () => void): this;
196
+ addListener(event: 'speech', listener: () => void): this;
197
+ addListener(event: 'silence', listener: () => void): this;
198
+ addListener(event: string | symbol, listener: (...args: any[]) => void): this;
199
+
200
+ emit(event: 'close'): boolean;
201
+ emit(event: 'data', chunk: Buffer): boolean;
202
+ emit(event: 'end'): boolean;
203
+ emit(event: 'error', err: Error): boolean;
204
+ emit(event: 'pause'): boolean;
205
+ emit(event: 'readable'): boolean;
206
+ emit(event: 'resume'): boolean;
207
+ emit(event: 'backpressure'): boolean;
208
+ emit(event: 'speech'): boolean;
209
+ emit(event: 'silence'): boolean;
210
+ emit(event: string | symbol, ...args: any[]): boolean;
211
+
212
+ on(event: 'close', listener: () => void): this;
213
+ on(event: 'data', listener: (chunk: Buffer) => void): this;
214
+ on(event: 'end', listener: () => void): this;
215
+ on(event: 'error', listener: (err: Error) => void): this;
216
+ on(event: 'pause', listener: () => void): this;
217
+ on(event: 'readable', listener: () => void): this;
218
+ on(event: 'resume', listener: () => void): this;
219
+ on(event: 'backpressure', listener: () => void): this;
220
+ on(event: 'speech', listener: () => void): this;
221
+ on(event: 'silence', listener: () => void): this;
222
+ on(event: string | symbol, listener: (...args: any[]) => void): this;
223
+
224
+ once(event: 'close', listener: () => void): this;
225
+ once(event: 'data', listener: (chunk: Buffer) => void): this;
226
+ once(event: 'end', listener: () => void): this;
227
+ once(event: 'error', listener: (err: Error) => void): this;
228
+ once(event: 'pause', listener: () => void): this;
229
+ once(event: 'readable', listener: () => void): this;
230
+ once(event: 'resume', listener: () => void): this;
231
+ once(event: 'backpressure', listener: () => void): this;
232
+ once(event: 'speech', listener: () => void): this;
233
+ once(event: 'silence', listener: () => void): this;
234
+ once(event: string | symbol, listener: (...args: any[]) => void): this;
235
+
236
+ prependListener(event: 'close', listener: () => void): this;
237
+ prependListener(event: 'data', listener: (chunk: Buffer) => void): this;
238
+ prependListener(event: 'end', listener: () => void): this;
239
+ prependListener(event: 'error', listener: (err: Error) => void): this;
240
+ prependListener(event: 'pause', listener: () => void): this;
241
+ prependListener(event: 'readable', listener: () => void): this;
242
+ prependListener(event: 'resume', listener: () => void): this;
243
+ prependListener(event: 'backpressure', listener: () => void): this;
244
+ prependListener(event: 'speech', listener: () => void): this;
245
+ prependListener(event: 'silence', listener: () => void): this;
246
+ prependListener(event: string | symbol, listener: (...args: any[]) => void): this;
247
+
248
+ prependOnceListener(event: 'close', listener: () => void): this;
249
+ prependOnceListener(event: 'data', listener: (chunk: Buffer) => void): this;
250
+ prependOnceListener(event: 'end', listener: () => void): this;
251
+ prependOnceListener(event: 'error', listener: (err: Error) => void): this;
252
+ prependOnceListener(event: 'pause', listener: () => void): this;
253
+ prependOnceListener(event: 'readable', listener: () => void): this;
254
+ prependOnceListener(event: 'resume', listener: () => void): this;
255
+ prependOnceListener(event: 'backpressure', listener: () => void): this;
256
+ prependOnceListener(event: 'speech', listener: () => void): this;
257
+ prependOnceListener(event: 'silence', listener: () => void): this;
258
+ prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this;
259
+
260
+ removeListener(event: 'close', listener: () => void): this;
261
+ removeListener(event: 'data', listener: (chunk: Buffer) => void): this;
262
+ removeListener(event: 'end', listener: () => void): this;
263
+ removeListener(event: 'error', listener: (err: Error) => void): this;
264
+ removeListener(event: 'pause', listener: () => void): this;
265
+ removeListener(event: 'readable', listener: () => void): this;
266
+ removeListener(event: 'resume', listener: () => void): this;
267
+ removeListener(event: 'backpressure', listener: () => void): this;
268
+ removeListener(event: 'speech', listener: () => void): this;
269
+ removeListener(event: 'silence', listener: () => void): this;
270
+ removeListener(event: string | symbol, listener: (...args: any[]) => void): this;
271
+ }
272
+
273
+ export = Decibri;