@memberjunction/ng-conversations 6.2.0-edge.4 → 6.2.0-edge.5
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 +29 -0
- package/dist/lib/components/conversation/conversation-agent-picker.component.d.ts +1 -1
- package/dist/lib/components/conversation/conversation-agent-picker.component.js +3 -3
- package/dist/lib/components/conversation/conversation-agent-picker.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +75 -14
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +711 -359
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.js +9 -9
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +137 -16
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +1361 -296
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +20 -2
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +28 -4
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/sidebar/routines-section.component.js +1 -1
- package/dist/lib/components/sidebar/routines-section.component.js.map +1 -1
- package/dist/lib/components/task/tasks-full-view.component.d.ts +152 -31
- package/dist/lib/components/task/tasks-full-view.component.d.ts.map +1 -1
- package/dist/lib/components/task/tasks-full-view.component.js +2227 -214
- package/dist/lib/components/task/tasks-full-view.component.js.map +1 -1
- package/dist/lib/components/tasks/tasks-dropdown.component.js +4 -4
- package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +11 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +25 -28
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/services/agent-state.service.d.ts.map +1 -1
- package/dist/lib/services/agent-state.service.js +8 -8
- package/dist/lib/services/agent-state.service.js.map +1 -1
- package/dist/lib/services/browser-realtime-media-host.d.ts +7 -7
- package/dist/lib/services/browser-realtime-media-host.js +8 -78
- package/dist/lib/services/browser-realtime-media-host.js.map +1 -1
- package/dist/lib/services/conversation-agent.service.d.ts +16 -8
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +57 -27
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-naming.d.ts.map +1 -1
- package/dist/lib/services/conversation-naming.js +9 -2
- package/dist/lib/services/conversation-naming.js.map +1 -1
- package/dist/lib/services/conversation-tasks-filter.d.ts +15 -0
- package/dist/lib/services/conversation-tasks-filter.d.ts.map +1 -0
- package/dist/lib/services/conversation-tasks-filter.js +69 -0
- package/dist/lib/services/conversation-tasks-filter.js.map +1 -0
- package/dist/lib/services/realtime-audio-recorder.d.ts +94 -86
- package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.js +222 -195
- package/dist/lib/services/realtime-audio-recorder.js.map +1 -1
- package/dist/lib/services/realtime-session.service.d.ts +30 -2
- package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
- package/dist/lib/services/realtime-session.service.js +33 -6
- package/dist/lib/services/realtime-session.service.js.map +1 -1
- package/dist/lib/services/recording/libopus-wasm-binary.d.ts +3 -0
- package/dist/lib/services/recording/libopus-wasm-binary.d.ts.map +1 -0
- package/dist/lib/services/recording/libopus-wasm-binary.js +489 -0
- package/dist/lib/services/recording/libopus-wasm-binary.js.map +1 -0
- package/dist/lib/services/recording/libopus-worker-source.d.ts +48 -0
- package/dist/lib/services/recording/libopus-worker-source.d.ts.map +1 -0
- package/dist/lib/services/recording/libopus-worker-source.js +170 -0
- package/dist/lib/services/recording/libopus-worker-source.js.map +1 -0
- package/dist/lib/services/recording/linear-resampler.d.ts +45 -0
- package/dist/lib/services/recording/linear-resampler.d.ts.map +1 -0
- package/dist/lib/services/recording/linear-resampler.js +85 -0
- package/dist/lib/services/recording/linear-resampler.js.map +1 -0
- package/dist/lib/services/recording/opus-packet-encoder.d.ts +50 -0
- package/dist/lib/services/recording/opus-packet-encoder.d.ts.map +1 -0
- package/dist/lib/services/recording/opus-packet-encoder.js +41 -0
- package/dist/lib/services/recording/opus-packet-encoder.js.map +1 -0
- package/dist/lib/services/recording/wasm-opus-encoder.d.ts +86 -0
- package/dist/lib/services/recording/wasm-opus-encoder.d.ts.map +1 -0
- package/dist/lib/services/recording/wasm-opus-encoder.js +232 -0
- package/dist/lib/services/recording/wasm-opus-encoder.js.map +1 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.d.ts +39 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.d.ts.map +1 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.js +101 -0
- package/dist/lib/services/recording/webcodecs-opus-encoder.js.map +1 -0
- package/dist/lib/services/search.service.d.ts.map +1 -1
- package/dist/lib/services/search.service.js +3 -16
- package/dist/lib/services/search.service.js.map +1 -1
- package/dist/lib/utils/distinct-artifacts.d.ts +9 -3
- package/dist/lib/utils/distinct-artifacts.d.ts.map +1 -1
- package/dist/lib/utils/distinct-artifacts.js +24 -5
- package/dist/lib/utils/distinct-artifacts.js.map +1 -1
- package/package.json +36 -36
- package/dist/lib/services/browser-recording-unload-guard.d.ts +0 -30
- package/dist/lib/services/browser-recording-unload-guard.d.ts.map +0 -1
- package/dist/lib/services/browser-recording-unload-guard.js +0 -43
- package/dist/lib/services/browser-recording-unload-guard.js.map +0 -1
- package/dist/lib/services/realtime-pcm-wav.d.ts +0 -79
- package/dist/lib/services/realtime-pcm-wav.d.ts.map +0 -1
- package/dist/lib/services/realtime-pcm-wav.js +0 -213
- package/dist/lib/services/realtime-pcm-wav.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-pcm-wav.d.ts","sourceRoot":"","sources":["../../../src/lib/services/realtime-pcm-wav.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,gFAAgF;AAChF,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAcnC;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,WAAW,CAkCrF;AAED,8CAA8C;AAC9C,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,WAAW,CAErF;AASD;;;;;;GAMG;AACH,qBAAa,eAAe;IACxB,iEAAiE;IACjE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,oGAAoG;IACpG,OAAO,CAAC,OAAO,CAAgB;IAC/B,gFAAgF;IAChF,OAAO,CAAC,gBAAgB,CAAK;IAC7B,8DAA8D;IAC9D,OAAO,CAAC,gBAAgB,CAAK;IAE7B;;;OAGG;gBACS,aAAa,SAAM;IAI/B,+DAA+D;IAC/D,IAAW,WAAW,IAAI,MAAM,CAE/B;IAED,uFAAuF;IAChF,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAMxC,kGAAkG;IAClG,OAAO,CAAC,UAAU;IAsBlB,gGAAgG;IAChG,OAAO,CAAC,IAAI;IAYZ;;;OAGG;IACI,SAAS,IAAI,MAAM,EAAE;CAgB/B;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,aAAa,SAAM,GAAG,MAAM,EAAE,CA4BpF;AAED,+CAA+C;AAC/C,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,aAAa,SAAM,GAAG,MAAM,EAAE,CAEpF"}
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Pure, browser-and-node-safe helpers for the CLIENT-DIRECT realtime recorder:
|
|
3
|
-
* encoding accumulated Float32 PCM into a seekable 16-bit PCM **WAV** container and computing a
|
|
4
|
-
* bounded, downsampled waveform **peak** array at capture time.
|
|
5
|
-
*
|
|
6
|
-
* These functions are deliberately free of any browser API (`AudioContext`, `Blob`, …) so they can
|
|
7
|
-
* be unit-tested in a plain Node environment. {@link RealtimeAudioRecorder} owns the live audio
|
|
8
|
-
* graph and feeds the captured samples here.
|
|
9
|
-
*
|
|
10
|
-
* Why WAV (PCM) over webm/opus: a RIFF/WAVE header carries the exact duration and maps a byte
|
|
11
|
-
* offset linearly to a time offset, so HTTP-range seeking is exact (no client-side duration nudge),
|
|
12
|
-
* and peak extraction is trivial. The tradeoff is size — PCM WAV is larger than opus — which is
|
|
13
|
-
* acceptable for these short session recordings.
|
|
14
|
-
*
|
|
15
|
-
* @module @memberjunction/ng-conversations/realtime-pcm-wav
|
|
16
|
-
*/
|
|
17
|
-
/** Lowest value representable by signed 16-bit PCM. */
|
|
18
|
-
const PCM16_MIN = -32768;
|
|
19
|
-
/** Highest value representable by signed 16-bit PCM. */
|
|
20
|
-
const PCM16_MAX = 32767;
|
|
21
|
-
/** Canonical WAV/PCM header size in bytes (RIFF + fmt + data chunk headers). */
|
|
22
|
-
export const WAV_HEADER_BYTES = 44;
|
|
23
|
-
/**
|
|
24
|
-
* Converts one Float32 sample (nominally in `[-1, 1]`) to a clamped signed 16-bit integer.
|
|
25
|
-
* Out-of-range values (a hot mix can briefly exceed unity) are clamped, not wrapped.
|
|
26
|
-
*/
|
|
27
|
-
function floatToPcm16(sample) {
|
|
28
|
-
const clamped = sample < -1 ? -1 : sample > 1 ? 1 : sample;
|
|
29
|
-
// Asymmetric scaling: negative full-scale is -32768, positive is +32767.
|
|
30
|
-
const scaled = clamped < 0 ? clamped * -PCM16_MIN : clamped * PCM16_MAX;
|
|
31
|
-
const rounded = Math.round(scaled);
|
|
32
|
-
return rounded < PCM16_MIN ? PCM16_MIN : rounded > PCM16_MAX ? PCM16_MAX : rounded;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Encodes mono Float32 PCM samples as a canonical single-chunk 16-bit PCM WAV (RIFF/WAVE).
|
|
36
|
-
* The returned `ArrayBuffer` is `WAV_HEADER_BYTES + samples.length * 2` bytes — a proper
|
|
37
|
-
* 44-byte header followed by little-endian PCM16 data, so it is seekable and self-describing.
|
|
38
|
-
*
|
|
39
|
-
* @param samples Mono Float32 PCM in `[-1, 1]` (downmixed by the caller).
|
|
40
|
-
* @param sampleRate Sample rate in Hz (from the capturing `AudioContext`).
|
|
41
|
-
* @returns A standalone `ArrayBuffer` containing the full WAV file.
|
|
42
|
-
*/
|
|
43
|
-
export function EncodePcm16Wav(samples, sampleRate) {
|
|
44
|
-
const numChannels = 1;
|
|
45
|
-
const bitsPerSample = 16;
|
|
46
|
-
const bytesPerSample = bitsPerSample / 8;
|
|
47
|
-
const blockAlign = numChannels * bytesPerSample;
|
|
48
|
-
const byteRate = sampleRate * blockAlign;
|
|
49
|
-
const dataSize = samples.length * bytesPerSample;
|
|
50
|
-
const buffer = new ArrayBuffer(WAV_HEADER_BYTES + dataSize);
|
|
51
|
-
const view = new DataView(buffer);
|
|
52
|
-
writeAscii(view, 0, 'RIFF');
|
|
53
|
-
view.setUint32(4, 36 + dataSize, true); // ChunkSize = 36 + Subchunk2Size
|
|
54
|
-
writeAscii(view, 8, 'WAVE');
|
|
55
|
-
writeAscii(view, 12, 'fmt ');
|
|
56
|
-
view.setUint32(16, 16, true); // Subchunk1Size (16 for PCM)
|
|
57
|
-
view.setUint16(20, 1, true); // AudioFormat = PCM
|
|
58
|
-
view.setUint16(22, numChannels, true);
|
|
59
|
-
view.setUint32(24, sampleRate, true);
|
|
60
|
-
view.setUint32(28, byteRate, true);
|
|
61
|
-
view.setUint16(32, blockAlign, true);
|
|
62
|
-
view.setUint16(34, bitsPerSample, true);
|
|
63
|
-
writeAscii(view, 36, 'data');
|
|
64
|
-
view.setUint32(40, dataSize, true);
|
|
65
|
-
let offset = WAV_HEADER_BYTES;
|
|
66
|
-
for (let i = 0; i < samples.length; i++) {
|
|
67
|
-
view.setInt16(offset, floatToPcm16(samples[i]), true);
|
|
68
|
-
offset += bytesPerSample;
|
|
69
|
-
}
|
|
70
|
-
return buffer;
|
|
71
|
-
}
|
|
72
|
-
/** @deprecated Use {@link EncodePcm16Wav}. */
|
|
73
|
-
export function encodePcm16Wav(samples, sampleRate) {
|
|
74
|
-
return EncodePcm16Wav(samples, sampleRate);
|
|
75
|
-
}
|
|
76
|
-
/** Writes an ASCII string into a {@link DataView} byte-by-byte at `offset`. */
|
|
77
|
-
function writeAscii(view, offset, text) {
|
|
78
|
-
for (let i = 0; i < text.length; i++) {
|
|
79
|
-
view.setUint8(offset + i, text.charCodeAt(i));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* A bounded, streaming waveform-peak accumulator. It maintains a fixed number of buckets
|
|
84
|
-
* (`targetBuckets`) of max-absolute amplitude across the WHOLE recording regardless of length:
|
|
85
|
-
* once every bucket has absorbed `samplesPerBucket` samples, the buckets are halved (pairwise
|
|
86
|
-
* max-merged) and the per-bucket capacity doubles — so memory + cost stay O(targetBuckets) for an
|
|
87
|
-
* arbitrarily long call. {@link Normalize} returns the final 0..1 peaks.
|
|
88
|
-
*/
|
|
89
|
-
export class PeakAccumulator {
|
|
90
|
-
/** Target (max) number of buckets in the produced peak array. */
|
|
91
|
-
targetBuckets;
|
|
92
|
-
/** Current max-abs amplitude per bucket (length grows up to `2 * targetBuckets` before folding). */
|
|
93
|
-
buckets = [];
|
|
94
|
-
/** How many samples each bucket currently absorbs before a new bucket opens. */
|
|
95
|
-
samplesPerBucket = 1;
|
|
96
|
-
/** Samples absorbed into the current (last) bucket so far. */
|
|
97
|
-
samplesInCurrent = 0;
|
|
98
|
-
/**
|
|
99
|
-
* @param targetBuckets Desired bucket count (waveform resolution). Clamped to >= 1.
|
|
100
|
-
* ~600 gives a smooth overview waveform at trivial cost.
|
|
101
|
-
*/
|
|
102
|
-
constructor(targetBuckets = 600) {
|
|
103
|
-
this.targetBuckets = Math.max(1, Math.floor(targetBuckets));
|
|
104
|
-
}
|
|
105
|
-
/** Number of buckets currently held (for tests/inspection). */
|
|
106
|
-
get BucketCount() {
|
|
107
|
-
return this.buckets.length;
|
|
108
|
-
}
|
|
109
|
-
/** Absorbs a block of Float32 PCM samples, updating the running per-bucket max-abs. */
|
|
110
|
-
Push(samples) {
|
|
111
|
-
for (let i = 0; i < samples.length; i++) {
|
|
112
|
-
this.pushSample(samples[i]);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
/** Absorbs one sample into the current bucket, opening/folding buckets as capacity is reached. */
|
|
116
|
-
pushSample(sample) {
|
|
117
|
-
if (this.buckets.length === 0) {
|
|
118
|
-
this.buckets.push(0);
|
|
119
|
-
this.samplesInCurrent = 0;
|
|
120
|
-
}
|
|
121
|
-
const abs = sample < 0 ? -sample : sample;
|
|
122
|
-
const last = this.buckets.length - 1;
|
|
123
|
-
if (abs > this.buckets[last]) {
|
|
124
|
-
this.buckets[last] = abs;
|
|
125
|
-
}
|
|
126
|
-
this.samplesInCurrent++;
|
|
127
|
-
if (this.samplesInCurrent >= this.samplesPerBucket) {
|
|
128
|
-
this.buckets.push(0);
|
|
129
|
-
this.samplesInCurrent = 0;
|
|
130
|
-
// Keep the bucket array bounded: once it reaches 2x the target, fold pairwise so the
|
|
131
|
-
// resolution stays under the cap while the per-bucket sample capacity doubles.
|
|
132
|
-
if (this.buckets.length >= this.targetBuckets * 2) {
|
|
133
|
-
this.fold();
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
/** Pairwise max-merges adjacent buckets, halving the count and doubling per-bucket capacity. */
|
|
138
|
-
fold() {
|
|
139
|
-
const folded = [];
|
|
140
|
-
for (let i = 0; i < this.buckets.length; i += 2) {
|
|
141
|
-
const a = this.buckets[i];
|
|
142
|
-
const b = i + 1 < this.buckets.length ? this.buckets[i + 1] : 0;
|
|
143
|
-
folded.push(a > b ? a : b);
|
|
144
|
-
}
|
|
145
|
-
this.buckets = folded;
|
|
146
|
-
this.samplesPerBucket *= 2;
|
|
147
|
-
this.samplesInCurrent = 0;
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Produces the final normalized peak array (each value 0..1, divided by the global max).
|
|
151
|
-
* Trailing empty buckets are trimmed; an all-silent / empty recording yields `[]`.
|
|
152
|
-
*/
|
|
153
|
-
Normalize() {
|
|
154
|
-
// Drop a trailing freshly-opened empty bucket that absorbed nothing.
|
|
155
|
-
const raw = this.buckets.length > 0 && this.samplesInCurrent === 0 && this.buckets.length > 1
|
|
156
|
-
? this.buckets.slice(0, -1)
|
|
157
|
-
: this.buckets.slice();
|
|
158
|
-
let max = 0;
|
|
159
|
-
for (const v of raw) {
|
|
160
|
-
if (v > max) {
|
|
161
|
-
max = v;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
if (max <= 0) {
|
|
165
|
-
return [];
|
|
166
|
-
}
|
|
167
|
-
return raw.map(v => v / max);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* One-shot peak downsampling of a complete Float32 PCM buffer into `targetBuckets` normalized
|
|
172
|
-
* max-abs peaks (0..1). The streaming {@link PeakAccumulator} is the production path; this is the
|
|
173
|
-
* direct, allocation-light equivalent used where the whole buffer is already in hand (and in tests).
|
|
174
|
-
*
|
|
175
|
-
* @param samples The full mono Float32 PCM buffer.
|
|
176
|
-
* @param targetBuckets Desired bucket count (clamped to >= 1). Buckets beyond the sample count are
|
|
177
|
-
* not produced — a short buffer yields at most `samples.length` peaks.
|
|
178
|
-
* @returns Normalized peaks; `[]` for an empty or all-silent buffer.
|
|
179
|
-
*/
|
|
180
|
-
export function DownsamplePeaks(samples, targetBuckets = 600) {
|
|
181
|
-
const target = Math.max(1, Math.floor(targetBuckets));
|
|
182
|
-
if (samples.length === 0) {
|
|
183
|
-
return [];
|
|
184
|
-
}
|
|
185
|
-
const buckets = Math.min(target, samples.length);
|
|
186
|
-
const samplesPerBucket = samples.length / buckets;
|
|
187
|
-
const peaks = new Array(buckets).fill(0);
|
|
188
|
-
let globalMax = 0;
|
|
189
|
-
for (let b = 0; b < buckets; b++) {
|
|
190
|
-
const start = Math.floor(b * samplesPerBucket);
|
|
191
|
-
const end = b === buckets - 1 ? samples.length : Math.floor((b + 1) * samplesPerBucket);
|
|
192
|
-
let localMax = 0;
|
|
193
|
-
for (let i = start; i < end; i++) {
|
|
194
|
-
const abs = samples[i] < 0 ? -samples[i] : samples[i];
|
|
195
|
-
if (abs > localMax) {
|
|
196
|
-
localMax = abs;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
peaks[b] = localMax;
|
|
200
|
-
if (localMax > globalMax) {
|
|
201
|
-
globalMax = localMax;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
if (globalMax <= 0) {
|
|
205
|
-
return [];
|
|
206
|
-
}
|
|
207
|
-
return peaks.map(v => v / globalMax);
|
|
208
|
-
}
|
|
209
|
-
/** @deprecated Use {@link DownsamplePeaks}. */
|
|
210
|
-
export function downsamplePeaks(samples, targetBuckets = 600) {
|
|
211
|
-
return DownsamplePeaks(samples, targetBuckets);
|
|
212
|
-
}
|
|
213
|
-
//# sourceMappingURL=realtime-pcm-wav.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-pcm-wav.js","sourceRoot":"","sources":["../../../src/lib/services/realtime-pcm-wav.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Pure, browser-and-node-safe helpers for the CLIENT-DIRECT realtime recorder:\n * encoding accumulated Float32 PCM into a seekable 16-bit PCM **WAV** container and computing a\n * bounded, downsampled waveform **peak** array at capture time.\n *\n * These functions are deliberately free of any browser API (`AudioContext`, `Blob`, …) so they can\n * be unit-tested in a plain Node environment. {@link RealtimeAudioRecorder} owns the live audio\n * graph and feeds the captured samples here.\n *\n * Why WAV (PCM) over webm/opus: a RIFF/WAVE header carries the exact duration and maps a byte\n * offset linearly to a time offset, so HTTP-range seeking is exact (no client-side duration nudge),\n * and peak extraction is trivial. The tradeoff is size — PCM WAV is larger than opus — which is\n * acceptable for these short session recordings.\n *\n * @module @memberjunction/ng-conversations/realtime-pcm-wav\n */\n\n/** Lowest value representable by signed 16-bit PCM. */\nconst PCM16_MIN = -32768;\n/** Highest value representable by signed 16-bit PCM. */\nconst PCM16_MAX = 32767;\n/** Canonical WAV/PCM header size in bytes (RIFF + fmt + data chunk headers). */\nexport const WAV_HEADER_BYTES = 44;\n\n/**\n * Converts one Float32 sample (nominally in `[-1, 1]`) to a clamped signed 16-bit integer.\n * Out-of-range values (a hot mix can briefly exceed unity) are clamped, not wrapped.\n */\nfunction floatToPcm16(sample: number): number {\n const clamped = sample < -1 ? -1 : sample > 1 ? 1 : sample;\n // Asymmetric scaling: negative full-scale is -32768, positive is +32767.\n const scaled = clamped < 0 ? clamped * -PCM16_MIN : clamped * PCM16_MAX;\n const rounded = Math.round(scaled);\n return rounded < PCM16_MIN ? PCM16_MIN : rounded > PCM16_MAX ? PCM16_MAX : rounded;\n}\n\n/**\n * Encodes mono Float32 PCM samples as a canonical single-chunk 16-bit PCM WAV (RIFF/WAVE).\n * The returned `ArrayBuffer` is `WAV_HEADER_BYTES + samples.length * 2` bytes — a proper\n * 44-byte header followed by little-endian PCM16 data, so it is seekable and self-describing.\n *\n * @param samples Mono Float32 PCM in `[-1, 1]` (downmixed by the caller).\n * @param sampleRate Sample rate in Hz (from the capturing `AudioContext`).\n * @returns A standalone `ArrayBuffer` containing the full WAV file.\n */\nexport function EncodePcm16Wav(samples: Float32Array, sampleRate: number): ArrayBuffer {\n const numChannels = 1;\n const bitsPerSample = 16;\n const bytesPerSample = bitsPerSample / 8;\n const blockAlign = numChannels * bytesPerSample;\n const byteRate = sampleRate * blockAlign;\n const dataSize = samples.length * bytesPerSample;\n\n const buffer = new ArrayBuffer(WAV_HEADER_BYTES + dataSize);\n const view = new DataView(buffer);\n\n writeAscii(view, 0, 'RIFF');\n view.setUint32(4, 36 + dataSize, true); // ChunkSize = 36 + Subchunk2Size\n writeAscii(view, 8, 'WAVE');\n\n writeAscii(view, 12, 'fmt ');\n view.setUint32(16, 16, true); // Subchunk1Size (16 for PCM)\n view.setUint16(20, 1, true); // AudioFormat = PCM\n view.setUint16(22, numChannels, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, byteRate, true);\n view.setUint16(32, blockAlign, true);\n view.setUint16(34, bitsPerSample, true);\n\n writeAscii(view, 36, 'data');\n view.setUint32(40, dataSize, true);\n\n let offset = WAV_HEADER_BYTES;\n for (let i = 0; i < samples.length; i++) {\n view.setInt16(offset, floatToPcm16(samples[i]), true);\n offset += bytesPerSample;\n }\n\n return buffer;\n}\n\n/** @deprecated Use {@link EncodePcm16Wav}. */\nexport function encodePcm16Wav(samples: Float32Array, sampleRate: number): ArrayBuffer {\n return EncodePcm16Wav(samples, sampleRate);\n}\n\n/** Writes an ASCII string into a {@link DataView} byte-by-byte at `offset`. */\nfunction writeAscii(view: DataView, offset: number, text: string): void {\n for (let i = 0; i < text.length; i++) {\n view.setUint8(offset + i, text.charCodeAt(i));\n }\n}\n\n/**\n * A bounded, streaming waveform-peak accumulator. It maintains a fixed number of buckets\n * (`targetBuckets`) of max-absolute amplitude across the WHOLE recording regardless of length:\n * once every bucket has absorbed `samplesPerBucket` samples, the buckets are halved (pairwise\n * max-merged) and the per-bucket capacity doubles — so memory + cost stay O(targetBuckets) for an\n * arbitrarily long call. {@link Normalize} returns the final 0..1 peaks.\n */\nexport class PeakAccumulator {\n /** Target (max) number of buckets in the produced peak array. */\n private readonly targetBuckets: number;\n /** Current max-abs amplitude per bucket (length grows up to `2 * targetBuckets` before folding). */\n private buckets: number[] = [];\n /** How many samples each bucket currently absorbs before a new bucket opens. */\n private samplesPerBucket = 1;\n /** Samples absorbed into the current (last) bucket so far. */\n private samplesInCurrent = 0;\n\n /**\n * @param targetBuckets Desired bucket count (waveform resolution). Clamped to >= 1.\n * ~600 gives a smooth overview waveform at trivial cost.\n */\n constructor(targetBuckets = 600) {\n this.targetBuckets = Math.max(1, Math.floor(targetBuckets));\n }\n\n /** Number of buckets currently held (for tests/inspection). */\n public get BucketCount(): number {\n return this.buckets.length;\n }\n\n /** Absorbs a block of Float32 PCM samples, updating the running per-bucket max-abs. */\n public Push(samples: Float32Array): void {\n for (let i = 0; i < samples.length; i++) {\n this.pushSample(samples[i]);\n }\n }\n\n /** Absorbs one sample into the current bucket, opening/folding buckets as capacity is reached. */\n private pushSample(sample: number): void {\n if (this.buckets.length === 0) {\n this.buckets.push(0);\n this.samplesInCurrent = 0;\n }\n const abs = sample < 0 ? -sample : sample;\n const last = this.buckets.length - 1;\n if (abs > this.buckets[last]) {\n this.buckets[last] = abs;\n }\n this.samplesInCurrent++;\n if (this.samplesInCurrent >= this.samplesPerBucket) {\n this.buckets.push(0);\n this.samplesInCurrent = 0;\n // Keep the bucket array bounded: once it reaches 2x the target, fold pairwise so the\n // resolution stays under the cap while the per-bucket sample capacity doubles.\n if (this.buckets.length >= this.targetBuckets * 2) {\n this.fold();\n }\n }\n }\n\n /** Pairwise max-merges adjacent buckets, halving the count and doubling per-bucket capacity. */\n private fold(): void {\n const folded: number[] = [];\n for (let i = 0; i < this.buckets.length; i += 2) {\n const a = this.buckets[i];\n const b = i + 1 < this.buckets.length ? this.buckets[i + 1] : 0;\n folded.push(a > b ? a : b);\n }\n this.buckets = folded;\n this.samplesPerBucket *= 2;\n this.samplesInCurrent = 0;\n }\n\n /**\n * Produces the final normalized peak array (each value 0..1, divided by the global max).\n * Trailing empty buckets are trimmed; an all-silent / empty recording yields `[]`.\n */\n public Normalize(): number[] {\n // Drop a trailing freshly-opened empty bucket that absorbed nothing.\n const raw = this.buckets.length > 0 && this.samplesInCurrent === 0 && this.buckets.length > 1\n ? this.buckets.slice(0, -1)\n : this.buckets.slice();\n let max = 0;\n for (const v of raw) {\n if (v > max) {\n max = v;\n }\n }\n if (max <= 0) {\n return [];\n }\n return raw.map(v => v / max);\n }\n}\n\n/**\n * One-shot peak downsampling of a complete Float32 PCM buffer into `targetBuckets` normalized\n * max-abs peaks (0..1). The streaming {@link PeakAccumulator} is the production path; this is the\n * direct, allocation-light equivalent used where the whole buffer is already in hand (and in tests).\n *\n * @param samples The full mono Float32 PCM buffer.\n * @param targetBuckets Desired bucket count (clamped to >= 1). Buckets beyond the sample count are\n * not produced — a short buffer yields at most `samples.length` peaks.\n * @returns Normalized peaks; `[]` for an empty or all-silent buffer.\n */\nexport function DownsamplePeaks(samples: Float32Array, targetBuckets = 600): number[] {\n const target = Math.max(1, Math.floor(targetBuckets));\n if (samples.length === 0) {\n return [];\n }\n const buckets = Math.min(target, samples.length);\n const samplesPerBucket = samples.length / buckets;\n const peaks = new Array<number>(buckets).fill(0);\n let globalMax = 0;\n for (let b = 0; b < buckets; b++) {\n const start = Math.floor(b * samplesPerBucket);\n const end = b === buckets - 1 ? samples.length : Math.floor((b + 1) * samplesPerBucket);\n let localMax = 0;\n for (let i = start; i < end; i++) {\n const abs = samples[i] < 0 ? -samples[i] : samples[i];\n if (abs > localMax) {\n localMax = abs;\n }\n }\n peaks[b] = localMax;\n if (localMax > globalMax) {\n globalMax = localMax;\n }\n }\n if (globalMax <= 0) {\n return [];\n }\n return peaks.map(v => v / globalMax);\n}\n\n/** @deprecated Use {@link DownsamplePeaks}. */\nexport function downsamplePeaks(samples: Float32Array, targetBuckets = 600): number[] {\n return DownsamplePeaks(samples, targetBuckets);\n}\n"]}
|