speechrecorderng 2.25.3 → 3.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/esm2020/lib/audio/array_audio_buffer.mjs +101 -0
- package/esm2020/lib/audio/array_audio_buffer_input_stream.mjs +86 -0
- package/esm2020/lib/audio/audio_data_holder.mjs +109 -0
- package/esm2020/lib/audio/audio_display.mjs +5 -5
- package/esm2020/lib/audio/audio_player.mjs +9 -7
- package/esm2020/lib/audio/capture/capture.mjs +6 -1
- package/esm2020/lib/audio/dsp/level_measure.mjs +97 -55
- package/esm2020/lib/audio/io/stream.mjs +3 -3
- package/esm2020/lib/audio/persistor.mjs +5 -6
- package/esm2020/lib/audio/playback/array_audio_buffer_source_node.mjs +265 -0
- package/esm2020/lib/audio/playback/player.mjs +184 -50
- package/esm2020/lib/audio/ui/audio_canvas_layer_comp.mjs +25 -13
- package/esm2020/lib/audio/ui/audio_display_scroll_pane.mjs +2 -2
- package/esm2020/lib/audio/ui/audiosignal.mjs +206 -77
- package/esm2020/lib/audio/ui/container.mjs +14 -14
- package/esm2020/lib/audio/ui/livelevel.mjs +15 -2
- package/esm2020/lib/audio/ui/sonagram.mjs +343 -160
- package/esm2020/lib/io/stream.mjs +77 -1
- package/esm2020/lib/net/uploader.mjs +15 -3
- package/esm2020/lib/speechrecorder/recording.mjs +52 -7
- package/esm2020/lib/speechrecorder/recordings/recordings.service.mjs +99 -7
- package/esm2020/lib/speechrecorder/session/audiorecorder.mjs +117 -101
- package/esm2020/lib/speechrecorder/session/basicrecorder.mjs +34 -6
- package/esm2020/lib/speechrecorder/session/progress.mjs +2 -2
- package/esm2020/lib/speechrecorder/session/prompting.mjs +2 -2
- package/esm2020/lib/speechrecorder/session/recorder_combi_pane.mjs +6 -3
- package/esm2020/lib/speechrecorder/session/recording_file_cache.mjs +182 -0
- package/esm2020/lib/speechrecorder/session/recording_list.mjs +23 -10
- package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-meta.component.mjs +12 -6
- package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-u-i.component.mjs +5 -5
- package/esm2020/lib/speechrecorder/session/recordingfile/recording-file-view.component.mjs +13 -9
- package/esm2020/lib/speechrecorder/session/recordingfile/recordingfile-service.mjs +8 -5
- package/esm2020/lib/speechrecorder/session/sessionmanager.mjs +118 -95
- package/esm2020/lib/speechrecorderng.component.mjs +2 -2
- package/esm2020/lib/speechrecorderng.module.mjs +5 -4
- package/esm2020/lib/spr.module.version.mjs +2 -2
- package/esm2020/lib/ui/recordingitem_display.mjs +2 -2
- package/fesm2015/speechrecorderng.mjs +2321 -743
- package/fesm2015/speechrecorderng.mjs.map +1 -1
- package/fesm2020/speechrecorderng.mjs +2321 -753
- package/fesm2020/speechrecorderng.mjs.map +1 -1
- package/lib/audio/array_audio_buffer.d.ts +15 -0
- package/lib/audio/array_audio_buffer_input_stream.d.ts +14 -0
- package/lib/audio/audio_data_holder.d.ts +29 -0
- package/lib/audio/audio_display.d.ts +2 -1
- package/lib/audio/audio_player.d.ts +2 -1
- package/lib/audio/capture/capture.d.ts +2 -0
- package/lib/audio/dsp/level_measure.d.ts +2 -1
- package/lib/audio/persistor.d.ts +4 -3
- package/lib/audio/playback/array_audio_buffer_source_node.d.ts +24 -0
- package/lib/audio/playback/player.d.ts +6 -0
- package/lib/audio/ui/audio_canvas_layer_comp.d.ts +4 -1
- package/lib/audio/ui/audio_display_scroll_pane.d.ts +2 -1
- package/lib/audio/ui/audiosignal.d.ts +3 -2
- package/lib/audio/ui/container.d.ts +3 -2
- package/lib/audio/ui/livelevel.d.ts +3 -1
- package/lib/audio/ui/sonagram.d.ts +3 -2
- package/lib/io/stream.d.ts +17 -0
- package/lib/net/uploader.d.ts +6 -1
- package/lib/speechrecorder/recording.d.ts +15 -3
- package/lib/speechrecorder/recordings/recordings.service.d.ts +2 -0
- package/lib/speechrecorder/session/audiorecorder.d.ts +2 -7
- package/lib/speechrecorder/session/basicrecorder.d.ts +9 -3
- package/lib/speechrecorder/session/progress.d.ts +1 -1
- package/lib/speechrecorder/session/prompting.d.ts +1 -1
- package/lib/speechrecorder/session/recorder_combi_pane.d.ts +3 -1
- package/lib/speechrecorder/session/recording_file_cache.d.ts +30 -0
- package/lib/speechrecorder/session/recording_list.d.ts +3 -1
- package/lib/speechrecorder/session/recordingfile/recording-file-meta.component.d.ts +2 -1
- package/lib/speechrecorder/session/recordingfile/recording-file-view.component.d.ts +1 -0
- package/lib/speechrecorder/session/sessionmanager.d.ts +5 -11
- package/lib/speechrecorderng.module.d.ts +2 -1
- package/lib/spr.module.version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -36,6 +36,7 @@ import * as i2$2 from '@angular/material/table';
|
|
|
36
36
|
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
|
37
37
|
import { MatSelectModule } from '@angular/material/select';
|
|
38
38
|
import { MatInputModule } from '@angular/material/input';
|
|
39
|
+
import { MatMenuModule } from '@angular/material/menu';
|
|
39
40
|
|
|
40
41
|
class ActionEvent {
|
|
41
42
|
constructor(_value = null) {
|
|
@@ -109,6 +110,514 @@ class Action {
|
|
|
109
110
|
}
|
|
110
111
|
}
|
|
111
112
|
|
|
113
|
+
class ArrayAudioBufferInputStream {
|
|
114
|
+
constructor(arrayAudioBuffer) {
|
|
115
|
+
this.arrayAudioBuffer = arrayAudioBuffer;
|
|
116
|
+
this._framePos = 0;
|
|
117
|
+
this.chunkFramePos = 0;
|
|
118
|
+
this.chunkIdx = 0;
|
|
119
|
+
this.eod = false;
|
|
120
|
+
//console.debug("Array audio input stream array audio buffer frames: "+arrayAudioBuffer.frameLen);
|
|
121
|
+
}
|
|
122
|
+
close() {
|
|
123
|
+
}
|
|
124
|
+
skipFrames(n) {
|
|
125
|
+
let toSkip = n;
|
|
126
|
+
if (this.chunkIdx >= this.arrayAudioBuffer.chunkCount) {
|
|
127
|
+
this.eod = true;
|
|
128
|
+
if (toSkip > 0) {
|
|
129
|
+
throw Error('Skip out of bounds: Cannot skip ' + toSkip + ' frames.');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
let chunkBuf0 = this.arrayAudioBuffer.data[0][this.chunkIdx];
|
|
134
|
+
let chunkBufsLen = chunkBuf0.length;
|
|
135
|
+
let currBufSkippable = chunkBufsLen - this.chunkFramePos;
|
|
136
|
+
if (n >= currBufSkippable) {
|
|
137
|
+
this._framePos += currBufSkippable;
|
|
138
|
+
toSkip -= currBufSkippable;
|
|
139
|
+
this.chunkIdx++;
|
|
140
|
+
this.chunkFramePos = 0;
|
|
141
|
+
if (this.chunkIdx < this.arrayAudioBuffer.chunkCount) {
|
|
142
|
+
this.skipFrames(toSkip);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
if (toSkip > 0) {
|
|
146
|
+
throw Error('Skip out of bounds: Cannot skip ' + toSkip + ' frames.');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
toSkip -= n;
|
|
152
|
+
this.chunkFramePos += n;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
read(buffers) {
|
|
157
|
+
let read = 0;
|
|
158
|
+
let toRead = buffers[0].length;
|
|
159
|
+
while (read < toRead && !this.eod) {
|
|
160
|
+
//console.debug("Chunk "+this.chunkIdx+" of "+this.arrayAudioBuffer.chunkCount+" chunks.")
|
|
161
|
+
if (this.chunkIdx >= this.arrayAudioBuffer.chunkCount) {
|
|
162
|
+
this.eod = true;
|
|
163
|
+
//console.debug("Array audio input stream end of data read frames: "+this.framePos);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
let chunkBuf0 = this.arrayAudioBuffer.data[0][this.chunkIdx];
|
|
167
|
+
let chunkBufsLen = chunkBuf0.length;
|
|
168
|
+
let chunkBufAvail = chunkBufsLen - this.chunkFramePos;
|
|
169
|
+
let r = chunkBufAvail;
|
|
170
|
+
if (r > toRead - read) {
|
|
171
|
+
r = toRead - read;
|
|
172
|
+
}
|
|
173
|
+
for (let ch = 0; ch < buffers.length; ch++) {
|
|
174
|
+
let chChunkBuf = this.arrayAudioBuffer.data[ch][this.chunkIdx];
|
|
175
|
+
for (let bi = 0; bi < r; bi++) {
|
|
176
|
+
buffers[ch][read + bi] = chChunkBuf[this.chunkFramePos + bi];
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
read += r;
|
|
180
|
+
this.chunkFramePos += r;
|
|
181
|
+
if (this.chunkFramePos >= chunkBufsLen) {
|
|
182
|
+
this.chunkIdx++;
|
|
183
|
+
this.chunkFramePos = 0;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
this._framePos += read;
|
|
188
|
+
//console.debug("Read: "+read+", frame pos: "+this.framePos)
|
|
189
|
+
if (this._framePos > this.arrayAudioBuffer.frameLen) {
|
|
190
|
+
console.error("Array audio input stream frame pos: " + this._framePos + " greater then frame length: " + this.arrayAudioBuffer.frameLen);
|
|
191
|
+
}
|
|
192
|
+
return read;
|
|
193
|
+
}
|
|
194
|
+
get framePos() {
|
|
195
|
+
return this._framePos;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
class EditFloat32ArrayInputStream {
|
|
200
|
+
constructor(_srcInputStream, offset = 0, length) {
|
|
201
|
+
this._srcInputStream = _srcInputStream;
|
|
202
|
+
this.offset = offset;
|
|
203
|
+
this.length = length;
|
|
204
|
+
this.framePos = 0;
|
|
205
|
+
this.readFrames = 0;
|
|
206
|
+
if (this.offset < 0) {
|
|
207
|
+
throw Error('Parameter offset must be undefined or greater or equal zero.');
|
|
208
|
+
}
|
|
209
|
+
if (this.length !== undefined && this.length < 0) {
|
|
210
|
+
throw Error('Parameter length must be undefined or greater or equal zero.');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
skipToOffset() {
|
|
214
|
+
if (this.framePos == 0 && this.offset > 0) {
|
|
215
|
+
this._srcInputStream.skipFrames(this.offset);
|
|
216
|
+
this.framePos += this.offset;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
read(buffers) {
|
|
220
|
+
this.skipToOffset();
|
|
221
|
+
let read = 0;
|
|
222
|
+
if (this.length === undefined) {
|
|
223
|
+
read = this._srcInputStream.read(buffers);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
if (buffers.length > 0) {
|
|
227
|
+
let bufsCh0 = buffers[0];
|
|
228
|
+
let bufsLen = bufsCh0.length;
|
|
229
|
+
let avail = this.length - this.readFrames;
|
|
230
|
+
if (avail > 0) {
|
|
231
|
+
if (avail > bufsLen) {
|
|
232
|
+
read = this._srcInputStream.read(buffers);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
// temporary buffers required
|
|
236
|
+
let tmpBufs = new Array(buffers.length);
|
|
237
|
+
for (let ch = 0; ch < buffers.length; ch++) {
|
|
238
|
+
tmpBufs[ch] = new Float32Array(avail);
|
|
239
|
+
}
|
|
240
|
+
read = this._srcInputStream.read(tmpBufs);
|
|
241
|
+
for (let ch = 0; ch < buffers.length; ch++) {
|
|
242
|
+
buffers[ch].set(tmpBufs[ch]);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
this.readFrames += read;
|
|
249
|
+
this.framePos += read;
|
|
250
|
+
return read;
|
|
251
|
+
}
|
|
252
|
+
skipFrames(n) {
|
|
253
|
+
this.skipToOffset();
|
|
254
|
+
if (this.length === undefined) {
|
|
255
|
+
this._srcInputStream.skipFrames(n);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
let avail = this.length - this.readFrames;
|
|
259
|
+
if (avail > 0) {
|
|
260
|
+
if (avail >= n) {
|
|
261
|
+
this._srcInputStream.skipFrames(n);
|
|
262
|
+
this.readFrames += n;
|
|
263
|
+
this.framePos += n;
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
throw Error('Tried to skip out of bounds.');
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
close() {
|
|
272
|
+
this._srcInputStream.close();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
class Float32ArrayChunkerOutStream {
|
|
276
|
+
constructor(outStream) {
|
|
277
|
+
this.outStream = outStream;
|
|
278
|
+
this.bufs = new Array();
|
|
279
|
+
this._channels = 0;
|
|
280
|
+
this._chunkSize = 0;
|
|
281
|
+
this.filled = 0;
|
|
282
|
+
this.receivedFrames = 0;
|
|
283
|
+
this.sentFrames = 0;
|
|
284
|
+
}
|
|
285
|
+
createBuffers() {
|
|
286
|
+
this.bufs = new Array(this._channels);
|
|
287
|
+
for (let ch = 0; ch < this._channels; ch++) {
|
|
288
|
+
this.bufs[ch] = new Float32Array(this._chunkSize);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
set chunkSize(chunkSize) {
|
|
292
|
+
this._chunkSize = chunkSize;
|
|
293
|
+
this.createBuffers();
|
|
294
|
+
}
|
|
295
|
+
get chunkSize() {
|
|
296
|
+
return this._chunkSize;
|
|
297
|
+
}
|
|
298
|
+
set channels(channels) {
|
|
299
|
+
this._channels = channels;
|
|
300
|
+
this.createBuffers();
|
|
301
|
+
}
|
|
302
|
+
get channels() {
|
|
303
|
+
return this._channels;
|
|
304
|
+
}
|
|
305
|
+
available() {
|
|
306
|
+
return this._chunkSize - this.filled;
|
|
307
|
+
}
|
|
308
|
+
write(buffers) {
|
|
309
|
+
let copied = 0;
|
|
310
|
+
if (buffers.length > 0) {
|
|
311
|
+
let buffersLen = buffers[0].length;
|
|
312
|
+
this.receivedFrames += buffersLen;
|
|
313
|
+
let avail = buffersLen;
|
|
314
|
+
// Fill out buffers until all values copied
|
|
315
|
+
while (avail > 0) {
|
|
316
|
+
let toFill = this._chunkSize - this.filled;
|
|
317
|
+
if (toFill > avail) {
|
|
318
|
+
toFill = avail;
|
|
319
|
+
}
|
|
320
|
+
let sliceEnd = copied + toFill;
|
|
321
|
+
// Firefox on Android sends only the first channel
|
|
322
|
+
for (let ch = 0; ch < buffersLen; ch++) {
|
|
323
|
+
if (buffers[ch]) {
|
|
324
|
+
let cpPrt = buffers[ch].slice(copied, sliceEnd);
|
|
325
|
+
let buf = this.bufs[ch];
|
|
326
|
+
buf.set(cpPrt, this.filled);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
copied += toFill;
|
|
330
|
+
avail -= toFill;
|
|
331
|
+
this.filled += toFill;
|
|
332
|
+
if (this.filled == this._chunkSize) {
|
|
333
|
+
this.outStream.write(this.bufs);
|
|
334
|
+
this.sentFrames += this.filled;
|
|
335
|
+
this.filled = 0;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return copied;
|
|
340
|
+
}
|
|
341
|
+
flush() {
|
|
342
|
+
if (this.filled > 0) {
|
|
343
|
+
let restBufs = new Array(this._channels);
|
|
344
|
+
for (let ch = 0; ch < this._channels; ch++) {
|
|
345
|
+
restBufs[ch] = this.bufs[ch].slice(0, this.filled);
|
|
346
|
+
}
|
|
347
|
+
this.outStream.write(restBufs);
|
|
348
|
+
this.outStream.flush();
|
|
349
|
+
this.sentFrames += this.filled;
|
|
350
|
+
this.filled = 0;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
close() {
|
|
354
|
+
this.outStream.close();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Code from audio_source_worklet.js as string constant to be loaded as module
|
|
359
|
+
// Changes in audio_source_worklet.js must be copied and pasted to this string constant
|
|
360
|
+
const aswpStr = "\n" +
|
|
361
|
+
"// Important note: Changes in audio_source_worklet.js must be copied and pasted to the string constant aswpStr in array_audio_buffer_source_node.ts\n" +
|
|
362
|
+
"\n" +
|
|
363
|
+
"\n" +
|
|
364
|
+
"class AudioSourceProcessor extends AudioWorkletProcessor{\n" +
|
|
365
|
+
"\n" +
|
|
366
|
+
" filledFrames=0;\n" +
|
|
367
|
+
" audioBuffers=new Array();\n" +
|
|
368
|
+
" currentAudioBuffer=null;\n" +
|
|
369
|
+
" currentAudioBufferFramePos=0;\n" +
|
|
370
|
+
" currentAudioBufferAvail=0;\n" +
|
|
371
|
+
" running=false;\n" +
|
|
372
|
+
" ended=false;\n" +
|
|
373
|
+
"\n" +
|
|
374
|
+
" constructor() {\n" +
|
|
375
|
+
" super({numberOfInputs:0,numberOfOutputs:1});\n" +
|
|
376
|
+
" this.port.onmessage=(msgEv)=>{\n" +
|
|
377
|
+
" // received audio playback data from application\n" +
|
|
378
|
+
" //console.debug(\"Audio source worklet msg: Received.\");\n" +
|
|
379
|
+
"\n" +
|
|
380
|
+
" if(msgEv.data.cmd){\n" +
|
|
381
|
+
" if('data'===msgEv.data.cmd) {\n" +
|
|
382
|
+
" let chs = msgEv.data.chs;\n" +
|
|
383
|
+
"\n" +
|
|
384
|
+
" let audioData = new Array(chs);\n" +
|
|
385
|
+
" for (let ch = 0; ch < chs; ch++) {\n" +
|
|
386
|
+
" audioData[ch] = new Float32Array(msgEv.data.audioData[ch]);\n" +
|
|
387
|
+
" }\n" +
|
|
388
|
+
" let msgChBufLen=audioData[0].length;\n" +
|
|
389
|
+
" this.audioBuffers.push(audioData);\n" +
|
|
390
|
+
" this.filledFrames += msgChBufLen;\n" +
|
|
391
|
+
" //console.debug(\"Audio source worklet msg: Filled \" + this.filledFrames+ \" in \"+this.audioBuffers.length+\" buffers.\");\n" +
|
|
392
|
+
"\n" +
|
|
393
|
+
" }else if('start'===msgEv.data.cmd){\n" +
|
|
394
|
+
" this.running=true;\n" +
|
|
395
|
+
" }else if('stop'===msgEv.data.cmd){\n" +
|
|
396
|
+
" //console.debug(\"Stop...\");\n" +
|
|
397
|
+
" this.running=false;\n" +
|
|
398
|
+
" // clear buffers\n" +
|
|
399
|
+
" this.filledFrames=0;\n" +
|
|
400
|
+
" while(this.audioBuffers.length > 0) {\n" +
|
|
401
|
+
" this.audioBuffers.pop();\n" +
|
|
402
|
+
" }\n" +
|
|
403
|
+
" this.currentAudioBuffer=new Float32Array(0);\n" +
|
|
404
|
+
" }\n" +
|
|
405
|
+
" }\n" +
|
|
406
|
+
" }\n" +
|
|
407
|
+
" }\n" +
|
|
408
|
+
"\n" +
|
|
409
|
+
" process(\n" +
|
|
410
|
+
" inputs,\n" +
|
|
411
|
+
" outputs,\n" +
|
|
412
|
+
" parameters\n" +
|
|
413
|
+
" ){\n" +
|
|
414
|
+
" //console.debug(\"Audio source worklet: process \"+outputs.length+ \" output buffers.\");\n" +
|
|
415
|
+
" // copy ring buffer data to outputs\n" +
|
|
416
|
+
" if(!this.running){\n" +
|
|
417
|
+
" return !this.ended;\n" +
|
|
418
|
+
" }\n" +
|
|
419
|
+
"\n" +
|
|
420
|
+
" let output=outputs[0];\n" +
|
|
421
|
+
" let chs=output.length;\n" +
|
|
422
|
+
" //console.debug(\"Audio source worklet: Output channels: \"+chs);\n" +
|
|
423
|
+
" if(chs>0) {\n" +
|
|
424
|
+
"\n" +
|
|
425
|
+
" let outCh0 = output[0];\n" +
|
|
426
|
+
" let outChLen = outCh0.length;\n" +
|
|
427
|
+
"\n" +
|
|
428
|
+
" if(!this.currentAudioBuffer){\n" +
|
|
429
|
+
" // get first buffer\n" +
|
|
430
|
+
" let nxtBuff=this.audioBuffers.shift();\n" +
|
|
431
|
+
" if(nxtBuff) {\n" +
|
|
432
|
+
" this.currentAudioBuffer = nxtBuff;\n" +
|
|
433
|
+
" this.currentAudioBufferFramePos=0;\n" +
|
|
434
|
+
" this.currentAudioBufferAvail=this.currentAudioBuffer[0].length;\n" +
|
|
435
|
+
" }else{\n" +
|
|
436
|
+
" return true;\n" +
|
|
437
|
+
" }\n" +
|
|
438
|
+
" }\n" +
|
|
439
|
+
"\n" +
|
|
440
|
+
" let copied=0;\n" +
|
|
441
|
+
" do{\n" +
|
|
442
|
+
" if(this.currentAudioBufferAvail==0){\n" +
|
|
443
|
+
" let nxtBuff=this.audioBuffers.shift();\n" +
|
|
444
|
+
" if(nxtBuff){\n" +
|
|
445
|
+
" this.currentAudioBuffer=nxtBuff;\n" +
|
|
446
|
+
" this.currentAudioBufferFramePos=0;\n" +
|
|
447
|
+
" this.currentAudioBufferAvail=this.currentAudioBuffer[0].length;\n" +
|
|
448
|
+
" //console.debug(\"Next buffer with \"+this.currentAudioBufferAvail+ \" frames\");\n" +
|
|
449
|
+
" this.port.postMessage({eventType:'bufferNotification',filledFrames:this.filledFrames});\n" +
|
|
450
|
+
" }else{\n" +
|
|
451
|
+
" this.ended=true;\n" +
|
|
452
|
+
" this.port.postMessage({eventType:'ended'});\n" +
|
|
453
|
+
" //console.debug(\"Stream ended\");\n" +
|
|
454
|
+
" break;\n" +
|
|
455
|
+
" }\n" +
|
|
456
|
+
" }\n" +
|
|
457
|
+
" //console.debug(\"outChLen: \"+outChLen+\", copied: \"+copied+\", current avail: \"+this.currentAudioBufferAvail);\n" +
|
|
458
|
+
" let toCopy=outChLen-copied;\n" +
|
|
459
|
+
" if(toCopy>this.currentAudioBufferAvail){\n" +
|
|
460
|
+
" toCopy=this.currentAudioBufferAvail;\n" +
|
|
461
|
+
" }\n" +
|
|
462
|
+
" //console.debug(\"Copy \"+toCopy+\" frames...\");\n" +
|
|
463
|
+
" for(let ch=0;ch<chs;ch++) {\n" +
|
|
464
|
+
" let outCh=output[ch];\n" +
|
|
465
|
+
" for (let i = 0; i < toCopy; i++) {\n" +
|
|
466
|
+
" outCh[copied+i]=this.currentAudioBuffer[ch][this.currentAudioBufferFramePos+i];\n" +
|
|
467
|
+
" }\n" +
|
|
468
|
+
" }\n" +
|
|
469
|
+
" copied+=toCopy;\n" +
|
|
470
|
+
" this.currentAudioBufferFramePos+=toCopy;\n" +
|
|
471
|
+
" this.currentAudioBufferAvail-=toCopy;\n" +
|
|
472
|
+
"\n" +
|
|
473
|
+
" }while(copied<outChLen);\n" +
|
|
474
|
+
" this.filledFrames-=copied;\n" +
|
|
475
|
+
" //console.debug(\"Copied \"+copied+\" frames.\");\n" +
|
|
476
|
+
" }\n" +
|
|
477
|
+
" return !this.ended;\n" +
|
|
478
|
+
" }\n" +
|
|
479
|
+
"}\n" +
|
|
480
|
+
"\n" +
|
|
481
|
+
"registerProcessor('audio-source-worklet',AudioSourceProcessor);\n";
|
|
482
|
+
class ArrayAudioBufferSourceNode extends AudioWorkletNode {
|
|
483
|
+
constructor(context) {
|
|
484
|
+
super(context, 'audio-source-worklet');
|
|
485
|
+
this._bufferFillSeconds = ArrayAudioBufferSourceNode.DEFAULT_BUFFER_FILL_SECONDS;
|
|
486
|
+
this.bufferFillFrames = 0;
|
|
487
|
+
this._arrayAudioBuffer = null;
|
|
488
|
+
this._audioInputStream = null;
|
|
489
|
+
this._aisBufs = null;
|
|
490
|
+
this.filledFrames = 0;
|
|
491
|
+
this.onended = null;
|
|
492
|
+
this.channelCountMode = 'explicit';
|
|
493
|
+
this.port.onmessage = (msgEv) => {
|
|
494
|
+
if (msgEv.data) {
|
|
495
|
+
let evType = msgEv.data.eventType;
|
|
496
|
+
if (evType) {
|
|
497
|
+
if ('bufferNotification' === evType) {
|
|
498
|
+
this.filledFrames = msgEv.data.filledFrames;
|
|
499
|
+
//console.debug("Buffer notification: filled frames: " + this.filledFrames);
|
|
500
|
+
this.fillBuffer();
|
|
501
|
+
}
|
|
502
|
+
else if ('ended' === evType) {
|
|
503
|
+
let drainTime = 0;
|
|
504
|
+
if (this._arrayAudioBuffer?.sampleRate) {
|
|
505
|
+
drainTime = ArrayAudioBufferSourceNode.QUANTUM_FRAME_LEN / this._arrayAudioBuffer.sampleRate;
|
|
506
|
+
}
|
|
507
|
+
//let dstAny:any=this.context.destination;
|
|
508
|
+
//console.debug('Destination node tail-time: '+dstAny['tail-time']);
|
|
509
|
+
window.setTimeout(() => {
|
|
510
|
+
this.onended?.call(this);
|
|
511
|
+
}, drainTime * 1000);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
fillBuffer(frameOffset) {
|
|
518
|
+
if (this._arrayAudioBuffer && this._audioInputStream && this._aisBufs) {
|
|
519
|
+
let filled = this.filledFrames;
|
|
520
|
+
let bufLen = 0;
|
|
521
|
+
while (filled < this.bufferFillFrames) {
|
|
522
|
+
let read = this._audioInputStream.read(this._aisBufs);
|
|
523
|
+
//console.log("ArrayAudioBufferSourceNode: read: "+read)
|
|
524
|
+
if (read) {
|
|
525
|
+
let trBuffers = new Array(this.channelCount);
|
|
526
|
+
for (let ch = 0; ch < this.channelCount; ch++) {
|
|
527
|
+
let adCh = this._aisBufs[ch];
|
|
528
|
+
let adChCopy = new Float32Array(adCh.length);
|
|
529
|
+
bufLen = adChCopy.length;
|
|
530
|
+
adChCopy.set(adCh);
|
|
531
|
+
trBuffers[ch] = adChCopy.buffer;
|
|
532
|
+
}
|
|
533
|
+
this.port.postMessage({
|
|
534
|
+
cmd: 'data',
|
|
535
|
+
chs: this.channelCount,
|
|
536
|
+
audioData: trBuffers
|
|
537
|
+
}, trBuffers);
|
|
538
|
+
filled += read;
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
break;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
get arrayAudioBuffer() {
|
|
547
|
+
return this._arrayAudioBuffer;
|
|
548
|
+
}
|
|
549
|
+
set arrayAudioBuffer(value) {
|
|
550
|
+
this._arrayAudioBuffer = value;
|
|
551
|
+
if (this._arrayAudioBuffer?.channelCount) {
|
|
552
|
+
this.channelCount = this._arrayAudioBuffer?.channelCount;
|
|
553
|
+
this.bufferFillFrames = this._arrayAudioBuffer.sampleRate * this._bufferFillSeconds;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
get bufferFillSeconds() {
|
|
557
|
+
return this._bufferFillSeconds;
|
|
558
|
+
}
|
|
559
|
+
set bufferFillSeconds(value) {
|
|
560
|
+
this._bufferFillSeconds = value;
|
|
561
|
+
}
|
|
562
|
+
start(when, offset, duration) {
|
|
563
|
+
if (when) {
|
|
564
|
+
throw Error("when, offest,duration parameters currently not supported by ArrayAudioBufferSourceNode class");
|
|
565
|
+
}
|
|
566
|
+
if (this._arrayAudioBuffer) {
|
|
567
|
+
let arrAis = new ArrayAudioBufferInputStream(this._arrayAudioBuffer);
|
|
568
|
+
if (offset === undefined && duration === undefined) {
|
|
569
|
+
this._audioInputStream = arrAis;
|
|
570
|
+
}
|
|
571
|
+
else {
|
|
572
|
+
let offsetFrames = 0;
|
|
573
|
+
let durationFrames = undefined;
|
|
574
|
+
if (offset !== undefined) {
|
|
575
|
+
offsetFrames = Math.floor(offset * this._arrayAudioBuffer.sampleRate);
|
|
576
|
+
}
|
|
577
|
+
if (duration !== undefined) {
|
|
578
|
+
durationFrames = Math.floor(duration * this._arrayAudioBuffer.sampleRate);
|
|
579
|
+
}
|
|
580
|
+
this._audioInputStream = new EditFloat32ArrayInputStream(arrAis, offsetFrames, durationFrames);
|
|
581
|
+
}
|
|
582
|
+
let chs = this._arrayAudioBuffer.channelCount;
|
|
583
|
+
this._aisBufs = new Array(chs);
|
|
584
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
585
|
+
this._aisBufs[ch] = new Float32Array(1024);
|
|
586
|
+
}
|
|
587
|
+
this.fillBuffer();
|
|
588
|
+
this.port.postMessage({ cmd: 'start' });
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
stop() {
|
|
592
|
+
this.port.postMessage({ cmd: 'stop' });
|
|
593
|
+
this.onended?.call(this);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
ArrayAudioBufferSourceNode.QUANTUM_FRAME_LEN = 128;
|
|
597
|
+
ArrayAudioBufferSourceNode.DEFAULT_BUFFER_FILL_SECONDS = 10;
|
|
598
|
+
class AudioSourceWorkletModuleLoader {
|
|
599
|
+
static loadModule(context) {
|
|
600
|
+
return new Promise((resolve, reject) => {
|
|
601
|
+
if (AudioSourceWorkletModuleLoader.moduleLoaded) {
|
|
602
|
+
resolve.call(self);
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
let audioWorkletModuleBlob = new Blob([aswpStr], { type: 'text/javascript' });
|
|
606
|
+
let audioWorkletModuleBlobUrl = window.URL.createObjectURL(audioWorkletModuleBlob);
|
|
607
|
+
context.resume();
|
|
608
|
+
context.audioWorklet.addModule(audioWorkletModuleBlobUrl).then(() => {
|
|
609
|
+
AudioSourceWorkletModuleLoader.moduleLoaded = true;
|
|
610
|
+
resolve.call(self);
|
|
611
|
+
}).catch((reason) => {
|
|
612
|
+
console.error(reason);
|
|
613
|
+
reject.call(reason);
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
AudioSourceWorkletModuleLoader.moduleLoaded = false;
|
|
620
|
+
|
|
112
621
|
var EventType;
|
|
113
622
|
(function (EventType) {
|
|
114
623
|
EventType[EventType["CLOSED"] = 0] = "CLOSED";
|
|
@@ -135,10 +644,17 @@ class AudioPlayer {
|
|
|
135
644
|
this.running = false;
|
|
136
645
|
this._audioClip = null;
|
|
137
646
|
this._audioBuffer = null;
|
|
647
|
+
this._arrayAudioBuffer = null;
|
|
138
648
|
this.sourceBufferNode = null;
|
|
649
|
+
this.sourceAudioWorkletNode = null;
|
|
139
650
|
this.playStartTime = null;
|
|
140
651
|
this.timerVar = null;
|
|
141
652
|
this.context = context;
|
|
653
|
+
// AudioSourceWorkletModuleLoader.loadModule(this.context).then(()=>{
|
|
654
|
+
// console.debug("Audio source worklet module loaded.");
|
|
655
|
+
// }).catch((error: any)=>{
|
|
656
|
+
// console.error('Could not add module '+error);
|
|
657
|
+
// });
|
|
142
658
|
this.listener = listener;
|
|
143
659
|
this.bufSize = AudioPlayer.DEFAULT_BUFSIZE;
|
|
144
660
|
this.n = navigator;
|
|
@@ -169,17 +685,23 @@ class AudioPlayer {
|
|
|
169
685
|
return this._stopAction;
|
|
170
686
|
}
|
|
171
687
|
set audioClip(audioClip) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if (audioClip && audioClip.
|
|
175
|
-
|
|
688
|
+
let length = 0;
|
|
689
|
+
let chs = 0;
|
|
690
|
+
if (audioClip && audioClip.audioDataHolder) {
|
|
691
|
+
let audioDataHolder = audioClip.audioDataHolder;
|
|
692
|
+
chs = audioDataHolder.numberOfChannels;
|
|
176
693
|
if (chs > 0) {
|
|
177
|
-
length =
|
|
694
|
+
length = audioDataHolder.frameLen;
|
|
178
695
|
if (chs > this.context.destination.maxChannelCount) {
|
|
179
696
|
// TODO exception
|
|
180
697
|
}
|
|
181
698
|
}
|
|
182
|
-
|
|
699
|
+
if (audioDataHolder.buffer) {
|
|
700
|
+
this.audioBuffer = audioDataHolder.buffer;
|
|
701
|
+
}
|
|
702
|
+
if (audioDataHolder.arrayBuffer) {
|
|
703
|
+
this.arrayAudioBuffer = audioDataHolder.arrayBuffer;
|
|
704
|
+
}
|
|
183
705
|
audioClip.addSelectionObserver((ac) => {
|
|
184
706
|
this._startSelectionAction.disabled = this.startSelectionDisabled();
|
|
185
707
|
if (!this.startSelectionAction.disabled && this._autoPlayOnSelectToggleAction.value) {
|
|
@@ -189,12 +711,14 @@ class AudioPlayer {
|
|
|
189
711
|
}
|
|
190
712
|
else {
|
|
191
713
|
this.audioBuffer = null;
|
|
714
|
+
//this.arrayAudioBuffer=null;
|
|
192
715
|
}
|
|
193
716
|
this._audioClip = audioClip;
|
|
194
717
|
}
|
|
195
718
|
set audioBuffer(audioBuffer) {
|
|
196
719
|
this.stop();
|
|
197
720
|
this._audioBuffer = audioBuffer;
|
|
721
|
+
this._arrayAudioBuffer = null;
|
|
198
722
|
if (audioBuffer && this.context) {
|
|
199
723
|
this._startAction.disabled = false;
|
|
200
724
|
this._startSelectionAction.disabled = this.startSelectionDisabled();
|
|
@@ -213,23 +737,86 @@ class AudioPlayer {
|
|
|
213
737
|
get audioBuffer() {
|
|
214
738
|
return this._audioBuffer;
|
|
215
739
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
740
|
+
set arrayAudioBuffer(arrayAudioBuffer) {
|
|
741
|
+
this.stop();
|
|
742
|
+
this._audioBuffer = null;
|
|
743
|
+
this._arrayAudioBuffer = arrayAudioBuffer;
|
|
744
|
+
if (arrayAudioBuffer && this.context) {
|
|
745
|
+
AudioSourceWorkletModuleLoader.loadModule(this.context).then(() => {
|
|
746
|
+
this._startAction.disabled = false;
|
|
747
|
+
this._startSelectionAction.disabled = this.startSelectionDisabled();
|
|
748
|
+
if (this.listener) {
|
|
749
|
+
this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.READY));
|
|
750
|
+
}
|
|
751
|
+
}).catch((error) => {
|
|
752
|
+
this._startAction.disabled = true;
|
|
753
|
+
this._startSelectionAction.disabled = true;
|
|
754
|
+
if (this.listener) {
|
|
755
|
+
this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.CLOSED));
|
|
756
|
+
}
|
|
757
|
+
console.error('Could not add module ' + error);
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
227
761
|
this._startAction.disabled = true;
|
|
228
762
|
this._startSelectionAction.disabled = true;
|
|
229
|
-
this._stopAction.disabled = false;
|
|
230
|
-
//this.timerVar = window.setInterval((e)=>this.updatePlayPosition(), 200);
|
|
231
763
|
if (this.listener) {
|
|
232
|
-
this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.
|
|
764
|
+
this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.CLOSED));
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
get arrayAudioBuffer() {
|
|
769
|
+
return this._arrayAudioBuffer;
|
|
770
|
+
}
|
|
771
|
+
start() {
|
|
772
|
+
if (!this._startAction.disabled && !this.running) {
|
|
773
|
+
this.context.resume();
|
|
774
|
+
if (this._audioBuffer) {
|
|
775
|
+
this.sourceBufferNode = this.context.createBufferSource();
|
|
776
|
+
this.sourceBufferNode.buffer = this._audioBuffer;
|
|
777
|
+
this.sourceBufferNode.connect(this.context.destination);
|
|
778
|
+
this.sourceBufferNode.onended = () => this.onended();
|
|
779
|
+
this.playStartTime = this.context.currentTime;
|
|
780
|
+
this.running = true;
|
|
781
|
+
this.sourceBufferNode.start();
|
|
782
|
+
this.playStartTime = this.context.currentTime;
|
|
783
|
+
this._startAction.disabled = true;
|
|
784
|
+
this._startSelectionAction.disabled = true;
|
|
785
|
+
this._stopAction.disabled = false;
|
|
786
|
+
//this.timerVar = window.setInterval((e)=>this.updatePlayPosition(), 200);
|
|
787
|
+
if (this.listener) {
|
|
788
|
+
this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.STARTED));
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
else if (this._arrayAudioBuffer) {
|
|
792
|
+
if (this._arrayAudioBuffer) {
|
|
793
|
+
this.sourceAudioWorkletNode = new ArrayAudioBufferSourceNode(this.context);
|
|
794
|
+
this.sourceAudioWorkletNode.onprocessorerror = (ev) => {
|
|
795
|
+
let msg = 'Unknwon error';
|
|
796
|
+
if (ev instanceof ErrorEvent) {
|
|
797
|
+
msg = ev.message;
|
|
798
|
+
}
|
|
799
|
+
console.error("Audio source worklet error: " + msg);
|
|
800
|
+
if (this.listener) {
|
|
801
|
+
// TODO
|
|
802
|
+
// this.listener.error(msg);
|
|
803
|
+
// this.listener.audioPlayerUpdate(new AudioPlayerEvent());
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
this.sourceAudioWorkletNode.arrayAudioBuffer = this._arrayAudioBuffer;
|
|
807
|
+
this.sourceAudioWorkletNode.connect(this.context.destination); // this already starts playing
|
|
808
|
+
this.sourceAudioWorkletNode.onended = () => this.onended();
|
|
809
|
+
this.playStartTime = this.context.currentTime;
|
|
810
|
+
this.running = true;
|
|
811
|
+
this.sourceAudioWorkletNode.start();
|
|
812
|
+
this.playStartTime = this.context.currentTime;
|
|
813
|
+
this._startAction.disabled = true;
|
|
814
|
+
this._startSelectionAction.disabled = true;
|
|
815
|
+
this._stopAction.disabled = false;
|
|
816
|
+
if (this.listener) {
|
|
817
|
+
this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.STARTED));
|
|
818
|
+
}
|
|
819
|
+
}
|
|
233
820
|
}
|
|
234
821
|
}
|
|
235
822
|
}
|
|
@@ -239,34 +826,79 @@ class AudioPlayer {
|
|
|
239
826
|
startSelected() {
|
|
240
827
|
if (!this._startAction.disabled && !this.running) {
|
|
241
828
|
this.context.resume();
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
this.listener
|
|
829
|
+
if (this._audioBuffer) {
|
|
830
|
+
this.sourceBufferNode = this.context.createBufferSource();
|
|
831
|
+
this.sourceBufferNode.buffer = this._audioBuffer;
|
|
832
|
+
this.sourceBufferNode.connect(this.context.destination);
|
|
833
|
+
this.sourceBufferNode.onended = () => this.onended();
|
|
834
|
+
this.playStartTime = this.context.currentTime;
|
|
835
|
+
this.running = true;
|
|
836
|
+
// unfortunately Web Audio API uses time values not frames
|
|
837
|
+
let ac = this._audioClip;
|
|
838
|
+
let offset = 0;
|
|
839
|
+
if (ac && ac.selection) {
|
|
840
|
+
let s = ac.selection;
|
|
841
|
+
let sr = ac.audioDataHolder.sampleRate;
|
|
842
|
+
offset = s.leftFrame / sr;
|
|
843
|
+
let stopPosInsecs = s.rightFrame / sr;
|
|
844
|
+
let dur = stopPosInsecs - offset;
|
|
845
|
+
// TODO check valid values
|
|
846
|
+
this.sourceBufferNode.start(0, offset, dur);
|
|
847
|
+
}
|
|
848
|
+
else {
|
|
849
|
+
this.sourceBufferNode.start();
|
|
850
|
+
}
|
|
851
|
+
this.playStartTime = this.context.currentTime - offset;
|
|
852
|
+
this._startAction.disabled = true;
|
|
853
|
+
this._startSelectionAction.disabled = true;
|
|
854
|
+
this._stopAction.disabled = false;
|
|
855
|
+
//this.timerVar = window.setInterval((e)=>this.updatePlayPosition(), 200);
|
|
856
|
+
if (this.listener) {
|
|
857
|
+
this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.STARTED));
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
else if (this._arrayAudioBuffer) {
|
|
861
|
+
if (this._arrayAudioBuffer) {
|
|
862
|
+
let aabsn = new ArrayAudioBufferSourceNode(this.context);
|
|
863
|
+
this.sourceAudioWorkletNode = aabsn;
|
|
864
|
+
aabsn.onprocessorerror = (ev) => {
|
|
865
|
+
let msg = 'Unknwon error';
|
|
866
|
+
if (ev instanceof ErrorEvent) {
|
|
867
|
+
msg = ev.message;
|
|
868
|
+
}
|
|
869
|
+
console.error("Audio source worklet error: " + msg);
|
|
870
|
+
if (this.listener) {
|
|
871
|
+
// TODO
|
|
872
|
+
// this.listener.error(msg);
|
|
873
|
+
// this.listener.audioPlayerUpdate(new AudioPlayerEvent());
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
aabsn.arrayAudioBuffer = this._arrayAudioBuffer;
|
|
877
|
+
aabsn.connect(this.context.destination); // this already starts playing
|
|
878
|
+
aabsn.onended = () => this.onended();
|
|
879
|
+
this.playStartTime = this.context.currentTime;
|
|
880
|
+
this.running = true;
|
|
881
|
+
let ac = this._audioClip;
|
|
882
|
+
let offset = 0;
|
|
883
|
+
if (ac && ac.selection) {
|
|
884
|
+
let s = ac.selection;
|
|
885
|
+
let sr = ac.audioDataHolder.sampleRate;
|
|
886
|
+
offset = s.leftFrame / sr;
|
|
887
|
+
let stopPosInsecs = s.rightFrame / sr;
|
|
888
|
+
let dur = stopPosInsecs - offset;
|
|
889
|
+
aabsn.start(0, offset, dur);
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
aabsn.start();
|
|
893
|
+
}
|
|
894
|
+
this.playStartTime = this.context.currentTime - offset;
|
|
895
|
+
this._startAction.disabled = true;
|
|
896
|
+
this._startSelectionAction.disabled = true;
|
|
897
|
+
this._stopAction.disabled = false;
|
|
898
|
+
if (this.listener) {
|
|
899
|
+
this.listener.audioPlayerUpdate(new AudioPlayerEvent(EventType.STARTED));
|
|
900
|
+
}
|
|
901
|
+
}
|
|
270
902
|
}
|
|
271
903
|
}
|
|
272
904
|
}
|
|
@@ -275,6 +907,9 @@ class AudioPlayer {
|
|
|
275
907
|
if (this.sourceBufferNode) {
|
|
276
908
|
this.sourceBufferNode.stop();
|
|
277
909
|
}
|
|
910
|
+
if (this.sourceAudioWorkletNode) {
|
|
911
|
+
this.sourceAudioWorkletNode.stop();
|
|
912
|
+
}
|
|
278
913
|
if (this.timerVar !== null) {
|
|
279
914
|
window.clearInterval(this.timerVar);
|
|
280
915
|
}
|
|
@@ -288,7 +923,7 @@ class AudioPlayer {
|
|
|
288
923
|
if (this.timerVar != null) {
|
|
289
924
|
window.clearInterval(this.timerVar);
|
|
290
925
|
}
|
|
291
|
-
this._startAction.disabled = !(this.audioBuffer);
|
|
926
|
+
this._startAction.disabled = !(this.audioBuffer || this.arrayAudioBuffer);
|
|
292
927
|
this._startSelectionAction.disabled = this.startSelectionDisabled();
|
|
293
928
|
this._stopAction.disabled = true;
|
|
294
929
|
this.running = false;
|
|
@@ -305,10 +940,17 @@ class AudioPlayer {
|
|
|
305
940
|
}
|
|
306
941
|
get playPositionFrames() {
|
|
307
942
|
let ppFrs = null;
|
|
943
|
+
let sr = null;
|
|
308
944
|
if (this._audioBuffer) {
|
|
945
|
+
sr = this._audioBuffer.sampleRate;
|
|
946
|
+
}
|
|
947
|
+
else if (this._arrayAudioBuffer) {
|
|
948
|
+
sr = this._arrayAudioBuffer.sampleRate;
|
|
949
|
+
}
|
|
950
|
+
if (sr) {
|
|
309
951
|
let ppTime = this.playPositionTime;
|
|
310
952
|
if (ppTime !== null) {
|
|
311
|
-
ppFrs =
|
|
953
|
+
ppFrs = sr * ppTime;
|
|
312
954
|
}
|
|
313
955
|
}
|
|
314
956
|
return ppFrs;
|
|
@@ -522,6 +1164,107 @@ class ProjectUtil {
|
|
|
522
1164
|
}
|
|
523
1165
|
ProjectUtil.DEFAULT_AUDIO_CHANNEL_COUNT = 2;
|
|
524
1166
|
|
|
1167
|
+
class ArrayAudioBuffer {
|
|
1168
|
+
constructor(_channelCount, _sampleRate, _data) {
|
|
1169
|
+
this._channelCount = _channelCount;
|
|
1170
|
+
this._sampleRate = _sampleRate;
|
|
1171
|
+
this._data = _data;
|
|
1172
|
+
this._chunkCount = 0;
|
|
1173
|
+
this._frameLen = 0;
|
|
1174
|
+
if (this._data.length > 0) {
|
|
1175
|
+
let ch0Data = this.data[0];
|
|
1176
|
+
for (let ch0Chk of ch0Data) {
|
|
1177
|
+
this._chunkCount++;
|
|
1178
|
+
this._frameLen += ch0Chk.length;
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
static fromAudioBuffer(audioBuffer, chunkFrameSize = 8192) {
|
|
1183
|
+
let aab;
|
|
1184
|
+
let chs = audioBuffer.numberOfChannels;
|
|
1185
|
+
let frameLength = audioBuffer.length;
|
|
1186
|
+
//let chunksSize=Math.ceil(frameLength/chunkFrameSize);
|
|
1187
|
+
let framePos = 0;
|
|
1188
|
+
let data = new Array(chs);
|
|
1189
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
1190
|
+
data[ch] = new Array();
|
|
1191
|
+
}
|
|
1192
|
+
let toCopy = frameLength - framePos;
|
|
1193
|
+
while (toCopy > 0) {
|
|
1194
|
+
let toCopyChunk = chunkFrameSize;
|
|
1195
|
+
if (toCopyChunk > toCopy) {
|
|
1196
|
+
// last chunk, the rest
|
|
1197
|
+
toCopyChunk = toCopy;
|
|
1198
|
+
}
|
|
1199
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
1200
|
+
data[ch].push(audioBuffer.getChannelData(ch).slice(framePos, framePos + toCopyChunk));
|
|
1201
|
+
}
|
|
1202
|
+
framePos += toCopyChunk;
|
|
1203
|
+
toCopy -= toCopyChunk;
|
|
1204
|
+
}
|
|
1205
|
+
aab = new ArrayAudioBuffer(chs, audioBuffer.sampleRate, data);
|
|
1206
|
+
return aab;
|
|
1207
|
+
}
|
|
1208
|
+
get channelCount() {
|
|
1209
|
+
return this._channelCount;
|
|
1210
|
+
}
|
|
1211
|
+
frames(framePos, frameLen, bufs) {
|
|
1212
|
+
let ccFramePos = 0;
|
|
1213
|
+
let trgFramePos = framePos;
|
|
1214
|
+
let ch0Data = this.data[0];
|
|
1215
|
+
let cPos = 0;
|
|
1216
|
+
let filled = 0;
|
|
1217
|
+
let ci = 0;
|
|
1218
|
+
while (filled < frameLen && ci < this._chunkCount) {
|
|
1219
|
+
// Current chunk
|
|
1220
|
+
let cc0 = ch0Data[ci];
|
|
1221
|
+
let ccLen = cc0.length;
|
|
1222
|
+
let ccFrameEndPos = ccFramePos + ccLen;
|
|
1223
|
+
if (trgFramePos >= ccFramePos && trgFramePos < ccFrameEndPos) {
|
|
1224
|
+
let toCp = frameLen - filled;
|
|
1225
|
+
cPos = trgFramePos - ccFramePos;
|
|
1226
|
+
if (cPos + toCp > ccLen) {
|
|
1227
|
+
toCp = ccLen - cPos;
|
|
1228
|
+
}
|
|
1229
|
+
for (let ch = 0; ch < bufs.length; ch++) {
|
|
1230
|
+
let cc = this.data[ch][ci];
|
|
1231
|
+
for (let i = 0; i < toCp; i++) {
|
|
1232
|
+
bufs[ch][filled + i] = cc[cPos + i];
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
filled += toCp;
|
|
1236
|
+
trgFramePos += toCp;
|
|
1237
|
+
cPos += toCp;
|
|
1238
|
+
ccFramePos += toCp;
|
|
1239
|
+
if (cPos >= ccLen) {
|
|
1240
|
+
ccFramePos = ccFrameEndPos;
|
|
1241
|
+
cPos = 0;
|
|
1242
|
+
ci++;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
else {
|
|
1246
|
+
// next chunk
|
|
1247
|
+
ccFramePos = ccFrameEndPos;
|
|
1248
|
+
cPos = 0;
|
|
1249
|
+
ci++;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
return filled;
|
|
1253
|
+
}
|
|
1254
|
+
get sampleRate() {
|
|
1255
|
+
return this._sampleRate;
|
|
1256
|
+
}
|
|
1257
|
+
get frameLen() {
|
|
1258
|
+
return this._frameLen;
|
|
1259
|
+
}
|
|
1260
|
+
get chunkCount() {
|
|
1261
|
+
return this._chunkCount;
|
|
1262
|
+
}
|
|
1263
|
+
get data() {
|
|
1264
|
+
return this._data;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
|
|
525
1268
|
const CHROME_ACTIVATE_ECHO_CANCELLATION_WITH_AGC = false;
|
|
526
1269
|
const DEBUG_TRACE_LEVEL = 0;
|
|
527
1270
|
const ENABLE_AUDIO_WORKLET = true;
|
|
@@ -1092,6 +1835,10 @@ class AudioCapture {
|
|
|
1092
1835
|
}
|
|
1093
1836
|
return ab;
|
|
1094
1837
|
}
|
|
1838
|
+
audioBufferArray() {
|
|
1839
|
+
let aba = new ArrayAudioBuffer(this.channelCount, this.currentSampleRate, this.data);
|
|
1840
|
+
return aba;
|
|
1841
|
+
}
|
|
1095
1842
|
}
|
|
1096
1843
|
AudioCapture.BUFFER_SIZE = 8192;
|
|
1097
1844
|
|
|
@@ -1471,21 +2218,28 @@ class RecordingFileDescriptorImpl {
|
|
|
1471
2218
|
constructor() { }
|
|
1472
2219
|
}
|
|
1473
2220
|
class RecordingFile {
|
|
1474
|
-
constructor(uuid, sessionId,
|
|
2221
|
+
constructor(uuid, sessionId, audioDataHolder) {
|
|
1475
2222
|
this.recordingFileId = null;
|
|
1476
2223
|
this.uuid = null;
|
|
2224
|
+
this.serverPersisted = false;
|
|
2225
|
+
this.keepAudioDataCache = false;
|
|
1477
2226
|
this.date = null;
|
|
1478
2227
|
this._dateAsDateObj = null;
|
|
1479
2228
|
this.startedDate = null;
|
|
1480
2229
|
this._startedAsDateObj = null;
|
|
1481
|
-
this.
|
|
2230
|
+
this.audioDataHolder = null;
|
|
1482
2231
|
this.session = null;
|
|
1483
2232
|
this.frames = null;
|
|
2233
|
+
this.timeLength = null;
|
|
1484
2234
|
this.editSampleRate = null;
|
|
1485
2235
|
this.editStartFrame = null;
|
|
1486
2236
|
this.editEndFrame = null;
|
|
1487
2237
|
this.session = sessionId;
|
|
1488
|
-
this.
|
|
2238
|
+
this.audioDataHolder = audioDataHolder;
|
|
2239
|
+
if (audioDataHolder) {
|
|
2240
|
+
this.frames = audioDataHolder.frameLen;
|
|
2241
|
+
this.timeLength = audioDataHolder.duration;
|
|
2242
|
+
}
|
|
1489
2243
|
this.uuid = uuid;
|
|
1490
2244
|
}
|
|
1491
2245
|
filenameString() {
|
|
@@ -1497,14 +2251,27 @@ class RecordingFile {
|
|
|
1497
2251
|
fns += this.uuid;
|
|
1498
2252
|
return fns;
|
|
1499
2253
|
}
|
|
2254
|
+
equals(otherRecordingFile) {
|
|
2255
|
+
if (otherRecordingFile !== null) {
|
|
2256
|
+
if (otherRecordingFile === this) {
|
|
2257
|
+
return true;
|
|
2258
|
+
}
|
|
2259
|
+
if (otherRecordingFile.uuid === this.uuid) {
|
|
2260
|
+
return true;
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
return false;
|
|
2264
|
+
}
|
|
2265
|
+
toString() {
|
|
2266
|
+
return 'Recording file: UUID: ' + this.uuid + ', session: ' + this.session;
|
|
2267
|
+
}
|
|
1500
2268
|
}
|
|
1501
2269
|
class SprRecordingFile extends RecordingFile {
|
|
1502
|
-
constructor(sessionId, itemcode, version,
|
|
1503
|
-
super(UUID.generate(), sessionId,
|
|
2270
|
+
constructor(sessionId, itemcode, version, audioDataHolder) {
|
|
2271
|
+
super(UUID.generate(), sessionId, audioDataHolder);
|
|
1504
2272
|
this.session = sessionId;
|
|
1505
2273
|
this.itemCode = itemcode;
|
|
1506
2274
|
this.version = version;
|
|
1507
|
-
this.audioBuffer = audioBuffer;
|
|
1508
2275
|
}
|
|
1509
2276
|
filenameString() {
|
|
1510
2277
|
let fns = '';
|
|
@@ -1519,6 +2286,31 @@ class SprRecordingFile extends RecordingFile {
|
|
|
1519
2286
|
fns += this.uuid;
|
|
1520
2287
|
return fns;
|
|
1521
2288
|
}
|
|
2289
|
+
toString() {
|
|
2290
|
+
return 'Recording file: UUID: ' + this.uuid + ', session: ' + this.session + ', itemcode: ' + this.itemCode + ', version: ' + this.version + ', UUID: ' + this.uuid;
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
class RecordingFileUtils {
|
|
2294
|
+
static setAudioData(rf, audioDataHolder) {
|
|
2295
|
+
rf.audioDataHolder = audioDataHolder;
|
|
2296
|
+
if (audioDataHolder) {
|
|
2297
|
+
rf.frames = audioDataHolder.frameLen;
|
|
2298
|
+
rf.timeLength = audioDataHolder.duration;
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
static sampleCount(rf) {
|
|
2302
|
+
if (rf.audioDataHolder) {
|
|
2303
|
+
return rf.audioDataHolder.sampleCounts();
|
|
2304
|
+
}
|
|
2305
|
+
else {
|
|
2306
|
+
return 0;
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
static expireAudioData(rf) {
|
|
2310
|
+
let rv = rf.audioDataHolder;
|
|
2311
|
+
rf.audioDataHolder = null;
|
|
2312
|
+
return rv;
|
|
2313
|
+
}
|
|
1522
2314
|
}
|
|
1523
2315
|
|
|
1524
2316
|
// state of an upload
|
|
@@ -1569,7 +2361,8 @@ class UploaderStatusChangeEvent {
|
|
|
1569
2361
|
}
|
|
1570
2362
|
}
|
|
1571
2363
|
class Upload {
|
|
1572
|
-
constructor(blob, url) {
|
|
2364
|
+
constructor(blob, url, serverPersistable = null) {
|
|
2365
|
+
this.serverPersistable = serverPersistable;
|
|
1573
2366
|
this.toString = () => {
|
|
1574
2367
|
let s = `Upload: Status: ${this.status}, URL: ${this._url}`;
|
|
1575
2368
|
if (this._data instanceof Blob) {
|
|
@@ -1590,6 +2383,17 @@ class Upload {
|
|
|
1590
2383
|
get data() {
|
|
1591
2384
|
return this._data;
|
|
1592
2385
|
}
|
|
2386
|
+
done() {
|
|
2387
|
+
this.status = UploadStatus$1.DONE;
|
|
2388
|
+
//console.debug("Single upload done.");
|
|
2389
|
+
if (this.serverPersistable) {
|
|
2390
|
+
this.serverPersistable.serverPersisted = true;
|
|
2391
|
+
//console.debug("Single upload set server persisted: "+this.serverPersistable);
|
|
2392
|
+
}
|
|
2393
|
+
else {
|
|
2394
|
+
//console.debug("Server persistable not set.");
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
1593
2397
|
}
|
|
1594
2398
|
class Uploader {
|
|
1595
2399
|
constructor(http, withCredentials = false) {
|
|
@@ -1628,7 +2432,7 @@ class Uploader {
|
|
|
1628
2432
|
return si;
|
|
1629
2433
|
}
|
|
1630
2434
|
uploadDone(ul) {
|
|
1631
|
-
ul.
|
|
2435
|
+
ul.done();
|
|
1632
2436
|
// remove upload from queue
|
|
1633
2437
|
for (let i = 0; i < this.que.length; i++) {
|
|
1634
2438
|
if (this.que[i] === ul) {
|
|
@@ -2059,16 +2863,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
2059
2863
|
}], ctorParameters: function () { return []; } });
|
|
2060
2864
|
|
|
2061
2865
|
class AudioClip {
|
|
2062
|
-
constructor(
|
|
2866
|
+
constructor(_audioDataHolder) {
|
|
2867
|
+
this._audioDataHolder = _audioDataHolder;
|
|
2063
2868
|
this._selection = null;
|
|
2064
2869
|
this._levelInfos = null;
|
|
2065
2870
|
this.selectionObservers = new Array();
|
|
2066
|
-
this._buffer = buffer;
|
|
2067
2871
|
}
|
|
2068
|
-
get
|
|
2069
|
-
return this.
|
|
2872
|
+
get audioDataHolder() {
|
|
2873
|
+
return this._audioDataHolder;
|
|
2070
2874
|
}
|
|
2071
|
-
;
|
|
2072
2875
|
get selection() {
|
|
2073
2876
|
return this._selection;
|
|
2074
2877
|
}
|
|
@@ -2171,19 +2974,31 @@ class ViewSelection {
|
|
|
2171
2974
|
class BasicAudioCanvasLayerComponent extends CanvasLayerComponent {
|
|
2172
2975
|
constructor() {
|
|
2173
2976
|
super(...arguments);
|
|
2174
|
-
|
|
2977
|
+
//protected _audioData: AudioBuffer|null=null;
|
|
2978
|
+
//protected _arrayAudioData: ArrayAudioBuffer|null=null;
|
|
2979
|
+
this._audioDataHolder = null;
|
|
2175
2980
|
this._bgColor = 'white';
|
|
2176
2981
|
this._selectColor = 'rgba(0%,0%,100%,25%)';
|
|
2177
2982
|
}
|
|
2983
|
+
frameLength() {
|
|
2984
|
+
let frameLength = null;
|
|
2985
|
+
// if (this._audioData && this._audioData.numberOfChannels > 0) {
|
|
2986
|
+
// let ch0 = this._audioData.getChannelData(0);
|
|
2987
|
+
// frameLength = ch0.length;
|
|
2988
|
+
//
|
|
2989
|
+
// }else if(this._arrayAudioData){
|
|
2990
|
+
// frameLength=this._arrayAudioData.frameLen;
|
|
2991
|
+
// }
|
|
2992
|
+
return frameLength;
|
|
2993
|
+
}
|
|
2178
2994
|
/**
|
|
2179
2995
|
* Returns pixel position depending on current zoom setting.
|
|
2180
2996
|
* @param framePos audio frame (sample) position
|
|
2181
2997
|
*/
|
|
2182
2998
|
frameToXPixelPosition(framePos) {
|
|
2183
2999
|
let pixelPos = null;
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
let frameLength = ch0.length;
|
|
3000
|
+
let frameLength = this._audioDataHolder?.frameLen;
|
|
3001
|
+
if (frameLength !== undefined) {
|
|
2187
3002
|
let vw;
|
|
2188
3003
|
if (this.bounds) {
|
|
2189
3004
|
vw = this.bounds.dimension.width;
|
|
@@ -2213,9 +3028,8 @@ class BasicAudioCanvasLayerComponent extends CanvasLayerComponent {
|
|
|
2213
3028
|
}
|
|
2214
3029
|
viewPortXPixelToFramePosition(xViewPortPixelPos) {
|
|
2215
3030
|
let vpXramePos = null;
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
let frameLength = ch0.length;
|
|
3031
|
+
let frameLength = this._audioDataHolder?.frameLen;
|
|
3032
|
+
if (frameLength !== undefined) {
|
|
2219
3033
|
let vw;
|
|
2220
3034
|
if (this.bounds) {
|
|
2221
3035
|
vw = this.bounds.dimension.width;
|
|
@@ -2392,8 +3206,8 @@ class AudioCanvasLayerComponent extends BasicAudioCanvasLayerComponent {
|
|
|
2392
3206
|
if (viewSel) {
|
|
2393
3207
|
let frameStart = this.viewPortXPixelToFramePosition(viewSel.startX);
|
|
2394
3208
|
let frameEnd = this.viewPortXPixelToFramePosition(viewSel.endX);
|
|
2395
|
-
if (this.
|
|
2396
|
-
ns = new Selection(this.
|
|
3209
|
+
if (this._audioDataHolder && frameStart != null && frameEnd != null) {
|
|
3210
|
+
ns = new Selection(this._audioDataHolder.sampleRate, frameStart, frameEnd);
|
|
2397
3211
|
}
|
|
2398
3212
|
}
|
|
2399
3213
|
this.selectingEventEmitter.emit(ns);
|
|
@@ -2403,8 +3217,8 @@ class AudioCanvasLayerComponent extends BasicAudioCanvasLayerComponent {
|
|
|
2403
3217
|
if (viewSel) {
|
|
2404
3218
|
let frameStart = this.viewPortXPixelToFramePosition(viewSel.startX);
|
|
2405
3219
|
let frameEnd = this.viewPortXPixelToFramePosition(viewSel.endX);
|
|
2406
|
-
if (this.
|
|
2407
|
-
ns = new Selection(this.
|
|
3220
|
+
if (this._audioDataHolder && frameStart != null && frameEnd != null) {
|
|
3221
|
+
ns = new Selection(this._audioDataHolder.sampleRate, frameStart, frameEnd);
|
|
2408
3222
|
}
|
|
2409
3223
|
}
|
|
2410
3224
|
this.selectedEventEmitter.emit(ns);
|
|
@@ -2485,7 +3299,7 @@ class AudioCanvasLayerComponent extends BasicAudioCanvasLayerComponent {
|
|
|
2485
3299
|
g.lineTo(xViewPortPixelpos, h);
|
|
2486
3300
|
g.closePath();
|
|
2487
3301
|
g.stroke();
|
|
2488
|
-
if (this.
|
|
3302
|
+
if (this._audioDataHolder) {
|
|
2489
3303
|
g.font = '14px sans-serif';
|
|
2490
3304
|
g.fillStyle = 'yellow';
|
|
2491
3305
|
g.fillText(framePos.toString(), xViewPortPixelpos + 2, 50);
|
|
@@ -2497,6 +3311,7 @@ class AudioCanvasLayerComponent extends BasicAudioCanvasLayerComponent {
|
|
|
2497
3311
|
}
|
|
2498
3312
|
}
|
|
2499
3313
|
}
|
|
3314
|
+
AudioCanvasLayerComponent.ENABLE_STREAMING_NUMBER_OF_SAMPLES_THRESHOLD = 10 * 60 * 48000; // Use streaming/chunking if audio clip has more than this number of samples
|
|
2500
3315
|
AudioCanvasLayerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AudioCanvasLayerComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
2501
3316
|
AudioCanvasLayerComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.11", type: AudioCanvasLayerComponent, inputs: { pointerPosition: "pointerPosition", selecting: "selecting", selection: "selection" }, outputs: { pointerPositionEventEmitter: "pointerPositionEventEmitter", selectingEventEmitter: "selectingEventEmitter", selectedEventEmitter: "selectedEventEmitter" }, host: { listeners: { "document:mouseup": "onMouseup($event)" } }, viewQueries: [{ propertyName: "bgCanvasRef", first: true, predicate: ["bg"], descendants: true, static: true }, { propertyName: "cursorCanvasRef", first: true, predicate: ["cursor"], descendants: true, static: true }], usesInheritance: true, ngImport: i0 });
|
|
2502
3317
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AudioCanvasLayerComponent, decorators: [{
|
|
@@ -2531,7 +3346,7 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2531
3346
|
this._playFramePosition = null;
|
|
2532
3347
|
this.worker = null;
|
|
2533
3348
|
this.workerURL = WorkerHelper.buildWorkerBlobURL(this.workerFunction);
|
|
2534
|
-
this.
|
|
3349
|
+
this._audioDataHolder = null;
|
|
2535
3350
|
this._bgColor = 'black';
|
|
2536
3351
|
this._selectColor = 'rgba(255,255,0,0.8)';
|
|
2537
3352
|
}
|
|
@@ -2584,25 +3399,26 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2584
3399
|
*/
|
|
2585
3400
|
workerFunction() {
|
|
2586
3401
|
addEventListener('message', ({ data }) => {
|
|
2587
|
-
let audioData = data.audioData;
|
|
2588
|
-
let
|
|
2589
|
-
let
|
|
2590
|
-
let
|
|
2591
|
-
let vw = data.vw;
|
|
2592
|
-
let chs = data.chs;
|
|
2593
|
-
let
|
|
3402
|
+
let audioData = data.audioData; // audio data part required to render view port
|
|
3403
|
+
let auOffset = data.audioDataOffset;
|
|
3404
|
+
let l = data.l; // left pixel position of view port
|
|
3405
|
+
let w = data.w; // width of viewport
|
|
3406
|
+
let vw = data.vw; // total width of (virtual) audio view (not viewport width)
|
|
3407
|
+
let chs = data.chs; // number of channels
|
|
3408
|
+
let dataFrameLength = data.audioDataFrameLength; // frame length of audio data part required for view port
|
|
3409
|
+
let frameLength = data.frameLength; // total frame length (of audio clip)
|
|
3410
|
+
//console.debug("W: left: "+l+", w:"+w+", vw: "+vw+", chs: "+chs+", frameLength: "+frameLength);
|
|
2594
3411
|
let psMinMax = new Float32Array(0);
|
|
2595
|
-
if (audioData && w >= 0 && vw > 0) {
|
|
3412
|
+
if (audioData && audioData.length > 0 && w >= 0 && vw > 0) {
|
|
2596
3413
|
let framesPerPixel = frameLength / vw;
|
|
2597
|
-
let y = 0;
|
|
2598
3414
|
let pointsLen = w * chs;
|
|
2599
3415
|
// one for min one for max
|
|
2600
3416
|
let arrLen = pointsLen * 2;
|
|
2601
3417
|
psMinMax = new Float32Array(arrLen);
|
|
2602
3418
|
let chFramePos = 0;
|
|
3419
|
+
let chFrameLength = audioData.length / chs;
|
|
2603
3420
|
for (let ch = 0; ch < chs; ch++) {
|
|
2604
|
-
|
|
2605
|
-
chFramePos = ch * frameLength;
|
|
3421
|
+
chFramePos = ch * chFrameLength;
|
|
2606
3422
|
for (let pii = 0; pii < w; pii++) {
|
|
2607
3423
|
let virtPii = l + pii;
|
|
2608
3424
|
let pMin = Infinity;
|
|
@@ -2612,24 +3428,28 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2612
3428
|
for (let ai = 0; ai < framesPerPixel; ai++) {
|
|
2613
3429
|
let framePos = pixelFramePos + ai;
|
|
2614
3430
|
let a = 0;
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
3431
|
+
let bufPos = framePos - auOffset;
|
|
3432
|
+
//let bufPos=framePos;
|
|
3433
|
+
if (bufPos >= 0 && bufPos < audioData.length) {
|
|
3434
|
+
a = audioData[bufPos];
|
|
3435
|
+
//console.debug("W: ch: "+ch+", pixelFramePos: "+pixelFramePos+", framePos: "+framePos+", auOffset: "+auOffset+", bufPos: "+bufPos+", audioData.length: "+audioData.length+", a: "+a);
|
|
3436
|
+
if (a < pMin) {
|
|
3437
|
+
pMin = a;
|
|
3438
|
+
}
|
|
3439
|
+
if (a > pMax) {
|
|
3440
|
+
pMax = a;
|
|
3441
|
+
}
|
|
2623
3442
|
}
|
|
2624
3443
|
}
|
|
2625
3444
|
let psMinPos = ch * w + pii;
|
|
2626
3445
|
psMinMax[psMinPos] = pMin;
|
|
2627
3446
|
let psMaxPos = pointsLen + psMinPos;
|
|
2628
3447
|
psMinMax[psMaxPos] = pMax;
|
|
3448
|
+
//console.debug("psMinMax["+psMinPos+"]="+pMin+",psMinMax["+psMaxPos+"]="+pMax);
|
|
2629
3449
|
}
|
|
2630
3450
|
}
|
|
2631
3451
|
}
|
|
2632
|
-
postMessage({ psMinMax: psMinMax, l: data.l,
|
|
3452
|
+
postMessage({ psMinMax: psMinMax, l: data.l, w: data.w, chs: data.chs, eod: data.eod }, [psMinMax.buffer]);
|
|
2633
3453
|
});
|
|
2634
3454
|
}
|
|
2635
3455
|
startDraw(clear = true) {
|
|
@@ -2657,41 +3477,143 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2657
3477
|
if (this.bounds && this.bounds.dimension) {
|
|
2658
3478
|
let w = Math.round(this.bounds.dimension.width);
|
|
2659
3479
|
let h = Math.round(this.bounds.dimension.height);
|
|
2660
|
-
if (this.
|
|
3480
|
+
if (this._audioDataHolder && w > 0 && h > 0) {
|
|
2661
3481
|
//this.wo = new Worker('./audiosignal.worker.js',{type: 'module'});
|
|
2662
3482
|
this.worker = new Worker(this.workerURL);
|
|
2663
3483
|
//this.wo = new Worker('worker/audiosignal.worker.ts');
|
|
2664
3484
|
//let Worker = require('worker!../../../workers/uploader/main');
|
|
2665
|
-
let chs = this.
|
|
2666
|
-
let
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
let
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
//let
|
|
3485
|
+
let chs = this._audioDataHolder.numberOfChannels;
|
|
3486
|
+
let leftPos = Math.round(this.bounds.position.left);
|
|
3487
|
+
let renderPos = leftPos;
|
|
3488
|
+
let vw = Math.round(this.virtualDimension.width);
|
|
3489
|
+
let frameLength = this._audioDataHolder.frameLen;
|
|
3490
|
+
let framesPerPixel = Math.ceil(frameLength / vw);
|
|
3491
|
+
let audioBuffer = this._audioDataHolder.buffer;
|
|
3492
|
+
//let arrayAudioBuffer=this._audioDataHolder.arrayBuffer;
|
|
3493
|
+
let arrAbBuf;
|
|
3494
|
+
//let ais:ArrayAudioBufferInputStream|null=null;
|
|
3495
|
+
//let aisBuf:Float32Array[]|null=null;
|
|
3496
|
+
let psMinMax = null;
|
|
2675
3497
|
if (this.worker) {
|
|
2676
3498
|
this.worker.onmessage = (me) => {
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
3499
|
+
if (me.data.eod === true) {
|
|
3500
|
+
let psMinMaxTmp;
|
|
3501
|
+
if (psMinMax) {
|
|
3502
|
+
psMinMaxTmp = psMinMax;
|
|
3503
|
+
}
|
|
3504
|
+
else {
|
|
3505
|
+
psMinMaxTmp = me.data.psMinMax;
|
|
3506
|
+
}
|
|
3507
|
+
this.drawRendered(leftPos, w, h, chs, psMinMaxTmp);
|
|
3508
|
+
if (this.worker) {
|
|
3509
|
+
this.worker.terminate();
|
|
3510
|
+
}
|
|
3511
|
+
this.worker = null;
|
|
3512
|
+
}
|
|
3513
|
+
else if (this._audioDataHolder && arrAbBuf) {
|
|
3514
|
+
let rw = me.data.w;
|
|
3515
|
+
let rPointsLen = chs * rw;
|
|
3516
|
+
let pointsLen = chs * w;
|
|
3517
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
3518
|
+
if (psMinMax) {
|
|
3519
|
+
let rBasePos = ch * rw;
|
|
3520
|
+
let basePos = ch * w;
|
|
3521
|
+
let rPosMin = rBasePos;
|
|
3522
|
+
let rPosMax = rPointsLen + rPosMin;
|
|
3523
|
+
let posMin = basePos + (renderPos - leftPos);
|
|
3524
|
+
let posMax = pointsLen + posMin;
|
|
3525
|
+
psMinMax[posMin] = me.data.psMinMax[rPosMin];
|
|
3526
|
+
//console.debug('Min: ('+pos+'): '+me.data.psMinMax[0]);
|
|
3527
|
+
psMinMax[posMax] = me.data.psMinMax[rPosMax];
|
|
3528
|
+
// console.debug('Max: ('+(pointsLen+pos)+'): '+me.data.psMinMax[1]);
|
|
3529
|
+
//console.debug("psMinMax["+posMin+"]="+me.data.psMinMax[rPosMin]+" (rPosMin="+rPosMin+"),psMinMax["+posMax+"]="+me.data.psMinMax[rPosMax]);
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
let eod = false;
|
|
3533
|
+
renderPos++;
|
|
3534
|
+
let ad;
|
|
3535
|
+
let leftFramePos = Math.floor(frameLength * renderPos / vw);
|
|
3536
|
+
if (renderPos < leftPos + w) {
|
|
3537
|
+
let read = this._audioDataHolder.frames(leftFramePos, framesPerPixel, arrAbBuf);
|
|
3538
|
+
//console.debug("First read frame: "+arrAbBuf[0][0]);
|
|
3539
|
+
ad = new Float32Array(chs * framesPerPixel);
|
|
3540
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
3541
|
+
ad.set(arrAbBuf[ch], ch * framesPerPixel);
|
|
3542
|
+
}
|
|
3543
|
+
eod = (read <= 0);
|
|
3544
|
+
}
|
|
3545
|
+
else {
|
|
3546
|
+
ad = new Float32Array();
|
|
3547
|
+
eod = true;
|
|
3548
|
+
}
|
|
3549
|
+
let adBuf = ad.buffer;
|
|
3550
|
+
if (this.worker) {
|
|
3551
|
+
this.worker.postMessage({
|
|
3552
|
+
l: renderPos,
|
|
3553
|
+
w: me.data.w,
|
|
3554
|
+
h: h,
|
|
3555
|
+
vw: vw,
|
|
3556
|
+
chs: chs,
|
|
3557
|
+
frameLength: frameLength,
|
|
3558
|
+
audioData: ad,
|
|
3559
|
+
audioDataOffset: leftFramePos,
|
|
3560
|
+
eod: eod
|
|
3561
|
+
}, [adBuf]);
|
|
3562
|
+
}
|
|
2681
3563
|
}
|
|
2682
|
-
this.worker = null;
|
|
2683
3564
|
};
|
|
2684
3565
|
}
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
3566
|
+
if (audioBuffer && audioBuffer.length * audioBuffer.numberOfChannels < AudioCanvasLayerComponent.ENABLE_STREAMING_NUMBER_OF_SAMPLES_THRESHOLD) {
|
|
3567
|
+
// Render whole clip at once
|
|
3568
|
+
arrAbBuf = null;
|
|
3569
|
+
psMinMax = null;
|
|
3570
|
+
let ad = new Float32Array(chs * frameLength);
|
|
3571
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
3572
|
+
ad.set(audioBuffer.getChannelData(ch), ch * frameLength);
|
|
3573
|
+
}
|
|
3574
|
+
this.worker.postMessage({
|
|
3575
|
+
l: leftPos,
|
|
3576
|
+
w: w,
|
|
3577
|
+
vw: vw,
|
|
3578
|
+
chs: chs,
|
|
3579
|
+
frameLength: frameLength,
|
|
3580
|
+
audioData: ad,
|
|
3581
|
+
audioDataOffset: 0,
|
|
3582
|
+
eod: true
|
|
3583
|
+
}, [ad.buffer]);
|
|
3584
|
+
}
|
|
3585
|
+
else {
|
|
3586
|
+
// Render pixel by pixel
|
|
3587
|
+
if (w > 0) {
|
|
3588
|
+
if (framesPerPixel > 0) {
|
|
3589
|
+
let rw = 1;
|
|
3590
|
+
//ais = new ArrayAudioBufferInputStream(arrayAudioBuffer);
|
|
3591
|
+
arrAbBuf = new Array(chs);
|
|
3592
|
+
psMinMax = new Float32Array(chs * w * 2);
|
|
3593
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
3594
|
+
arrAbBuf[ch] = new Float32Array(framesPerPixel);
|
|
3595
|
+
}
|
|
3596
|
+
let leftFramePos = Math.floor(frameLength * renderPos / vw);
|
|
3597
|
+
let auOffset = leftFramePos; // should always be 0
|
|
3598
|
+
//let read=arrayAudioBuffer.frames(leftFramePos,framesPerPixel,arrAbBuf);
|
|
3599
|
+
let read = this._audioDataHolder.frames(leftFramePos, framesPerPixel, arrAbBuf);
|
|
3600
|
+
let ad = new Float32Array(chs * framesPerPixel);
|
|
3601
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
3602
|
+
ad.set(arrAbBuf[ch], ch * framesPerPixel);
|
|
3603
|
+
}
|
|
3604
|
+
this.worker.postMessage({
|
|
3605
|
+
l: renderPos,
|
|
3606
|
+
w: rw,
|
|
3607
|
+
vw: vw,
|
|
3608
|
+
chs: chs,
|
|
3609
|
+
frameLength: frameLength,
|
|
3610
|
+
audioData: ad,
|
|
3611
|
+
audioDataOffset: auOffset,
|
|
3612
|
+
eod: (read <= 0)
|
|
3613
|
+
}, [ad.buffer]);
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
3616
|
+
}
|
|
2695
3617
|
}
|
|
2696
3618
|
else {
|
|
2697
3619
|
let g = this.signalCanvas.getContext("2d");
|
|
@@ -2701,42 +3623,42 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2701
3623
|
}
|
|
2702
3624
|
}
|
|
2703
3625
|
}
|
|
2704
|
-
drawRendered(
|
|
3626
|
+
drawRendered(left, w, h, chs, psMinMax) {
|
|
2705
3627
|
this.drawBg();
|
|
2706
|
-
this.signalCanvas.style.left =
|
|
2707
|
-
this.signalCanvas.width =
|
|
2708
|
-
this.signalCanvas.height =
|
|
3628
|
+
this.signalCanvas.style.left = left.toString() + 'px';
|
|
3629
|
+
this.signalCanvas.width = w;
|
|
3630
|
+
this.signalCanvas.height = h;
|
|
2709
3631
|
let g = this.signalCanvas.getContext("2d");
|
|
2710
3632
|
if (g) {
|
|
2711
|
-
g.clearRect(0, 0,
|
|
3633
|
+
g.clearRect(0, 0, w, h);
|
|
2712
3634
|
//g.fillStyle = "black";
|
|
2713
3635
|
//g.fillRect(0, 0, me.data.w, me.data.h);
|
|
2714
|
-
let pointsLen =
|
|
3636
|
+
let pointsLen = w * chs;
|
|
2715
3637
|
// one for min one for max
|
|
2716
3638
|
let arrLen = pointsLen * 2;
|
|
2717
|
-
if (this.
|
|
3639
|
+
if (this._audioDataHolder) {
|
|
2718
3640
|
let std = Date.now();
|
|
2719
|
-
let chH =
|
|
3641
|
+
let chH = h / chs;
|
|
2720
3642
|
let y = 0;
|
|
2721
|
-
for (let ch = 0; ch <
|
|
3643
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
2722
3644
|
let x = 0;
|
|
2723
|
-
let psMinPos = ch *
|
|
3645
|
+
let psMinPos = ch * w;
|
|
2724
3646
|
let psMaxPos = pointsLen + psMinPos;
|
|
2725
3647
|
g.fillStyle = 'green';
|
|
2726
3648
|
g.strokeStyle = 'green';
|
|
2727
3649
|
// draw audio signal as single polygon
|
|
2728
3650
|
g.beginPath();
|
|
2729
|
-
g.moveTo(0, y + (chH / 2) +
|
|
2730
|
-
for (let pii = 0; pii <
|
|
2731
|
-
let psMax =
|
|
3651
|
+
g.moveTo(0, y + (chH / 2) + psMinMax[psMaxPos] * chH / 2);
|
|
3652
|
+
for (let pii = 0; pii < w; pii++) {
|
|
3653
|
+
let psMax = psMinMax[psMaxPos + pii];
|
|
2732
3654
|
let pv = psMax * chH / 2;
|
|
2733
3655
|
let yd = y + (chH / 2) - pv;
|
|
2734
3656
|
//console.log("LineTo: : "+pii+" "+yd)
|
|
2735
3657
|
g.lineTo(pii, yd);
|
|
2736
3658
|
}
|
|
2737
|
-
let revPixelStart =
|
|
3659
|
+
let revPixelStart = w - 1;
|
|
2738
3660
|
for (let pii = revPixelStart; pii >= 0; pii--) {
|
|
2739
|
-
let psMin =
|
|
3661
|
+
let psMin = psMinMax[psMinPos + pii];
|
|
2740
3662
|
let pv = psMin * chH / 2;
|
|
2741
3663
|
let yd = y + (chH / 2) - pv;
|
|
2742
3664
|
//console.log("LineTo: : "+pii+" "+yd)
|
|
@@ -2760,13 +3682,23 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2760
3682
|
g.clearRect(0, 0, w, h);
|
|
2761
3683
|
//g.fillStyle = "black";
|
|
2762
3684
|
//g.fillRect(0, 0, w, h);
|
|
2763
|
-
if (this.
|
|
3685
|
+
if (this._audioDataHolder) {
|
|
2764
3686
|
let std = Date.now();
|
|
2765
|
-
let chs = this.
|
|
3687
|
+
let chs = this._audioDataHolder.numberOfChannels;
|
|
2766
3688
|
let chH = h / chs;
|
|
2767
|
-
let frameLength = this.
|
|
3689
|
+
let frameLength = this._audioDataHolder.frameLen;
|
|
2768
3690
|
let framesPerPixel = frameLength / w;
|
|
2769
3691
|
let y = 0;
|
|
3692
|
+
let ais = null;
|
|
3693
|
+
let audioBuffer = this._audioDataHolder.buffer;
|
|
3694
|
+
let aisBuffer = null;
|
|
3695
|
+
if (!audioBuffer) {
|
|
3696
|
+
ais = this._audioDataHolder.audioInputStream();
|
|
3697
|
+
aisBuffer = new Array(chs);
|
|
3698
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
3699
|
+
aisBuffer[ch] = new Float32Array(framesPerPixel);
|
|
3700
|
+
}
|
|
3701
|
+
}
|
|
2770
3702
|
for (let ch = 0; ch < chs; ch++) {
|
|
2771
3703
|
let x = 0;
|
|
2772
3704
|
let psMin = new Float32Array(w);
|
|
@@ -2775,20 +3707,33 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2775
3707
|
for (let pii = 0; pii < w; pii++) {
|
|
2776
3708
|
let pMin = 0;
|
|
2777
3709
|
let pMax = 0;
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
pMin
|
|
3710
|
+
if (audioBuffer) {
|
|
3711
|
+
// calculate pixel min/max amplitude
|
|
3712
|
+
for (let ai = 0; ai < framesPerPixel; ai++) {
|
|
3713
|
+
//let framePos=(pii*framesPerPixel)+ai;
|
|
3714
|
+
let a = audioBuffer.getChannelData(ch)[framePos++];
|
|
3715
|
+
if (a < pMin) {
|
|
3716
|
+
pMin = a;
|
|
3717
|
+
}
|
|
3718
|
+
if (a > pMax) {
|
|
3719
|
+
pMax = a;
|
|
3720
|
+
}
|
|
2784
3721
|
}
|
|
2785
|
-
|
|
2786
|
-
|
|
3722
|
+
}
|
|
3723
|
+
else if (ais && aisBuffer) {
|
|
3724
|
+
let r = ais.read(aisBuffer);
|
|
3725
|
+
for (let ai = 0; ai < r; ai++) {
|
|
3726
|
+
let a = aisBuffer[ch][ai];
|
|
3727
|
+
if (a < pMin) {
|
|
3728
|
+
pMin = a;
|
|
3729
|
+
}
|
|
3730
|
+
if (a > pMax) {
|
|
3731
|
+
pMax = a;
|
|
3732
|
+
}
|
|
2787
3733
|
}
|
|
2788
3734
|
}
|
|
2789
3735
|
psMin[pii] = pMin;
|
|
2790
3736
|
psMax[pii] = pMax;
|
|
2791
|
-
//console.log("Min: ", pMin, " max: ", pMax);
|
|
2792
3737
|
}
|
|
2793
3738
|
g.fillStyle = 'green';
|
|
2794
3739
|
g.strokeStyle = 'green';
|
|
@@ -2813,12 +3758,11 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2813
3758
|
g.stroke();
|
|
2814
3759
|
y += chH;
|
|
2815
3760
|
}
|
|
2816
|
-
//this.drawPlayPosition();
|
|
2817
3761
|
}
|
|
2818
3762
|
}
|
|
2819
3763
|
}
|
|
2820
3764
|
setData(audioData) {
|
|
2821
|
-
this.
|
|
3765
|
+
this._audioDataHolder = audioData;
|
|
2822
3766
|
this.playFramePosition = 0;
|
|
2823
3767
|
}
|
|
2824
3768
|
}
|
|
@@ -3187,7 +4131,7 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3187
4131
|
this._playFramePosition = null;
|
|
3188
4132
|
this.dftSize = DEFAULT_DFT_SIZE;
|
|
3189
4133
|
this.worker = null;
|
|
3190
|
-
this.
|
|
4134
|
+
this._audioDataHolder = null;
|
|
3191
4135
|
this.markers = new Array();
|
|
3192
4136
|
this.dft = new DFTFloat32(this.dftSize);
|
|
3193
4137
|
this.workerURL = WorkerHelper.buildWorkerBlobURL(this.workerFunction);
|
|
@@ -3240,7 +4184,7 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3240
4184
|
g.lineTo(xViewPortPixelpos, h);
|
|
3241
4185
|
g.closePath();
|
|
3242
4186
|
g.stroke();
|
|
3243
|
-
if (this.
|
|
4187
|
+
if (this._audioDataHolder) {
|
|
3244
4188
|
let framePosRound = this.viewPortXPixelToFramePosition(xViewPortPixelpos);
|
|
3245
4189
|
if (framePosRound != null) {
|
|
3246
4190
|
g.font = '14px sans-serif';
|
|
@@ -3504,11 +4448,21 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3504
4448
|
}
|
|
3505
4449
|
GaussianWindow.DEFAULT_SIGMA = 0.3;
|
|
3506
4450
|
self.onmessage = function (msg) {
|
|
4451
|
+
//console.debug("Sonagram render thread");
|
|
3507
4452
|
let l = msg.data.l;
|
|
3508
4453
|
let w = msg.data.w;
|
|
3509
4454
|
let h = msg.data.h;
|
|
3510
4455
|
let vw = msg.data.vw;
|
|
3511
4456
|
let chs = msg.data.chs;
|
|
4457
|
+
let audioDataOffset = 0;
|
|
4458
|
+
let adOffset = msg.data.audioDataOffset;
|
|
4459
|
+
if (adOffset) {
|
|
4460
|
+
audioDataOffset = adOffset;
|
|
4461
|
+
}
|
|
4462
|
+
let maxPsd = null;
|
|
4463
|
+
if (msg.data.maxPsd !== undefined) {
|
|
4464
|
+
maxPsd = msg.data.maxPsd;
|
|
4465
|
+
}
|
|
3512
4466
|
let audioData = new Array(chs);
|
|
3513
4467
|
for (let ch = 0; ch < chs; ch++) {
|
|
3514
4468
|
audioData[ch] = new Float32Array(msg.data['audioData'][ch]);
|
|
@@ -3524,16 +4478,17 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3524
4478
|
}
|
|
3525
4479
|
let imgData = new Uint8ClampedArray(arrSize);
|
|
3526
4480
|
//console.log("Render method:");
|
|
3527
|
-
|
|
4481
|
+
//console.debug("Created imgData arrSize: "+arrSize+" ", w, "x", h);
|
|
4482
|
+
let calcMaxPsd = -Infinity;
|
|
4483
|
+
if (arrSize > 0) {
|
|
3528
4484
|
let chH = Math.round(h / chs);
|
|
3529
4485
|
let framesPerPixel = frameLength / vw;
|
|
3530
|
-
//console.
|
|
4486
|
+
//console.debug("Render: ", w, "x", h);
|
|
3531
4487
|
let b = new Float32Array(dftSize);
|
|
3532
4488
|
let sona = new Array(chs);
|
|
3533
|
-
let
|
|
3534
|
-
let p = 0;
|
|
4489
|
+
//let p = 0;
|
|
3535
4490
|
for (let ch = 0; ch < chs; ch++) {
|
|
3536
|
-
p = ch * frameLength;
|
|
4491
|
+
//p = ch * frameLength;
|
|
3537
4492
|
let chDataLen = audioData[ch].length;
|
|
3538
4493
|
let x = 0;
|
|
3539
4494
|
// initialize DFT array buffer
|
|
@@ -3550,8 +4505,13 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3550
4505
|
// initialize for negative sample positions and out of bounds positions
|
|
3551
4506
|
let chDat = 0;
|
|
3552
4507
|
// Set audio sample if available
|
|
3553
|
-
|
|
3554
|
-
|
|
4508
|
+
let adp = samplePos - audioDataOffset;
|
|
4509
|
+
if (adp >= 0 && adp < chDataLen) {
|
|
4510
|
+
chDat = audioData[ch][adp];
|
|
4511
|
+
//console.debug("Audio data: "+chDat);
|
|
4512
|
+
}
|
|
4513
|
+
else {
|
|
4514
|
+
//console.debug("Sample buf pos oob: adp: "+adp+", chDataLen: "+chDataLen+", samplePos: "+samplePos+", i: "+i);
|
|
3555
4515
|
}
|
|
3556
4516
|
// apply Window
|
|
3557
4517
|
b[i] = chDat * wf.getScale(i);
|
|
@@ -3561,63 +4521,78 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3561
4521
|
// Get maximum value of spectral energy
|
|
3562
4522
|
for (let s = 0; s < dftBands; s++) {
|
|
3563
4523
|
let psd = (2 * Math.pow(spectr[s], 2)) / dftBands;
|
|
3564
|
-
if (psd >
|
|
3565
|
-
|
|
4524
|
+
if (psd > calcMaxPsd) {
|
|
4525
|
+
calcMaxPsd = psd;
|
|
3566
4526
|
}
|
|
3567
4527
|
}
|
|
3568
4528
|
// Set render model data for this pixel
|
|
3569
4529
|
sona[ch][pii] = spectr;
|
|
3570
4530
|
}
|
|
3571
4531
|
}
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
scaledVal =
|
|
3592
|
-
|
|
3593
|
-
scaledVal
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
rgbVal =
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
4532
|
+
if (!msg.data.norender) {
|
|
4533
|
+
if (!maxPsd) {
|
|
4534
|
+
maxPsd = calcMaxPsd;
|
|
4535
|
+
}
|
|
4536
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4537
|
+
for (let pii = 0; pii < w; pii++) {
|
|
4538
|
+
let allBlack = true;
|
|
4539
|
+
for (let y = 0; y < chH; y++) {
|
|
4540
|
+
let freqIdx = Math.round(y * dftBands / chH);
|
|
4541
|
+
// calculate the one sided power spectral density PSD (f, t) in Pa2/Hz
|
|
4542
|
+
// PSD(f) proportional to 2|X(f)|2 / (t2 - t1)
|
|
4543
|
+
let val = sona[ch][pii][freqIdx];
|
|
4544
|
+
let psd = (2 * Math.pow(val, 2)) / dftBands;
|
|
4545
|
+
// Calculate logarithmic value
|
|
4546
|
+
//let psdLog = ips.dsp.DSPUtils.toLevelInDB(psd / maxPsd);
|
|
4547
|
+
let linearLevel = psd / maxPsd;
|
|
4548
|
+
let psdLog = 10 * Math.log(linearLevel) / Math.log(10);
|
|
4549
|
+
// Fixed dynamic Range value of 70dB for now
|
|
4550
|
+
let dynRangeInDb = 70;
|
|
4551
|
+
let scaledVal = (psdLog + dynRangeInDb) / dynRangeInDb;
|
|
4552
|
+
// are the following checks necessary for clamped array ?
|
|
4553
|
+
if (scaledVal > 1.0)
|
|
4554
|
+
scaledVal = 1;
|
|
4555
|
+
if (scaledVal < 0.0) {
|
|
4556
|
+
scaledVal = 0;
|
|
4557
|
+
}
|
|
4558
|
+
let rgbVal = Math.round(255 * scaledVal);
|
|
4559
|
+
if (rgbVal < 0) {
|
|
4560
|
+
// System.out.println("Neg RGB val: "+rgbVal);
|
|
4561
|
+
rgbVal = 0;
|
|
4562
|
+
}
|
|
4563
|
+
if (rgbVal > 255) {
|
|
4564
|
+
rgbVal = 255;
|
|
4565
|
+
}
|
|
4566
|
+
rgbVal = 255 - rgbVal;
|
|
4567
|
+
if (rgbVal > 0) {
|
|
4568
|
+
allBlack = false;
|
|
4569
|
+
}
|
|
4570
|
+
let py = chH - y;
|
|
4571
|
+
let dataPos = ((((ch * chH) + py) * w) + pii) * 4;
|
|
4572
|
+
imgData[dataPos + 0] = rgbVal; //R
|
|
4573
|
+
imgData[dataPos + 1] = rgbVal; //G
|
|
4574
|
+
imgData[dataPos + 2] = rgbVal; //B
|
|
4575
|
+
imgData[dataPos + 3] = 255; //A (alpha: fully opaque)
|
|
4576
|
+
//console.debug("Rendered: py: "+py+", rgbval: "+rgbVal);
|
|
4577
|
+
// example 1x1, 2chs
|
|
4578
|
+
// ch0x0y0R,ch0x0y0G,ch0x0y0B,ch0x0y0A,
|
|
4579
|
+
// ch0x1y0R,ch0x1y0G,ch0x1y0B,ch0x1y0A,
|
|
4580
|
+
// ch0x0y0R,ch0x0y0G,ch0x0y0B,ch0x0y0A,
|
|
4581
|
+
// ch0x1y1R,ch0x1y1G,ch0x1y1B,ch0x1y1A,
|
|
4582
|
+
// ch1x0y0R,ch1x0y0G,ch1x0y0B,ch1x0y0A,
|
|
4583
|
+
// ch1x1y0R,ch1x1y0G,ch1x1y0B,ch1x1y0A,
|
|
4584
|
+
// ch1x0y0R,ch1x0y0G,ch1x0y0B,ch1x0y0A,
|
|
4585
|
+
// ch1x1y1R,ch1x1y1G,ch1x1y1B,ch1x1y1A
|
|
3606
4586
|
}
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
imgData[dataPos + 1] = rgbVal; //G
|
|
3611
|
-
imgData[dataPos + 2] = rgbVal; //B
|
|
3612
|
-
imgData[dataPos + 3] = 255; //A (alpha: fully opaque)
|
|
4587
|
+
// if (allBlack) {
|
|
4588
|
+
// console.log("Black: ", pii, " ", ch);
|
|
4589
|
+
// }
|
|
3613
4590
|
}
|
|
3614
|
-
// if (allBlack) {
|
|
3615
|
-
// console.log("Black: ", pii, " ", ch);
|
|
3616
|
-
// }
|
|
3617
4591
|
}
|
|
3618
4592
|
}
|
|
3619
4593
|
}
|
|
3620
|
-
|
|
4594
|
+
//console.debug("Render thread post message imgData: "+imgData.length)
|
|
4595
|
+
postMessage({ imgData: imgData, l: l, w: msg.data.w, h: msg.data.h, vw: vw, maxPsd: calcMaxPsd, terminate: msg.data.terminate }, [imgData.buffer]);
|
|
3621
4596
|
};
|
|
3622
4597
|
}
|
|
3623
4598
|
startDraw(clear = true) {
|
|
@@ -3647,42 +4622,190 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3647
4622
|
if (this.bounds) {
|
|
3648
4623
|
let w = Math.round(this.bounds.dimension.width);
|
|
3649
4624
|
let h = Math.round(this.bounds.dimension.height);
|
|
3650
|
-
if (this.
|
|
4625
|
+
if (this._audioDataHolder && w > 0 && h > 0) {
|
|
3651
4626
|
this.worker = new Worker(this.workerURL);
|
|
3652
4627
|
//this.wo = new Worker('./worker/sonagram.worker', { type: `module` });
|
|
3653
|
-
let chs = this.
|
|
3654
|
-
let
|
|
3655
|
-
let
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
let
|
|
4628
|
+
let chs = this._audioDataHolder.numberOfChannels;
|
|
4629
|
+
let vw = Math.round(this.virtualDimension.width);
|
|
4630
|
+
let frameLength = this._audioDataHolder.frameLen;
|
|
4631
|
+
let framesPerPixel = Math.ceil(frameLength / vw);
|
|
4632
|
+
let leftPos = Math.round(this.bounds.position.left);
|
|
4633
|
+
let renderPos = leftPos;
|
|
4634
|
+
let audioBuffer = this._audioDataHolder.buffer;
|
|
4635
|
+
//let arrayAudioBuffer=this._audioDataHolder.arrayBuffer;
|
|
4636
|
+
let arrAbBuf;
|
|
4637
|
+
let imgData;
|
|
4638
|
+
let maxPsd = -Infinity;
|
|
4639
|
+
let norender = true;
|
|
3661
4640
|
if (this.worker) {
|
|
3662
4641
|
this.worker.onmessage = (me) => {
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
4642
|
+
if (true === me.data.terminate) {
|
|
4643
|
+
let drawImgData;
|
|
4644
|
+
if (imgData) {
|
|
4645
|
+
drawImgData = imgData;
|
|
4646
|
+
}
|
|
4647
|
+
else {
|
|
4648
|
+
drawImgData = me.data.imgData;
|
|
4649
|
+
}
|
|
4650
|
+
this.drawRendered(w, h, drawImgData);
|
|
4651
|
+
if (this.worker) {
|
|
4652
|
+
this.worker.terminate();
|
|
4653
|
+
}
|
|
4654
|
+
this.worker = null;
|
|
4655
|
+
}
|
|
4656
|
+
else {
|
|
4657
|
+
// set rendered vertical values of one pixel of timescale
|
|
4658
|
+
//let dataPos = renderPos * h * 4;
|
|
4659
|
+
if (norender) {
|
|
4660
|
+
if (me.data.maxPsd > maxPsd) {
|
|
4661
|
+
maxPsd = me.data.maxPsd;
|
|
4662
|
+
//console.debug("new maxPsd: "+maxPsd);
|
|
4663
|
+
}
|
|
4664
|
+
}
|
|
4665
|
+
else {
|
|
4666
|
+
let chH = Math.round(h / chs);
|
|
4667
|
+
let idp = me.data.l - leftPos;
|
|
4668
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4669
|
+
for (let y = 0; y < chH; y++) {
|
|
4670
|
+
let py = chH - y;
|
|
4671
|
+
let dataPos = ((((ch * chH) + py) * w) + idp) * 4;
|
|
4672
|
+
let mePos = ((ch * chH) + py) * 4;
|
|
4673
|
+
//let lastPos = dataPos + me.data.imgData.length;
|
|
4674
|
+
//if (lastPos < imgData.length) {
|
|
4675
|
+
// set one pixel
|
|
4676
|
+
imgData[dataPos] = me.data.imgData[mePos];
|
|
4677
|
+
imgData[dataPos + 1] = me.data.imgData[mePos + 1];
|
|
4678
|
+
imgData[dataPos + 2] = me.data.imgData[mePos + 2];
|
|
4679
|
+
imgData[dataPos + 3] = me.data.imgData[mePos + 3];
|
|
4680
|
+
//} else {
|
|
4681
|
+
//console.error("Out of range: " + dataPos + "+" + me.data.imgData.length + ">=" + imgData.length);
|
|
4682
|
+
// }
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
}
|
|
4686
|
+
if (this._audioDataHolder && arrAbBuf && this.worker) {
|
|
4687
|
+
// proceed with next pixel
|
|
4688
|
+
renderPos++;
|
|
4689
|
+
//console.debug("Render pos: "+renderPos);
|
|
4690
|
+
let terminate = false;
|
|
4691
|
+
let windowEnd = renderPos >= leftPos + w;
|
|
4692
|
+
if (windowEnd) {
|
|
4693
|
+
if (norender) {
|
|
4694
|
+
// phase two: rendering
|
|
4695
|
+
norender = false;
|
|
4696
|
+
// start from beginning
|
|
4697
|
+
renderPos = leftPos;
|
|
4698
|
+
//console.debug("now rendering: maxPsd: "+maxPsd);
|
|
4699
|
+
}
|
|
4700
|
+
else {
|
|
4701
|
+
// terminate render phase
|
|
4702
|
+
terminate = true;
|
|
4703
|
+
}
|
|
4704
|
+
}
|
|
4705
|
+
let leftFramePos = Math.floor(frameLength * renderPos / vw) - this.dftSize / 2;
|
|
4706
|
+
if (leftFramePos < 0) {
|
|
4707
|
+
leftFramePos = 0;
|
|
4708
|
+
}
|
|
4709
|
+
let ada = new Array(chs);
|
|
4710
|
+
//console.debug("Render pos: "+renderPos+" leftFramePos: "+leftFramePos);
|
|
4711
|
+
if (!terminate) {
|
|
4712
|
+
if (this._audioDataHolder) {
|
|
4713
|
+
let read = this._audioDataHolder.frames(leftFramePos, this.dftSize, arrAbBuf);
|
|
4714
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4715
|
+
// Need a copy here for the worker, otherwise this.audioData is not accessible after posting to the worker
|
|
4716
|
+
ada[ch] = arrAbBuf[ch].buffer.slice(0);
|
|
4717
|
+
}
|
|
4718
|
+
}
|
|
4719
|
+
}
|
|
4720
|
+
else {
|
|
4721
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4722
|
+
ada[ch] = new ArrayBuffer(0);
|
|
4723
|
+
}
|
|
4724
|
+
}
|
|
4725
|
+
this.worker.postMessage({
|
|
4726
|
+
audioData: ada,
|
|
4727
|
+
audioDataOffset: leftFramePos,
|
|
4728
|
+
l: renderPos,
|
|
4729
|
+
w: me.data.w,
|
|
4730
|
+
h: h,
|
|
4731
|
+
vw: vw,
|
|
4732
|
+
chs: chs,
|
|
4733
|
+
frameLength: frameLength,
|
|
4734
|
+
dftSize: this.dftSize,
|
|
4735
|
+
maxPsd: maxPsd,
|
|
4736
|
+
norender: norender,
|
|
4737
|
+
terminate: terminate
|
|
4738
|
+
}, ada);
|
|
4739
|
+
}
|
|
3666
4740
|
}
|
|
3667
|
-
this.worker = null;
|
|
3668
4741
|
};
|
|
3669
4742
|
}
|
|
3670
|
-
if (
|
|
3671
|
-
let
|
|
3672
|
-
|
|
3673
|
-
|
|
4743
|
+
if (audioBuffer && audioBuffer.length * audioBuffer.numberOfChannels < AudioCanvasLayerComponent.ENABLE_STREAMING_NUMBER_OF_SAMPLES_THRESHOLD) {
|
|
4744
|
+
let ada = new Array(chs);
|
|
4745
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4746
|
+
// Need a copy here for the worker, otherwise this.audioData is not accessible after posting to the worker
|
|
4747
|
+
ada[ch] = audioBuffer.getChannelData(ch).buffer.slice(0);
|
|
4748
|
+
}
|
|
4749
|
+
let start = Date.now();
|
|
4750
|
+
if (this.markerCanvas) {
|
|
4751
|
+
let g = this.markerCanvas.getContext("2d");
|
|
4752
|
+
if (g) {
|
|
4753
|
+
g.fillText("Rendering...", 10, 20);
|
|
4754
|
+
}
|
|
4755
|
+
}
|
|
4756
|
+
this.worker.postMessage({
|
|
4757
|
+
audioData: ada,
|
|
4758
|
+
l: leftPos,
|
|
4759
|
+
w: w,
|
|
4760
|
+
h: h,
|
|
4761
|
+
vw: Math.round(this.virtualDimension.width),
|
|
4762
|
+
chs: chs,
|
|
4763
|
+
frameLength: frameLength,
|
|
4764
|
+
dftSize: this.dftSize,
|
|
4765
|
+
terminate: true
|
|
4766
|
+
}, ada);
|
|
4767
|
+
}
|
|
4768
|
+
else {
|
|
4769
|
+
if (w > 0) {
|
|
4770
|
+
if (framesPerPixel > 0) {
|
|
4771
|
+
let arrSize = w * h * 4;
|
|
4772
|
+
if (arrSize < 0) {
|
|
4773
|
+
arrSize = 0;
|
|
4774
|
+
}
|
|
4775
|
+
imgData = new Uint8ClampedArray(arrSize);
|
|
4776
|
+
let rw = 1;
|
|
4777
|
+
//ais = new ArrayAudioBufferInputStream(arrayAudioBuffer);
|
|
4778
|
+
arrAbBuf = new Array(chs);
|
|
4779
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4780
|
+
arrAbBuf[ch] = new Float32Array(this.dftSize);
|
|
4781
|
+
}
|
|
4782
|
+
let leftFramePos = Math.floor(frameLength * renderPos / vw) - this.dftSize / 2;
|
|
4783
|
+
let framesToRead = this.dftSize;
|
|
4784
|
+
if (leftFramePos < 0) {
|
|
4785
|
+
//framesToRead=this.dftSize+leftFramePos;
|
|
4786
|
+
leftFramePos = 0;
|
|
4787
|
+
}
|
|
4788
|
+
let read = this._audioDataHolder.frames(leftFramePos, framesToRead, arrAbBuf);
|
|
4789
|
+
let ad = new Float32Array(chs * framesToRead);
|
|
4790
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4791
|
+
ad.set(arrAbBuf[ch], ch * framesToRead);
|
|
4792
|
+
}
|
|
4793
|
+
this.worker.postMessage({
|
|
4794
|
+
l: renderPos,
|
|
4795
|
+
w: rw,
|
|
4796
|
+
h: h,
|
|
4797
|
+
vw: vw,
|
|
4798
|
+
chs: chs,
|
|
4799
|
+
frameLength: frameLength,
|
|
4800
|
+
audioData: ad,
|
|
4801
|
+
audioDataOffset: leftFramePos,
|
|
4802
|
+
dftSize: this.dftSize,
|
|
4803
|
+
norender: norender,
|
|
4804
|
+
terminate: false
|
|
4805
|
+
}, [ad.buffer]);
|
|
4806
|
+
}
|
|
3674
4807
|
}
|
|
3675
4808
|
}
|
|
3676
|
-
this.worker.postMessage({
|
|
3677
|
-
audioData: ada,
|
|
3678
|
-
l: Math.round(this.bounds.position.left),
|
|
3679
|
-
w: w,
|
|
3680
|
-
h: h,
|
|
3681
|
-
vw: Math.round(this.virtualDimension.width),
|
|
3682
|
-
chs: chs,
|
|
3683
|
-
frameLength: frameLength,
|
|
3684
|
-
dftSize: this.dftSize
|
|
3685
|
-
}, ada);
|
|
3686
4809
|
}
|
|
3687
4810
|
else {
|
|
3688
4811
|
let g = this.sonagramCanvas.getContext("2d");
|
|
@@ -3692,17 +4815,17 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3692
4815
|
}
|
|
3693
4816
|
}
|
|
3694
4817
|
}
|
|
3695
|
-
drawRendered(
|
|
4818
|
+
drawRendered(w, h, imgData) {
|
|
3696
4819
|
if (this.sonagramCanvas) {
|
|
3697
|
-
this.sonagramCanvas.width =
|
|
3698
|
-
this.sonagramCanvas.height =
|
|
4820
|
+
this.sonagramCanvas.width = w;
|
|
4821
|
+
this.sonagramCanvas.height = h;
|
|
3699
4822
|
let g = this.sonagramCanvas.getContext("2d");
|
|
3700
4823
|
if (g) {
|
|
3701
|
-
let imgDataArr =
|
|
3702
|
-
if (
|
|
3703
|
-
let
|
|
3704
|
-
|
|
3705
|
-
g.putImageData(
|
|
4824
|
+
let imgDataArr = imgData;
|
|
4825
|
+
if (w > 0 && h > 0) {
|
|
4826
|
+
let gImgData = g.createImageData(w, h);
|
|
4827
|
+
gImgData.data.set(imgDataArr);
|
|
4828
|
+
g.putImageData(gImgData, 0, 0);
|
|
3706
4829
|
}
|
|
3707
4830
|
}
|
|
3708
4831
|
}
|
|
@@ -3715,94 +4838,98 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3715
4838
|
let w = this.sonagramCanvas.width;
|
|
3716
4839
|
let h = this.sonagramCanvas.height;
|
|
3717
4840
|
if (g) {
|
|
3718
|
-
g.clearRect(0, 0, w, h);
|
|
3719
|
-
g.fillStyle = "white";
|
|
3720
|
-
g.fillRect(0, 0, w, h);
|
|
3721
|
-
if (this.
|
|
3722
|
-
let spectSize = Math.floor(this.dftSize / 2);
|
|
3723
|
-
let chs = this.
|
|
3724
|
-
let chH = h / chs;
|
|
3725
|
-
let frameLength = this.
|
|
3726
|
-
let framesPerPixel = frameLength / w;
|
|
3727
|
-
let y = 0;
|
|
3728
|
-
|
|
3729
|
-
let
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
let
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
framePos =
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
sona[ch][pii] = spectr;
|
|
3748
|
-
// @ts-ignore
|
|
3749
|
-
let pMax = Math.max.apply(null, spectr);
|
|
3750
|
-
if (pMax > max) {
|
|
3751
|
-
max = pMax;
|
|
3752
|
-
}
|
|
3753
|
-
for (let s = 0; s < spectSize; s++) {
|
|
3754
|
-
let psd = (2 * Math.pow(spectr[s], 2)) / spectSize;
|
|
3755
|
-
if (psd > maxPsd) {
|
|
3756
|
-
maxPsd = psd;
|
|
4841
|
+
g.clearRect(0, 0, w, h);
|
|
4842
|
+
g.fillStyle = "white";
|
|
4843
|
+
g.fillRect(0, 0, w, h);
|
|
4844
|
+
if (this._audioDataHolder) {
|
|
4845
|
+
let spectSize = Math.floor(this.dftSize / 2);
|
|
4846
|
+
let chs = this._audioDataHolder.numberOfChannels;
|
|
4847
|
+
let chH = h / chs;
|
|
4848
|
+
let frameLength = this._audioDataHolder.frameLen;
|
|
4849
|
+
let framesPerPixel = frameLength / w;
|
|
4850
|
+
let y = 0;
|
|
4851
|
+
let audioBuffer = this._audioDataHolder.buffer;
|
|
4852
|
+
let arrayAudioBuffer = this._audioDataHolder.arrayBuffer;
|
|
4853
|
+
if (audioBuffer) {
|
|
4854
|
+
let b = new Float32Array(this.dftSize);
|
|
4855
|
+
let sona = new Array(chs);
|
|
4856
|
+
let max = 0;
|
|
4857
|
+
let maxPsd = -Infinity;
|
|
4858
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4859
|
+
let x = 0;
|
|
4860
|
+
sona[ch] = new Array(w);
|
|
4861
|
+
let chData = audioBuffer.getChannelData(ch);
|
|
4862
|
+
// TODO center buffer
|
|
4863
|
+
let framePos = 0;
|
|
4864
|
+
for (let pii = 0; pii < w; pii++) {
|
|
4865
|
+
framePos = Math.round(pii * framesPerPixel);
|
|
4866
|
+
// calculate DFT at pixel position
|
|
4867
|
+
for (let i = 0; i < this.dftSize; i++) {
|
|
4868
|
+
let chDat = chData[framePos + i];
|
|
4869
|
+
b[i] = chDat;
|
|
3757
4870
|
}
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
let framePos = 0;
|
|
3765
|
-
for (let pii = 0; pii < w; pii++) {
|
|
3766
|
-
framePos = pii * framesPerPixel;
|
|
3767
|
-
for (let y = 0; y < h; y++) {
|
|
3768
|
-
let freqIdx = Math.round(y * spectSize / h);
|
|
3769
|
-
// calculate the one sided power spectral density PSD (f, t) in Pa2/Hz
|
|
3770
|
-
// PSD(f) proportional to 2|X(f)|2 / (t2 - t1)
|
|
3771
|
-
let val = sona[ch][pii][freqIdx];
|
|
3772
|
-
let psd = (2 * Math.pow(val, 2)) / spectSize;
|
|
3773
|
-
// Calculate logarithmic
|
|
3774
|
-
let psdLog = DSPUtils.toLevelInDB(psd / maxPsd);
|
|
3775
|
-
let dynRangeInDb = 70;
|
|
3776
|
-
let scaledVal = (psdLog + dynRangeInDb) / dynRangeInDb;
|
|
3777
|
-
if (scaledVal > 1)
|
|
3778
|
-
scaledVal = 1;
|
|
3779
|
-
if (scaledVal < 0) {
|
|
3780
|
-
scaledVal = 0;
|
|
4871
|
+
let spectr = this.dft.processRealMagnitude(b);
|
|
4872
|
+
sona[ch][pii] = spectr;
|
|
4873
|
+
// @ts-ignore
|
|
4874
|
+
let pMax = Math.max.apply(null, spectr);
|
|
4875
|
+
if (pMax > max) {
|
|
4876
|
+
max = pMax;
|
|
3781
4877
|
}
|
|
3782
|
-
let
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
4878
|
+
for (let s = 0; s < spectSize; s++) {
|
|
4879
|
+
let psd = (2 * Math.pow(spectr[s], 2)) / spectSize;
|
|
4880
|
+
if (psd > maxPsd) {
|
|
4881
|
+
maxPsd = psd;
|
|
4882
|
+
}
|
|
3786
4883
|
}
|
|
3787
|
-
|
|
3788
|
-
|
|
4884
|
+
}
|
|
4885
|
+
}
|
|
4886
|
+
//console.log("max: ", max);
|
|
4887
|
+
maxPsd = (2 * Math.pow(max, 2)) / spectSize;
|
|
4888
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4889
|
+
let framePos = 0;
|
|
4890
|
+
for (let pii = 0; pii < w; pii++) {
|
|
4891
|
+
framePos = pii * framesPerPixel;
|
|
4892
|
+
for (let y = 0; y < h; y++) {
|
|
4893
|
+
let freqIdx = Math.round(y * spectSize / h);
|
|
4894
|
+
// calculate the one sided power spectral density PSD (f, t) in Pa2/Hz
|
|
4895
|
+
// PSD(f) proportional to 2|X(f)|2 / (t2 - t1)
|
|
4896
|
+
let val = sona[ch][pii][freqIdx];
|
|
4897
|
+
let psd = (2 * Math.pow(val, 2)) / spectSize;
|
|
4898
|
+
// Calculate logarithmic
|
|
4899
|
+
let psdLog = DSPUtils.toLevelInDB(psd / maxPsd);
|
|
4900
|
+
let dynRangeInDb = 70;
|
|
4901
|
+
let scaledVal = (psdLog + dynRangeInDb) / dynRangeInDb;
|
|
4902
|
+
if (scaledVal > 1)
|
|
4903
|
+
scaledVal = 1;
|
|
4904
|
+
if (scaledVal < 0) {
|
|
4905
|
+
scaledVal = 0;
|
|
4906
|
+
}
|
|
4907
|
+
let rgbVal = (255 * scaledVal);
|
|
4908
|
+
if (rgbVal < 0) {
|
|
4909
|
+
// System.out.println("Neg RGB val: "+rgbVal);
|
|
4910
|
+
rgbVal = 0;
|
|
4911
|
+
}
|
|
4912
|
+
if (rgbVal > 255) {
|
|
4913
|
+
rgbVal = 255;
|
|
4914
|
+
}
|
|
4915
|
+
rgbVal = 255 - rgbVal;
|
|
4916
|
+
let colorStr = CSSUtils.toColorString(rgbVal, rgbVal, rgbVal);
|
|
4917
|
+
g.fillStyle = colorStr;
|
|
4918
|
+
g.fillRect(pii, chH - y, 1, 1);
|
|
3789
4919
|
}
|
|
3790
|
-
rgbVal = 255 - rgbVal;
|
|
3791
|
-
let colorStr = CSSUtils.toColorString(rgbVal, rgbVal, rgbVal);
|
|
3792
|
-
g.fillStyle = colorStr;
|
|
3793
|
-
g.fillRect(pii, chH - y, 1, 1);
|
|
3794
4920
|
}
|
|
3795
4921
|
}
|
|
4922
|
+
this.drawPlayPosition();
|
|
4923
|
+
}
|
|
4924
|
+
else if (arrayAudioBuffer) {
|
|
4925
|
+
throw Error("Redraw with array audio buffer not supported.");
|
|
3796
4926
|
}
|
|
3797
|
-
this.drawPlayPosition();
|
|
3798
4927
|
}
|
|
3799
4928
|
}
|
|
3800
4929
|
}
|
|
3801
4930
|
setData(audioData) {
|
|
3802
|
-
this.
|
|
4931
|
+
this._audioDataHolder = audioData;
|
|
3803
4932
|
this.playFramePosition = 0;
|
|
3804
|
-
//this.redraw();
|
|
3805
|
-
//this.startRender();
|
|
3806
4933
|
}
|
|
3807
4934
|
}
|
|
3808
4935
|
Sonagram.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: Sonagram, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
@@ -4027,13 +5154,13 @@ class AudioClipUIContainer extends BasicAudioCanvasLayerComponent {
|
|
|
4027
5154
|
}
|
|
4028
5155
|
currentXZoom() {
|
|
4029
5156
|
let xz = this._xZoom;
|
|
4030
|
-
if (xz == null && this.
|
|
5157
|
+
if (xz == null && this._audioDataHolder) {
|
|
4031
5158
|
let ow = this.ce.offsetWidth;
|
|
4032
5159
|
if (ow < 1) {
|
|
4033
5160
|
// at least one pixel width to avoid x-zoom zero values
|
|
4034
5161
|
ow = 1;
|
|
4035
5162
|
}
|
|
4036
|
-
xz = ow / this.
|
|
5163
|
+
xz = ow / this._audioDataHolder.duration;
|
|
4037
5164
|
}
|
|
4038
5165
|
return xz;
|
|
4039
5166
|
}
|
|
@@ -4114,7 +5241,7 @@ class AudioClipUIContainer extends BasicAudioCanvasLayerComponent {
|
|
|
4114
5241
|
layout(clear = true) {
|
|
4115
5242
|
if (this.ce && this.dc) {
|
|
4116
5243
|
const clientW = this.ce.clientWidth;
|
|
4117
|
-
if (this.
|
|
5244
|
+
if (this._audioDataHolder) {
|
|
4118
5245
|
if (this._fixFitToPanel) {
|
|
4119
5246
|
// Set the virtual canvas width to the visible width
|
|
4120
5247
|
if (this.ce.style.width != '100%') {
|
|
@@ -4125,7 +5252,7 @@ class AudioClipUIContainer extends BasicAudioCanvasLayerComponent {
|
|
|
4125
5252
|
else {
|
|
4126
5253
|
if (this._xZoom) {
|
|
4127
5254
|
// Set the virtual canvas width according to the value of the user selected xZoom value
|
|
4128
|
-
const newClW = Math.round(this._xZoom * this.
|
|
5255
|
+
const newClW = Math.round(this._xZoom * this._audioDataHolder?.duration);
|
|
4129
5256
|
this.ce.style.width = newClW + 'px';
|
|
4130
5257
|
}
|
|
4131
5258
|
else {
|
|
@@ -4137,22 +5264,22 @@ class AudioClipUIContainer extends BasicAudioCanvasLayerComponent {
|
|
|
4137
5264
|
this._layout(clear, true);
|
|
4138
5265
|
}
|
|
4139
5266
|
}
|
|
4140
|
-
set audioData(
|
|
5267
|
+
set audioData(audioDataHolder) {
|
|
4141
5268
|
this._audioClip = null;
|
|
4142
|
-
this.
|
|
4143
|
-
this.as.setData(
|
|
4144
|
-
this.so.setData(
|
|
5269
|
+
this._audioDataHolder = audioDataHolder;
|
|
5270
|
+
this.as.setData(audioDataHolder);
|
|
5271
|
+
this.so.setData(audioDataHolder);
|
|
4145
5272
|
this.layout();
|
|
4146
5273
|
}
|
|
4147
5274
|
get audioData() {
|
|
4148
|
-
return this.
|
|
5275
|
+
return this._audioDataHolder;
|
|
4149
5276
|
}
|
|
4150
5277
|
set audioClip(audioClip) {
|
|
4151
5278
|
this._audioClip = audioClip;
|
|
4152
5279
|
let audioData = null;
|
|
4153
5280
|
let sel = null;
|
|
4154
5281
|
if (audioClip) {
|
|
4155
|
-
audioData = audioClip.
|
|
5282
|
+
audioData = audioClip.audioDataHolder;
|
|
4156
5283
|
if (this._audioClip) {
|
|
4157
5284
|
this._audioClip.addSelectionObserver((clip) => {
|
|
4158
5285
|
this.selection = clip.selection;
|
|
@@ -4160,9 +5287,9 @@ class AudioClipUIContainer extends BasicAudioCanvasLayerComponent {
|
|
|
4160
5287
|
}
|
|
4161
5288
|
sel = audioClip.selection;
|
|
4162
5289
|
}
|
|
4163
|
-
this.
|
|
4164
|
-
this.as.setData(this.
|
|
4165
|
-
this.so.setData(this.
|
|
5290
|
+
this._audioDataHolder = audioData;
|
|
5291
|
+
this.as.setData(this._audioDataHolder);
|
|
5292
|
+
this.so.setData(this._audioDataHolder);
|
|
4166
5293
|
this.selecting = null;
|
|
4167
5294
|
this.selection = sel;
|
|
4168
5295
|
this.layout();
|
|
@@ -4354,7 +5481,7 @@ class AudioDisplayScrollPane {
|
|
|
4354
5481
|
let audioData = null;
|
|
4355
5482
|
let sel = null;
|
|
4356
5483
|
if (audioClip) {
|
|
4357
|
-
audioData = audioClip.
|
|
5484
|
+
audioData = audioClip.audioDataHolder;
|
|
4358
5485
|
sel = audioClip.selection;
|
|
4359
5486
|
audioClip.addSelectionObserver((clip) => {
|
|
4360
5487
|
this.zoomSelectedAction.disabled = (clip.selection == null);
|
|
@@ -4625,17 +5752,17 @@ class AudioDisplay {
|
|
|
4625
5752
|
console.log("Play started");
|
|
4626
5753
|
this.status = 'Playing...';
|
|
4627
5754
|
}
|
|
4628
|
-
set audioData(
|
|
4629
|
-
this.audioDisplayScrollPane.audioData =
|
|
5755
|
+
set audioData(audioData) {
|
|
5756
|
+
this.audioDisplayScrollPane.audioData = audioData;
|
|
4630
5757
|
if (this.playStartAction) {
|
|
4631
|
-
this.playStartAction.disabled = (
|
|
5758
|
+
this.playStartAction.disabled = (audioData == null);
|
|
4632
5759
|
}
|
|
4633
5760
|
}
|
|
4634
5761
|
set audioClip(audioClip) {
|
|
4635
5762
|
let audioData = null;
|
|
4636
5763
|
let sel = null;
|
|
4637
5764
|
if (audioClip) {
|
|
4638
|
-
audioData = audioClip.buffer;
|
|
5765
|
+
audioData = audioClip.audioDataHolder.buffer;
|
|
4639
5766
|
sel = audioClip.selection;
|
|
4640
5767
|
}
|
|
4641
5768
|
this._audioClip = audioClip;
|
|
@@ -4748,7 +5875,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
4748
5875
|
|
|
4749
5876
|
class Progress {
|
|
4750
5877
|
constructor() {
|
|
4751
|
-
this.items =
|
|
5878
|
+
this.items = undefined;
|
|
4752
5879
|
this.selectedItemIdx = 0;
|
|
4753
5880
|
this.enableDownload = false;
|
|
4754
5881
|
this.onRowSelect = new EventEmitter();
|
|
@@ -5488,7 +6615,7 @@ class Prompting {
|
|
|
5488
6615
|
constructor() {
|
|
5489
6616
|
this.promptItem = null;
|
|
5490
6617
|
this.showPrompt = false;
|
|
5491
|
-
this.items =
|
|
6618
|
+
this.items = undefined;
|
|
5492
6619
|
this.enableDownload = false;
|
|
5493
6620
|
this.audioSignalCollapsed = true;
|
|
5494
6621
|
this.displayAudioClip = null;
|
|
@@ -5799,6 +6926,7 @@ class LevelBar {
|
|
|
5799
6926
|
this._streamingMode = false;
|
|
5800
6927
|
this._staticLevelInfos = null;
|
|
5801
6928
|
this._playFramePosition = null;
|
|
6929
|
+
this._stateLoading = false;
|
|
5802
6930
|
this.warnDBLevel = DEFAULT_WARN_DB_LEVEL$1;
|
|
5803
6931
|
this.dbValues = new Array();
|
|
5804
6932
|
}
|
|
@@ -5844,6 +6972,10 @@ class LevelBar {
|
|
|
5844
6972
|
}
|
|
5845
6973
|
this.layoutStatic();
|
|
5846
6974
|
}
|
|
6975
|
+
set stateLoading(loading) {
|
|
6976
|
+
this._stateLoading = loading;
|
|
6977
|
+
this.layoutStatic();
|
|
6978
|
+
}
|
|
5847
6979
|
set channelCount(channelCount) {
|
|
5848
6980
|
this.reset();
|
|
5849
6981
|
}
|
|
@@ -6024,6 +7156,12 @@ class LevelBar {
|
|
|
6024
7156
|
}
|
|
6025
7157
|
}
|
|
6026
7158
|
}
|
|
7159
|
+
else if (this._stateLoading) {
|
|
7160
|
+
g.strokeStyle = 'white';
|
|
7161
|
+
g.fillStyle = 'white';
|
|
7162
|
+
g.font = '20px sans-serif';
|
|
7163
|
+
g.fillText("Loading...", 10, 25);
|
|
7164
|
+
}
|
|
6027
7165
|
}
|
|
6028
7166
|
}
|
|
6029
7167
|
}
|
|
@@ -6066,7 +7204,7 @@ class LevelBar {
|
|
|
6066
7204
|
}
|
|
6067
7205
|
}
|
|
6068
7206
|
LevelBar.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: LevelBar, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
6069
|
-
LevelBar.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: LevelBar, selector: "audio-levelbar", inputs: { streamingMode: "streamingMode", displayLevelInfos: "displayLevelInfos" }, host: { listeners: { "scroll": "onScroll($event)", "window:resize": "onResize($event)" } }, viewQueries: [{ propertyName: "virtualCanvasRef", first: true, predicate: ["virtualCanvas"], descendants: true, static: true }, { propertyName: "liveLevelCanvasRef", first: true, predicate: ["levelbar"], descendants: true, static: true }, { propertyName: "markerCanvasRef", first: true, predicate: ["markerCanvas"], descendants: true, static: true }], ngImport: i0, template: `
|
|
7207
|
+
LevelBar.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: LevelBar, selector: "audio-levelbar", inputs: { streamingMode: "streamingMode", displayLevelInfos: "displayLevelInfos", stateLoading: "stateLoading" }, host: { listeners: { "scroll": "onScroll($event)", "window:resize": "onResize($event)" } }, viewQueries: [{ propertyName: "virtualCanvasRef", first: true, predicate: ["virtualCanvas"], descendants: true, static: true }, { propertyName: "liveLevelCanvasRef", first: true, predicate: ["levelbar"], descendants: true, static: true }, { propertyName: "markerCanvasRef", first: true, predicate: ["markerCanvas"], descendants: true, static: true }], ngImport: i0, template: `
|
|
6070
7208
|
<div #virtualCanvas>
|
|
6071
7209
|
<canvas #levelbar></canvas>
|
|
6072
7210
|
<canvas #markerCanvas></canvas>
|
|
@@ -6123,6 +7261,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
6123
7261
|
type: Input
|
|
6124
7262
|
}], displayLevelInfos: [{
|
|
6125
7263
|
type: Input
|
|
7264
|
+
}], stateLoading: [{
|
|
7265
|
+
type: Input
|
|
6126
7266
|
}], onResize: [{
|
|
6127
7267
|
type: HostListener,
|
|
6128
7268
|
args: ['window:resize', ['$event']]
|
|
@@ -6713,47 +7853,66 @@ class PeakLevelInterceptor {
|
|
|
6713
7853
|
}
|
|
6714
7854
|
}
|
|
6715
7855
|
class LevelMeasure {
|
|
7856
|
+
//private bufferLevelInfos=new Array<LevelInfo>();
|
|
7857
|
+
//private peakLevelInfo!:LevelInfo;
|
|
6716
7858
|
constructor() {
|
|
6717
7859
|
this.worker = null;
|
|
6718
7860
|
this.workerURL = WorkerHelper.buildWorkerBlobURL(this.workerFunction);
|
|
6719
7861
|
}
|
|
6720
|
-
calcBufferLevelInfos(
|
|
7862
|
+
calcBufferLevelInfos(audioDataHolder, bufferTimeLength) {
|
|
6721
7863
|
return new Promise((resolve) => {
|
|
6722
|
-
let chs =
|
|
6723
|
-
let bufferFrameLength = Math.round(
|
|
6724
|
-
let
|
|
7864
|
+
let chs = audioDataHolder.numberOfChannels;
|
|
7865
|
+
let bufferFrameLength = Math.round(audioDataHolder.sampleRate * bufferTimeLength);
|
|
7866
|
+
let ais = audioDataHolder.audioInputStream();
|
|
7867
|
+
let audioBuffers = new Array(chs);
|
|
7868
|
+
let trBuffers = new Array(chs);
|
|
6725
7869
|
for (let ch = 0; ch < chs; ch++) {
|
|
6726
|
-
|
|
6727
|
-
let adChCopy = new Float32Array(adCh.length);
|
|
6728
|
-
adChCopy.set(adCh);
|
|
6729
|
-
buffers[ch] = adChCopy.buffer;
|
|
7870
|
+
audioBuffers[ch] = new Float32Array(bufferFrameLength);
|
|
6730
7871
|
}
|
|
7872
|
+
let bufferLevelInfos = new Array();
|
|
7873
|
+
let peakLevelInfo = new LevelInfo(chs);
|
|
6731
7874
|
this.worker = new Worker(this.workerURL);
|
|
6732
7875
|
this.worker.onmessage = (me) => {
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
7876
|
+
if (me.data.linLevelBuffers) {
|
|
7877
|
+
let linLevelArrs = new Array(chs);
|
|
7878
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
7879
|
+
linLevelArrs[ch] = new Float32Array(me.data.linLevelBuffers[ch]);
|
|
7880
|
+
}
|
|
7881
|
+
let bufferCount = Math.ceil(me.data.frameLength / me.data.bufferFrameLength);
|
|
7882
|
+
let framePos = 0;
|
|
7883
|
+
for (let bi = 0; bi < bufferCount; bi++) {
|
|
7884
|
+
let minLevels = new Array(chs);
|
|
7885
|
+
let maxLevels = new Array(chs);
|
|
7886
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
7887
|
+
let linLvlArrPos = bi * 2;
|
|
7888
|
+
minLevels[ch] = linLevelArrs[ch][linLvlArrPos];
|
|
7889
|
+
maxLevels[ch] = linLevelArrs[ch][linLvlArrPos + 1];
|
|
7890
|
+
}
|
|
7891
|
+
let bli = new LevelInfo(chs, framePos, me.data.bufferFrameLength, minLevels, maxLevels);
|
|
7892
|
+
bufferLevelInfos.push(bli);
|
|
7893
|
+
peakLevelInfo.merge(bli);
|
|
7894
|
+
}
|
|
7895
|
+
}
|
|
7896
|
+
if (me.data.eod === true) {
|
|
7897
|
+
// end of data, terminate worker and return result
|
|
7898
|
+
this.terminateWorker();
|
|
7899
|
+
resolve(new LevelInfos(bufferLevelInfos, peakLevelInfo));
|
|
7900
|
+
}
|
|
7901
|
+
else {
|
|
7902
|
+
let read = ais.read(audioBuffers);
|
|
6744
7903
|
for (let ch = 0; ch < chs; ch++) {
|
|
6745
|
-
let
|
|
6746
|
-
|
|
6747
|
-
maxLevels[ch] = linLevelArrs[ch][linLvlArrPos + 1];
|
|
7904
|
+
let copy = new Float32Array(audioBuffers[ch]);
|
|
7905
|
+
trBuffers[ch] = copy.buffer;
|
|
6748
7906
|
}
|
|
6749
|
-
|
|
6750
|
-
bufferLevelInfos.push(bli);
|
|
6751
|
-
peakLevelInfo.merge(bli);
|
|
7907
|
+
this.worker?.postMessage({ bufferFrameLength: bufferFrameLength, audioData: trBuffers, chs: chs, len: read }, trBuffers);
|
|
6752
7908
|
}
|
|
6753
|
-
this.terminateWorker();
|
|
6754
|
-
resolve(new LevelInfos(bufferLevelInfos, peakLevelInfo));
|
|
6755
7909
|
};
|
|
6756
|
-
|
|
7910
|
+
let read = ais.read(audioBuffers);
|
|
7911
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
7912
|
+
let copy = new Float32Array(audioBuffers[ch]);
|
|
7913
|
+
trBuffers[ch] = copy.buffer;
|
|
7914
|
+
}
|
|
7915
|
+
this.worker?.postMessage({ bufferFrameLength: bufferFrameLength, audioData: trBuffers, chs: chs, len: read }, trBuffers);
|
|
6757
7916
|
});
|
|
6758
7917
|
}
|
|
6759
7918
|
terminateWorker() {
|
|
@@ -6764,40 +7923,63 @@ class LevelMeasure {
|
|
|
6764
7923
|
*/
|
|
6765
7924
|
workerFunction() {
|
|
6766
7925
|
self.onmessage = function (msg) {
|
|
6767
|
-
let
|
|
7926
|
+
let len = msg.data.len;
|
|
6768
7927
|
let bufferFrameLength = msg.data.bufferFrameLength;
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
7928
|
+
if (len == -1) {
|
|
7929
|
+
// start
|
|
7930
|
+
postMessage({
|
|
7931
|
+
eod: false,
|
|
7932
|
+
bufferFrameLength: bufferFrameLength,
|
|
7933
|
+
frameLength: len
|
|
7934
|
+
});
|
|
6773
7935
|
}
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
7936
|
+
if (len == 0) {
|
|
7937
|
+
postMessage({
|
|
7938
|
+
eod: true,
|
|
7939
|
+
bufferFrameLength: bufferFrameLength,
|
|
7940
|
+
frameLength: len
|
|
7941
|
+
});
|
|
6778
7942
|
}
|
|
6779
|
-
|
|
7943
|
+
else {
|
|
7944
|
+
let chs = msg.data.chs;
|
|
7945
|
+
let audioData = new Array(chs);
|
|
7946
|
+
let linLevels = new Array(chs);
|
|
6780
7947
|
for (let ch = 0; ch < chs; ch++) {
|
|
6781
|
-
|
|
6782
|
-
for (let s = 0; s < frameLength; s++) {
|
|
6783
|
-
let bi = Math.floor(s / bufferFrameLength);
|
|
6784
|
-
let lvlArrPos = bi * 2;
|
|
6785
|
-
//let bs = s % bufferFrameLength;
|
|
6786
|
-
let chSample = chData[s];
|
|
6787
|
-
if (chSample < linLevels[ch][lvlArrPos]) {
|
|
6788
|
-
linLevels[ch][lvlArrPos] = chSample;
|
|
6789
|
-
}
|
|
6790
|
-
lvlArrPos++;
|
|
6791
|
-
if (chSample > linLevels[ch][lvlArrPos]) {
|
|
6792
|
-
linLevels[ch][lvlArrPos] = chSample;
|
|
6793
|
-
}
|
|
6794
|
-
}
|
|
7948
|
+
audioData[ch] = new Float32Array(msg.data.audioData[ch]);
|
|
6795
7949
|
}
|
|
6796
|
-
|
|
7950
|
+
//let frameLength = audioData[0].length;
|
|
7951
|
+
let bufferCount = Math.ceil(len / bufferFrameLength);
|
|
6797
7952
|
for (let ch = 0; ch < chs; ch++) {
|
|
6798
|
-
|
|
7953
|
+
linLevels[ch] = new Float32Array(bufferCount * 2);
|
|
7954
|
+
}
|
|
7955
|
+
if (audioData && chs > 0) {
|
|
7956
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
7957
|
+
let chData = audioData[ch];
|
|
7958
|
+
for (let s = 0; s < len; s++) {
|
|
7959
|
+
let bi = Math.floor(s / bufferFrameLength);
|
|
7960
|
+
let lvlArrPos = bi * 2;
|
|
7961
|
+
//let bs = s % bufferFrameLength;
|
|
7962
|
+
let chSample = chData[s];
|
|
7963
|
+
if (chSample < linLevels[ch][lvlArrPos]) {
|
|
7964
|
+
linLevels[ch][lvlArrPos] = chSample;
|
|
7965
|
+
}
|
|
7966
|
+
lvlArrPos++;
|
|
7967
|
+
if (chSample > linLevels[ch][lvlArrPos]) {
|
|
7968
|
+
linLevels[ch][lvlArrPos] = chSample;
|
|
7969
|
+
}
|
|
7970
|
+
}
|
|
7971
|
+
}
|
|
7972
|
+
const linLevelBufs = new Array(chs);
|
|
7973
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
7974
|
+
linLevelBufs[ch] = linLevels[ch].buffer;
|
|
7975
|
+
}
|
|
7976
|
+
postMessage({
|
|
7977
|
+
eod: false,
|
|
7978
|
+
bufferFrameLength: bufferFrameLength,
|
|
7979
|
+
frameLength: len,
|
|
7980
|
+
linLevelBuffers: linLevelBufs
|
|
7981
|
+
}, linLevelBufs);
|
|
6799
7982
|
}
|
|
6800
|
-
postMessage({ bufferFrameLength: bufferFrameLength, frameLength: frameLength, linLevelBuffers: linLevelBufs }, linLevelBufs);
|
|
6801
7983
|
}
|
|
6802
7984
|
};
|
|
6803
7985
|
}
|
|
@@ -7169,7 +8351,7 @@ RecordingItemDisplay.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", v
|
|
|
7169
8351
|
<audio-levelbar fxFlex="1 0 1" [streamingMode]="streamingMode" [displayLevelInfos]="_displayLevelInfos"></audio-levelbar>
|
|
7170
8352
|
<spr-recordingitemcontrols fxFlex="0 0 0" [audioLoaded]="displayAudioBuffer!==null" [playStartAction]="playStartAction" [playStopAction]="playStopAction" [peakDbLvl]="peakDbLvl" [agc]="_agc" (onShowRecordingDetails)="onShowRecordingDetails.emit()"></spr-recordingitemcontrols>
|
|
7171
8353
|
</div>
|
|
7172
|
-
`, isInline: true, styles: ["div{width:100%;background:darkgray;padding:4px;box-sizing:border-box;flex-wrap:nowrap}\n", "audio-levelbar{box-sizing:border-box}\n"], components: [{ type: LevelBar, selector: "audio-levelbar", inputs: ["streamingMode", "displayLevelInfos"] }, { type: RecordingItemControls, selector: "spr-recordingitemcontrols", inputs: ["audioSignalCollapsed", "enableDownload", "peakDbLvl", "agc", "audioLoaded", "playStartAction", "playStopAction", "displayLevelInfos"], outputs: ["onShowRecordingDetails", "onDownloadRecording"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i3$1.DefaultStyleDirective, selector: " [ngStyle], [ngStyle.xs], [ngStyle.sm], [ngStyle.md], [ngStyle.lg], [ngStyle.xl], [ngStyle.lt-sm], [ngStyle.lt-md], [ngStyle.lt-lg], [ngStyle.lt-xl], [ngStyle.gt-xs], [ngStyle.gt-sm], [ngStyle.gt-md], [ngStyle.gt-lg]", inputs: ["ngStyle", "ngStyle.xs", "ngStyle.sm", "ngStyle.md", "ngStyle.lg", "ngStyle.xl", "ngStyle.lt-sm", "ngStyle.lt-md", "ngStyle.lt-lg", "ngStyle.lt-xl", "ngStyle.gt-xs", "ngStyle.gt-sm", "ngStyle.gt-md", "ngStyle.gt-lg"] }, { type: i4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }] });
|
|
8354
|
+
`, isInline: true, styles: ["div{width:100%;background:darkgray;padding:4px;box-sizing:border-box;flex-wrap:nowrap}\n", "audio-levelbar{box-sizing:border-box}\n"], components: [{ type: LevelBar, selector: "audio-levelbar", inputs: ["streamingMode", "displayLevelInfos", "stateLoading"] }, { type: RecordingItemControls, selector: "spr-recordingitemcontrols", inputs: ["audioSignalCollapsed", "enableDownload", "peakDbLvl", "agc", "audioLoaded", "playStartAction", "playStopAction", "displayLevelInfos"], outputs: ["onShowRecordingDetails", "onDownloadRecording"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i3$1.DefaultStyleDirective, selector: " [ngStyle], [ngStyle.xs], [ngStyle.sm], [ngStyle.md], [ngStyle.lg], [ngStyle.xl], [ngStyle.lt-sm], [ngStyle.lt-md], [ngStyle.lt-lg], [ngStyle.lt-xl], [ngStyle.gt-xs], [ngStyle.gt-sm], [ngStyle.gt-md], [ngStyle.gt-lg]", inputs: ["ngStyle", "ngStyle.xs", "ngStyle.sm", "ngStyle.md", "ngStyle.lg", "ngStyle.xl", "ngStyle.lt-sm", "ngStyle.lt-md", "ngStyle.lt-lg", "ngStyle.lt-xl", "ngStyle.gt-xs", "ngStyle.gt-sm", "ngStyle.gt-md", "ngStyle.gt-lg"] }, { type: i4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }] });
|
|
7173
8355
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: RecordingItemDisplay, decorators: [{
|
|
7174
8356
|
type: Component,
|
|
7175
8357
|
args: [{
|
|
@@ -7215,89 +8397,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
7215
8397
|
type: Input
|
|
7216
8398
|
}] } });
|
|
7217
8399
|
|
|
7218
|
-
class Float32ArrayChunkerOutStream {
|
|
7219
|
-
constructor(outStream) {
|
|
7220
|
-
this.outStream = outStream;
|
|
7221
|
-
this.bufs = new Array();
|
|
7222
|
-
this._channels = 0;
|
|
7223
|
-
this._chunkSize = 0;
|
|
7224
|
-
this.filled = 0;
|
|
7225
|
-
this.receivedFrames = 0;
|
|
7226
|
-
this.sentFrames = 0;
|
|
7227
|
-
}
|
|
7228
|
-
createBuffers() {
|
|
7229
|
-
this.bufs = new Array(this._channels);
|
|
7230
|
-
for (let ch = 0; ch < this._channels; ch++) {
|
|
7231
|
-
this.bufs[ch] = new Float32Array(this._chunkSize);
|
|
7232
|
-
}
|
|
7233
|
-
}
|
|
7234
|
-
set chunkSize(chunkSize) {
|
|
7235
|
-
this._chunkSize = chunkSize;
|
|
7236
|
-
this.createBuffers();
|
|
7237
|
-
}
|
|
7238
|
-
get chunkSize() {
|
|
7239
|
-
return this._chunkSize;
|
|
7240
|
-
}
|
|
7241
|
-
set channels(channels) {
|
|
7242
|
-
this._channels = channels;
|
|
7243
|
-
this.createBuffers();
|
|
7244
|
-
}
|
|
7245
|
-
get channels() {
|
|
7246
|
-
return this._channels;
|
|
7247
|
-
}
|
|
7248
|
-
available() {
|
|
7249
|
-
return this._chunkSize - this.filled;
|
|
7250
|
-
}
|
|
7251
|
-
write(buffers) {
|
|
7252
|
-
let copied = 0;
|
|
7253
|
-
if (buffers.length > 0) {
|
|
7254
|
-
let buffersLen = buffers[0].length;
|
|
7255
|
-
this.receivedFrames += buffersLen;
|
|
7256
|
-
let avail = buffersLen;
|
|
7257
|
-
// Fill out buffers until all values copied
|
|
7258
|
-
while (avail > 0) {
|
|
7259
|
-
let toFill = this._chunkSize - this.filled;
|
|
7260
|
-
if (toFill > avail) {
|
|
7261
|
-
toFill = avail;
|
|
7262
|
-
}
|
|
7263
|
-
let sliceEnd = copied + toFill;
|
|
7264
|
-
// Firefox on Android sends only the first channel
|
|
7265
|
-
for (let ch = 0; ch < buffersLen; ch++) {
|
|
7266
|
-
if (buffers[ch]) {
|
|
7267
|
-
let cpPrt = buffers[ch].slice(copied, sliceEnd);
|
|
7268
|
-
let buf = this.bufs[ch];
|
|
7269
|
-
buf.set(cpPrt, this.filled);
|
|
7270
|
-
}
|
|
7271
|
-
}
|
|
7272
|
-
copied += toFill;
|
|
7273
|
-
avail -= toFill;
|
|
7274
|
-
this.filled += toFill;
|
|
7275
|
-
if (this.filled == this._chunkSize) {
|
|
7276
|
-
this.outStream.write(this.bufs);
|
|
7277
|
-
this.sentFrames += this.filled;
|
|
7278
|
-
this.filled = 0;
|
|
7279
|
-
}
|
|
7280
|
-
}
|
|
7281
|
-
}
|
|
7282
|
-
return copied;
|
|
7283
|
-
}
|
|
7284
|
-
flush() {
|
|
7285
|
-
if (this.filled > 0) {
|
|
7286
|
-
let restBufs = new Array(this._channels);
|
|
7287
|
-
for (let ch = 0; ch < this._channels; ch++) {
|
|
7288
|
-
restBufs[ch] = this.bufs[ch].slice(0, this.filled);
|
|
7289
|
-
}
|
|
7290
|
-
this.outStream.write(restBufs);
|
|
7291
|
-
this.outStream.flush();
|
|
7292
|
-
this.sentFrames += this.filled;
|
|
7293
|
-
this.filled = 0;
|
|
7294
|
-
}
|
|
7295
|
-
}
|
|
7296
|
-
close() {
|
|
7297
|
-
this.outStream.close();
|
|
7298
|
-
}
|
|
7299
|
-
}
|
|
7300
|
-
|
|
7301
8400
|
class SequenceAudioFloat32ChunkerOutStream extends Float32ArrayChunkerOutStream {
|
|
7302
8401
|
constructor(outStream, chunkDurationSeconds) {
|
|
7303
8402
|
super(outStream);
|
|
@@ -7306,11 +8405,11 @@ class SequenceAudioFloat32ChunkerOutStream extends Float32ArrayChunkerOutStream
|
|
|
7306
8405
|
this.sequenceAudioFloat32OutStream = outStream;
|
|
7307
8406
|
}
|
|
7308
8407
|
setFormat(channels, sampleRate) {
|
|
7309
|
-
console.debug("SequenceAudioFloat32ChunkerOutStream:setFormat(channels: "
|
|
8408
|
+
//console.debug("SequenceAudioFloat32ChunkerOutStream:setFormat(channels: "+channels+",sampleRate: "+sampleRate+")")
|
|
7310
8409
|
this.channels = channels;
|
|
7311
8410
|
this.sampleRate = sampleRate;
|
|
7312
8411
|
this.chunkSize = Math.round(sampleRate * this.chunkDurationSeconds);
|
|
7313
|
-
console.debug("SequenceAudioFloat32ChunkerOutStream: chunkSize: "
|
|
8412
|
+
//console.debug("SequenceAudioFloat32ChunkerOutStream: chunkSize: "+this.chunkSize);
|
|
7314
8413
|
this.sequenceAudioFloat32OutStream.setFormat(channels, sampleRate);
|
|
7315
8414
|
}
|
|
7316
8415
|
nextStream() {
|
|
@@ -7516,7 +8615,8 @@ class ChunkManager {
|
|
|
7516
8615
|
}
|
|
7517
8616
|
}
|
|
7518
8617
|
let BasicRecorder = class BasicRecorder {
|
|
7519
|
-
constructor(dialog, sessionService, uploader, config) {
|
|
8618
|
+
constructor(changeDetectorRef, dialog, sessionService, uploader, config) {
|
|
8619
|
+
this.changeDetectorRef = changeDetectorRef;
|
|
7520
8620
|
this.dialog = dialog;
|
|
7521
8621
|
this.sessionService = sessionService;
|
|
7522
8622
|
this.uploader = uploader;
|
|
@@ -7531,6 +8631,7 @@ let BasicRecorder = class BasicRecorder {
|
|
|
7531
8631
|
this._selectedDeviceId = undefined;
|
|
7532
8632
|
this._channelCount = 2;
|
|
7533
8633
|
this._session = null;
|
|
8634
|
+
this._recordingFile = null;
|
|
7534
8635
|
this.startedDate = null;
|
|
7535
8636
|
this.uploadProgress = 100;
|
|
7536
8637
|
this.uploadStatus = 'ok';
|
|
@@ -7538,6 +8639,7 @@ let BasicRecorder = class BasicRecorder {
|
|
|
7538
8639
|
this.peakLevelInDb = MIN_DB_LEVEL;
|
|
7539
8640
|
this.displayAudioClip = null;
|
|
7540
8641
|
this.audioFetchSubscription = null;
|
|
8642
|
+
this.audioFetching = false;
|
|
7541
8643
|
this.destroyed = false;
|
|
7542
8644
|
this.navigationDisabled = true;
|
|
7543
8645
|
// Default: Disabled chunked upload
|
|
@@ -7631,6 +8733,28 @@ let BasicRecorder = class BasicRecorder {
|
|
|
7631
8733
|
this.ac.audioOutStream = outStream;
|
|
7632
8734
|
}
|
|
7633
8735
|
}
|
|
8736
|
+
showRecording() {
|
|
8737
|
+
this._controlAudioPlayer.stop();
|
|
8738
|
+
if (this.displayAudioClip) {
|
|
8739
|
+
let dap = this.displayAudioClip;
|
|
8740
|
+
let adh = dap.audioDataHolder;
|
|
8741
|
+
if (adh) {
|
|
8742
|
+
this.levelMeasure.calcBufferLevelInfos(adh, LEVEL_BAR_INTERVALL_SECONDS).then((levelInfos) => {
|
|
8743
|
+
dap.levelInfos = levelInfos;
|
|
8744
|
+
this.changeDetectorRef.detectChanges();
|
|
8745
|
+
});
|
|
8746
|
+
}
|
|
8747
|
+
this.playStartAction.disabled = false;
|
|
8748
|
+
}
|
|
8749
|
+
else {
|
|
8750
|
+
this.playStartAction.disabled = true;
|
|
8751
|
+
// Collapse audio signal display if open
|
|
8752
|
+
if (!this.audioSignalCollapsed) {
|
|
8753
|
+
this.audioSignalCollapsed = true;
|
|
8754
|
+
}
|
|
8755
|
+
}
|
|
8756
|
+
this.changeDetectorRef.detectChanges();
|
|
8757
|
+
}
|
|
7634
8758
|
start() {
|
|
7635
8759
|
this.statusAlertType = 'info';
|
|
7636
8760
|
this.statusMsg = 'Starting session...';
|
|
@@ -7851,9 +8975,9 @@ let BasicRecorder = class BasicRecorder {
|
|
|
7851
8975
|
}
|
|
7852
8976
|
this.transportActions.startAction.disabled = true;
|
|
7853
8977
|
}
|
|
7854
|
-
postRecording(wavFile, recUrl) {
|
|
8978
|
+
postRecording(wavFile, recUrl, rf) {
|
|
7855
8979
|
let wavBlob = new Blob([wavFile], { type: 'audio/wav' });
|
|
7856
|
-
let ul = new Upload(wavBlob, recUrl);
|
|
8980
|
+
let ul = new Upload(wavBlob, recUrl, rf);
|
|
7857
8981
|
this.uploader.queueUpload(ul);
|
|
7858
8982
|
}
|
|
7859
8983
|
postAudioStreamStart() {
|
|
@@ -7881,48 +9005,340 @@ let BasicRecorder = class BasicRecorder {
|
|
|
7881
9005
|
console.error("Recording file UUID not set!");
|
|
7882
9006
|
}
|
|
7883
9007
|
}
|
|
7884
|
-
postAudioStreamEnd(chunkCount) {
|
|
7885
|
-
if (this.rfUuid) {
|
|
7886
|
-
let apiEndPoint = '';
|
|
7887
|
-
if (this.config && this.config.apiEndPoint) {
|
|
7888
|
-
apiEndPoint = this.config.apiEndPoint;
|
|
9008
|
+
postAudioStreamEnd(chunkCount) {
|
|
9009
|
+
if (this.rfUuid) {
|
|
9010
|
+
let apiEndPoint = '';
|
|
9011
|
+
if (this.config && this.config.apiEndPoint) {
|
|
9012
|
+
apiEndPoint = this.config.apiEndPoint;
|
|
9013
|
+
}
|
|
9014
|
+
if (apiEndPoint !== '') {
|
|
9015
|
+
apiEndPoint = apiEndPoint + '/';
|
|
9016
|
+
}
|
|
9017
|
+
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
9018
|
+
let recUrl = sessionsUrl + '/' + this.session?.sessionId + '/' + RECFILE_API_CTX + '/' + this.rfUuid + '/concatChunksRequest';
|
|
9019
|
+
let fd = new FormData();
|
|
9020
|
+
fd.set('uuid', this.rfUuid);
|
|
9021
|
+
fd.set('chunkCount', chunkCount.toString());
|
|
9022
|
+
let ul = new Upload(fd, recUrl, this._recordingFile);
|
|
9023
|
+
this.uploader.queueUpload(ul);
|
|
9024
|
+
console.debug("Queued for upload: " + this._recordingFile);
|
|
9025
|
+
}
|
|
9026
|
+
else {
|
|
9027
|
+
console.error("Recording file UUID not set!");
|
|
9028
|
+
}
|
|
9029
|
+
}
|
|
9030
|
+
closed() {
|
|
9031
|
+
this.statusAlertType = 'info';
|
|
9032
|
+
this.statusMsg = 'Session closed.';
|
|
9033
|
+
}
|
|
9034
|
+
error(msg = 'An unknown error occured during recording.', advice = 'Please retry.') {
|
|
9035
|
+
this.statusMsg = 'ERROR: Recording.';
|
|
9036
|
+
this.statusAlertType = 'error';
|
|
9037
|
+
this.dialog.open(MessageDialog, {
|
|
9038
|
+
data: {
|
|
9039
|
+
type: 'error',
|
|
9040
|
+
title: 'Recording error',
|
|
9041
|
+
msg: msg,
|
|
9042
|
+
advice: advice
|
|
9043
|
+
}
|
|
9044
|
+
});
|
|
9045
|
+
}
|
|
9046
|
+
};
|
|
9047
|
+
// Enable only for developemnt/debug purposes of array audio buffers !!
|
|
9048
|
+
BasicRecorder.FORCE_ARRRAY_AUDIO_BUFFER = false;
|
|
9049
|
+
BasicRecorder.DEFAULT_CHUNK_SIZE_SECONDS = 30;
|
|
9050
|
+
BasicRecorder = __decorate([
|
|
9051
|
+
__param(4, Inject(SPEECHRECORDER_CONFIG))
|
|
9052
|
+
], BasicRecorder);
|
|
9053
|
+
|
|
9054
|
+
class AudioDataHolder {
|
|
9055
|
+
constructor(_buffer, _arrayBuffer = null) {
|
|
9056
|
+
this._buffer = _buffer;
|
|
9057
|
+
this._arrayBuffer = _arrayBuffer;
|
|
9058
|
+
this._numberOfChannels = 0;
|
|
9059
|
+
this._sampleRate = 0;
|
|
9060
|
+
this._frameLen = 0;
|
|
9061
|
+
this._duration = 0;
|
|
9062
|
+
if (this._buffer && this._arrayBuffer) {
|
|
9063
|
+
throw Error('Only one of either audio buffer or array audio buffer must be set!');
|
|
9064
|
+
}
|
|
9065
|
+
if (this._buffer || this._arrayBuffer) {
|
|
9066
|
+
if (this._buffer) {
|
|
9067
|
+
this._numberOfChannels = this._buffer.numberOfChannels;
|
|
9068
|
+
this._sampleRate = this._buffer.sampleRate;
|
|
9069
|
+
this._frameLen = this._buffer.length;
|
|
9070
|
+
this._duration = this._frameLen / this._sampleRate;
|
|
9071
|
+
}
|
|
9072
|
+
else if (this._arrayBuffer) {
|
|
9073
|
+
this._numberOfChannels = this._arrayBuffer.channelCount;
|
|
9074
|
+
this._sampleRate = this._arrayBuffer.sampleRate;
|
|
9075
|
+
this._frameLen = this._arrayBuffer.frameLen;
|
|
9076
|
+
this._duration = this._frameLen / this._sampleRate;
|
|
9077
|
+
}
|
|
9078
|
+
}
|
|
9079
|
+
else {
|
|
9080
|
+
throw Error(AudioDataHolder.ONE_OF_MUST_BE_SET_ERR_MSG);
|
|
9081
|
+
}
|
|
9082
|
+
}
|
|
9083
|
+
get duration() {
|
|
9084
|
+
return this._duration;
|
|
9085
|
+
}
|
|
9086
|
+
get sampleRate() {
|
|
9087
|
+
return this._sampleRate;
|
|
9088
|
+
}
|
|
9089
|
+
get numberOfChannels() {
|
|
9090
|
+
return this._numberOfChannels;
|
|
9091
|
+
}
|
|
9092
|
+
get frameLen() {
|
|
9093
|
+
return this._frameLen;
|
|
9094
|
+
}
|
|
9095
|
+
sampleCounts() {
|
|
9096
|
+
return this._numberOfChannels * this._frameLen;
|
|
9097
|
+
}
|
|
9098
|
+
frames(framePos, frameLen, bufs) {
|
|
9099
|
+
let read = 0;
|
|
9100
|
+
if (this._buffer) {
|
|
9101
|
+
let toRead = frameLen;
|
|
9102
|
+
if (this._buffer.length < framePos + frameLen) {
|
|
9103
|
+
toRead = this._buffer.length - framePos;
|
|
9104
|
+
}
|
|
9105
|
+
for (let ch = 0; ch < bufs.length; ch++) {
|
|
9106
|
+
let chData = this._buffer.getChannelData(ch);
|
|
9107
|
+
for (let i = 0; i < toRead; i++) {
|
|
9108
|
+
bufs[ch][i] = chData[framePos + i];
|
|
9109
|
+
}
|
|
9110
|
+
}
|
|
9111
|
+
read = toRead;
|
|
9112
|
+
}
|
|
9113
|
+
else if (this._arrayBuffer) {
|
|
9114
|
+
read = this._arrayBuffer.frames(framePos, frameLen, bufs);
|
|
9115
|
+
}
|
|
9116
|
+
return read;
|
|
9117
|
+
}
|
|
9118
|
+
audioInputStream() {
|
|
9119
|
+
if (this._buffer) {
|
|
9120
|
+
return new AudioBufferInputStream(this._buffer);
|
|
9121
|
+
}
|
|
9122
|
+
if (this._arrayBuffer) {
|
|
9123
|
+
return new ArrayAudioBufferInputStream(this._arrayBuffer);
|
|
9124
|
+
}
|
|
9125
|
+
throw Error(AudioDataHolder.ONE_OF_MUST_BE_SET_ERR_MSG);
|
|
9126
|
+
}
|
|
9127
|
+
get buffer() {
|
|
9128
|
+
return this._buffer;
|
|
9129
|
+
}
|
|
9130
|
+
get arrayBuffer() {
|
|
9131
|
+
return this._arrayBuffer;
|
|
9132
|
+
}
|
|
9133
|
+
}
|
|
9134
|
+
AudioDataHolder.ONE_OF_MUST_BE_SET_ERR_MSG = 'One of either audio buffer or array audio buffer must be set!';
|
|
9135
|
+
class AudioBufferInputStream {
|
|
9136
|
+
constructor(audioBuffer) {
|
|
9137
|
+
this.audioBuffer = audioBuffer;
|
|
9138
|
+
this.framePos = 0;
|
|
9139
|
+
}
|
|
9140
|
+
close() {
|
|
9141
|
+
}
|
|
9142
|
+
skipFrames(n) {
|
|
9143
|
+
this.framePos += n;
|
|
9144
|
+
}
|
|
9145
|
+
read(buffers) {
|
|
9146
|
+
let read = 0;
|
|
9147
|
+
let toRead = buffers[0].length;
|
|
9148
|
+
if (this.framePos + toRead > this.audioBuffer.length) {
|
|
9149
|
+
toRead = this.audioBuffer.length - this.framePos;
|
|
9150
|
+
}
|
|
9151
|
+
for (let ch = 0; ch < buffers.length; ch++) {
|
|
9152
|
+
for (let i = 0; i < toRead; i++) {
|
|
9153
|
+
buffers[ch][i] = this.audioBuffer.getChannelData(ch)[this.framePos + i];
|
|
9154
|
+
}
|
|
9155
|
+
}
|
|
9156
|
+
read = toRead;
|
|
9157
|
+
this.framePos += toRead;
|
|
9158
|
+
return read;
|
|
9159
|
+
}
|
|
9160
|
+
}
|
|
9161
|
+
|
|
9162
|
+
class BasicRecFilesCache {
|
|
9163
|
+
constructor() {
|
|
9164
|
+
//public static readonly DEFAULT_MAX_SAMPLES=30*48000; // TEST 30 seconds
|
|
9165
|
+
this._sampleCount = 0;
|
|
9166
|
+
this.maxSampleCount = SprItemsCache.DEFAULT_MAX_SAMPLES;
|
|
9167
|
+
this.currentRecordingFile = null;
|
|
9168
|
+
}
|
|
9169
|
+
}
|
|
9170
|
+
BasicRecFilesCache.DEBUG = false;
|
|
9171
|
+
BasicRecFilesCache.DEFAULT_MAX_SAMPLES = 10 * 60 * 48000; // 20 Minutes mono 48kHz
|
|
9172
|
+
class SprItemsCache extends BasicRecFilesCache {
|
|
9173
|
+
constructor() {
|
|
9174
|
+
super(...arguments);
|
|
9175
|
+
this._items = new Array();
|
|
9176
|
+
}
|
|
9177
|
+
get items() {
|
|
9178
|
+
return this._items;
|
|
9179
|
+
}
|
|
9180
|
+
addItem(item) {
|
|
9181
|
+
this._items.push(item);
|
|
9182
|
+
}
|
|
9183
|
+
getItem(index) {
|
|
9184
|
+
return this._items[index];
|
|
9185
|
+
}
|
|
9186
|
+
length() {
|
|
9187
|
+
return this._items.length;
|
|
9188
|
+
}
|
|
9189
|
+
tryExpire(toBeExpiredRf) {
|
|
9190
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9191
|
+
console.debug("Rec. files cache: " + toBeExpiredRf.toString() + " try expire:");
|
|
9192
|
+
if (!toBeExpiredRf.equals(this.currentRecordingFile)) {
|
|
9193
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9194
|
+
console.debug("Rec. files cache: " + toBeExpiredRf.toString() + " not current file...");
|
|
9195
|
+
if (toBeExpiredRf.serverPersisted) {
|
|
9196
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9197
|
+
console.debug("Rec. files cache: " + toBeExpiredRf.toString() + " is server persisted...");
|
|
9198
|
+
// expire recording files first stored to the cache
|
|
9199
|
+
let expiredAudio = RecordingFileUtils.expireAudioData(toBeExpiredRf);
|
|
9200
|
+
if (expiredAudio) {
|
|
9201
|
+
this._sampleCount -= expiredAudio.sampleCounts();
|
|
9202
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9203
|
+
console.debug("Rec. files cache: Expired: " + toBeExpiredRf.toString() + ". Cache samples now: " + this._sampleCount);
|
|
9204
|
+
}
|
|
7889
9205
|
}
|
|
7890
|
-
|
|
7891
|
-
|
|
9206
|
+
else {
|
|
9207
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9208
|
+
console.debug("Rec. files cache: #" + toBeExpiredRf.toString() + " not yet persisted on server.");
|
|
7892
9209
|
}
|
|
7893
|
-
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
7894
|
-
let recUrl = sessionsUrl + '/' + this.session?.sessionId + '/' + RECFILE_API_CTX + '/' + this.rfUuid + '/concatChunksRequest';
|
|
7895
|
-
let fd = new FormData();
|
|
7896
|
-
fd.set('uuid', this.rfUuid);
|
|
7897
|
-
fd.set('chunkCount', chunkCount.toString());
|
|
7898
|
-
let ul = new Upload(fd, recUrl);
|
|
7899
|
-
this.uploader.queueUpload(ul);
|
|
7900
9210
|
}
|
|
7901
9211
|
else {
|
|
7902
|
-
|
|
9212
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9213
|
+
console.debug("Rec. files cache: " + toBeExpiredRf.toString() + " is current file.");
|
|
9214
|
+
}
|
|
9215
|
+
}
|
|
9216
|
+
expire() {
|
|
9217
|
+
// expire corrected versions first
|
|
9218
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9219
|
+
console.debug("Rec. files cache: Expire? current: " + this._sampleCount + ", max: " + this.maxSampleCount);
|
|
9220
|
+
if (this._sampleCount > this.maxSampleCount) {
|
|
9221
|
+
// expire older versions of an item first
|
|
9222
|
+
for (let ii = 0; ii < this._items.length; ii++) {
|
|
9223
|
+
if (this._sampleCount <= this.maxSampleCount) {
|
|
9224
|
+
break;
|
|
9225
|
+
}
|
|
9226
|
+
let it = this._items[ii];
|
|
9227
|
+
let itRfs = it.recs;
|
|
9228
|
+
if (itRfs && itRfs.length > 1) {
|
|
9229
|
+
for (let rfi = 0; rfi < itRfs.length - 1; rfi++) {
|
|
9230
|
+
if (this._sampleCount <= this.maxSampleCount) {
|
|
9231
|
+
break;
|
|
9232
|
+
}
|
|
9233
|
+
let toBeExpiredRf = itRfs[rfi];
|
|
9234
|
+
this.tryExpire(toBeExpiredRf);
|
|
9235
|
+
}
|
|
9236
|
+
}
|
|
9237
|
+
}
|
|
9238
|
+
// if that's not sufficient expire audio data of latest versions as well
|
|
9239
|
+
for (let ii = 0; ii < this._items.length; ii++) {
|
|
9240
|
+
if (this._sampleCount <= this.maxSampleCount) {
|
|
9241
|
+
break;
|
|
9242
|
+
}
|
|
9243
|
+
let it = this._items[ii];
|
|
9244
|
+
let itRfs = it.recs;
|
|
9245
|
+
if (itRfs && itRfs.length > 0) {
|
|
9246
|
+
for (let rfi = 0; rfi < itRfs.length; rfi++) {
|
|
9247
|
+
if (this._sampleCount <= this.maxSampleCount) {
|
|
9248
|
+
break;
|
|
9249
|
+
}
|
|
9250
|
+
let toBeExpiredRf = itRfs[rfi];
|
|
9251
|
+
this.tryExpire(toBeExpiredRf);
|
|
9252
|
+
}
|
|
9253
|
+
}
|
|
9254
|
+
}
|
|
7903
9255
|
}
|
|
7904
9256
|
}
|
|
7905
|
-
|
|
7906
|
-
this.
|
|
7907
|
-
|
|
9257
|
+
addSprRecFile(item, sprRecFile) {
|
|
9258
|
+
this.expire();
|
|
9259
|
+
if (!item.recs) {
|
|
9260
|
+
item.recs = new Array();
|
|
9261
|
+
}
|
|
9262
|
+
item.recs.push(sprRecFile);
|
|
9263
|
+
this._sampleCount += RecordingFileUtils.sampleCount(sprRecFile);
|
|
9264
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9265
|
+
console.debug("Rec. files cache: Added. Cache samples: " + this._sampleCount);
|
|
7908
9266
|
}
|
|
7909
|
-
|
|
7910
|
-
this.
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
9267
|
+
setSprRecFileAudioData(sprRecFile, adh) {
|
|
9268
|
+
this.expire();
|
|
9269
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9270
|
+
console.debug("Rec. files cache: Set audio data after expire. Cache samples: " + this._sampleCount);
|
|
9271
|
+
let currSampleCnt = RecordingFileUtils.sampleCount(sprRecFile);
|
|
9272
|
+
this._sampleCount -= currSampleCnt;
|
|
9273
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9274
|
+
console.debug("Rec. files cache: Set audio data subtracted curr sample count: " + currSampleCnt + ". Cache samples: " + this._sampleCount);
|
|
9275
|
+
RecordingFileUtils.setAudioData(sprRecFile, adh);
|
|
9276
|
+
let newSampleCnt = RecordingFileUtils.sampleCount(sprRecFile);
|
|
9277
|
+
this._sampleCount += newSampleCnt;
|
|
9278
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9279
|
+
console.debug("Rec. files cache: Set audio data added new sample count: " + newSampleCnt + ". Cache samples: " + this._sampleCount);
|
|
9280
|
+
let fl = adh?.frameLen;
|
|
9281
|
+
if (fl) {
|
|
9282
|
+
sprRecFile.frames = fl;
|
|
9283
|
+
}
|
|
9284
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9285
|
+
console.debug("Rec. files cache: Set audio data. Cache samples: " + this._sampleCount);
|
|
9286
|
+
}
|
|
9287
|
+
}
|
|
9288
|
+
class RecFilesCache extends BasicRecFilesCache {
|
|
9289
|
+
constructor() {
|
|
9290
|
+
super(...arguments);
|
|
9291
|
+
this._recFiles = new Array();
|
|
9292
|
+
}
|
|
9293
|
+
get recFiles() {
|
|
9294
|
+
return this._recFiles;
|
|
9295
|
+
}
|
|
9296
|
+
getRecFile(index) {
|
|
9297
|
+
return this._recFiles[index];
|
|
9298
|
+
}
|
|
9299
|
+
length() {
|
|
9300
|
+
return this._recFiles.length;
|
|
9301
|
+
}
|
|
9302
|
+
expire() {
|
|
9303
|
+
if (this._sampleCount > this.maxSampleCount) {
|
|
9304
|
+
// audio recorder list is sorted: lower index is newer
|
|
9305
|
+
for (let rfI = this._recFiles.length - 1; rfI >= 0; rfI--) {
|
|
9306
|
+
if (this._sampleCount <= this.maxSampleCount) {
|
|
9307
|
+
break;
|
|
9308
|
+
}
|
|
9309
|
+
let toBeExpiredRf = this._recFiles[rfI];
|
|
9310
|
+
if (toBeExpiredRf.serverPersisted) {
|
|
9311
|
+
// expire recording files first stored to the cache
|
|
9312
|
+
let expiredAudio = RecordingFileUtils.expireAudioData(toBeExpiredRf);
|
|
9313
|
+
if (expiredAudio) {
|
|
9314
|
+
this._sampleCount -= expiredAudio.sampleCounts();
|
|
9315
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9316
|
+
console.debug("Rec. files cache: Expired #" + rfI + ". Cache samples: " + this._sampleCount);
|
|
9317
|
+
}
|
|
9318
|
+
}
|
|
9319
|
+
else {
|
|
9320
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9321
|
+
console.debug("Rec. files cache: #" + rfI + " not yet server persisted.");
|
|
9322
|
+
}
|
|
7918
9323
|
}
|
|
7919
|
-
}
|
|
9324
|
+
}
|
|
7920
9325
|
}
|
|
7921
|
-
|
|
7922
|
-
|
|
7923
|
-
|
|
7924
|
-
|
|
7925
|
-
|
|
9326
|
+
addRecFile(recFile) {
|
|
9327
|
+
this.expire();
|
|
9328
|
+
this._recFiles.push(recFile);
|
|
9329
|
+
this._sampleCount += RecordingFileUtils.sampleCount(recFile);
|
|
9330
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9331
|
+
console.debug("Rec. files cache: Added. Cache samples: " + this._sampleCount);
|
|
9332
|
+
}
|
|
9333
|
+
setRecFileAudioData(recFile, adh) {
|
|
9334
|
+
this.expire();
|
|
9335
|
+
this._sampleCount -= RecordingFileUtils.sampleCount(recFile);
|
|
9336
|
+
RecordingFileUtils.setAudioData(recFile, adh);
|
|
9337
|
+
this._sampleCount += RecordingFileUtils.sampleCount(recFile);
|
|
9338
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9339
|
+
console.debug("Rec. files cache: Set audio data. Cache samples: " + this._sampleCount);
|
|
9340
|
+
}
|
|
9341
|
+
}
|
|
7926
9342
|
|
|
7927
9343
|
/**
|
|
7928
9344
|
* Created by klausj on 17.06.2017.
|
|
@@ -8015,16 +9431,65 @@ class RecordingService {
|
|
|
8015
9431
|
let recUrl = recFilesUrl + '/' + encItemcode + '/' + version;
|
|
8016
9432
|
return this.audioRequest(recUrl);
|
|
8017
9433
|
}
|
|
9434
|
+
fetchRecordingFileAudioBuffer(aCtx, projectName, recordingFile) {
|
|
9435
|
+
let wobs = new Observable(observer => {
|
|
9436
|
+
let recFileId = recordingFile.recordingFileId;
|
|
9437
|
+
if (!recFileId) {
|
|
9438
|
+
recFileId = recordingFile.uuid;
|
|
9439
|
+
}
|
|
9440
|
+
if (recordingFile.session && recFileId) {
|
|
9441
|
+
let obs = this.fetchAudiofile(projectName, recordingFile.session, recFileId);
|
|
9442
|
+
obs.subscribe({
|
|
9443
|
+
next: resp => {
|
|
9444
|
+
// Do not use Promise version, which does not work with Safari 13 (13.0.5)
|
|
9445
|
+
if (resp.body) {
|
|
9446
|
+
aCtx.decodeAudioData(resp.body, ab => {
|
|
9447
|
+
observer.next(ab);
|
|
9448
|
+
observer.complete();
|
|
9449
|
+
}, error => {
|
|
9450
|
+
observer.error(error);
|
|
9451
|
+
observer.complete();
|
|
9452
|
+
});
|
|
9453
|
+
}
|
|
9454
|
+
else {
|
|
9455
|
+
observer.error('Fetching audio file: response has no body');
|
|
9456
|
+
}
|
|
9457
|
+
},
|
|
9458
|
+
error: (error) => {
|
|
9459
|
+
if (error.status == 404) {
|
|
9460
|
+
// Interpret not as an error, the file ist not recorded yet
|
|
9461
|
+
observer.next(null);
|
|
9462
|
+
observer.complete();
|
|
9463
|
+
}
|
|
9464
|
+
else {
|
|
9465
|
+
// all other states are errors
|
|
9466
|
+
observer.error(error);
|
|
9467
|
+
observer.complete();
|
|
9468
|
+
}
|
|
9469
|
+
}
|
|
9470
|
+
});
|
|
9471
|
+
}
|
|
9472
|
+
else {
|
|
9473
|
+
observer.error();
|
|
9474
|
+
}
|
|
9475
|
+
});
|
|
9476
|
+
return wobs;
|
|
9477
|
+
}
|
|
8018
9478
|
fetchAndApplyRecordingFile(aCtx, projectName, recordingFile) {
|
|
8019
9479
|
let wobs = new Observable(observer => {
|
|
8020
|
-
|
|
8021
|
-
|
|
9480
|
+
let recFileId = recordingFile.recordingFileId;
|
|
9481
|
+
if (!recFileId) {
|
|
9482
|
+
recFileId = recordingFile.uuid;
|
|
9483
|
+
}
|
|
9484
|
+
if (recordingFile.session && recFileId) {
|
|
9485
|
+
let obs = this.fetchAudiofile(projectName, recordingFile.session, recFileId);
|
|
8022
9486
|
obs.subscribe(resp => {
|
|
8023
9487
|
//console.log("Fetched audio file. HTTP response status: "+resp.status+", type: "+resp.type+", byte length: "+ resp.body.byteLength);
|
|
8024
9488
|
// Do not use Promise version, which does not work with Safari 13 (13.0.5)
|
|
8025
9489
|
if (resp.body) {
|
|
8026
9490
|
aCtx.decodeAudioData(resp.body, ab => {
|
|
8027
|
-
|
|
9491
|
+
let adh = new AudioDataHolder(ab, null);
|
|
9492
|
+
RecordingFileUtils.setAudioData(recordingFile, adh);
|
|
8028
9493
|
if (this.debugDelay > 0) {
|
|
8029
9494
|
window.setTimeout(() => {
|
|
8030
9495
|
observer.next(recordingFile);
|
|
@@ -8062,6 +9527,47 @@ class RecordingService {
|
|
|
8062
9527
|
});
|
|
8063
9528
|
return wobs;
|
|
8064
9529
|
}
|
|
9530
|
+
fetchSprRecordingFileAudioBuffer(aCtx, projectName, recordingFile) {
|
|
9531
|
+
let wobs = new Observable(observer => {
|
|
9532
|
+
if (recordingFile.session) {
|
|
9533
|
+
let obs = this.fetchSprAudiofile(projectName, recordingFile.session, recordingFile.itemCode, recordingFile.version);
|
|
9534
|
+
obs.subscribe({
|
|
9535
|
+
next: resp => {
|
|
9536
|
+
// Do not use Promise version, which does not work with Safari 13 (13.0.5)
|
|
9537
|
+
if (resp.body) {
|
|
9538
|
+
aCtx.decodeAudioData(resp.body, ab => {
|
|
9539
|
+
//RecordingFileUtils.setAudioData(recordingFile,new AudioDataHolder(ab,null));
|
|
9540
|
+
observer.next(ab);
|
|
9541
|
+
observer.complete();
|
|
9542
|
+
}, error => {
|
|
9543
|
+
observer.error(error);
|
|
9544
|
+
observer.complete();
|
|
9545
|
+
});
|
|
9546
|
+
}
|
|
9547
|
+
else {
|
|
9548
|
+
observer.error('Fetching audio file: response has no body');
|
|
9549
|
+
}
|
|
9550
|
+
},
|
|
9551
|
+
error: (error) => {
|
|
9552
|
+
if (error.status == 404) {
|
|
9553
|
+
// Interpret not as an error, the file ist not recorded yet
|
|
9554
|
+
observer.next(null);
|
|
9555
|
+
observer.complete();
|
|
9556
|
+
}
|
|
9557
|
+
else {
|
|
9558
|
+
// all other states are errors
|
|
9559
|
+
observer.error(error);
|
|
9560
|
+
observer.complete();
|
|
9561
|
+
}
|
|
9562
|
+
}
|
|
9563
|
+
});
|
|
9564
|
+
}
|
|
9565
|
+
else {
|
|
9566
|
+
observer.error();
|
|
9567
|
+
}
|
|
9568
|
+
});
|
|
9569
|
+
return wobs;
|
|
9570
|
+
}
|
|
8065
9571
|
fetchAndApplySprRecordingFile(aCtx, projectName, recordingFile) {
|
|
8066
9572
|
let wobs = new Observable(observer => {
|
|
8067
9573
|
if (recordingFile.session) {
|
|
@@ -8071,7 +9577,7 @@ class RecordingService {
|
|
|
8071
9577
|
// Do not use Promise version, which does not work with Safari 13 (13.0.5)
|
|
8072
9578
|
if (resp.body) {
|
|
8073
9579
|
aCtx.decodeAudioData(resp.body, ab => {
|
|
8074
|
-
recordingFile
|
|
9580
|
+
RecordingFileUtils.setAudioData(recordingFile, new AudioDataHolder(ab, null));
|
|
8075
9581
|
if (this.debugDelay > 0) {
|
|
8076
9582
|
window.setTimeout(() => {
|
|
8077
9583
|
observer.next(recordingFile);
|
|
@@ -8116,7 +9622,8 @@ class RecordingService {
|
|
|
8116
9622
|
// Do not use Promise version, which does not work with Safari 13
|
|
8117
9623
|
if (resp.body) {
|
|
8118
9624
|
aCtx.decodeAudioData(resp.body, ab => {
|
|
8119
|
-
let
|
|
9625
|
+
let adh = new AudioDataHolder(ab, null);
|
|
9626
|
+
let rf = new SprRecordingFile(sessId, itemcode, version, adh);
|
|
8120
9627
|
if (this.debugDelay > 0) {
|
|
8121
9628
|
window.setTimeout(() => {
|
|
8122
9629
|
observer.next(rf);
|
|
@@ -8232,14 +9739,9 @@ const DEFAULT_PRE_REC_DELAY = 1000;
|
|
|
8232
9739
|
const DEFAULT_POST_REC_DELAY = 500;
|
|
8233
9740
|
class SessionManager extends BasicRecorder {
|
|
8234
9741
|
constructor(changeDetectorRef, renderer, dialog, sessionService, recFileService, uploader, config) {
|
|
8235
|
-
super(dialog, sessionService, uploader, config);
|
|
8236
|
-
this.changeDetectorRef = changeDetectorRef;
|
|
9742
|
+
super(changeDetectorRef, dialog, sessionService, uploader, config);
|
|
8237
9743
|
this.renderer = renderer;
|
|
8238
|
-
this.dialog = dialog;
|
|
8239
|
-
this.sessionService = sessionService;
|
|
8240
9744
|
this.recFileService = recFileService;
|
|
8241
|
-
this.uploader = uploader;
|
|
8242
|
-
this.config = config;
|
|
8243
9745
|
this.enableUploadRecordings = true;
|
|
8244
9746
|
this.enableDownloadRecordings = false;
|
|
8245
9747
|
this.status = 0 /* BLOCKED */;
|
|
@@ -8273,7 +9775,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8273
9775
|
};
|
|
8274
9776
|
}
|
|
8275
9777
|
ngOnDestroy() {
|
|
8276
|
-
console.debug("Com destroy, disable wake lock.")
|
|
9778
|
+
//console.debug("Com destroy, disable wake lock.")
|
|
8277
9779
|
this.disableWakeLockCond();
|
|
8278
9780
|
this.destroyed = true;
|
|
8279
9781
|
// TODO stop capture /playback
|
|
@@ -8404,7 +9906,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8404
9906
|
progressPercentValue() {
|
|
8405
9907
|
let v = 100;
|
|
8406
9908
|
if (this.items) {
|
|
8407
|
-
v = this.promptIndex * 100 / (this.items.length - 1);
|
|
9909
|
+
v = this.promptIndex * 100 / (this.items.length() - 1);
|
|
8408
9910
|
}
|
|
8409
9911
|
return v;
|
|
8410
9912
|
}
|
|
@@ -8418,9 +9920,6 @@ class SessionManager extends BasicRecorder {
|
|
|
8418
9920
|
return ((this._session != null) && (this._session.type === 'TEST_DEF_A') && (this.audioDevices != null) && this.audioDevices.length > 0);
|
|
8419
9921
|
}
|
|
8420
9922
|
set controlAudioPlayer(controlAudioPlayer) {
|
|
8421
|
-
if (this._controlAudioPlayer) {
|
|
8422
|
-
//this._controlAudioPlayer.listener=null;
|
|
8423
|
-
}
|
|
8424
9923
|
this._controlAudioPlayer = controlAudioPlayer;
|
|
8425
9924
|
if (this._controlAudioPlayer) {
|
|
8426
9925
|
this._controlAudioPlayer.listener = this;
|
|
@@ -8505,6 +10004,8 @@ class SessionManager extends BasicRecorder {
|
|
|
8505
10004
|
this.autorecording = true;
|
|
8506
10005
|
}
|
|
8507
10006
|
if (this.ac != null) {
|
|
10007
|
+
// Hide loading hint on livelevel display
|
|
10008
|
+
this.audioFetching = false;
|
|
8508
10009
|
if (!this.ac.opened) {
|
|
8509
10010
|
if (this._selectedDeviceId) {
|
|
8510
10011
|
console.log("Open session with audio device Id: \'" + this._selectedDeviceId + "\' for " + this._channelCount + " channels");
|
|
@@ -8521,7 +10022,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8521
10022
|
}
|
|
8522
10023
|
loadScript() {
|
|
8523
10024
|
this.promptItemCount = 0;
|
|
8524
|
-
this.items = new
|
|
10025
|
+
this.items = new SprItemsCache();
|
|
8525
10026
|
let ln = 0;
|
|
8526
10027
|
//TODO randomize not supported
|
|
8527
10028
|
for (let si = 0; si < this._script.sections.length; si++) {
|
|
@@ -8535,7 +10036,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8535
10036
|
let pi = pis[piSectIdx];
|
|
8536
10037
|
let promptAsStr = PromptitemUtil.toPlainTextString(pi);
|
|
8537
10038
|
let it = new Item$1(promptAsStr, section.training, (!pi.type || pi.type === 'recording'));
|
|
8538
|
-
this.items.
|
|
10039
|
+
this.items.addItem(it);
|
|
8539
10040
|
ln++;
|
|
8540
10041
|
}
|
|
8541
10042
|
}
|
|
@@ -8576,10 +10077,10 @@ class SessionManager extends BasicRecorder {
|
|
|
8576
10077
|
}
|
|
8577
10078
|
downloadRecording() {
|
|
8578
10079
|
if (this.displayRecFile) {
|
|
8579
|
-
let ab = this.displayRecFile.
|
|
10080
|
+
let ab = this.displayRecFile.audioDataHolder;
|
|
8580
10081
|
let ww = new WavWriter();
|
|
8581
|
-
if (ab) {
|
|
8582
|
-
let wavFile = ww.writeAsync(ab, (wavFile) => {
|
|
10082
|
+
if (ab?.buffer) {
|
|
10083
|
+
let wavFile = ww.writeAsync(ab.buffer, (wavFile) => {
|
|
8583
10084
|
let blob = new Blob([wavFile], { type: 'audio/wav' });
|
|
8584
10085
|
let rfUrl = URL.createObjectURL(blob);
|
|
8585
10086
|
let dataDnlLnk = this.renderer.createElement('a');
|
|
@@ -8602,7 +10103,10 @@ class SessionManager extends BasicRecorder {
|
|
|
8602
10103
|
set displayRecFile(displayRecFile) {
|
|
8603
10104
|
this._displayRecFile = displayRecFile;
|
|
8604
10105
|
if (this._displayRecFile) {
|
|
8605
|
-
|
|
10106
|
+
if (this.items) {
|
|
10107
|
+
this.items.currentRecordingFile = this._displayRecFile;
|
|
10108
|
+
}
|
|
10109
|
+
let ab = this._displayRecFile.audioDataHolder;
|
|
8606
10110
|
if (ab) {
|
|
8607
10111
|
this.displayAudioClip = new AudioClip(ab);
|
|
8608
10112
|
this.controlAudioPlayer.audioClip = this.displayAudioClip;
|
|
@@ -8610,27 +10114,46 @@ class SessionManager extends BasicRecorder {
|
|
|
8610
10114
|
else {
|
|
8611
10115
|
// clear for now ...
|
|
8612
10116
|
this.displayAudioClip = null;
|
|
8613
|
-
this.controlAudioPlayer
|
|
10117
|
+
if (this.controlAudioPlayer) {
|
|
10118
|
+
this.controlAudioPlayer.audioClip = null;
|
|
10119
|
+
}
|
|
8614
10120
|
if (this._controlAudioPlayer && this._session) {
|
|
8615
10121
|
//... and try to fetch from server
|
|
8616
|
-
this.
|
|
8617
|
-
|
|
8618
|
-
|
|
8619
|
-
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
10122
|
+
this.audioFetching = true;
|
|
10123
|
+
let rf = this._displayRecFile;
|
|
10124
|
+
this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
|
|
10125
|
+
next: (ab) => {
|
|
10126
|
+
this.audioFetching = false;
|
|
10127
|
+
let fabDh = null;
|
|
10128
|
+
if (ab) {
|
|
10129
|
+
if (rf && this.items) {
|
|
10130
|
+
if (SessionManager.FORCE_ARRRAY_AUDIO_BUFFER) {
|
|
10131
|
+
let aab = ArrayAudioBuffer.fromAudioBuffer(ab);
|
|
10132
|
+
fabDh = new AudioDataHolder(null, aab);
|
|
10133
|
+
}
|
|
10134
|
+
else {
|
|
10135
|
+
fabDh = new AudioDataHolder(ab);
|
|
10136
|
+
}
|
|
10137
|
+
this.items.setSprRecFileAudioData(rf, fabDh);
|
|
10138
|
+
}
|
|
10139
|
+
}
|
|
10140
|
+
else {
|
|
10141
|
+
// Should actually be handled by the error resolver
|
|
10142
|
+
this.statusMsg = 'Recording file could not be loaded.';
|
|
10143
|
+
this.statusAlertType = 'error';
|
|
10144
|
+
}
|
|
10145
|
+
if (fabDh) {
|
|
10146
|
+
// this.displayAudioClip could have been changed meanwhile, but the recorder unsubcribes before changing the item. Therefore there should be no risk to set to wrong item
|
|
10147
|
+
this.displayAudioClip = new AudioClip(fabDh);
|
|
10148
|
+
}
|
|
10149
|
+
this.controlAudioPlayer.audioClip = this.displayAudioClip;
|
|
10150
|
+
this.showRecording();
|
|
10151
|
+
}, error: err => {
|
|
10152
|
+
console.error("Could not load recording file from server: " + err);
|
|
10153
|
+
this.audioFetching = false;
|
|
10154
|
+
this.statusMsg = 'Recording file could not be loaded: ' + err;
|
|
8623
10155
|
this.statusAlertType = 'error';
|
|
8624
10156
|
}
|
|
8625
|
-
if (fab) {
|
|
8626
|
-
this.displayAudioClip = new AudioClip(fab);
|
|
8627
|
-
}
|
|
8628
|
-
this.controlAudioPlayer.audioClip = this.displayAudioClip;
|
|
8629
|
-
this.showRecording();
|
|
8630
|
-
}, err => {
|
|
8631
|
-
console.error("Could not load recording file from server: " + err);
|
|
8632
|
-
this.statusMsg = 'Recording file could not be loaded: ' + err;
|
|
8633
|
-
this.statusAlertType = 'error';
|
|
8634
10157
|
});
|
|
8635
10158
|
}
|
|
8636
10159
|
else {
|
|
@@ -8641,31 +10164,14 @@ class SessionManager extends BasicRecorder {
|
|
|
8641
10164
|
}
|
|
8642
10165
|
else {
|
|
8643
10166
|
this.displayAudioClip = null;
|
|
8644
|
-
this.controlAudioPlayer
|
|
10167
|
+
if (this.controlAudioPlayer) {
|
|
10168
|
+
this.controlAudioPlayer.audioClip = null;
|
|
10169
|
+
}
|
|
8645
10170
|
}
|
|
8646
10171
|
}
|
|
8647
10172
|
get displayRecFile() {
|
|
8648
10173
|
return this._displayRecFile;
|
|
8649
10174
|
}
|
|
8650
|
-
showRecording() {
|
|
8651
|
-
this.controlAudioPlayer.stop();
|
|
8652
|
-
if (this.displayAudioClip) {
|
|
8653
|
-
let dap = this.displayAudioClip;
|
|
8654
|
-
this.levelMeasure.calcBufferLevelInfos(dap.buffer, LEVEL_BAR_INTERVALL_SECONDS).then((levelInfos) => {
|
|
8655
|
-
dap.levelInfos = levelInfos;
|
|
8656
|
-
this.changeDetectorRef.detectChanges();
|
|
8657
|
-
});
|
|
8658
|
-
this.playStartAction.disabled = false;
|
|
8659
|
-
}
|
|
8660
|
-
else {
|
|
8661
|
-
this.playStartAction.disabled = true;
|
|
8662
|
-
// Collapse audio signal display if open
|
|
8663
|
-
if (!this.audioSignalCollapsed) {
|
|
8664
|
-
this.audioSignalCollapsed = true;
|
|
8665
|
-
}
|
|
8666
|
-
}
|
|
8667
|
-
this.changeDetectorRef.detectChanges();
|
|
8668
|
-
}
|
|
8669
10175
|
isRecordingItem() {
|
|
8670
10176
|
return (this.promptItem != null && this.promptItem.type !== 'nonrecording');
|
|
8671
10177
|
}
|
|
@@ -8680,6 +10186,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8680
10186
|
if (this.audioFetchSubscription) {
|
|
8681
10187
|
this.audioFetchSubscription.unsubscribe();
|
|
8682
10188
|
}
|
|
10189
|
+
this.audioFetching = false;
|
|
8683
10190
|
this.clearPrompt();
|
|
8684
10191
|
let isNonrecording = (this.promptItem.type === 'nonrecording');
|
|
8685
10192
|
if (isNonrecording || !this.section.promptphase || this.section.promptphase === 'IDLE') {
|
|
@@ -8692,7 +10199,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8692
10199
|
}
|
|
8693
10200
|
else {
|
|
8694
10201
|
if (this.items) {
|
|
8695
|
-
let it = this.items
|
|
10202
|
+
let it = this.items.getItem(this.promptIndex);
|
|
8696
10203
|
if (!it.recs) {
|
|
8697
10204
|
it.recs = new Array();
|
|
8698
10205
|
}
|
|
@@ -8753,7 +10260,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8753
10260
|
updateNavigationActions() {
|
|
8754
10261
|
let fwdNxtActionDisabled = true;
|
|
8755
10262
|
if (this.items) {
|
|
8756
|
-
let currRecs = this.items
|
|
10263
|
+
let currRecs = this.items.getItem(this._promptIndex).recs;
|
|
8757
10264
|
fwdNxtActionDisabled = !(currRecs != null && currRecs.length > 0);
|
|
8758
10265
|
}
|
|
8759
10266
|
this.transportActions.fwdNextAction.disabled = this.navigationDisabled || fwdNxtActionDisabled;
|
|
@@ -8767,10 +10274,10 @@ class SessionManager extends BasicRecorder {
|
|
|
8767
10274
|
newPrIdx = 0;
|
|
8768
10275
|
}
|
|
8769
10276
|
if (this.items != null) {
|
|
8770
|
-
let itRecs = this.items
|
|
10277
|
+
let itRecs = this.items.getItem(newPrIdx).recs;
|
|
8771
10278
|
while (itRecs != null && (itRecs.length > 0) && newPrIdx < this.promptItemCount) {
|
|
8772
10279
|
newPrIdx++;
|
|
8773
|
-
itRecs = this.items
|
|
10280
|
+
itRecs = this.items.getItem(newPrIdx).recs;
|
|
8774
10281
|
}
|
|
8775
10282
|
if (!itRecs || itRecs.length == 0) {
|
|
8776
10283
|
this.promptIndex = newPrIdx;
|
|
@@ -8791,6 +10298,23 @@ class SessionManager extends BasicRecorder {
|
|
|
8791
10298
|
}
|
|
8792
10299
|
}
|
|
8793
10300
|
started() {
|
|
10301
|
+
let ic = this.promptItem.itemcode;
|
|
10302
|
+
let rf = null;
|
|
10303
|
+
if (this._session && ic) {
|
|
10304
|
+
let sessId = this._session.sessionId;
|
|
10305
|
+
let cpIdx = this.promptIndex;
|
|
10306
|
+
if (this.items) {
|
|
10307
|
+
let it = this.items.getItem(cpIdx);
|
|
10308
|
+
if (!it.recs) {
|
|
10309
|
+
it.recs = new Array();
|
|
10310
|
+
}
|
|
10311
|
+
rf = new SprRecordingFile(sessId, ic, it.recs.length, null);
|
|
10312
|
+
//it.recs.push(rf);
|
|
10313
|
+
this.items.addSprRecFile(it, rf);
|
|
10314
|
+
this.items.currentRecordingFile = rf;
|
|
10315
|
+
}
|
|
10316
|
+
}
|
|
10317
|
+
this._recordingFile = rf;
|
|
8794
10318
|
this.status = 3 /* PRE_RECORDING */;
|
|
8795
10319
|
super.started();
|
|
8796
10320
|
this.startStopSignalState = 1 /* PRERECORDING */;
|
|
@@ -8917,13 +10441,14 @@ class SessionManager extends BasicRecorder {
|
|
|
8917
10441
|
if (rfd.recording && rfd.recording.itemcode) {
|
|
8918
10442
|
let prIdx = this.promptIndexByItemcode(rfd.recording.itemcode);
|
|
8919
10443
|
if (this.items != null && prIdx !== null) {
|
|
8920
|
-
let it = this.items
|
|
10444
|
+
let it = this.items.getItem(prIdx);
|
|
8921
10445
|
if (it && this._session) {
|
|
8922
|
-
if (!it.recs) {
|
|
8923
|
-
|
|
8924
|
-
}
|
|
10446
|
+
// if (!it.recs) {
|
|
10447
|
+
// it.recs = new Array<SprRecordingFile>();
|
|
10448
|
+
// }
|
|
8925
10449
|
let rf = new SprRecordingFile(this._session.sessionId, rfd.recording.itemcode, rfd.version, null);
|
|
8926
|
-
|
|
10450
|
+
rf.serverPersisted = true;
|
|
10451
|
+
this.items.addSprRecFile(it, rf);
|
|
8927
10452
|
}
|
|
8928
10453
|
else {
|
|
8929
10454
|
//console.debug("WARN: No recording item with code: \"" +rfd.recording.itemcode+ "\" found.");
|
|
@@ -8945,22 +10470,24 @@ class SessionManager extends BasicRecorder {
|
|
|
8945
10470
|
this.statusMsg = 'Recorded.';
|
|
8946
10471
|
this.startStopSignalState = 0 /* IDLE */;
|
|
8947
10472
|
let ad = null;
|
|
10473
|
+
let ada = null;
|
|
10474
|
+
let adh = null;
|
|
10475
|
+
let frameLen = 0;
|
|
8948
10476
|
if (this.ac != null) {
|
|
8949
|
-
|
|
8950
|
-
|
|
8951
|
-
|
|
8952
|
-
let rf = null;
|
|
8953
|
-
if (this._session && ic) {
|
|
8954
|
-
let sessId = this._session.sessionId;
|
|
8955
|
-
let cpIdx = this.promptIndex;
|
|
8956
|
-
if (this.items) {
|
|
8957
|
-
let it = this.items[cpIdx];
|
|
8958
|
-
if (!it.recs) {
|
|
8959
|
-
it.recs = new Array();
|
|
8960
|
-
}
|
|
8961
|
-
rf = new SprRecordingFile(sessId, ic, it.recs.length, ad);
|
|
8962
|
-
it.recs.push(rf);
|
|
10477
|
+
if (this.uploadChunkSizeSeconds || SessionManager.FORCE_ARRRAY_AUDIO_BUFFER) {
|
|
10478
|
+
ada = this.ac.audioBufferArray();
|
|
10479
|
+
frameLen = ada.frameLen;
|
|
8963
10480
|
}
|
|
10481
|
+
else {
|
|
10482
|
+
ad = this.ac.audioBuffer();
|
|
10483
|
+
frameLen = ad.length;
|
|
10484
|
+
}
|
|
10485
|
+
adh = new AudioDataHolder(ad, ada);
|
|
10486
|
+
}
|
|
10487
|
+
// Use an own reference since the writing of the wave file is asynchronous and this._recordingFile might already contain the next recording
|
|
10488
|
+
let rf = this._recordingFile;
|
|
10489
|
+
if (rf && rf instanceof SprRecordingFile) {
|
|
10490
|
+
this.items?.setSprRecFileAudioData(rf, adh);
|
|
8964
10491
|
if (this.enableUploadRecordings && !this.uploadChunkSizeSeconds) {
|
|
8965
10492
|
// TODO use SpeechRecorderconfig resp. RecfileService
|
|
8966
10493
|
// convert asynchronously to 16-bit integer PCM
|
|
@@ -8968,7 +10495,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8968
10495
|
// TODO duplicate conversion for manual download
|
|
8969
10496
|
//console.log("Build wav writer...");
|
|
8970
10497
|
this.processingRecording = true;
|
|
8971
|
-
if (ad
|
|
10498
|
+
if (ad) {
|
|
8972
10499
|
let ww = new WavWriter();
|
|
8973
10500
|
//new REST API URL
|
|
8974
10501
|
let apiEndPoint = '';
|
|
@@ -8981,7 +10508,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8981
10508
|
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
8982
10509
|
let recUrl = sessionsUrl + '/' + rf.session + '/' + RECFILE_API_CTX + '/' + rf.itemCode;
|
|
8983
10510
|
ww.writeAsync(ad, (wavFile) => {
|
|
8984
|
-
this.postRecording(wavFile, recUrl);
|
|
10511
|
+
this.postRecording(wavFile, recUrl, rf);
|
|
8985
10512
|
this.processingRecording = false;
|
|
8986
10513
|
this.updateWakeLock();
|
|
8987
10514
|
});
|
|
@@ -8992,8 +10519,8 @@ class SessionManager extends BasicRecorder {
|
|
|
8992
10519
|
let complete = true;
|
|
8993
10520
|
if (this.items) {
|
|
8994
10521
|
// search backwards, to gain faster detection of incomplete state
|
|
8995
|
-
for (let ri = this.items.length - 1; ri >= 0; ri--) {
|
|
8996
|
-
let it = this.items
|
|
10522
|
+
for (let ri = this.items.length() - 1; ri >= 0; ri--) {
|
|
10523
|
+
let it = this.items.getItem(ri);
|
|
8997
10524
|
if (it.recording && !it.training && (!it.recs || it.recs.length == 0)) {
|
|
8998
10525
|
complete = false;
|
|
8999
10526
|
break;
|
|
@@ -9057,13 +10584,13 @@ class SessionManager extends BasicRecorder {
|
|
|
9057
10584
|
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
9058
10585
|
let recUrl = sessionsUrl + '/' + this.session?.sessionId + '/' + RECFILE_API_CTX + '/' + this.promptItem.itemcode + '/' + this.rfUuid + '/' + chunkIdx;
|
|
9059
10586
|
ww.writeAsync(audioBuffer, (wavFile) => {
|
|
9060
|
-
this.postRecording(wavFile, recUrl);
|
|
10587
|
+
this.postRecording(wavFile, recUrl, null);
|
|
9061
10588
|
this.processingRecording = false;
|
|
9062
10589
|
});
|
|
9063
10590
|
}
|
|
9064
|
-
postRecording(wavFile, recUrl) {
|
|
10591
|
+
postRecording(wavFile, recUrl, rf) {
|
|
9065
10592
|
let wavBlob = new Blob([wavFile], { type: 'audio/wav' });
|
|
9066
|
-
let ul = new Upload(wavBlob, recUrl);
|
|
10593
|
+
let ul = new Upload(wavBlob, recUrl, rf);
|
|
9067
10594
|
this.uploader.queueUpload(ul);
|
|
9068
10595
|
}
|
|
9069
10596
|
stop() {
|
|
@@ -9099,7 +10626,7 @@ SessionManager.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version
|
|
|
9099
10626
|
<app-warningbar [show]="isDefaultAudioTestSession()" warningText="This test uses default audio device! Regular sessions may require a particular audio device (microphone)!"></app-warningbar>
|
|
9100
10627
|
<app-sprprompting [projectName]="projectName"
|
|
9101
10628
|
[startStopSignalState]="startStopSignalState" [promptItem]="promptItem" [showPrompt]="showPrompt"
|
|
9102
|
-
[items]="items"
|
|
10629
|
+
[items]="items?.items"
|
|
9103
10630
|
[transportActions]="transportActions"
|
|
9104
10631
|
[selectedItemIdx]="promptIndex" (onItemSelect)="itemSelect($event)" (onNextItem)="nextItem()" (onPrevItem)="prevItem()"
|
|
9105
10632
|
[audioSignalCollapsed]="audioSignalCollapsed" [displayAudioClip]="displayAudioClip"
|
|
@@ -9113,10 +10640,10 @@ SessionManager.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version
|
|
|
9113
10640
|
|
|
9114
10641
|
|
|
9115
10642
|
<div fxLayout="row" fxLayout.xs="column" [ngStyle]="{'height.px':100,'min-height.px': 100}" [ngStyle.xs]="{'height.px':125,'min-height.px': 125}">
|
|
9116
|
-
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()" [displayLevelInfos]="displayAudioClip?.levelInfos"></audio-levelbar>
|
|
10643
|
+
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()" [displayLevelInfos]="displayAudioClip?.levelInfos" [stateLoading]="audioFetching"></audio-levelbar>
|
|
9117
10644
|
<div fxLayout="row">
|
|
9118
10645
|
<spr-recordingitemcontrols fxFlex="10 0 1"
|
|
9119
|
-
[audioLoaded]="displayAudioClip?.
|
|
10646
|
+
[audioLoaded]="displayAudioClip?.audioDataHolder!==null"
|
|
9120
10647
|
[playStartAction]="controlAudioPlayer?.startAction"
|
|
9121
10648
|
[playStopAction]="controlAudioPlayer?.stopAction"
|
|
9122
10649
|
[peakDbLvl]="peakLevelInDb"
|
|
@@ -9134,7 +10661,7 @@ SessionManager.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version
|
|
|
9134
10661
|
<div fxFlex="1 1 30%" fxLayoutAlign="start center">
|
|
9135
10662
|
<app-sprstatusdisplay fxHide.xs [statusMsg]="statusMsg" [statusAlertType]="statusAlertType" [statusWaiting]="statusWaiting"></app-sprstatusdisplay>
|
|
9136
10663
|
</div>
|
|
9137
|
-
<app-sprtransport fxFlex="10 0 30%" fxLayoutAlign="center center" [readonly]="readonly" [actions]="transportActions" [navigationEnabled]="items
|
|
10664
|
+
<app-sprtransport fxFlex="10 0 30%" fxLayoutAlign="center center" [readonly]="readonly" [actions]="transportActions" [navigationEnabled]="!items || items.length()>1"></app-sprtransport>
|
|
9138
10665
|
<div fxFlex="1 1 30%" fxLayoutAlign="end center" fxLayout="row">
|
|
9139
10666
|
<app-uploadstatus class="ricontrols" fxHide.xs fxLayoutAlign="end center" *ngIf="enableUploadRecordings" [value]="uploadProgress"
|
|
9140
10667
|
[status]="uploadStatus" [awaitNewUpload]="processingRecording"></app-uploadstatus>
|
|
@@ -9142,7 +10669,7 @@ SessionManager.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version
|
|
|
9142
10669
|
<app-readystateindicator class="ricontrols" fxLayoutAlign="end center" fxHide.xs [ready]="dataSaved && !isActive()"></app-readystateindicator>
|
|
9143
10670
|
</div>
|
|
9144
10671
|
</div>
|
|
9145
|
-
`, isInline: true, styles: [":host{flex:2;background:lightgrey;display:flex;flex-direction:column;margin:0;padding:0;min-height:0px;overflow:hidden}\n", ".ricontrols{padding:4px;box-sizing:border-box;height:100%}\n", ".dark{background:darkgray}\n", ".controlpanel{align-content:center;align-items:center;margin:0;padding:20px;min-height:min-content}\n"], components: [{ type: WarningBar, selector: "app-warningbar", inputs: ["warningText", "show"] }, { type: Prompting, selector: "app-sprprompting", inputs: ["projectName", "startStopSignalState", "promptItem", "showPrompt", "items", "selectedItemIdx", "transportActions", "enableDownload", "audioSignalCollapsed", "displayAudioClip", "playStartAction", "playSelectionAction", "autoPlayOnSelectToggleAction", "playStopAction"], outputs: ["onItemSelect", "onNextItem", "onPrevItem"] }, { type: i7.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { type: LevelBar, selector: "audio-levelbar", inputs: ["streamingMode", "displayLevelInfos"] }, { type: RecordingItemControls, selector: "spr-recordingitemcontrols", inputs: ["audioSignalCollapsed", "enableDownload", "peakDbLvl", "agc", "audioLoaded", "playStartAction", "playStopAction", "displayLevelInfos"], outputs: ["onShowRecordingDetails", "onDownloadRecording"] }, { type: UploadStatus, selector: "app-uploadstatus", inputs: ["value", "awaitNewUpload", "status"] }, { type: WakeLockIndicator, selector: "app-wakelockindicator", inputs: ["screenLocked"] }, { type: ReadyStateIndicator, selector: "app-readystateindicator", inputs: ["ready"] }, { type: StatusDisplay, selector: "app-sprstatusdisplay", inputs: ["statusAlertType", "statusMsg", "statusWaiting"] }, { type: TransportPanel, selector: "app-sprtransport", inputs: ["readonly", "actions", "navigationEnabled", "pausingEnabled"] }], directives: [{ type: i3$1.DefaultShowHideDirective, selector: " [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]", inputs: ["fxShow", "fxShow.print", "fxShow.xs", "fxShow.sm", "fxShow.md", "fxShow.lg", "fxShow.xl", "fxShow.lt-sm", "fxShow.lt-md", "fxShow.lt-lg", "fxShow.lt-xl", "fxShow.gt-xs", "fxShow.gt-sm", "fxShow.gt-md", "fxShow.gt-lg", "fxHide", "fxHide.print", "fxHide.xs", "fxHide.sm", "fxHide.md", "fxHide.lg", "fxHide.xl", "fxHide.lt-sm", "fxHide.lt-md", "fxHide.lt-lg", "fxHide.lt-xl", "fxHide.gt-xs", "fxHide.gt-sm", "fxHide.gt-md", "fxHide.gt-lg"] }, { type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i3$1.DefaultStyleDirective, selector: " [ngStyle], [ngStyle.xs], [ngStyle.sm], [ngStyle.md], [ngStyle.lg], [ngStyle.xl], [ngStyle.lt-sm], [ngStyle.lt-md], [ngStyle.lt-lg], [ngStyle.lt-xl], [ngStyle.gt-xs], [ngStyle.gt-sm], [ngStyle.gt-md], [ngStyle.gt-lg]", inputs: ["ngStyle", "ngStyle.xs", "ngStyle.sm", "ngStyle.md", "ngStyle.lg", "ngStyle.xl", "ngStyle.lt-sm", "ngStyle.lt-md", "ngStyle.lt-lg", "ngStyle.lt-xl", "ngStyle.gt-xs", "ngStyle.gt-sm", "ngStyle.gt-md", "ngStyle.gt-lg"] }, { type: i4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }] });
|
|
10672
|
+
`, isInline: true, styles: [":host{flex:2;background:lightgrey;display:flex;flex-direction:column;margin:0;padding:0;min-height:0px;overflow:hidden}\n", ".ricontrols{padding:4px;box-sizing:border-box;height:100%}\n", ".dark{background:darkgray}\n", ".controlpanel{align-content:center;align-items:center;margin:0;padding:20px;min-height:min-content}\n"], components: [{ type: WarningBar, selector: "app-warningbar", inputs: ["warningText", "show"] }, { type: Prompting, selector: "app-sprprompting", inputs: ["projectName", "startStopSignalState", "promptItem", "showPrompt", "items", "selectedItemIdx", "transportActions", "enableDownload", "audioSignalCollapsed", "displayAudioClip", "playStartAction", "playSelectionAction", "autoPlayOnSelectToggleAction", "playStopAction"], outputs: ["onItemSelect", "onNextItem", "onPrevItem"] }, { type: i7.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { type: LevelBar, selector: "audio-levelbar", inputs: ["streamingMode", "displayLevelInfos", "stateLoading"] }, { type: RecordingItemControls, selector: "spr-recordingitemcontrols", inputs: ["audioSignalCollapsed", "enableDownload", "peakDbLvl", "agc", "audioLoaded", "playStartAction", "playStopAction", "displayLevelInfos"], outputs: ["onShowRecordingDetails", "onDownloadRecording"] }, { type: UploadStatus, selector: "app-uploadstatus", inputs: ["value", "awaitNewUpload", "status"] }, { type: WakeLockIndicator, selector: "app-wakelockindicator", inputs: ["screenLocked"] }, { type: ReadyStateIndicator, selector: "app-readystateindicator", inputs: ["ready"] }, { type: StatusDisplay, selector: "app-sprstatusdisplay", inputs: ["statusAlertType", "statusMsg", "statusWaiting"] }, { type: TransportPanel, selector: "app-sprtransport", inputs: ["readonly", "actions", "navigationEnabled", "pausingEnabled"] }], directives: [{ type: i3$1.DefaultShowHideDirective, selector: " [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]", inputs: ["fxShow", "fxShow.print", "fxShow.xs", "fxShow.sm", "fxShow.md", "fxShow.lg", "fxShow.xl", "fxShow.lt-sm", "fxShow.lt-md", "fxShow.lt-lg", "fxShow.lt-xl", "fxShow.gt-xs", "fxShow.gt-sm", "fxShow.gt-md", "fxShow.gt-lg", "fxHide", "fxHide.print", "fxHide.xs", "fxHide.sm", "fxHide.md", "fxHide.lg", "fxHide.xl", "fxHide.lt-sm", "fxHide.lt-md", "fxHide.lt-lg", "fxHide.lt-xl", "fxHide.gt-xs", "fxHide.gt-sm", "fxHide.gt-md", "fxHide.gt-lg"] }, { type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i3$1.DefaultStyleDirective, selector: " [ngStyle], [ngStyle.xs], [ngStyle.sm], [ngStyle.md], [ngStyle.lg], [ngStyle.xl], [ngStyle.lt-sm], [ngStyle.lt-md], [ngStyle.lt-lg], [ngStyle.lt-xl], [ngStyle.gt-xs], [ngStyle.gt-sm], [ngStyle.gt-md], [ngStyle.gt-lg]", inputs: ["ngStyle", "ngStyle.xs", "ngStyle.sm", "ngStyle.md", "ngStyle.lg", "ngStyle.xl", "ngStyle.lt-sm", "ngStyle.lt-md", "ngStyle.lt-lg", "ngStyle.lt-xl", "ngStyle.gt-xs", "ngStyle.gt-sm", "ngStyle.gt-md", "ngStyle.gt-lg"] }, { type: i4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }] });
|
|
9146
10673
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: SessionManager, decorators: [{
|
|
9147
10674
|
type: Component,
|
|
9148
10675
|
args: [{
|
|
@@ -9153,7 +10680,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
9153
10680
|
<app-warningbar [show]="isDefaultAudioTestSession()" warningText="This test uses default audio device! Regular sessions may require a particular audio device (microphone)!"></app-warningbar>
|
|
9154
10681
|
<app-sprprompting [projectName]="projectName"
|
|
9155
10682
|
[startStopSignalState]="startStopSignalState" [promptItem]="promptItem" [showPrompt]="showPrompt"
|
|
9156
|
-
[items]="items"
|
|
10683
|
+
[items]="items?.items"
|
|
9157
10684
|
[transportActions]="transportActions"
|
|
9158
10685
|
[selectedItemIdx]="promptIndex" (onItemSelect)="itemSelect($event)" (onNextItem)="nextItem()" (onPrevItem)="prevItem()"
|
|
9159
10686
|
[audioSignalCollapsed]="audioSignalCollapsed" [displayAudioClip]="displayAudioClip"
|
|
@@ -9167,10 +10694,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
9167
10694
|
|
|
9168
10695
|
|
|
9169
10696
|
<div fxLayout="row" fxLayout.xs="column" [ngStyle]="{'height.px':100,'min-height.px': 100}" [ngStyle.xs]="{'height.px':125,'min-height.px': 125}">
|
|
9170
|
-
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()" [displayLevelInfos]="displayAudioClip?.levelInfos"></audio-levelbar>
|
|
10697
|
+
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()" [displayLevelInfos]="displayAudioClip?.levelInfos" [stateLoading]="audioFetching"></audio-levelbar>
|
|
9171
10698
|
<div fxLayout="row">
|
|
9172
10699
|
<spr-recordingitemcontrols fxFlex="10 0 1"
|
|
9173
|
-
[audioLoaded]="displayAudioClip?.
|
|
10700
|
+
[audioLoaded]="displayAudioClip?.audioDataHolder!==null"
|
|
9174
10701
|
[playStartAction]="controlAudioPlayer?.startAction"
|
|
9175
10702
|
[playStopAction]="controlAudioPlayer?.stopAction"
|
|
9176
10703
|
[peakDbLvl]="peakLevelInDb"
|
|
@@ -9188,7 +10715,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
9188
10715
|
<div fxFlex="1 1 30%" fxLayoutAlign="start center">
|
|
9189
10716
|
<app-sprstatusdisplay fxHide.xs [statusMsg]="statusMsg" [statusAlertType]="statusAlertType" [statusWaiting]="statusWaiting"></app-sprstatusdisplay>
|
|
9190
10717
|
</div>
|
|
9191
|
-
<app-sprtransport fxFlex="10 0 30%" fxLayoutAlign="center center" [readonly]="readonly" [actions]="transportActions" [navigationEnabled]="items
|
|
10718
|
+
<app-sprtransport fxFlex="10 0 30%" fxLayoutAlign="center center" [readonly]="readonly" [actions]="transportActions" [navigationEnabled]="!items || items.length()>1"></app-sprtransport>
|
|
9192
10719
|
<div fxFlex="1 1 30%" fxLayoutAlign="end center" fxLayout="row">
|
|
9193
10720
|
<app-uploadstatus class="ricontrols" fxHide.xs fxLayoutAlign="end center" *ngIf="enableUploadRecordings" [value]="uploadProgress"
|
|
9194
10721
|
[status]="uploadStatus" [awaitNewUpload]="processingRecording"></app-uploadstatus>
|
|
@@ -9477,7 +11004,7 @@ class SpeechrecorderngComponent extends RecorderComponent {
|
|
|
9477
11004
|
this.uploadUpdate(ue);
|
|
9478
11005
|
};
|
|
9479
11006
|
window.addEventListener('beforeunload', (e) => {
|
|
9480
|
-
console.debug("Before page unload event");
|
|
11007
|
+
//console.debug("Before page unload event");
|
|
9481
11008
|
if (this.ready()) {
|
|
9482
11009
|
return;
|
|
9483
11010
|
}
|
|
@@ -9796,14 +11323,15 @@ class AudioDisplayPlayer {
|
|
|
9796
11323
|
if (this.aCtx) {
|
|
9797
11324
|
this.aCtx.decodeAudioData(data, (audioBuffer) => {
|
|
9798
11325
|
//console.debug("Audio Buffer Samplerate: ", audioBuffer.sampleRate)
|
|
9799
|
-
|
|
11326
|
+
let adh = new AudioDataHolder(audioBuffer, null);
|
|
11327
|
+
this.audioClip = new AudioClip(adh);
|
|
9800
11328
|
});
|
|
9801
11329
|
}
|
|
9802
11330
|
}
|
|
9803
|
-
set audioData(
|
|
9804
|
-
this.audioDisplayScrollPane.audioData =
|
|
9805
|
-
if (
|
|
9806
|
-
let clip = new AudioClip(
|
|
11331
|
+
set audioData(audioData) {
|
|
11332
|
+
this.audioDisplayScrollPane.audioData = audioData;
|
|
11333
|
+
if (audioData) {
|
|
11334
|
+
let clip = new AudioClip(audioData);
|
|
9807
11335
|
if (this.ap) {
|
|
9808
11336
|
this.ap.audioClip = clip;
|
|
9809
11337
|
this.playStartAction.disabled = false;
|
|
@@ -9825,7 +11353,7 @@ class AudioDisplayPlayer {
|
|
|
9825
11353
|
let audioData = null;
|
|
9826
11354
|
let sel = null;
|
|
9827
11355
|
if (audioClip) {
|
|
9828
|
-
audioData = audioClip.
|
|
11356
|
+
audioData = audioClip.audioDataHolder;
|
|
9829
11357
|
sel = audioClip.selection;
|
|
9830
11358
|
if (this._audioClip) {
|
|
9831
11359
|
this._audioClip.addSelectionObserver((ac) => {
|
|
@@ -10096,7 +11624,7 @@ class RecordingFileService {
|
|
|
10096
11624
|
// Do not use Promise version, which does not work with Safari 13
|
|
10097
11625
|
if (resp.body) {
|
|
10098
11626
|
aCtx.decodeAudioData(resp.body, ab => {
|
|
10099
|
-
recordingFile
|
|
11627
|
+
RecordingFileUtils.setAudioData(recordingFile, new AudioDataHolder(ab));
|
|
10100
11628
|
if (this.debugDelay > 0) {
|
|
10101
11629
|
window.setTimeout(() => {
|
|
10102
11630
|
observer.next(recordingFile);
|
|
@@ -10146,7 +11674,7 @@ class RecordingFileService {
|
|
|
10146
11674
|
if (resp.body) {
|
|
10147
11675
|
aCtx.decodeAudioData(resp.body, ab => {
|
|
10148
11676
|
if (rf) {
|
|
10149
|
-
rf
|
|
11677
|
+
RecordingFileUtils.setAudioData(rf, new AudioDataHolder(ab));
|
|
10150
11678
|
}
|
|
10151
11679
|
else {
|
|
10152
11680
|
observer.error('Recording file object null');
|
|
@@ -10197,7 +11725,8 @@ class RecordingFileService {
|
|
|
10197
11725
|
if (resp.body) {
|
|
10198
11726
|
aCtx.decodeAudioData(resp.body, ab => {
|
|
10199
11727
|
if (rf) {
|
|
10200
|
-
|
|
11728
|
+
let adh = new AudioDataHolder(ab);
|
|
11729
|
+
RecordingFileUtils.setAudioData(rf, adh);
|
|
10201
11730
|
}
|
|
10202
11731
|
else {
|
|
10203
11732
|
observer.error('Recording file object null');
|
|
@@ -10240,7 +11769,7 @@ class RecordingFileService {
|
|
|
10240
11769
|
// append UUID to make request URL unique to avoid localhost server caching
|
|
10241
11770
|
recUrl = recUrl + '.json?requestUUID=' + UUID.generate();
|
|
10242
11771
|
}
|
|
10243
|
-
console.log("Path request URL: "
|
|
11772
|
+
//console.log("Path request URL: "+recUrl)
|
|
10244
11773
|
return this.http.patch(recUrl, { editSampleRate: editSampleRate, editStartFrame: editStartFrame, editEndFrame: editEndFrame }, { withCredentials: this.withCredentials });
|
|
10245
11774
|
}
|
|
10246
11775
|
}
|
|
@@ -10258,6 +11787,7 @@ class RecordingFileMetaComponent {
|
|
|
10258
11787
|
constructor() {
|
|
10259
11788
|
this.sessionId = null;
|
|
10260
11789
|
this._recordingFile = null;
|
|
11790
|
+
this.stateLoading = false;
|
|
10261
11791
|
this.itemCode = null;
|
|
10262
11792
|
this.uuid = null;
|
|
10263
11793
|
}
|
|
@@ -10273,12 +11803,12 @@ class RecordingFileMetaComponent {
|
|
|
10273
11803
|
}
|
|
10274
11804
|
if (this.itemCode) {
|
|
10275
11805
|
this.uuid = null;
|
|
10276
|
-
console.debug("SprRecordingFile: "
|
|
11806
|
+
//console.debug("SprRecordingFile: "+this.itemCode+ " UUID: "+this.uuid)
|
|
10277
11807
|
}
|
|
10278
11808
|
else {
|
|
10279
11809
|
this.itemCode = null;
|
|
10280
11810
|
this.uuid = this._recordingFile?.uuid;
|
|
10281
|
-
console.debug("RecordingFile: "
|
|
11811
|
+
//console.debug("RecordingFile: "+this.itemCode+ " UUID: "+this.uuid)
|
|
10282
11812
|
}
|
|
10283
11813
|
}
|
|
10284
11814
|
else {
|
|
@@ -10295,10 +11825,11 @@ class RecordingFileMetaComponent {
|
|
|
10295
11825
|
}
|
|
10296
11826
|
}
|
|
10297
11827
|
RecordingFileMetaComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: RecordingFileMetaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10298
|
-
RecordingFileMetaComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: RecordingFileMetaComponent, selector: "app-recording-file-meta", inputs: { sessionId: "sessionId", recordingFile: "recordingFile" }, ngImport: i0, template: `
|
|
11828
|
+
RecordingFileMetaComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: RecordingFileMetaComponent, selector: "app-recording-file-meta", inputs: { sessionId: "sessionId", stateLoading: "stateLoading", recordingFile: "recordingFile" }, ngImport: i0, template: `
|
|
10299
11829
|
<mat-card>
|
|
10300
11830
|
<mat-card-title>Recording file ID: {{recordingFile?.recordingFileId}}</mat-card-title>
|
|
10301
11831
|
<mat-card-content>
|
|
11832
|
+
<mat-progress-spinner *ngIf="stateLoading" mode="indeterminate" [diameter]="20"></mat-progress-spinner>
|
|
10302
11833
|
<table>
|
|
10303
11834
|
<tr *ngIf="itemCode">
|
|
10304
11835
|
<td>Itemcode:</td>
|
|
@@ -10328,7 +11859,7 @@ RecordingFileMetaComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0
|
|
|
10328
11859
|
</table>
|
|
10329
11860
|
</mat-card-content>
|
|
10330
11861
|
</mat-card>
|
|
10331
|
-
`, isInline: true, components: [{ type: i1$4.MatCard, selector: "mat-card", exportAs: ["matCard"] }], directives: [{ type: i1$4.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { type: i1$4.MatCardContent, selector: "mat-card-content, [mat-card-content], [matCardContent]" }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
11862
|
+
`, isInline: true, components: [{ type: i1$4.MatCard, selector: "mat-card", exportAs: ["matCard"] }, { type: i1$3.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }], directives: [{ type: i1$4.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { type: i1$4.MatCardContent, selector: "mat-card-content, [mat-card-content], [matCardContent]" }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
10332
11863
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: RecordingFileMetaComponent, decorators: [{
|
|
10333
11864
|
type: Component,
|
|
10334
11865
|
args: [{
|
|
@@ -10337,6 +11868,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
10337
11868
|
<mat-card>
|
|
10338
11869
|
<mat-card-title>Recording file ID: {{recordingFile?.recordingFileId}}</mat-card-title>
|
|
10339
11870
|
<mat-card-content>
|
|
11871
|
+
<mat-progress-spinner *ngIf="stateLoading" mode="indeterminate" [diameter]="20"></mat-progress-spinner>
|
|
10340
11872
|
<table>
|
|
10341
11873
|
<tr *ngIf="itemCode">
|
|
10342
11874
|
<td>Itemcode:</td>
|
|
@@ -10371,6 +11903,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
10371
11903
|
}]
|
|
10372
11904
|
}], propDecorators: { sessionId: [{
|
|
10373
11905
|
type: Input
|
|
11906
|
+
}], stateLoading: [{
|
|
11907
|
+
type: Input
|
|
10374
11908
|
}], recordingFile: [{
|
|
10375
11909
|
type: Input
|
|
10376
11910
|
}] } });
|
|
@@ -10513,6 +12047,7 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
|
|
|
10513
12047
|
this.recordingFileVersion = null;
|
|
10514
12048
|
this.routedByQueryParam = false;
|
|
10515
12049
|
this.posInList = null;
|
|
12050
|
+
this.audioFetching = false;
|
|
10516
12051
|
this.naviInfoLoading = false;
|
|
10517
12052
|
this.parentE = this.eRef.nativeElement;
|
|
10518
12053
|
this.firstAction = new Action('First');
|
|
@@ -10682,18 +12217,20 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
|
|
|
10682
12217
|
this.updateActions();
|
|
10683
12218
|
let audioContext = AudioContextProvider.audioContextInstance();
|
|
10684
12219
|
if (audioContext) {
|
|
12220
|
+
this.audioFetching = true;
|
|
10685
12221
|
this.recordingFileService.fetchSprRecordingFile(audioContext, rfId).subscribe(value => {
|
|
12222
|
+
this.audioFetching = false;
|
|
10686
12223
|
this.status = 'Audio file loaded.';
|
|
10687
12224
|
let clip = null;
|
|
10688
12225
|
this.recordingFile = value;
|
|
10689
12226
|
if (this.recordingFile) {
|
|
10690
|
-
let ab = this.recordingFile.
|
|
12227
|
+
let ab = this.recordingFile.audioDataHolder;
|
|
10691
12228
|
if (ab) {
|
|
10692
12229
|
clip = new AudioClip(ab);
|
|
10693
12230
|
let esffsr = null;
|
|
10694
12231
|
let eeffsr = null;
|
|
10695
12232
|
let esr = null;
|
|
10696
|
-
if (clip.
|
|
12233
|
+
if (clip.audioDataHolder != null) {
|
|
10697
12234
|
esr = ab.sampleRate;
|
|
10698
12235
|
if (esr != null) {
|
|
10699
12236
|
esffsr = RecordingFileUtil.editStartFrameForSampleRate(this.recordingFile, esr);
|
|
@@ -10705,8 +12242,8 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
|
|
|
10705
12242
|
sel = new Selection(ab.sampleRate, esffsr, eeffsr);
|
|
10706
12243
|
}
|
|
10707
12244
|
else {
|
|
10708
|
-
let ch0 = ab.getChannelData(0);
|
|
10709
|
-
let frameLength =
|
|
12245
|
+
//let ch0 = ab.getChannelData(0);
|
|
12246
|
+
let frameLength = ab.frameLen;
|
|
10710
12247
|
sel = new Selection(esr, esffsr, frameLength);
|
|
10711
12248
|
}
|
|
10712
12249
|
}
|
|
@@ -10720,6 +12257,7 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
|
|
|
10720
12257
|
this.audioClip = clip;
|
|
10721
12258
|
this.loadedRecfile();
|
|
10722
12259
|
}, error1 => {
|
|
12260
|
+
this.audioFetching = false;
|
|
10723
12261
|
this.status = 'Error loading audio file!';
|
|
10724
12262
|
});
|
|
10725
12263
|
}
|
|
@@ -10829,7 +12367,7 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
|
|
|
10829
12367
|
for (let avRfV of avRf) {
|
|
10830
12368
|
os += avRfV.version + '/';
|
|
10831
12369
|
}
|
|
10832
|
-
console.debug(os);
|
|
12370
|
+
//console.debug(os);
|
|
10833
12371
|
}
|
|
10834
12372
|
}
|
|
10835
12373
|
this.updatePos();
|
|
@@ -10845,7 +12383,7 @@ RecordingFileViewComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0
|
|
|
10845
12383
|
|
|
10846
12384
|
<audio-display-scroll-pane #audioDisplayScrollPane></audio-display-scroll-pane>
|
|
10847
12385
|
<div class="ctrlview">
|
|
10848
|
-
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile"></app-recording-file-meta>
|
|
12386
|
+
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile" [stateLoading]="audioFetching"></app-recording-file-meta>
|
|
10849
12387
|
|
|
10850
12388
|
<audio-display-control [audioClip]="audioClip"
|
|
10851
12389
|
[playStartAction]="playStartAction"
|
|
@@ -10858,7 +12396,7 @@ RecordingFileViewComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0
|
|
|
10858
12396
|
[zoomFitToPanelAction]="zoomFitToPanelAction"></audio-display-control>
|
|
10859
12397
|
<app-recording-file-navi [items]="availRecFiles?.length" [itemPos]="posInList" [version]="recordingFileVersion" [versions]="versions" [firstAction]="firstAction" [prevAction]="prevAction" [nextAction]="nextAction" [lastAction]="lastAction" [selectVersion]="toVersionAction" [naviInfoLoading]="naviInfoLoading"></app-recording-file-navi>
|
|
10860
12398
|
</div>
|
|
10861
|
-
`, isInline: true, styles: [":host{flex:2;display:flex;flex-direction:column;min-height:0;overflow:hidden;padding:20px;z-index:5;box-sizing:border-box;background-color:#fff}\n", ".ctrlview{display:flex;flex-direction:row}\n", "audio-display-control{flex:3}\n"], components: [{ type: AudioDisplayScrollPane, selector: "audio-display-scroll-pane", inputs: ["audioClip"], outputs: ["zoomInAction", "zoomOutAction", "zoomSelectedAction", "zoomFitToPanelAction"] }, { type: RecordingFileMetaComponent, selector: "app-recording-file-meta", inputs: ["sessionId", "recordingFile"] }, { type: AudioDisplayControl, selector: "audio-display-control", inputs: ["audioClip", "playStartAction", "playSelectionAction", "playStopAction", "zoomInAction", "zoomOutAction", "zoomFitToPanelAction", "zoomSelectedAction", "autoPlayOnSelectToggleAction"] }, { type: RecordingFileNaviComponent, selector: "app-recording-file-navi", inputs: ["firstAction", "prevAction", "nextAction", "lastAction", "items", "itemPos", "selectVersion", "versions", "version", "naviInfoLoading"] }] });
|
|
12399
|
+
`, isInline: true, styles: [":host{flex:2;display:flex;flex-direction:column;min-height:0;overflow:hidden;padding:20px;z-index:5;box-sizing:border-box;background-color:#fff}\n", ".ctrlview{display:flex;flex-direction:row}\n", "audio-display-control{flex:3}\n"], components: [{ type: AudioDisplayScrollPane, selector: "audio-display-scroll-pane", inputs: ["audioClip"], outputs: ["zoomInAction", "zoomOutAction", "zoomSelectedAction", "zoomFitToPanelAction"] }, { type: RecordingFileMetaComponent, selector: "app-recording-file-meta", inputs: ["sessionId", "stateLoading", "recordingFile"] }, { type: AudioDisplayControl, selector: "audio-display-control", inputs: ["audioClip", "playStartAction", "playSelectionAction", "playStopAction", "zoomInAction", "zoomOutAction", "zoomFitToPanelAction", "zoomSelectedAction", "autoPlayOnSelectToggleAction"] }, { type: RecordingFileNaviComponent, selector: "app-recording-file-navi", inputs: ["firstAction", "prevAction", "nextAction", "lastAction", "items", "itemPos", "selectVersion", "versions", "version", "naviInfoLoading"] }] });
|
|
10862
12400
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: RecordingFileViewComponent, decorators: [{
|
|
10863
12401
|
type: Component,
|
|
10864
12402
|
args: [{
|
|
@@ -10867,7 +12405,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
10867
12405
|
|
|
10868
12406
|
<audio-display-scroll-pane #audioDisplayScrollPane></audio-display-scroll-pane>
|
|
10869
12407
|
<div class="ctrlview">
|
|
10870
|
-
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile"></app-recording-file-meta>
|
|
12408
|
+
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile" [stateLoading]="audioFetching"></app-recording-file-meta>
|
|
10871
12409
|
|
|
10872
12410
|
<audio-display-control [audioClip]="audioClip"
|
|
10873
12411
|
[playStartAction]="playStartAction"
|
|
@@ -10960,7 +12498,7 @@ class RecordingFileUI extends RecordingFileViewComponent {
|
|
|
10960
12498
|
}
|
|
10961
12499
|
applySelection() {
|
|
10962
12500
|
if (this.audioClip) {
|
|
10963
|
-
let ab = this.audioClip.
|
|
12501
|
+
let ab = this.audioClip.audioDataHolder;
|
|
10964
12502
|
let s = this.audioClip.selection;
|
|
10965
12503
|
if (ab && this.recordingFile?.recordingFileId) {
|
|
10966
12504
|
let sr = null;
|
|
@@ -10998,7 +12536,7 @@ RecordingFileUI.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", versio
|
|
|
10998
12536
|
|
|
10999
12537
|
<audio-display-scroll-pane #audioDisplayScrollPane></audio-display-scroll-pane>
|
|
11000
12538
|
<div class="ctrlview">
|
|
11001
|
-
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile"></app-recording-file-meta>
|
|
12539
|
+
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile" [stateLoading]="audioFetching"></app-recording-file-meta>
|
|
11002
12540
|
<audio-display-control [audioClip]="audioClip"
|
|
11003
12541
|
[playStartAction]="playStartAction"
|
|
11004
12542
|
[playSelectionAction]="playSelectionAction"
|
|
@@ -11012,7 +12550,7 @@ RecordingFileUI.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", versio
|
|
|
11012
12550
|
</div>
|
|
11013
12551
|
|
|
11014
12552
|
<button mat-raised-button color="accent" (click)="applySelection()" [disabled]="editSaved">{{this.applyButtonText()}}</button>
|
|
11015
|
-
`, isInline: true, styles: [":host{flex:2;display:flex;flex-direction:column;min-height:0;overflow:hidden;padding:20px;z-index:5;box-sizing:border-box;background-color:#fff}\n", ".ctrlview{display:flex;flex-direction:row}\n", "audio-display-control{flex:3}\n"], components: [{ type: AudioDisplayScrollPane, selector: "audio-display-scroll-pane", inputs: ["audioClip"], outputs: ["zoomInAction", "zoomOutAction", "zoomSelectedAction", "zoomFitToPanelAction"] }, { type: RecordingFileMetaComponent, selector: "app-recording-file-meta", inputs: ["sessionId", "recordingFile"] }, { type: AudioDisplayControl, selector: "audio-display-control", inputs: ["audioClip", "playStartAction", "playSelectionAction", "playStopAction", "zoomInAction", "zoomOutAction", "zoomFitToPanelAction", "zoomSelectedAction", "autoPlayOnSelectToggleAction"] }, { type: RecordingFileNaviComponent, selector: "app-recording-file-navi", inputs: ["firstAction", "prevAction", "nextAction", "lastAction", "items", "itemPos", "selectVersion", "versions", "version", "naviInfoLoading"] }, { type: i3$2.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }] });
|
|
12553
|
+
`, isInline: true, styles: [":host{flex:2;display:flex;flex-direction:column;min-height:0;overflow:hidden;padding:20px;z-index:5;box-sizing:border-box;background-color:#fff}\n", ".ctrlview{display:flex;flex-direction:row}\n", "audio-display-control{flex:3}\n"], components: [{ type: AudioDisplayScrollPane, selector: "audio-display-scroll-pane", inputs: ["audioClip"], outputs: ["zoomInAction", "zoomOutAction", "zoomSelectedAction", "zoomFitToPanelAction"] }, { type: RecordingFileMetaComponent, selector: "app-recording-file-meta", inputs: ["sessionId", "stateLoading", "recordingFile"] }, { type: AudioDisplayControl, selector: "audio-display-control", inputs: ["audioClip", "playStartAction", "playSelectionAction", "playStopAction", "zoomInAction", "zoomOutAction", "zoomFitToPanelAction", "zoomSelectedAction", "autoPlayOnSelectToggleAction"] }, { type: RecordingFileNaviComponent, selector: "app-recording-file-navi", inputs: ["firstAction", "prevAction", "nextAction", "lastAction", "items", "itemPos", "selectVersion", "versions", "version", "naviInfoLoading"] }, { type: i3$2.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }] });
|
|
11016
12554
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: RecordingFileUI, decorators: [{
|
|
11017
12555
|
type: Component,
|
|
11018
12556
|
args: [{
|
|
@@ -11023,7 +12561,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
11023
12561
|
|
|
11024
12562
|
<audio-display-scroll-pane #audioDisplayScrollPane></audio-display-scroll-pane>
|
|
11025
12563
|
<div class="ctrlview">
|
|
11026
|
-
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile"></app-recording-file-meta>
|
|
12564
|
+
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile" [stateLoading]="audioFetching"></app-recording-file-meta>
|
|
11027
12565
|
<audio-display-control [audioClip]="audioClip"
|
|
11028
12566
|
[playStartAction]="playStartAction"
|
|
11029
12567
|
[playSelectionAction]="playSelectionAction"
|
|
@@ -11080,7 +12618,8 @@ class MediaUtils {
|
|
|
11080
12618
|
|
|
11081
12619
|
class RecordingList {
|
|
11082
12620
|
constructor() {
|
|
11083
|
-
|
|
12621
|
+
//private recordingList:Array<RecordingFile>=new Array<RecordingFile>();
|
|
12622
|
+
this.recordingList = new RecFilesCache();
|
|
11084
12623
|
//cols=['index','length','samples','samplerate','action'];
|
|
11085
12624
|
this.cols = ['index', 'startedDate', 'length', 'action'];
|
|
11086
12625
|
this.selectDisabled = false;
|
|
@@ -11092,7 +12631,7 @@ class RecordingList {
|
|
|
11092
12631
|
this.buildDataSource();
|
|
11093
12632
|
}
|
|
11094
12633
|
buildDataSource() {
|
|
11095
|
-
this.recordingList.sort((a, b) => {
|
|
12634
|
+
this.recordingList.recFiles.sort((a, b) => {
|
|
11096
12635
|
let cmp = 0;
|
|
11097
12636
|
let aD = null;
|
|
11098
12637
|
let bD = null;
|
|
@@ -11113,24 +12652,35 @@ class RecordingList {
|
|
|
11113
12652
|
}
|
|
11114
12653
|
return cmp;
|
|
11115
12654
|
});
|
|
11116
|
-
this.recordingListDataSource.data = this.recordingList;
|
|
12655
|
+
this.recordingListDataSource.data = this.recordingList.recFiles;
|
|
11117
12656
|
}
|
|
11118
|
-
|
|
11119
|
-
this.recordingList.
|
|
12657
|
+
addRecFile(rf) {
|
|
12658
|
+
this.recordingList.addRecFile(rf);
|
|
11120
12659
|
this.buildDataSource();
|
|
11121
12660
|
}
|
|
12661
|
+
setRecFileAudioData(recFile, adh) {
|
|
12662
|
+
this.recordingList.setRecFileAudioData(recFile, adh);
|
|
12663
|
+
}
|
|
11122
12664
|
selectRecordingFile(rf) {
|
|
12665
|
+
this.recordingList.currentRecordingFile = rf;
|
|
11123
12666
|
this.selectedRecordingFileChanged.emit(rf);
|
|
11124
12667
|
}
|
|
11125
12668
|
selectTop() {
|
|
11126
|
-
if (this.recordingList.length > 0) {
|
|
11127
|
-
this.selectRecordingFile(this.recordingList[0]);
|
|
12669
|
+
if (this.recordingList.recFiles.length > 0) {
|
|
12670
|
+
this.selectRecordingFile(this.recordingList.recFiles[0]);
|
|
11128
12671
|
}
|
|
11129
12672
|
}
|
|
11130
12673
|
lengthTimeFormatted(rf) {
|
|
11131
12674
|
let str = '--:--:--';
|
|
11132
|
-
|
|
11133
|
-
|
|
12675
|
+
let tl = null;
|
|
12676
|
+
if (rf.timeLength) {
|
|
12677
|
+
tl = rf.timeLength;
|
|
12678
|
+
}
|
|
12679
|
+
else if (rf.frames && rf.audioDataHolder) {
|
|
12680
|
+
tl = rf.frames / rf.audioDataHolder?.sampleRate;
|
|
12681
|
+
}
|
|
12682
|
+
if (tl) {
|
|
12683
|
+
str = MediaUtils.toMediaTime(tl);
|
|
11134
12684
|
}
|
|
11135
12685
|
return str;
|
|
11136
12686
|
}
|
|
@@ -11216,8 +12766,11 @@ class RecorderCombiPane {
|
|
|
11216
12766
|
}
|
|
11217
12767
|
ngAfterViewInit() {
|
|
11218
12768
|
}
|
|
11219
|
-
|
|
11220
|
-
this.recordingListComp.
|
|
12769
|
+
addRecFile(rf) {
|
|
12770
|
+
this.recordingListComp.addRecFile(rf);
|
|
12771
|
+
}
|
|
12772
|
+
setRecFileAudioData(recFile, adh) {
|
|
12773
|
+
this.recordingListComp.setRecFileAudioData(recFile, adh);
|
|
11221
12774
|
}
|
|
11222
12775
|
selectRecordingFile(rf) {
|
|
11223
12776
|
this.selectedRecordingFileChanged.emit(rf);
|
|
@@ -11290,15 +12843,11 @@ class Item {
|
|
|
11290
12843
|
}
|
|
11291
12844
|
class AudioRecorder extends BasicRecorder {
|
|
11292
12845
|
constructor(changeDetectorRef, renderer, route, dialog, sessionService, recFileService, uploader, config) {
|
|
11293
|
-
super(dialog, sessionService, uploader, config);
|
|
11294
|
-
this.changeDetectorRef = changeDetectorRef;
|
|
12846
|
+
super(changeDetectorRef, dialog, sessionService, uploader, config);
|
|
11295
12847
|
this.renderer = renderer;
|
|
11296
12848
|
this.route = route;
|
|
11297
|
-
this.dialog = dialog;
|
|
11298
|
-
this.sessionService = sessionService;
|
|
11299
12849
|
this.recFileService = recFileService;
|
|
11300
12850
|
this.uploader = uploader;
|
|
11301
|
-
this.config = config;
|
|
11302
12851
|
this._project = null;
|
|
11303
12852
|
this.projectName = null;
|
|
11304
12853
|
this.enableUploadRecordings = true;
|
|
@@ -11481,13 +13030,15 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11481
13030
|
if (rfs) {
|
|
11482
13031
|
if (rfs instanceof Array) {
|
|
11483
13032
|
rfs.forEach((rf) => {
|
|
13033
|
+
// the list comes from the server, asssuem all recording files as server persisted
|
|
13034
|
+
rf.serverPersisted = true;
|
|
11484
13035
|
if (rf.startedDate) {
|
|
11485
13036
|
rf._startedAsDateObj = new Date(rf.startedDate);
|
|
11486
13037
|
}
|
|
11487
13038
|
if (rf.date) {
|
|
11488
13039
|
rf._dateAsDateObj = new Date(rf.date);
|
|
11489
13040
|
}
|
|
11490
|
-
this.recorderCombiPane.
|
|
13041
|
+
this.recorderCombiPane.addRecFile(rf);
|
|
11491
13042
|
});
|
|
11492
13043
|
}
|
|
11493
13044
|
else {
|
|
@@ -11541,6 +13092,7 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11541
13092
|
return this._project;
|
|
11542
13093
|
}
|
|
11543
13094
|
selectRecordingFile(rf) {
|
|
13095
|
+
this.audioFetching = false;
|
|
11544
13096
|
this.displayRecFile = rf;
|
|
11545
13097
|
}
|
|
11546
13098
|
uploadUpdate(ue) {
|
|
@@ -11562,9 +13114,6 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11562
13114
|
this.changeDetectorRef.detectChanges();
|
|
11563
13115
|
}
|
|
11564
13116
|
set controlAudioPlayer(controlAudioPlayer) {
|
|
11565
|
-
if (this._controlAudioPlayer) {
|
|
11566
|
-
//this._controlAudioPlayer.listener=null;
|
|
11567
|
-
}
|
|
11568
13117
|
this._controlAudioPlayer = controlAudioPlayer;
|
|
11569
13118
|
if (this._controlAudioPlayer) {
|
|
11570
13119
|
this._controlAudioPlayer.listener = this;
|
|
@@ -11644,6 +13193,7 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11644
13193
|
this.displayAudioClip = null;
|
|
11645
13194
|
this.showRecording();
|
|
11646
13195
|
if (this.ac) {
|
|
13196
|
+
this.audioFetching = false;
|
|
11647
13197
|
if (!this.ac.opened) {
|
|
11648
13198
|
if (this._selectedDeviceId) {
|
|
11649
13199
|
console.log("Open session with audio device Id: \'" + this._selectedDeviceId + "\' for " + this._channelCount + " channels");
|
|
@@ -11660,10 +13210,10 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11660
13210
|
}
|
|
11661
13211
|
downloadRecording() {
|
|
11662
13212
|
if (this.displayRecFile) {
|
|
11663
|
-
let ab = this.displayRecFile.
|
|
13213
|
+
let ab = this.displayRecFile.audioDataHolder;
|
|
11664
13214
|
let ww = new WavWriter();
|
|
11665
|
-
if (ab) {
|
|
11666
|
-
let wavFile = ww.writeAsync(ab, (wavFile) => {
|
|
13215
|
+
if (ab?.buffer) {
|
|
13216
|
+
let wavFile = ww.writeAsync(ab.buffer, (wavFile) => {
|
|
11667
13217
|
let blob = new Blob([wavFile], { type: 'audio/wav' });
|
|
11668
13218
|
let rfUrl = URL.createObjectURL(blob);
|
|
11669
13219
|
let dataDnlLnk = this.renderer.createElement('a');
|
|
@@ -11686,35 +13236,50 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11686
13236
|
set displayRecFile(displayRecFile) {
|
|
11687
13237
|
this._displayRecFile = displayRecFile;
|
|
11688
13238
|
if (this._displayRecFile) {
|
|
11689
|
-
let
|
|
11690
|
-
if (
|
|
11691
|
-
this.displayAudioClip = new AudioClip(
|
|
13239
|
+
let adh = this._displayRecFile.audioDataHolder;
|
|
13240
|
+
if (adh) {
|
|
13241
|
+
this.displayAudioClip = new AudioClip(adh);
|
|
13242
|
+
console.debug(" set recording file: display audio clip set");
|
|
11692
13243
|
this.controlAudioPlayer.audioClip = this.displayAudioClip;
|
|
11693
13244
|
}
|
|
11694
13245
|
else {
|
|
11695
13246
|
// clear for now ...
|
|
11696
13247
|
this.displayAudioClip = null;
|
|
13248
|
+
console.debug("set recording file: display audio clip null");
|
|
11697
13249
|
this.controlAudioPlayer.audioClip = null;
|
|
11698
13250
|
if (this._controlAudioPlayer && this._session) {
|
|
11699
13251
|
//... and try to fetch from server
|
|
11700
|
-
this.
|
|
11701
|
-
|
|
11702
|
-
|
|
11703
|
-
|
|
11704
|
-
|
|
11705
|
-
|
|
11706
|
-
|
|
13252
|
+
this.audioFetching = true;
|
|
13253
|
+
let rf = this._displayRecFile;
|
|
13254
|
+
let clip = this.displayAudioClip;
|
|
13255
|
+
this.audioFetchSubscription = this.recFileService.fetchRecordingFileAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
|
|
13256
|
+
next: ab => {
|
|
13257
|
+
this.audioFetching = false;
|
|
13258
|
+
let fabDh = null;
|
|
13259
|
+
if (ab) {
|
|
13260
|
+
if (rf) {
|
|
13261
|
+
fabDh = new AudioDataHolder(ab);
|
|
13262
|
+
this.recorderCombiPane.setRecFileAudioData(rf, fabDh);
|
|
13263
|
+
}
|
|
13264
|
+
}
|
|
13265
|
+
else {
|
|
13266
|
+
console.error('Recording file could not be loaded.');
|
|
13267
|
+
this.statusMsg = 'Recording file could not be loaded.';
|
|
13268
|
+
this.statusAlertType = 'error';
|
|
13269
|
+
}
|
|
13270
|
+
if (fabDh) {
|
|
13271
|
+
// this.displayAudioClip could have been changed meanwhile, but the recorder unsubcribes before changing the item. Therefore there should be no risk to set to wrong item
|
|
13272
|
+
this.displayAudioClip = new AudioClip(fabDh);
|
|
13273
|
+
//console.debug("set recording file: display audio clip from fetched audio buffer");
|
|
13274
|
+
}
|
|
13275
|
+
this.controlAudioPlayer.audioClip = this.displayAudioClip;
|
|
13276
|
+
this.showRecording();
|
|
13277
|
+
}, error: err => {
|
|
13278
|
+
console.error("Could not load recording file from server: " + err);
|
|
13279
|
+
this.audioFetching = false;
|
|
13280
|
+
this.statusMsg = 'Recording file could not be loaded: ' + err;
|
|
11707
13281
|
this.statusAlertType = 'error';
|
|
11708
13282
|
}
|
|
11709
|
-
if (fab) {
|
|
11710
|
-
this.displayAudioClip = new AudioClip(fab);
|
|
11711
|
-
}
|
|
11712
|
-
this.controlAudioPlayer.audioClip = this.displayAudioClip;
|
|
11713
|
-
this.showRecording();
|
|
11714
|
-
}, err => {
|
|
11715
|
-
console.error("Could not load recording file from server: " + err);
|
|
11716
|
-
this.statusMsg = 'Recording file could not be loaded: ' + err;
|
|
11717
|
-
this.statusAlertType = 'error';
|
|
11718
13283
|
});
|
|
11719
13284
|
}
|
|
11720
13285
|
else {
|
|
@@ -11724,6 +13289,7 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11724
13289
|
}
|
|
11725
13290
|
}
|
|
11726
13291
|
else {
|
|
13292
|
+
console.debug("recording file null");
|
|
11727
13293
|
this.displayAudioClip = null;
|
|
11728
13294
|
this.controlAudioPlayer.audioClip = null;
|
|
11729
13295
|
}
|
|
@@ -11732,25 +13298,6 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11732
13298
|
get displayRecFile() {
|
|
11733
13299
|
return this._displayRecFile;
|
|
11734
13300
|
}
|
|
11735
|
-
showRecording() {
|
|
11736
|
-
this.controlAudioPlayer.stop();
|
|
11737
|
-
if (this.displayAudioClip) {
|
|
11738
|
-
let dap = this.displayAudioClip;
|
|
11739
|
-
this.levelMeasure.calcBufferLevelInfos(dap.buffer, LEVEL_BAR_INTERVALL_SECONDS).then((levelInfos) => {
|
|
11740
|
-
dap.levelInfos = levelInfos;
|
|
11741
|
-
this.changeDetectorRef.detectChanges();
|
|
11742
|
-
});
|
|
11743
|
-
this.playStartAction.disabled = false;
|
|
11744
|
-
}
|
|
11745
|
-
else {
|
|
11746
|
-
this.playStartAction.disabled = true;
|
|
11747
|
-
// Collapse audio signal display if open
|
|
11748
|
-
if (!this.audioSignalCollapsed) {
|
|
11749
|
-
this.audioSignalCollapsed = true;
|
|
11750
|
-
}
|
|
11751
|
-
}
|
|
11752
|
-
this.changeDetectorRef.detectChanges();
|
|
11753
|
-
}
|
|
11754
13301
|
updateStartActionDisableState() {
|
|
11755
13302
|
this.transportActions.startAction.disabled = !(this.ac);
|
|
11756
13303
|
}
|
|
@@ -11794,6 +13341,19 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11794
13341
|
super.started();
|
|
11795
13342
|
this.statusAlertType = 'info';
|
|
11796
13343
|
this.statusMsg = 'Recording...';
|
|
13344
|
+
if (!this.rfUuid) {
|
|
13345
|
+
this.rfUuid = UUID.generate();
|
|
13346
|
+
}
|
|
13347
|
+
let sessId = 0;
|
|
13348
|
+
if (this._session) {
|
|
13349
|
+
sessId = this._session.sessionId;
|
|
13350
|
+
}
|
|
13351
|
+
let rf = new RecordingFile(this.rfUuid, sessId, null);
|
|
13352
|
+
rf._startedAsDateObj = this.startedDate;
|
|
13353
|
+
if (rf._startedAsDateObj) {
|
|
13354
|
+
rf.startedDate = rf._startedAsDateObj.toString();
|
|
13355
|
+
}
|
|
13356
|
+
this._recordingFile = rf;
|
|
11797
13357
|
let maxRecordingTimeMs = MAX_RECORDING_TIME_MS;
|
|
11798
13358
|
this.maxRecTimerId = window.setTimeout(() => {
|
|
11799
13359
|
this.stopRecordingMaxRec();
|
|
@@ -11830,68 +13390,75 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11830
13390
|
this.transportActions.pauseAction.disabled = true;
|
|
11831
13391
|
this.statusAlertType = 'info';
|
|
11832
13392
|
this.statusMsg = 'Recorded.';
|
|
11833
|
-
let ad;
|
|
13393
|
+
let ad = null;
|
|
13394
|
+
let ada = null;
|
|
13395
|
+
let adh = null;
|
|
13396
|
+
let frameLen = 0;
|
|
11834
13397
|
if (this.ac) {
|
|
11835
|
-
|
|
13398
|
+
if (this.uploadChunkSizeSeconds || AudioRecorder.FORCE_ARRRAY_AUDIO_BUFFER) {
|
|
13399
|
+
ada = this.ac.audioBufferArray();
|
|
13400
|
+
frameLen = ada.frameLen;
|
|
13401
|
+
}
|
|
13402
|
+
else {
|
|
13403
|
+
ad = this.ac.audioBuffer();
|
|
13404
|
+
frameLen = ad.length;
|
|
13405
|
+
}
|
|
13406
|
+
adh = new AudioDataHolder(ad, ada);
|
|
11836
13407
|
let sessId = 0;
|
|
11837
13408
|
if (this._session) {
|
|
11838
13409
|
sessId = this._session.sessionId;
|
|
11839
13410
|
}
|
|
11840
|
-
if (
|
|
11841
|
-
this.
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
|
|
13411
|
+
if (this._recordingFile) {
|
|
13412
|
+
// Use an own reference since the writing of the wave file is asynchronous and this._recordingFile might already contain the next recording
|
|
13413
|
+
let rf = this._recordingFile;
|
|
13414
|
+
RecordingFileUtils.setAudioData(rf, adh);
|
|
13415
|
+
this.recorderCombiPane.addRecFile(rf);
|
|
13416
|
+
// Upload if upload enabled and not in chunked upload mode
|
|
13417
|
+
if (this.enableUploadRecordings && !this.uploadChunkSizeSeconds && rf != null && ad != null) {
|
|
13418
|
+
let apiEndPoint = '';
|
|
13419
|
+
if (this.config && this.config.apiEndPoint) {
|
|
13420
|
+
apiEndPoint = this.config.apiEndPoint;
|
|
13421
|
+
}
|
|
13422
|
+
if (apiEndPoint !== '') {
|
|
13423
|
+
apiEndPoint = apiEndPoint + '/';
|
|
13424
|
+
}
|
|
13425
|
+
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
13426
|
+
let recUrl = sessionsUrl + '/' + rf.session + '/' + RECFILE_API_CTX + '/' + rf.uuid;
|
|
13427
|
+
// convert asynchronously to 16-bit integer PCM
|
|
13428
|
+
// TODO could we avoid conversion to save CPU resources and transfer float PCM directly?
|
|
13429
|
+
// TODO duplicate conversion for manual download
|
|
13430
|
+
this.processingRecording = true;
|
|
13431
|
+
let ww = new WavWriter();
|
|
13432
|
+
ww.writeAsync(ad, (wavFile) => {
|
|
13433
|
+
this.postRecordingMultipart(wavFile, recUrl, rf);
|
|
13434
|
+
this.processingRecording = false;
|
|
13435
|
+
this.updateWakeLock();
|
|
13436
|
+
this.changeDetectorRef.detectChanges();
|
|
13437
|
+
});
|
|
11859
13438
|
}
|
|
11860
|
-
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
11861
|
-
let recUrl = sessionsUrl + '/' + rf.session + '/' + RECFILE_API_CTX + '/' + rf.uuid;
|
|
11862
|
-
// convert asynchronously to 16-bit integer PCM
|
|
11863
|
-
// TODO could we avoid conversion to save CPU resources and transfer float PCM directly?
|
|
11864
|
-
// TODO duplicate conversion for manual download
|
|
11865
|
-
this.processingRecording = true;
|
|
11866
|
-
let ww = new WavWriter();
|
|
11867
|
-
ww.writeAsync(ad, (wavFile) => {
|
|
11868
|
-
this.postRecordingMultipart(wavFile, rf.uuid, rf.session, rf._startedAsDateObj, recUrl);
|
|
11869
|
-
this.processingRecording = false;
|
|
11870
|
-
this.updateWakeLock();
|
|
11871
|
-
this.changeDetectorRef.detectChanges();
|
|
11872
|
-
});
|
|
11873
13439
|
}
|
|
11874
13440
|
}
|
|
13441
|
+
this.displayRecFile = this._recordingFile;
|
|
11875
13442
|
this.status = 1 /* IDLE */;
|
|
11876
13443
|
this.navigationDisabled = false;
|
|
11877
13444
|
this.updateNavigationActions();
|
|
11878
13445
|
this.updateWakeLock();
|
|
11879
13446
|
this.changeDetectorRef.detectChanges();
|
|
11880
13447
|
}
|
|
11881
|
-
postRecordingMultipart(wavFile,
|
|
13448
|
+
postRecordingMultipart(wavFile, recUrl, rf) {
|
|
11882
13449
|
let wavBlob = new Blob([wavFile], { type: 'audio/wav' });
|
|
11883
13450
|
let fd = new FormData();
|
|
11884
|
-
if (uuid) {
|
|
11885
|
-
fd.set('uuid', uuid);
|
|
13451
|
+
if (rf.uuid) {
|
|
13452
|
+
fd.set('uuid', rf.uuid);
|
|
11886
13453
|
}
|
|
11887
|
-
if (
|
|
11888
|
-
fd.set('sessionId',
|
|
13454
|
+
if (rf.session !== null) {
|
|
13455
|
+
fd.set('sessionId', rf.session.toString());
|
|
11889
13456
|
}
|
|
11890
|
-
if (
|
|
11891
|
-
fd.set('startedDate',
|
|
13457
|
+
if (rf._startedAsDateObj) {
|
|
13458
|
+
fd.set('startedDate', rf._startedAsDateObj.toJSON());
|
|
11892
13459
|
}
|
|
11893
13460
|
fd.set('audio', wavBlob);
|
|
11894
|
-
let ul = new Upload(fd, recUrl);
|
|
13461
|
+
let ul = new Upload(fd, recUrl, rf);
|
|
11895
13462
|
this.uploader.queueUpload(ul);
|
|
11896
13463
|
}
|
|
11897
13464
|
postChunkAudioBuffer(audioBuffer, chunkIdx) {
|
|
@@ -11907,8 +13474,9 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11907
13474
|
}
|
|
11908
13475
|
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
11909
13476
|
let recUrl = sessionsUrl + '/' + this.session?.sessionId + '/' + RECFILE_API_CTX + '/' + this.rfUuid + '/' + chunkIdx;
|
|
13477
|
+
let rf = this._recordingFile;
|
|
11910
13478
|
ww.writeAsync(audioBuffer, (wavFile) => {
|
|
11911
|
-
this.postRecording(wavFile, recUrl);
|
|
13479
|
+
this.postRecording(wavFile, recUrl, rf);
|
|
11912
13480
|
this.processingRecording = false;
|
|
11913
13481
|
});
|
|
11914
13482
|
}
|
|
@@ -11957,11 +13525,11 @@ AudioRecorder.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version:
|
|
|
11957
13525
|
|
|
11958
13526
|
<div fxLayout="row" fxLayout.xs="column" [ngStyle]="{'height.px':100,'min-height.px': 100}"
|
|
11959
13527
|
[ngStyle.xs]="{'height.px':125,'min-height.px': 125}">
|
|
11960
|
-
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()"
|
|
13528
|
+
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()" [stateLoading]="audioFetching"
|
|
11961
13529
|
[displayLevelInfos]="displayAudioClip?.levelInfos"></audio-levelbar>
|
|
11962
13530
|
<div fxLayout="row">
|
|
11963
13531
|
<spr-recordingitemcontrols fxFlex="10 0 1"
|
|
11964
|
-
[audioLoaded]="displayAudioClip?.
|
|
13532
|
+
[audioLoaded]="displayAudioClip?.audioDataHolder!==null"
|
|
11965
13533
|
[playStartAction]="controlAudioPlayer?.startAction"
|
|
11966
13534
|
[playStopAction]="controlAudioPlayer?.stopAction"
|
|
11967
13535
|
[peakDbLvl]="peakLevelInDb"
|
|
@@ -12000,7 +13568,7 @@ AudioRecorder.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version:
|
|
|
12000
13568
|
[ready]="dataSaved && !isActive()"></app-readystateindicator>
|
|
12001
13569
|
</div>
|
|
12002
13570
|
</div>
|
|
12003
|
-
`, isInline: true, styles: [":host{flex:2;background:lightgrey;display:flex;flex-direction:column;margin:0;padding:0;height:100%;min-height:0px;overflow:hidden}\n", ".ricontrols{padding:4px;box-sizing:border-box;height:100%}\n", ".dark{background:darkgray}\n", ".controlpanel{align-content:center;align-items:center;margin:0;padding:20px;min-height:min-content}\n", ".startstop{width:100%;text-align:center;align-content:center;align-items:center}\n", ".bigbutton{min-width:70px;min-height:50px;font-size:50px;border-radius:20px}\n"], components: [{ type: WarningBar, selector: "app-warningbar", inputs: ["warningText", "show"] }, { type: RecorderCombiPane, selector: "app-recordercombipane", inputs: ["selectDisabled", "selectedRecordingFile", "audioSignalCollapsed", "displayAudioClip", "playStartAction", "playSelectionAction", "autoPlayOnSelectToggleAction", "playStopAction"], outputs: ["selectedRecordingFileChanged"] }, { type: LevelBar, selector: "audio-levelbar", inputs: ["streamingMode", "displayLevelInfos"] }, { type: RecordingItemControls, selector: "spr-recordingitemcontrols", inputs: ["audioSignalCollapsed", "enableDownload", "peakDbLvl", "agc", "audioLoaded", "playStartAction", "playStopAction", "displayLevelInfos"], outputs: ["onShowRecordingDetails", "onDownloadRecording"] }, { type: UploadStatus, selector: "app-uploadstatus", inputs: ["value", "awaitNewUpload", "status"] }, { type: WakeLockIndicator, selector: "app-wakelockindicator", inputs: ["screenLocked"] }, { type: ReadyStateIndicator, selector: "app-readystateindicator", inputs: ["ready"] }, { type: StatusDisplay, selector: "app-sprstatusdisplay", inputs: ["statusAlertType", "statusMsg", "statusWaiting"] }, { type: i3$2.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i3$1.DefaultStyleDirective, selector: " [ngStyle], [ngStyle.xs], [ngStyle.sm], [ngStyle.md], [ngStyle.lg], [ngStyle.xl], [ngStyle.lt-sm], [ngStyle.lt-md], [ngStyle.lt-lg], [ngStyle.lt-xl], [ngStyle.gt-xs], [ngStyle.gt-sm], [ngStyle.gt-md], [ngStyle.gt-lg]", inputs: ["ngStyle", "ngStyle.xs", "ngStyle.sm", "ngStyle.md", "ngStyle.lg", "ngStyle.xl", "ngStyle.lt-sm", "ngStyle.lt-md", "ngStyle.lt-lg", "ngStyle.lt-xl", "ngStyle.gt-xs", "ngStyle.gt-sm", "ngStyle.gt-md", "ngStyle.gt-lg"] }, { type: i4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3$1.DefaultShowHideDirective, selector: " [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]", inputs: ["fxShow", "fxShow.print", "fxShow.xs", "fxShow.sm", "fxShow.md", "fxShow.lg", "fxShow.xl", "fxShow.lt-sm", "fxShow.lt-md", "fxShow.lt-lg", "fxShow.lt-xl", "fxShow.gt-xs", "fxShow.gt-sm", "fxShow.gt-md", "fxShow.gt-lg", "fxHide", "fxHide.print", "fxHide.xs", "fxHide.sm", "fxHide.md", "fxHide.lg", "fxHide.xl", "fxHide.lt-sm", "fxHide.lt-md", "fxHide.lt-lg", "fxHide.lt-xl", "fxHide.gt-xs", "fxHide.gt-sm", "fxHide.gt-md", "fxHide.gt-lg"] }] });
|
|
13571
|
+
`, isInline: true, styles: [":host{flex:2;background:lightgrey;display:flex;flex-direction:column;margin:0;padding:0;height:100%;min-height:0px;overflow:hidden}\n", ".ricontrols{padding:4px;box-sizing:border-box;height:100%}\n", ".dark{background:darkgray}\n", ".controlpanel{align-content:center;align-items:center;margin:0;padding:20px;min-height:min-content}\n", ".startstop{width:100%;text-align:center;align-content:center;align-items:center}\n", ".bigbutton{min-width:70px;min-height:50px;font-size:50px;border-radius:20px}\n"], components: [{ type: WarningBar, selector: "app-warningbar", inputs: ["warningText", "show"] }, { type: RecorderCombiPane, selector: "app-recordercombipane", inputs: ["selectDisabled", "selectedRecordingFile", "audioSignalCollapsed", "displayAudioClip", "playStartAction", "playSelectionAction", "autoPlayOnSelectToggleAction", "playStopAction"], outputs: ["selectedRecordingFileChanged"] }, { type: LevelBar, selector: "audio-levelbar", inputs: ["streamingMode", "displayLevelInfos", "stateLoading"] }, { type: RecordingItemControls, selector: "spr-recordingitemcontrols", inputs: ["audioSignalCollapsed", "enableDownload", "peakDbLvl", "agc", "audioLoaded", "playStartAction", "playStopAction", "displayLevelInfos"], outputs: ["onShowRecordingDetails", "onDownloadRecording"] }, { type: UploadStatus, selector: "app-uploadstatus", inputs: ["value", "awaitNewUpload", "status"] }, { type: WakeLockIndicator, selector: "app-wakelockindicator", inputs: ["screenLocked"] }, { type: ReadyStateIndicator, selector: "app-readystateindicator", inputs: ["ready"] }, { type: StatusDisplay, selector: "app-sprstatusdisplay", inputs: ["statusAlertType", "statusMsg", "statusWaiting"] }, { type: i3$2.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i3$1.DefaultStyleDirective, selector: " [ngStyle], [ngStyle.xs], [ngStyle.sm], [ngStyle.md], [ngStyle.lg], [ngStyle.xl], [ngStyle.lt-sm], [ngStyle.lt-md], [ngStyle.lt-lg], [ngStyle.lt-xl], [ngStyle.gt-xs], [ngStyle.gt-sm], [ngStyle.gt-md], [ngStyle.gt-lg]", inputs: ["ngStyle", "ngStyle.xs", "ngStyle.sm", "ngStyle.md", "ngStyle.lg", "ngStyle.xl", "ngStyle.lt-sm", "ngStyle.lt-md", "ngStyle.lt-lg", "ngStyle.lt-xl", "ngStyle.gt-xs", "ngStyle.gt-sm", "ngStyle.gt-md", "ngStyle.gt-lg"] }, { type: i4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3$1.DefaultShowHideDirective, selector: " [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]", inputs: ["fxShow", "fxShow.print", "fxShow.xs", "fxShow.sm", "fxShow.md", "fxShow.lg", "fxShow.xl", "fxShow.lt-sm", "fxShow.lt-md", "fxShow.lt-lg", "fxShow.lt-xl", "fxShow.gt-xs", "fxShow.gt-sm", "fxShow.gt-md", "fxShow.gt-lg", "fxHide", "fxHide.print", "fxHide.xs", "fxHide.sm", "fxHide.md", "fxHide.lg", "fxHide.xl", "fxHide.lt-sm", "fxHide.lt-md", "fxHide.lt-lg", "fxHide.lt-xl", "fxHide.gt-xs", "fxHide.gt-sm", "fxHide.gt-md", "fxHide.gt-lg"] }] });
|
|
12004
13572
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AudioRecorder, decorators: [{
|
|
12005
13573
|
type: Component,
|
|
12006
13574
|
args: [{
|
|
@@ -12023,11 +13591,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
12023
13591
|
|
|
12024
13592
|
<div fxLayout="row" fxLayout.xs="column" [ngStyle]="{'height.px':100,'min-height.px': 100}"
|
|
12025
13593
|
[ngStyle.xs]="{'height.px':125,'min-height.px': 125}">
|
|
12026
|
-
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()"
|
|
13594
|
+
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()" [stateLoading]="audioFetching"
|
|
12027
13595
|
[displayLevelInfos]="displayAudioClip?.levelInfos"></audio-levelbar>
|
|
12028
13596
|
<div fxLayout="row">
|
|
12029
13597
|
<spr-recordingitemcontrols fxFlex="10 0 1"
|
|
12030
|
-
[audioLoaded]="displayAudioClip?.
|
|
13598
|
+
[audioLoaded]="displayAudioClip?.audioDataHolder!==null"
|
|
12031
13599
|
[playStartAction]="controlAudioPlayer?.startAction"
|
|
12032
13600
|
[playStopAction]="controlAudioPlayer?.stopAction"
|
|
12033
13601
|
[peakDbLvl]="peakLevelInDb"
|
|
@@ -12305,20 +13873,20 @@ class SpeechrecorderngModule {
|
|
|
12305
13873
|
}
|
|
12306
13874
|
SpeechrecorderngModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: SpeechrecorderngModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
12307
13875
|
SpeechrecorderngModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: SpeechrecorderngModule, declarations: [AudioSignal, Sonagram, ScrollPaneHorizontal, AudioClipUIContainer, AudioDisplayScrollPane, AudioDisplay, AudioDisplayPlayer, AudioDisplayControl, LevelBar, Progress, SimpleTrafficLight, Recinstructions, Prompter, PromptContainer, PromptingContainer, Prompting, StatusDisplay,
|
|
12308
|
-
ProgressDisplay, RecordingItemDisplay, RecordingItemControls, UploadStatus, TransportPanel, WakeLockIndicator, ReadyStateIndicator, ControlPanel, WarningBar, AudioRecorder, SessionManager, MessageDialog, SessionFinishedDialog, SpeechrecorderngComponent, AudioRecorderComponent, RecordingFileViewComponent, RecordingFileUI, ScrollIntoViewDirective, RecordingFileNaviComponent, RecordingFileMetaComponent, RecordingList, RecorderCombiPane, AudioRecorder], imports: [i1$1.RouterModule, FlexLayoutModule, CommonModule, MatIconModule, MatButtonModule, MatDialogModule, MatProgressBarModule, MatProgressSpinnerModule, MatTooltipModule, HttpClientModule, MatCheckboxModule, MatCardModule, MatDividerModule, MatGridListModule, MatTableModule, MatInputModule, MatSelectModule, MatSnackBarModule], exports: [MessageDialog, SpeechrecorderngComponent, ScrollPaneHorizontal, AudioClipUIContainer, AudioDisplayScrollPane, AudioDisplay, AudioDisplayPlayer, AudioDisplayControl, LevelBar, AudioRecorder] });
|
|
12309
|
-
SpeechrecorderngModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: SpeechrecorderngModule, providers: [SessionService, ProjectService, ScriptService, RecordingService, RecordingFileService, SpeechRecorderUploader], imports: [[RouterModule.forChild(SPR_ROUTES), FlexLayoutModule, CommonModule, MatIconModule, MatButtonModule, MatDialogModule, MatProgressBarModule, MatProgressSpinnerModule, MatTooltipModule, HttpClientModule, MatCheckboxModule, MatCardModule, MatDividerModule, MatGridListModule, MatTableModule, MatInputModule, MatSelectModule, MatSnackBarModule]] });
|
|
13876
|
+
ProgressDisplay, RecordingItemDisplay, RecordingItemControls, UploadStatus, TransportPanel, WakeLockIndicator, ReadyStateIndicator, ControlPanel, WarningBar, AudioRecorder, SessionManager, MessageDialog, SessionFinishedDialog, SpeechrecorderngComponent, AudioRecorderComponent, RecordingFileViewComponent, RecordingFileUI, ScrollIntoViewDirective, RecordingFileNaviComponent, RecordingFileMetaComponent, RecordingList, RecorderCombiPane, AudioRecorder], imports: [i1$1.RouterModule, FlexLayoutModule, CommonModule, MatIconModule, MatButtonModule, MatDialogModule, MatProgressBarModule, MatProgressSpinnerModule, MatTooltipModule, HttpClientModule, MatCheckboxModule, MatCardModule, MatDividerModule, MatGridListModule, MatTableModule, MatInputModule, MatSelectModule, MatSnackBarModule, MatMenuModule], exports: [MessageDialog, SpeechrecorderngComponent, ScrollPaneHorizontal, AudioClipUIContainer, AudioDisplayScrollPane, AudioDisplay, AudioDisplayPlayer, AudioDisplayControl, LevelBar, AudioRecorder] });
|
|
13877
|
+
SpeechrecorderngModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: SpeechrecorderngModule, providers: [SessionService, ProjectService, ScriptService, RecordingService, RecordingFileService, SpeechRecorderUploader], imports: [[RouterModule.forChild(SPR_ROUTES), FlexLayoutModule, CommonModule, MatIconModule, MatButtonModule, MatDialogModule, MatProgressBarModule, MatProgressSpinnerModule, MatTooltipModule, HttpClientModule, MatCheckboxModule, MatCardModule, MatDividerModule, MatGridListModule, MatTableModule, MatInputModule, MatSelectModule, MatSnackBarModule, MatMenuModule]] });
|
|
12310
13878
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: SpeechrecorderngModule, decorators: [{
|
|
12311
13879
|
type: NgModule,
|
|
12312
13880
|
args: [{
|
|
12313
13881
|
declarations: [AudioSignal, Sonagram, ScrollPaneHorizontal, AudioClipUIContainer, AudioDisplayScrollPane, AudioDisplay, AudioDisplayPlayer, AudioDisplayControl, LevelBar, Progress, SimpleTrafficLight, Recinstructions, Prompter, PromptContainer, PromptingContainer, Prompting, StatusDisplay,
|
|
12314
13882
|
ProgressDisplay, RecordingItemDisplay, RecordingItemControls, UploadStatus, TransportPanel, WakeLockIndicator, ReadyStateIndicator, ControlPanel, WarningBar, AudioRecorder, SessionManager, MessageDialog, SessionFinishedDialog, SpeechrecorderngComponent, AudioRecorderComponent, RecordingFileViewComponent, RecordingFileUI, ScrollIntoViewDirective, RecordingFileNaviComponent, RecordingFileMetaComponent, RecordingList, RecorderCombiPane, AudioRecorder],
|
|
12315
13883
|
exports: [MessageDialog, SpeechrecorderngComponent, ScrollPaneHorizontal, AudioClipUIContainer, AudioDisplayScrollPane, AudioDisplay, AudioDisplayPlayer, AudioDisplayControl, LevelBar, AudioRecorder],
|
|
12316
|
-
imports: [RouterModule.forChild(SPR_ROUTES), FlexLayoutModule, CommonModule, MatIconModule, MatButtonModule, MatDialogModule, MatProgressBarModule, MatProgressSpinnerModule, MatTooltipModule, HttpClientModule, MatCheckboxModule, MatCardModule, MatDividerModule, MatGridListModule, MatTableModule, MatInputModule, MatSelectModule, MatSnackBarModule],
|
|
13884
|
+
imports: [RouterModule.forChild(SPR_ROUTES), FlexLayoutModule, CommonModule, MatIconModule, MatButtonModule, MatDialogModule, MatProgressBarModule, MatProgressSpinnerModule, MatTooltipModule, HttpClientModule, MatCheckboxModule, MatCardModule, MatDividerModule, MatGridListModule, MatTableModule, MatInputModule, MatSelectModule, MatSnackBarModule, MatMenuModule],
|
|
12317
13885
|
providers: [SessionService, ProjectService, ScriptService, RecordingService, RecordingFileService, SpeechRecorderUploader]
|
|
12318
13886
|
}]
|
|
12319
13887
|
}] });
|
|
12320
13888
|
|
|
12321
|
-
const VERSION = '
|
|
13889
|
+
const VERSION = '3.0.0';
|
|
12322
13890
|
|
|
12323
13891
|
/*
|
|
12324
13892
|
* Public API Surface of speechrecorderng
|