speechrecorderng 2.25.2 → 3.0.1
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 +12 -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 +17 -3
- 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 +63 -7
- package/esm2020/lib/speechrecorder/recordings/recordings.service.mjs +96 -7
- package/esm2020/lib/speechrecorder/session/audiorecorder.mjs +119 -106
- package/esm2020/lib/speechrecorder/session/basicrecorder.mjs +34 -7
- 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 +195 -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 +123 -101
- 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 +2355 -753
- package/fesm2015/speechrecorderng.mjs.map +1 -1
- package/fesm2020/speechrecorderng.mjs +2338 -746
- 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 +8 -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 +4 -2
- 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 +16 -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 +10 -5
- 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 +33 -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,42 @@ 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 equals(recordinFile, otherRecordingFile) {
|
|
2295
|
+
if (recordinFile && otherRecordingFile) {
|
|
2296
|
+
if (otherRecordingFile === recordinFile) {
|
|
2297
|
+
return true;
|
|
2298
|
+
}
|
|
2299
|
+
if (otherRecordingFile.uuid === recordinFile.uuid) {
|
|
2300
|
+
return true;
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
return false;
|
|
2304
|
+
}
|
|
2305
|
+
static setAudioData(rf, audioDataHolder) {
|
|
2306
|
+
rf.audioDataHolder = audioDataHolder;
|
|
2307
|
+
if (audioDataHolder) {
|
|
2308
|
+
rf.frames = audioDataHolder.frameLen;
|
|
2309
|
+
rf.timeLength = audioDataHolder.duration;
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
static sampleCount(rf) {
|
|
2313
|
+
if (rf.audioDataHolder) {
|
|
2314
|
+
return rf.audioDataHolder.sampleCounts();
|
|
2315
|
+
}
|
|
2316
|
+
else {
|
|
2317
|
+
return 0;
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
static expireAudioData(rf) {
|
|
2321
|
+
let rv = rf.audioDataHolder;
|
|
2322
|
+
rf.audioDataHolder = null;
|
|
2323
|
+
return rv;
|
|
2324
|
+
}
|
|
1522
2325
|
}
|
|
1523
2326
|
|
|
1524
2327
|
// state of an upload
|
|
@@ -1569,7 +2372,8 @@ class UploaderStatusChangeEvent {
|
|
|
1569
2372
|
}
|
|
1570
2373
|
}
|
|
1571
2374
|
class Upload {
|
|
1572
|
-
constructor(blob, url) {
|
|
2375
|
+
constructor(blob, url, serverPersistable = null) {
|
|
2376
|
+
this.serverPersistable = serverPersistable;
|
|
1573
2377
|
this.toString = () => {
|
|
1574
2378
|
let s = `Upload: Status: ${this.status}, URL: ${this._url}`;
|
|
1575
2379
|
if (this._data instanceof Blob) {
|
|
@@ -1590,6 +2394,17 @@ class Upload {
|
|
|
1590
2394
|
get data() {
|
|
1591
2395
|
return this._data;
|
|
1592
2396
|
}
|
|
2397
|
+
done() {
|
|
2398
|
+
this.status = UploadStatus$1.DONE;
|
|
2399
|
+
//console.debug("Single upload done.");
|
|
2400
|
+
if (this.serverPersistable) {
|
|
2401
|
+
this.serverPersistable.serverPersisted = true;
|
|
2402
|
+
//console.debug("Single upload set server persisted: "+this.serverPersistable);
|
|
2403
|
+
}
|
|
2404
|
+
else {
|
|
2405
|
+
//console.debug("Server persistable not set.");
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
1593
2408
|
}
|
|
1594
2409
|
class Uploader {
|
|
1595
2410
|
constructor(http, withCredentials = false) {
|
|
@@ -1628,7 +2443,7 @@ class Uploader {
|
|
|
1628
2443
|
return si;
|
|
1629
2444
|
}
|
|
1630
2445
|
uploadDone(ul) {
|
|
1631
|
-
ul.
|
|
2446
|
+
ul.done();
|
|
1632
2447
|
// remove upload from queue
|
|
1633
2448
|
for (let i = 0; i < this.que.length; i++) {
|
|
1634
2449
|
if (this.que[i] === ul) {
|
|
@@ -2059,15 +2874,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
2059
2874
|
}], ctorParameters: function () { return []; } });
|
|
2060
2875
|
|
|
2061
2876
|
class AudioClip {
|
|
2062
|
-
constructor(
|
|
2877
|
+
constructor(_audioDataHolder) {
|
|
2878
|
+
this._audioDataHolder = _audioDataHolder;
|
|
2063
2879
|
this._selection = null;
|
|
2880
|
+
this._levelInfos = null;
|
|
2064
2881
|
this.selectionObservers = new Array();
|
|
2065
|
-
this._buffer = buffer;
|
|
2066
2882
|
}
|
|
2067
|
-
get
|
|
2068
|
-
return this.
|
|
2883
|
+
get audioDataHolder() {
|
|
2884
|
+
return this._audioDataHolder;
|
|
2069
2885
|
}
|
|
2070
|
-
;
|
|
2071
2886
|
get selection() {
|
|
2072
2887
|
return this._selection;
|
|
2073
2888
|
}
|
|
@@ -2082,6 +2897,12 @@ class AudioClip {
|
|
|
2082
2897
|
selObs(this);
|
|
2083
2898
|
}
|
|
2084
2899
|
}
|
|
2900
|
+
get levelInfos() {
|
|
2901
|
+
return this._levelInfos;
|
|
2902
|
+
}
|
|
2903
|
+
set levelInfos(value) {
|
|
2904
|
+
this._levelInfos = value;
|
|
2905
|
+
}
|
|
2085
2906
|
addSelectionObserver(selectionObserver, init = false) {
|
|
2086
2907
|
let obsAlreadyInList = this.selectionObservers.find((obs) => (obs === selectionObserver));
|
|
2087
2908
|
if (!obsAlreadyInList) {
|
|
@@ -2164,19 +2985,31 @@ class ViewSelection {
|
|
|
2164
2985
|
class BasicAudioCanvasLayerComponent extends CanvasLayerComponent {
|
|
2165
2986
|
constructor() {
|
|
2166
2987
|
super(...arguments);
|
|
2167
|
-
|
|
2988
|
+
//protected _audioData: AudioBuffer|null=null;
|
|
2989
|
+
//protected _arrayAudioData: ArrayAudioBuffer|null=null;
|
|
2990
|
+
this._audioDataHolder = null;
|
|
2168
2991
|
this._bgColor = 'white';
|
|
2169
2992
|
this._selectColor = 'rgba(0%,0%,100%,25%)';
|
|
2170
2993
|
}
|
|
2994
|
+
frameLength() {
|
|
2995
|
+
let frameLength = null;
|
|
2996
|
+
// if (this._audioData && this._audioData.numberOfChannels > 0) {
|
|
2997
|
+
// let ch0 = this._audioData.getChannelData(0);
|
|
2998
|
+
// frameLength = ch0.length;
|
|
2999
|
+
//
|
|
3000
|
+
// }else if(this._arrayAudioData){
|
|
3001
|
+
// frameLength=this._arrayAudioData.frameLen;
|
|
3002
|
+
// }
|
|
3003
|
+
return frameLength;
|
|
3004
|
+
}
|
|
2171
3005
|
/**
|
|
2172
3006
|
* Returns pixel position depending on current zoom setting.
|
|
2173
3007
|
* @param framePos audio frame (sample) position
|
|
2174
3008
|
*/
|
|
2175
3009
|
frameToXPixelPosition(framePos) {
|
|
2176
3010
|
let pixelPos = null;
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
let frameLength = ch0.length;
|
|
3011
|
+
let frameLength = this._audioDataHolder?.frameLen;
|
|
3012
|
+
if (frameLength !== undefined) {
|
|
2180
3013
|
let vw;
|
|
2181
3014
|
if (this.bounds) {
|
|
2182
3015
|
vw = this.bounds.dimension.width;
|
|
@@ -2206,9 +3039,8 @@ class BasicAudioCanvasLayerComponent extends CanvasLayerComponent {
|
|
|
2206
3039
|
}
|
|
2207
3040
|
viewPortXPixelToFramePosition(xViewPortPixelPos) {
|
|
2208
3041
|
let vpXramePos = null;
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
let frameLength = ch0.length;
|
|
3042
|
+
let frameLength = this._audioDataHolder?.frameLen;
|
|
3043
|
+
if (frameLength !== undefined) {
|
|
2212
3044
|
let vw;
|
|
2213
3045
|
if (this.bounds) {
|
|
2214
3046
|
vw = this.bounds.dimension.width;
|
|
@@ -2385,8 +3217,8 @@ class AudioCanvasLayerComponent extends BasicAudioCanvasLayerComponent {
|
|
|
2385
3217
|
if (viewSel) {
|
|
2386
3218
|
let frameStart = this.viewPortXPixelToFramePosition(viewSel.startX);
|
|
2387
3219
|
let frameEnd = this.viewPortXPixelToFramePosition(viewSel.endX);
|
|
2388
|
-
if (this.
|
|
2389
|
-
ns = new Selection(this.
|
|
3220
|
+
if (this._audioDataHolder && frameStart != null && frameEnd != null) {
|
|
3221
|
+
ns = new Selection(this._audioDataHolder.sampleRate, frameStart, frameEnd);
|
|
2390
3222
|
}
|
|
2391
3223
|
}
|
|
2392
3224
|
this.selectingEventEmitter.emit(ns);
|
|
@@ -2396,8 +3228,8 @@ class AudioCanvasLayerComponent extends BasicAudioCanvasLayerComponent {
|
|
|
2396
3228
|
if (viewSel) {
|
|
2397
3229
|
let frameStart = this.viewPortXPixelToFramePosition(viewSel.startX);
|
|
2398
3230
|
let frameEnd = this.viewPortXPixelToFramePosition(viewSel.endX);
|
|
2399
|
-
if (this.
|
|
2400
|
-
ns = new Selection(this.
|
|
3231
|
+
if (this._audioDataHolder && frameStart != null && frameEnd != null) {
|
|
3232
|
+
ns = new Selection(this._audioDataHolder.sampleRate, frameStart, frameEnd);
|
|
2401
3233
|
}
|
|
2402
3234
|
}
|
|
2403
3235
|
this.selectedEventEmitter.emit(ns);
|
|
@@ -2478,7 +3310,7 @@ class AudioCanvasLayerComponent extends BasicAudioCanvasLayerComponent {
|
|
|
2478
3310
|
g.lineTo(xViewPortPixelpos, h);
|
|
2479
3311
|
g.closePath();
|
|
2480
3312
|
g.stroke();
|
|
2481
|
-
if (this.
|
|
3313
|
+
if (this._audioDataHolder) {
|
|
2482
3314
|
g.font = '14px sans-serif';
|
|
2483
3315
|
g.fillStyle = 'yellow';
|
|
2484
3316
|
g.fillText(framePos.toString(), xViewPortPixelpos + 2, 50);
|
|
@@ -2490,6 +3322,7 @@ class AudioCanvasLayerComponent extends BasicAudioCanvasLayerComponent {
|
|
|
2490
3322
|
}
|
|
2491
3323
|
}
|
|
2492
3324
|
}
|
|
3325
|
+
AudioCanvasLayerComponent.ENABLE_STREAMING_NUMBER_OF_SAMPLES_THRESHOLD = 10 * 60 * 48000; // Use streaming/chunking if audio clip has more than this number of samples
|
|
2493
3326
|
AudioCanvasLayerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AudioCanvasLayerComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
2494
3327
|
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 });
|
|
2495
3328
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AudioCanvasLayerComponent, decorators: [{
|
|
@@ -2524,7 +3357,7 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2524
3357
|
this._playFramePosition = null;
|
|
2525
3358
|
this.worker = null;
|
|
2526
3359
|
this.workerURL = WorkerHelper.buildWorkerBlobURL(this.workerFunction);
|
|
2527
|
-
this.
|
|
3360
|
+
this._audioDataHolder = null;
|
|
2528
3361
|
this._bgColor = 'black';
|
|
2529
3362
|
this._selectColor = 'rgba(255,255,0,0.8)';
|
|
2530
3363
|
}
|
|
@@ -2577,25 +3410,26 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2577
3410
|
*/
|
|
2578
3411
|
workerFunction() {
|
|
2579
3412
|
addEventListener('message', ({ data }) => {
|
|
2580
|
-
let audioData = data.audioData;
|
|
2581
|
-
let
|
|
2582
|
-
let
|
|
2583
|
-
let
|
|
2584
|
-
let vw = data.vw;
|
|
2585
|
-
let chs = data.chs;
|
|
2586
|
-
let
|
|
3413
|
+
let audioData = data.audioData; // audio data part required to render view port
|
|
3414
|
+
let auOffset = data.audioDataOffset;
|
|
3415
|
+
let l = data.l; // left pixel position of view port
|
|
3416
|
+
let w = data.w; // width of viewport
|
|
3417
|
+
let vw = data.vw; // total width of (virtual) audio view (not viewport width)
|
|
3418
|
+
let chs = data.chs; // number of channels
|
|
3419
|
+
let dataFrameLength = data.audioDataFrameLength; // frame length of audio data part required for view port
|
|
3420
|
+
let frameLength = data.frameLength; // total frame length (of audio clip)
|
|
3421
|
+
//console.debug("W: left: "+l+", w:"+w+", vw: "+vw+", chs: "+chs+", frameLength: "+frameLength);
|
|
2587
3422
|
let psMinMax = new Float32Array(0);
|
|
2588
|
-
if (audioData && w >= 0 && vw > 0) {
|
|
3423
|
+
if (audioData && audioData.length > 0 && w >= 0 && vw > 0) {
|
|
2589
3424
|
let framesPerPixel = frameLength / vw;
|
|
2590
|
-
let y = 0;
|
|
2591
3425
|
let pointsLen = w * chs;
|
|
2592
3426
|
// one for min one for max
|
|
2593
3427
|
let arrLen = pointsLen * 2;
|
|
2594
3428
|
psMinMax = new Float32Array(arrLen);
|
|
2595
3429
|
let chFramePos = 0;
|
|
3430
|
+
let chFrameLength = audioData.length / chs;
|
|
2596
3431
|
for (let ch = 0; ch < chs; ch++) {
|
|
2597
|
-
|
|
2598
|
-
chFramePos = ch * frameLength;
|
|
3432
|
+
chFramePos = ch * chFrameLength;
|
|
2599
3433
|
for (let pii = 0; pii < w; pii++) {
|
|
2600
3434
|
let virtPii = l + pii;
|
|
2601
3435
|
let pMin = Infinity;
|
|
@@ -2605,24 +3439,28 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2605
3439
|
for (let ai = 0; ai < framesPerPixel; ai++) {
|
|
2606
3440
|
let framePos = pixelFramePos + ai;
|
|
2607
3441
|
let a = 0;
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
3442
|
+
let bufPos = framePos - auOffset;
|
|
3443
|
+
//let bufPos=framePos;
|
|
3444
|
+
if (bufPos >= 0 && bufPos < audioData.length) {
|
|
3445
|
+
a = audioData[bufPos];
|
|
3446
|
+
//console.debug("W: ch: "+ch+", pixelFramePos: "+pixelFramePos+", framePos: "+framePos+", auOffset: "+auOffset+", bufPos: "+bufPos+", audioData.length: "+audioData.length+", a: "+a);
|
|
3447
|
+
if (a < pMin) {
|
|
3448
|
+
pMin = a;
|
|
3449
|
+
}
|
|
3450
|
+
if (a > pMax) {
|
|
3451
|
+
pMax = a;
|
|
3452
|
+
}
|
|
2616
3453
|
}
|
|
2617
3454
|
}
|
|
2618
3455
|
let psMinPos = ch * w + pii;
|
|
2619
3456
|
psMinMax[psMinPos] = pMin;
|
|
2620
3457
|
let psMaxPos = pointsLen + psMinPos;
|
|
2621
3458
|
psMinMax[psMaxPos] = pMax;
|
|
3459
|
+
//console.debug("psMinMax["+psMinPos+"]="+pMin+",psMinMax["+psMaxPos+"]="+pMax);
|
|
2622
3460
|
}
|
|
2623
3461
|
}
|
|
2624
3462
|
}
|
|
2625
|
-
postMessage({ psMinMax: psMinMax, l: data.l,
|
|
3463
|
+
postMessage({ psMinMax: psMinMax, l: data.l, w: data.w, chs: data.chs, eod: data.eod }, [psMinMax.buffer]);
|
|
2626
3464
|
});
|
|
2627
3465
|
}
|
|
2628
3466
|
startDraw(clear = true) {
|
|
@@ -2650,41 +3488,143 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2650
3488
|
if (this.bounds && this.bounds.dimension) {
|
|
2651
3489
|
let w = Math.round(this.bounds.dimension.width);
|
|
2652
3490
|
let h = Math.round(this.bounds.dimension.height);
|
|
2653
|
-
if (this.
|
|
3491
|
+
if (this._audioDataHolder && w > 0 && h > 0) {
|
|
2654
3492
|
//this.wo = new Worker('./audiosignal.worker.js',{type: 'module'});
|
|
2655
3493
|
this.worker = new Worker(this.workerURL);
|
|
2656
3494
|
//this.wo = new Worker('worker/audiosignal.worker.ts');
|
|
2657
3495
|
//let Worker = require('worker!../../../workers/uploader/main');
|
|
2658
|
-
let chs = this.
|
|
2659
|
-
let
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
let
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
//let
|
|
3496
|
+
let chs = this._audioDataHolder.numberOfChannels;
|
|
3497
|
+
let leftPos = Math.round(this.bounds.position.left);
|
|
3498
|
+
let renderPos = leftPos;
|
|
3499
|
+
let vw = Math.round(this.virtualDimension.width);
|
|
3500
|
+
let frameLength = this._audioDataHolder.frameLen;
|
|
3501
|
+
let framesPerPixel = Math.ceil(frameLength / vw);
|
|
3502
|
+
let audioBuffer = this._audioDataHolder.buffer;
|
|
3503
|
+
//let arrayAudioBuffer=this._audioDataHolder.arrayBuffer;
|
|
3504
|
+
let arrAbBuf;
|
|
3505
|
+
//let ais:ArrayAudioBufferInputStream|null=null;
|
|
3506
|
+
//let aisBuf:Float32Array[]|null=null;
|
|
3507
|
+
let psMinMax = null;
|
|
2668
3508
|
if (this.worker) {
|
|
2669
3509
|
this.worker.onmessage = (me) => {
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
3510
|
+
if (me.data.eod === true) {
|
|
3511
|
+
let psMinMaxTmp;
|
|
3512
|
+
if (psMinMax) {
|
|
3513
|
+
psMinMaxTmp = psMinMax;
|
|
3514
|
+
}
|
|
3515
|
+
else {
|
|
3516
|
+
psMinMaxTmp = me.data.psMinMax;
|
|
3517
|
+
}
|
|
3518
|
+
this.drawRendered(leftPos, w, h, chs, psMinMaxTmp);
|
|
3519
|
+
if (this.worker) {
|
|
3520
|
+
this.worker.terminate();
|
|
3521
|
+
}
|
|
3522
|
+
this.worker = null;
|
|
3523
|
+
}
|
|
3524
|
+
else if (this._audioDataHolder && arrAbBuf) {
|
|
3525
|
+
let rw = me.data.w;
|
|
3526
|
+
let rPointsLen = chs * rw;
|
|
3527
|
+
let pointsLen = chs * w;
|
|
3528
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
3529
|
+
if (psMinMax) {
|
|
3530
|
+
let rBasePos = ch * rw;
|
|
3531
|
+
let basePos = ch * w;
|
|
3532
|
+
let rPosMin = rBasePos;
|
|
3533
|
+
let rPosMax = rPointsLen + rPosMin;
|
|
3534
|
+
let posMin = basePos + (renderPos - leftPos);
|
|
3535
|
+
let posMax = pointsLen + posMin;
|
|
3536
|
+
psMinMax[posMin] = me.data.psMinMax[rPosMin];
|
|
3537
|
+
//console.debug('Min: ('+pos+'): '+me.data.psMinMax[0]);
|
|
3538
|
+
psMinMax[posMax] = me.data.psMinMax[rPosMax];
|
|
3539
|
+
// console.debug('Max: ('+(pointsLen+pos)+'): '+me.data.psMinMax[1]);
|
|
3540
|
+
//console.debug("psMinMax["+posMin+"]="+me.data.psMinMax[rPosMin]+" (rPosMin="+rPosMin+"),psMinMax["+posMax+"]="+me.data.psMinMax[rPosMax]);
|
|
3541
|
+
}
|
|
3542
|
+
}
|
|
3543
|
+
let eod = false;
|
|
3544
|
+
renderPos++;
|
|
3545
|
+
let ad;
|
|
3546
|
+
let leftFramePos = Math.floor(frameLength * renderPos / vw);
|
|
3547
|
+
if (renderPos < leftPos + w) {
|
|
3548
|
+
let read = this._audioDataHolder.frames(leftFramePos, framesPerPixel, arrAbBuf);
|
|
3549
|
+
//console.debug("First read frame: "+arrAbBuf[0][0]);
|
|
3550
|
+
ad = new Float32Array(chs * framesPerPixel);
|
|
3551
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
3552
|
+
ad.set(arrAbBuf[ch], ch * framesPerPixel);
|
|
3553
|
+
}
|
|
3554
|
+
eod = (read <= 0);
|
|
3555
|
+
}
|
|
3556
|
+
else {
|
|
3557
|
+
ad = new Float32Array();
|
|
3558
|
+
eod = true;
|
|
3559
|
+
}
|
|
3560
|
+
let adBuf = ad.buffer;
|
|
3561
|
+
if (this.worker) {
|
|
3562
|
+
this.worker.postMessage({
|
|
3563
|
+
l: renderPos,
|
|
3564
|
+
w: me.data.w,
|
|
3565
|
+
h: h,
|
|
3566
|
+
vw: vw,
|
|
3567
|
+
chs: chs,
|
|
3568
|
+
frameLength: frameLength,
|
|
3569
|
+
audioData: ad,
|
|
3570
|
+
audioDataOffset: leftFramePos,
|
|
3571
|
+
eod: eod
|
|
3572
|
+
}, [adBuf]);
|
|
3573
|
+
}
|
|
2674
3574
|
}
|
|
2675
|
-
this.worker = null;
|
|
2676
3575
|
};
|
|
2677
3576
|
}
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
3577
|
+
if (audioBuffer && audioBuffer.length * audioBuffer.numberOfChannels < AudioCanvasLayerComponent.ENABLE_STREAMING_NUMBER_OF_SAMPLES_THRESHOLD) {
|
|
3578
|
+
// Render whole clip at once
|
|
3579
|
+
arrAbBuf = null;
|
|
3580
|
+
psMinMax = null;
|
|
3581
|
+
let ad = new Float32Array(chs * frameLength);
|
|
3582
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
3583
|
+
ad.set(audioBuffer.getChannelData(ch), ch * frameLength);
|
|
3584
|
+
}
|
|
3585
|
+
this.worker.postMessage({
|
|
3586
|
+
l: leftPos,
|
|
3587
|
+
w: w,
|
|
3588
|
+
vw: vw,
|
|
3589
|
+
chs: chs,
|
|
3590
|
+
frameLength: frameLength,
|
|
3591
|
+
audioData: ad,
|
|
3592
|
+
audioDataOffset: 0,
|
|
3593
|
+
eod: true
|
|
3594
|
+
}, [ad.buffer]);
|
|
3595
|
+
}
|
|
3596
|
+
else {
|
|
3597
|
+
// Render pixel by pixel
|
|
3598
|
+
if (w > 0) {
|
|
3599
|
+
if (framesPerPixel > 0) {
|
|
3600
|
+
let rw = 1;
|
|
3601
|
+
//ais = new ArrayAudioBufferInputStream(arrayAudioBuffer);
|
|
3602
|
+
arrAbBuf = new Array(chs);
|
|
3603
|
+
psMinMax = new Float32Array(chs * w * 2);
|
|
3604
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
3605
|
+
arrAbBuf[ch] = new Float32Array(framesPerPixel);
|
|
3606
|
+
}
|
|
3607
|
+
let leftFramePos = Math.floor(frameLength * renderPos / vw);
|
|
3608
|
+
let auOffset = leftFramePos; // should always be 0
|
|
3609
|
+
//let read=arrayAudioBuffer.frames(leftFramePos,framesPerPixel,arrAbBuf);
|
|
3610
|
+
let read = this._audioDataHolder.frames(leftFramePos, framesPerPixel, arrAbBuf);
|
|
3611
|
+
let ad = new Float32Array(chs * framesPerPixel);
|
|
3612
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
3613
|
+
ad.set(arrAbBuf[ch], ch * framesPerPixel);
|
|
3614
|
+
}
|
|
3615
|
+
this.worker.postMessage({
|
|
3616
|
+
l: renderPos,
|
|
3617
|
+
w: rw,
|
|
3618
|
+
vw: vw,
|
|
3619
|
+
chs: chs,
|
|
3620
|
+
frameLength: frameLength,
|
|
3621
|
+
audioData: ad,
|
|
3622
|
+
audioDataOffset: auOffset,
|
|
3623
|
+
eod: (read <= 0)
|
|
3624
|
+
}, [ad.buffer]);
|
|
3625
|
+
}
|
|
3626
|
+
}
|
|
3627
|
+
}
|
|
2688
3628
|
}
|
|
2689
3629
|
else {
|
|
2690
3630
|
let g = this.signalCanvas.getContext("2d");
|
|
@@ -2694,42 +3634,42 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2694
3634
|
}
|
|
2695
3635
|
}
|
|
2696
3636
|
}
|
|
2697
|
-
drawRendered(
|
|
3637
|
+
drawRendered(left, w, h, chs, psMinMax) {
|
|
2698
3638
|
this.drawBg();
|
|
2699
|
-
this.signalCanvas.style.left =
|
|
2700
|
-
this.signalCanvas.width =
|
|
2701
|
-
this.signalCanvas.height =
|
|
3639
|
+
this.signalCanvas.style.left = left.toString() + 'px';
|
|
3640
|
+
this.signalCanvas.width = w;
|
|
3641
|
+
this.signalCanvas.height = h;
|
|
2702
3642
|
let g = this.signalCanvas.getContext("2d");
|
|
2703
3643
|
if (g) {
|
|
2704
|
-
g.clearRect(0, 0,
|
|
3644
|
+
g.clearRect(0, 0, w, h);
|
|
2705
3645
|
//g.fillStyle = "black";
|
|
2706
3646
|
//g.fillRect(0, 0, me.data.w, me.data.h);
|
|
2707
|
-
let pointsLen =
|
|
3647
|
+
let pointsLen = w * chs;
|
|
2708
3648
|
// one for min one for max
|
|
2709
3649
|
let arrLen = pointsLen * 2;
|
|
2710
|
-
if (this.
|
|
3650
|
+
if (this._audioDataHolder) {
|
|
2711
3651
|
let std = Date.now();
|
|
2712
|
-
let chH =
|
|
3652
|
+
let chH = h / chs;
|
|
2713
3653
|
let y = 0;
|
|
2714
|
-
for (let ch = 0; ch <
|
|
3654
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
2715
3655
|
let x = 0;
|
|
2716
|
-
let psMinPos = ch *
|
|
3656
|
+
let psMinPos = ch * w;
|
|
2717
3657
|
let psMaxPos = pointsLen + psMinPos;
|
|
2718
3658
|
g.fillStyle = 'green';
|
|
2719
3659
|
g.strokeStyle = 'green';
|
|
2720
3660
|
// draw audio signal as single polygon
|
|
2721
3661
|
g.beginPath();
|
|
2722
|
-
g.moveTo(0, y + (chH / 2) +
|
|
2723
|
-
for (let pii = 0; pii <
|
|
2724
|
-
let psMax =
|
|
3662
|
+
g.moveTo(0, y + (chH / 2) + psMinMax[psMaxPos] * chH / 2);
|
|
3663
|
+
for (let pii = 0; pii < w; pii++) {
|
|
3664
|
+
let psMax = psMinMax[psMaxPos + pii];
|
|
2725
3665
|
let pv = psMax * chH / 2;
|
|
2726
3666
|
let yd = y + (chH / 2) - pv;
|
|
2727
3667
|
//console.log("LineTo: : "+pii+" "+yd)
|
|
2728
3668
|
g.lineTo(pii, yd);
|
|
2729
3669
|
}
|
|
2730
|
-
let revPixelStart =
|
|
3670
|
+
let revPixelStart = w - 1;
|
|
2731
3671
|
for (let pii = revPixelStart; pii >= 0; pii--) {
|
|
2732
|
-
let psMin =
|
|
3672
|
+
let psMin = psMinMax[psMinPos + pii];
|
|
2733
3673
|
let pv = psMin * chH / 2;
|
|
2734
3674
|
let yd = y + (chH / 2) - pv;
|
|
2735
3675
|
//console.log("LineTo: : "+pii+" "+yd)
|
|
@@ -2753,13 +3693,23 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2753
3693
|
g.clearRect(0, 0, w, h);
|
|
2754
3694
|
//g.fillStyle = "black";
|
|
2755
3695
|
//g.fillRect(0, 0, w, h);
|
|
2756
|
-
if (this.
|
|
3696
|
+
if (this._audioDataHolder) {
|
|
2757
3697
|
let std = Date.now();
|
|
2758
|
-
let chs = this.
|
|
3698
|
+
let chs = this._audioDataHolder.numberOfChannels;
|
|
2759
3699
|
let chH = h / chs;
|
|
2760
|
-
let frameLength = this.
|
|
3700
|
+
let frameLength = this._audioDataHolder.frameLen;
|
|
2761
3701
|
let framesPerPixel = frameLength / w;
|
|
2762
3702
|
let y = 0;
|
|
3703
|
+
let ais = null;
|
|
3704
|
+
let audioBuffer = this._audioDataHolder.buffer;
|
|
3705
|
+
let aisBuffer = null;
|
|
3706
|
+
if (!audioBuffer) {
|
|
3707
|
+
ais = this._audioDataHolder.audioInputStream();
|
|
3708
|
+
aisBuffer = new Array(chs);
|
|
3709
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
3710
|
+
aisBuffer[ch] = new Float32Array(framesPerPixel);
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
2763
3713
|
for (let ch = 0; ch < chs; ch++) {
|
|
2764
3714
|
let x = 0;
|
|
2765
3715
|
let psMin = new Float32Array(w);
|
|
@@ -2768,20 +3718,33 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2768
3718
|
for (let pii = 0; pii < w; pii++) {
|
|
2769
3719
|
let pMin = 0;
|
|
2770
3720
|
let pMax = 0;
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
pMin
|
|
3721
|
+
if (audioBuffer) {
|
|
3722
|
+
// calculate pixel min/max amplitude
|
|
3723
|
+
for (let ai = 0; ai < framesPerPixel; ai++) {
|
|
3724
|
+
//let framePos=(pii*framesPerPixel)+ai;
|
|
3725
|
+
let a = audioBuffer.getChannelData(ch)[framePos++];
|
|
3726
|
+
if (a < pMin) {
|
|
3727
|
+
pMin = a;
|
|
3728
|
+
}
|
|
3729
|
+
if (a > pMax) {
|
|
3730
|
+
pMax = a;
|
|
3731
|
+
}
|
|
2777
3732
|
}
|
|
2778
|
-
|
|
2779
|
-
|
|
3733
|
+
}
|
|
3734
|
+
else if (ais && aisBuffer) {
|
|
3735
|
+
let r = ais.read(aisBuffer);
|
|
3736
|
+
for (let ai = 0; ai < r; ai++) {
|
|
3737
|
+
let a = aisBuffer[ch][ai];
|
|
3738
|
+
if (a < pMin) {
|
|
3739
|
+
pMin = a;
|
|
3740
|
+
}
|
|
3741
|
+
if (a > pMax) {
|
|
3742
|
+
pMax = a;
|
|
3743
|
+
}
|
|
2780
3744
|
}
|
|
2781
3745
|
}
|
|
2782
3746
|
psMin[pii] = pMin;
|
|
2783
3747
|
psMax[pii] = pMax;
|
|
2784
|
-
//console.log("Min: ", pMin, " max: ", pMax);
|
|
2785
3748
|
}
|
|
2786
3749
|
g.fillStyle = 'green';
|
|
2787
3750
|
g.strokeStyle = 'green';
|
|
@@ -2806,12 +3769,11 @@ class AudioSignal extends AudioCanvasLayerComponent {
|
|
|
2806
3769
|
g.stroke();
|
|
2807
3770
|
y += chH;
|
|
2808
3771
|
}
|
|
2809
|
-
//this.drawPlayPosition();
|
|
2810
3772
|
}
|
|
2811
3773
|
}
|
|
2812
3774
|
}
|
|
2813
3775
|
setData(audioData) {
|
|
2814
|
-
this.
|
|
3776
|
+
this._audioDataHolder = audioData;
|
|
2815
3777
|
this.playFramePosition = 0;
|
|
2816
3778
|
}
|
|
2817
3779
|
}
|
|
@@ -3180,7 +4142,7 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3180
4142
|
this._playFramePosition = null;
|
|
3181
4143
|
this.dftSize = DEFAULT_DFT_SIZE;
|
|
3182
4144
|
this.worker = null;
|
|
3183
|
-
this.
|
|
4145
|
+
this._audioDataHolder = null;
|
|
3184
4146
|
this.markers = new Array();
|
|
3185
4147
|
this.dft = new DFTFloat32(this.dftSize);
|
|
3186
4148
|
this.workerURL = WorkerHelper.buildWorkerBlobURL(this.workerFunction);
|
|
@@ -3233,7 +4195,7 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3233
4195
|
g.lineTo(xViewPortPixelpos, h);
|
|
3234
4196
|
g.closePath();
|
|
3235
4197
|
g.stroke();
|
|
3236
|
-
if (this.
|
|
4198
|
+
if (this._audioDataHolder) {
|
|
3237
4199
|
let framePosRound = this.viewPortXPixelToFramePosition(xViewPortPixelpos);
|
|
3238
4200
|
if (framePosRound != null) {
|
|
3239
4201
|
g.font = '14px sans-serif';
|
|
@@ -3497,11 +4459,21 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3497
4459
|
}
|
|
3498
4460
|
GaussianWindow.DEFAULT_SIGMA = 0.3;
|
|
3499
4461
|
self.onmessage = function (msg) {
|
|
4462
|
+
//console.debug("Sonagram render thread");
|
|
3500
4463
|
let l = msg.data.l;
|
|
3501
4464
|
let w = msg.data.w;
|
|
3502
4465
|
let h = msg.data.h;
|
|
3503
4466
|
let vw = msg.data.vw;
|
|
3504
4467
|
let chs = msg.data.chs;
|
|
4468
|
+
let audioDataOffset = 0;
|
|
4469
|
+
let adOffset = msg.data.audioDataOffset;
|
|
4470
|
+
if (adOffset) {
|
|
4471
|
+
audioDataOffset = adOffset;
|
|
4472
|
+
}
|
|
4473
|
+
let maxPsd = null;
|
|
4474
|
+
if (msg.data.maxPsd !== undefined) {
|
|
4475
|
+
maxPsd = msg.data.maxPsd;
|
|
4476
|
+
}
|
|
3505
4477
|
let audioData = new Array(chs);
|
|
3506
4478
|
for (let ch = 0; ch < chs; ch++) {
|
|
3507
4479
|
audioData[ch] = new Float32Array(msg.data['audioData'][ch]);
|
|
@@ -3517,16 +4489,17 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3517
4489
|
}
|
|
3518
4490
|
let imgData = new Uint8ClampedArray(arrSize);
|
|
3519
4491
|
//console.log("Render method:");
|
|
3520
|
-
|
|
4492
|
+
//console.debug("Created imgData arrSize: "+arrSize+" ", w, "x", h);
|
|
4493
|
+
let calcMaxPsd = -Infinity;
|
|
4494
|
+
if (arrSize > 0) {
|
|
3521
4495
|
let chH = Math.round(h / chs);
|
|
3522
4496
|
let framesPerPixel = frameLength / vw;
|
|
3523
|
-
//console.
|
|
4497
|
+
//console.debug("Render: ", w, "x", h);
|
|
3524
4498
|
let b = new Float32Array(dftSize);
|
|
3525
4499
|
let sona = new Array(chs);
|
|
3526
|
-
let
|
|
3527
|
-
let p = 0;
|
|
4500
|
+
//let p = 0;
|
|
3528
4501
|
for (let ch = 0; ch < chs; ch++) {
|
|
3529
|
-
p = ch * frameLength;
|
|
4502
|
+
//p = ch * frameLength;
|
|
3530
4503
|
let chDataLen = audioData[ch].length;
|
|
3531
4504
|
let x = 0;
|
|
3532
4505
|
// initialize DFT array buffer
|
|
@@ -3543,8 +4516,13 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3543
4516
|
// initialize for negative sample positions and out of bounds positions
|
|
3544
4517
|
let chDat = 0;
|
|
3545
4518
|
// Set audio sample if available
|
|
3546
|
-
|
|
3547
|
-
|
|
4519
|
+
let adp = samplePos - audioDataOffset;
|
|
4520
|
+
if (adp >= 0 && adp < chDataLen) {
|
|
4521
|
+
chDat = audioData[ch][adp];
|
|
4522
|
+
//console.debug("Audio data: "+chDat);
|
|
4523
|
+
}
|
|
4524
|
+
else {
|
|
4525
|
+
//console.debug("Sample buf pos oob: adp: "+adp+", chDataLen: "+chDataLen+", samplePos: "+samplePos+", i: "+i);
|
|
3548
4526
|
}
|
|
3549
4527
|
// apply Window
|
|
3550
4528
|
b[i] = chDat * wf.getScale(i);
|
|
@@ -3554,63 +4532,78 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3554
4532
|
// Get maximum value of spectral energy
|
|
3555
4533
|
for (let s = 0; s < dftBands; s++) {
|
|
3556
4534
|
let psd = (2 * Math.pow(spectr[s], 2)) / dftBands;
|
|
3557
|
-
if (psd >
|
|
3558
|
-
|
|
4535
|
+
if (psd > calcMaxPsd) {
|
|
4536
|
+
calcMaxPsd = psd;
|
|
3559
4537
|
}
|
|
3560
4538
|
}
|
|
3561
4539
|
// Set render model data for this pixel
|
|
3562
4540
|
sona[ch][pii] = spectr;
|
|
3563
4541
|
}
|
|
3564
4542
|
}
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
scaledVal =
|
|
3585
|
-
|
|
3586
|
-
scaledVal
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
rgbVal =
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
4543
|
+
if (!msg.data.norender) {
|
|
4544
|
+
if (!maxPsd) {
|
|
4545
|
+
maxPsd = calcMaxPsd;
|
|
4546
|
+
}
|
|
4547
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4548
|
+
for (let pii = 0; pii < w; pii++) {
|
|
4549
|
+
let allBlack = true;
|
|
4550
|
+
for (let y = 0; y < chH; y++) {
|
|
4551
|
+
let freqIdx = Math.round(y * dftBands / chH);
|
|
4552
|
+
// calculate the one sided power spectral density PSD (f, t) in Pa2/Hz
|
|
4553
|
+
// PSD(f) proportional to 2|X(f)|2 / (t2 - t1)
|
|
4554
|
+
let val = sona[ch][pii][freqIdx];
|
|
4555
|
+
let psd = (2 * Math.pow(val, 2)) / dftBands;
|
|
4556
|
+
// Calculate logarithmic value
|
|
4557
|
+
//let psdLog = ips.dsp.DSPUtils.toLevelInDB(psd / maxPsd);
|
|
4558
|
+
let linearLevel = psd / maxPsd;
|
|
4559
|
+
let psdLog = 10 * Math.log(linearLevel) / Math.log(10);
|
|
4560
|
+
// Fixed dynamic Range value of 70dB for now
|
|
4561
|
+
let dynRangeInDb = 70;
|
|
4562
|
+
let scaledVal = (psdLog + dynRangeInDb) / dynRangeInDb;
|
|
4563
|
+
// are the following checks necessary for clamped array ?
|
|
4564
|
+
if (scaledVal > 1.0)
|
|
4565
|
+
scaledVal = 1;
|
|
4566
|
+
if (scaledVal < 0.0) {
|
|
4567
|
+
scaledVal = 0;
|
|
4568
|
+
}
|
|
4569
|
+
let rgbVal = Math.round(255 * scaledVal);
|
|
4570
|
+
if (rgbVal < 0) {
|
|
4571
|
+
// System.out.println("Neg RGB val: "+rgbVal);
|
|
4572
|
+
rgbVal = 0;
|
|
4573
|
+
}
|
|
4574
|
+
if (rgbVal > 255) {
|
|
4575
|
+
rgbVal = 255;
|
|
4576
|
+
}
|
|
4577
|
+
rgbVal = 255 - rgbVal;
|
|
4578
|
+
if (rgbVal > 0) {
|
|
4579
|
+
allBlack = false;
|
|
4580
|
+
}
|
|
4581
|
+
let py = chH - y;
|
|
4582
|
+
let dataPos = ((((ch * chH) + py) * w) + pii) * 4;
|
|
4583
|
+
imgData[dataPos + 0] = rgbVal; //R
|
|
4584
|
+
imgData[dataPos + 1] = rgbVal; //G
|
|
4585
|
+
imgData[dataPos + 2] = rgbVal; //B
|
|
4586
|
+
imgData[dataPos + 3] = 255; //A (alpha: fully opaque)
|
|
4587
|
+
//console.debug("Rendered: py: "+py+", rgbval: "+rgbVal);
|
|
4588
|
+
// example 1x1, 2chs
|
|
4589
|
+
// ch0x0y0R,ch0x0y0G,ch0x0y0B,ch0x0y0A,
|
|
4590
|
+
// ch0x1y0R,ch0x1y0G,ch0x1y0B,ch0x1y0A,
|
|
4591
|
+
// ch0x0y0R,ch0x0y0G,ch0x0y0B,ch0x0y0A,
|
|
4592
|
+
// ch0x1y1R,ch0x1y1G,ch0x1y1B,ch0x1y1A,
|
|
4593
|
+
// ch1x0y0R,ch1x0y0G,ch1x0y0B,ch1x0y0A,
|
|
4594
|
+
// ch1x1y0R,ch1x1y0G,ch1x1y0B,ch1x1y0A,
|
|
4595
|
+
// ch1x0y0R,ch1x0y0G,ch1x0y0B,ch1x0y0A,
|
|
4596
|
+
// ch1x1y1R,ch1x1y1G,ch1x1y1B,ch1x1y1A
|
|
3599
4597
|
}
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
imgData[dataPos + 1] = rgbVal; //G
|
|
3604
|
-
imgData[dataPos + 2] = rgbVal; //B
|
|
3605
|
-
imgData[dataPos + 3] = 255; //A (alpha: fully opaque)
|
|
4598
|
+
// if (allBlack) {
|
|
4599
|
+
// console.log("Black: ", pii, " ", ch);
|
|
4600
|
+
// }
|
|
3606
4601
|
}
|
|
3607
|
-
// if (allBlack) {
|
|
3608
|
-
// console.log("Black: ", pii, " ", ch);
|
|
3609
|
-
// }
|
|
3610
4602
|
}
|
|
3611
4603
|
}
|
|
3612
4604
|
}
|
|
3613
|
-
|
|
4605
|
+
//console.debug("Render thread post message imgData: "+imgData.length)
|
|
4606
|
+
postMessage({ imgData: imgData, l: l, w: msg.data.w, h: msg.data.h, vw: vw, maxPsd: calcMaxPsd, terminate: msg.data.terminate }, [imgData.buffer]);
|
|
3614
4607
|
};
|
|
3615
4608
|
}
|
|
3616
4609
|
startDraw(clear = true) {
|
|
@@ -3640,42 +4633,190 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3640
4633
|
if (this.bounds) {
|
|
3641
4634
|
let w = Math.round(this.bounds.dimension.width);
|
|
3642
4635
|
let h = Math.round(this.bounds.dimension.height);
|
|
3643
|
-
if (this.
|
|
4636
|
+
if (this._audioDataHolder && w > 0 && h > 0) {
|
|
3644
4637
|
this.worker = new Worker(this.workerURL);
|
|
3645
4638
|
//this.wo = new Worker('./worker/sonagram.worker', { type: `module` });
|
|
3646
|
-
let chs = this.
|
|
3647
|
-
let
|
|
3648
|
-
let
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
let
|
|
4639
|
+
let chs = this._audioDataHolder.numberOfChannels;
|
|
4640
|
+
let vw = Math.round(this.virtualDimension.width);
|
|
4641
|
+
let frameLength = this._audioDataHolder.frameLen;
|
|
4642
|
+
let framesPerPixel = Math.ceil(frameLength / vw);
|
|
4643
|
+
let leftPos = Math.round(this.bounds.position.left);
|
|
4644
|
+
let renderPos = leftPos;
|
|
4645
|
+
let audioBuffer = this._audioDataHolder.buffer;
|
|
4646
|
+
//let arrayAudioBuffer=this._audioDataHolder.arrayBuffer;
|
|
4647
|
+
let arrAbBuf;
|
|
4648
|
+
let imgData;
|
|
4649
|
+
let maxPsd = -Infinity;
|
|
4650
|
+
let norender = true;
|
|
3654
4651
|
if (this.worker) {
|
|
3655
4652
|
this.worker.onmessage = (me) => {
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
4653
|
+
if (true === me.data.terminate) {
|
|
4654
|
+
let drawImgData;
|
|
4655
|
+
if (imgData) {
|
|
4656
|
+
drawImgData = imgData;
|
|
4657
|
+
}
|
|
4658
|
+
else {
|
|
4659
|
+
drawImgData = me.data.imgData;
|
|
4660
|
+
}
|
|
4661
|
+
this.drawRendered(w, h, drawImgData);
|
|
4662
|
+
if (this.worker) {
|
|
4663
|
+
this.worker.terminate();
|
|
4664
|
+
}
|
|
4665
|
+
this.worker = null;
|
|
4666
|
+
}
|
|
4667
|
+
else {
|
|
4668
|
+
// set rendered vertical values of one pixel of timescale
|
|
4669
|
+
//let dataPos = renderPos * h * 4;
|
|
4670
|
+
if (norender) {
|
|
4671
|
+
if (me.data.maxPsd > maxPsd) {
|
|
4672
|
+
maxPsd = me.data.maxPsd;
|
|
4673
|
+
//console.debug("new maxPsd: "+maxPsd);
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
else {
|
|
4677
|
+
let chH = Math.round(h / chs);
|
|
4678
|
+
let idp = me.data.l - leftPos;
|
|
4679
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4680
|
+
for (let y = 0; y < chH; y++) {
|
|
4681
|
+
let py = chH - y;
|
|
4682
|
+
let dataPos = ((((ch * chH) + py) * w) + idp) * 4;
|
|
4683
|
+
let mePos = ((ch * chH) + py) * 4;
|
|
4684
|
+
//let lastPos = dataPos + me.data.imgData.length;
|
|
4685
|
+
//if (lastPos < imgData.length) {
|
|
4686
|
+
// set one pixel
|
|
4687
|
+
imgData[dataPos] = me.data.imgData[mePos];
|
|
4688
|
+
imgData[dataPos + 1] = me.data.imgData[mePos + 1];
|
|
4689
|
+
imgData[dataPos + 2] = me.data.imgData[mePos + 2];
|
|
4690
|
+
imgData[dataPos + 3] = me.data.imgData[mePos + 3];
|
|
4691
|
+
//} else {
|
|
4692
|
+
//console.error("Out of range: " + dataPos + "+" + me.data.imgData.length + ">=" + imgData.length);
|
|
4693
|
+
// }
|
|
4694
|
+
}
|
|
4695
|
+
}
|
|
4696
|
+
}
|
|
4697
|
+
if (this._audioDataHolder && arrAbBuf && this.worker) {
|
|
4698
|
+
// proceed with next pixel
|
|
4699
|
+
renderPos++;
|
|
4700
|
+
//console.debug("Render pos: "+renderPos);
|
|
4701
|
+
let terminate = false;
|
|
4702
|
+
let windowEnd = renderPos >= leftPos + w;
|
|
4703
|
+
if (windowEnd) {
|
|
4704
|
+
if (norender) {
|
|
4705
|
+
// phase two: rendering
|
|
4706
|
+
norender = false;
|
|
4707
|
+
// start from beginning
|
|
4708
|
+
renderPos = leftPos;
|
|
4709
|
+
//console.debug("now rendering: maxPsd: "+maxPsd);
|
|
4710
|
+
}
|
|
4711
|
+
else {
|
|
4712
|
+
// terminate render phase
|
|
4713
|
+
terminate = true;
|
|
4714
|
+
}
|
|
4715
|
+
}
|
|
4716
|
+
let leftFramePos = Math.floor(frameLength * renderPos / vw) - this.dftSize / 2;
|
|
4717
|
+
if (leftFramePos < 0) {
|
|
4718
|
+
leftFramePos = 0;
|
|
4719
|
+
}
|
|
4720
|
+
let ada = new Array(chs);
|
|
4721
|
+
//console.debug("Render pos: "+renderPos+" leftFramePos: "+leftFramePos);
|
|
4722
|
+
if (!terminate) {
|
|
4723
|
+
if (this._audioDataHolder) {
|
|
4724
|
+
let read = this._audioDataHolder.frames(leftFramePos, this.dftSize, arrAbBuf);
|
|
4725
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4726
|
+
// Need a copy here for the worker, otherwise this.audioData is not accessible after posting to the worker
|
|
4727
|
+
ada[ch] = arrAbBuf[ch].buffer.slice(0);
|
|
4728
|
+
}
|
|
4729
|
+
}
|
|
4730
|
+
}
|
|
4731
|
+
else {
|
|
4732
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4733
|
+
ada[ch] = new ArrayBuffer(0);
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
4736
|
+
this.worker.postMessage({
|
|
4737
|
+
audioData: ada,
|
|
4738
|
+
audioDataOffset: leftFramePos,
|
|
4739
|
+
l: renderPos,
|
|
4740
|
+
w: me.data.w,
|
|
4741
|
+
h: h,
|
|
4742
|
+
vw: vw,
|
|
4743
|
+
chs: chs,
|
|
4744
|
+
frameLength: frameLength,
|
|
4745
|
+
dftSize: this.dftSize,
|
|
4746
|
+
maxPsd: maxPsd,
|
|
4747
|
+
norender: norender,
|
|
4748
|
+
terminate: terminate
|
|
4749
|
+
}, ada);
|
|
4750
|
+
}
|
|
3659
4751
|
}
|
|
3660
|
-
this.worker = null;
|
|
3661
4752
|
};
|
|
3662
4753
|
}
|
|
3663
|
-
if (
|
|
3664
|
-
let
|
|
3665
|
-
|
|
3666
|
-
|
|
4754
|
+
if (audioBuffer && audioBuffer.length * audioBuffer.numberOfChannels < AudioCanvasLayerComponent.ENABLE_STREAMING_NUMBER_OF_SAMPLES_THRESHOLD) {
|
|
4755
|
+
let ada = new Array(chs);
|
|
4756
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4757
|
+
// Need a copy here for the worker, otherwise this.audioData is not accessible after posting to the worker
|
|
4758
|
+
ada[ch] = audioBuffer.getChannelData(ch).buffer.slice(0);
|
|
4759
|
+
}
|
|
4760
|
+
let start = Date.now();
|
|
4761
|
+
if (this.markerCanvas) {
|
|
4762
|
+
let g = this.markerCanvas.getContext("2d");
|
|
4763
|
+
if (g) {
|
|
4764
|
+
g.fillText("Rendering...", 10, 20);
|
|
4765
|
+
}
|
|
4766
|
+
}
|
|
4767
|
+
this.worker.postMessage({
|
|
4768
|
+
audioData: ada,
|
|
4769
|
+
l: leftPos,
|
|
4770
|
+
w: w,
|
|
4771
|
+
h: h,
|
|
4772
|
+
vw: Math.round(this.virtualDimension.width),
|
|
4773
|
+
chs: chs,
|
|
4774
|
+
frameLength: frameLength,
|
|
4775
|
+
dftSize: this.dftSize,
|
|
4776
|
+
terminate: true
|
|
4777
|
+
}, ada);
|
|
4778
|
+
}
|
|
4779
|
+
else {
|
|
4780
|
+
if (w > 0) {
|
|
4781
|
+
if (framesPerPixel > 0) {
|
|
4782
|
+
let arrSize = w * h * 4;
|
|
4783
|
+
if (arrSize < 0) {
|
|
4784
|
+
arrSize = 0;
|
|
4785
|
+
}
|
|
4786
|
+
imgData = new Uint8ClampedArray(arrSize);
|
|
4787
|
+
let rw = 1;
|
|
4788
|
+
//ais = new ArrayAudioBufferInputStream(arrayAudioBuffer);
|
|
4789
|
+
arrAbBuf = new Array(chs);
|
|
4790
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4791
|
+
arrAbBuf[ch] = new Float32Array(this.dftSize);
|
|
4792
|
+
}
|
|
4793
|
+
let leftFramePos = Math.floor(frameLength * renderPos / vw) - this.dftSize / 2;
|
|
4794
|
+
let framesToRead = this.dftSize;
|
|
4795
|
+
if (leftFramePos < 0) {
|
|
4796
|
+
//framesToRead=this.dftSize+leftFramePos;
|
|
4797
|
+
leftFramePos = 0;
|
|
4798
|
+
}
|
|
4799
|
+
let read = this._audioDataHolder.frames(leftFramePos, framesToRead, arrAbBuf);
|
|
4800
|
+
let ad = new Float32Array(chs * framesToRead);
|
|
4801
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4802
|
+
ad.set(arrAbBuf[ch], ch * framesToRead);
|
|
4803
|
+
}
|
|
4804
|
+
this.worker.postMessage({
|
|
4805
|
+
l: renderPos,
|
|
4806
|
+
w: rw,
|
|
4807
|
+
h: h,
|
|
4808
|
+
vw: vw,
|
|
4809
|
+
chs: chs,
|
|
4810
|
+
frameLength: frameLength,
|
|
4811
|
+
audioData: ad,
|
|
4812
|
+
audioDataOffset: leftFramePos,
|
|
4813
|
+
dftSize: this.dftSize,
|
|
4814
|
+
norender: norender,
|
|
4815
|
+
terminate: false
|
|
4816
|
+
}, [ad.buffer]);
|
|
4817
|
+
}
|
|
3667
4818
|
}
|
|
3668
4819
|
}
|
|
3669
|
-
this.worker.postMessage({
|
|
3670
|
-
audioData: ada,
|
|
3671
|
-
l: Math.round(this.bounds.position.left),
|
|
3672
|
-
w: w,
|
|
3673
|
-
h: h,
|
|
3674
|
-
vw: Math.round(this.virtualDimension.width),
|
|
3675
|
-
chs: chs,
|
|
3676
|
-
frameLength: frameLength,
|
|
3677
|
-
dftSize: this.dftSize
|
|
3678
|
-
}, ada);
|
|
3679
4820
|
}
|
|
3680
4821
|
else {
|
|
3681
4822
|
let g = this.sonagramCanvas.getContext("2d");
|
|
@@ -3685,17 +4826,17 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3685
4826
|
}
|
|
3686
4827
|
}
|
|
3687
4828
|
}
|
|
3688
|
-
drawRendered(
|
|
4829
|
+
drawRendered(w, h, imgData) {
|
|
3689
4830
|
if (this.sonagramCanvas) {
|
|
3690
|
-
this.sonagramCanvas.width =
|
|
3691
|
-
this.sonagramCanvas.height =
|
|
4831
|
+
this.sonagramCanvas.width = w;
|
|
4832
|
+
this.sonagramCanvas.height = h;
|
|
3692
4833
|
let g = this.sonagramCanvas.getContext("2d");
|
|
3693
4834
|
if (g) {
|
|
3694
|
-
let imgDataArr =
|
|
3695
|
-
if (
|
|
3696
|
-
let
|
|
3697
|
-
|
|
3698
|
-
g.putImageData(
|
|
4835
|
+
let imgDataArr = imgData;
|
|
4836
|
+
if (w > 0 && h > 0) {
|
|
4837
|
+
let gImgData = g.createImageData(w, h);
|
|
4838
|
+
gImgData.data.set(imgDataArr);
|
|
4839
|
+
g.putImageData(gImgData, 0, 0);
|
|
3699
4840
|
}
|
|
3700
4841
|
}
|
|
3701
4842
|
}
|
|
@@ -3711,91 +4852,95 @@ class Sonagram extends AudioCanvasLayerComponent {
|
|
|
3711
4852
|
g.clearRect(0, 0, w, h);
|
|
3712
4853
|
g.fillStyle = "white";
|
|
3713
4854
|
g.fillRect(0, 0, w, h);
|
|
3714
|
-
if (this.
|
|
4855
|
+
if (this._audioDataHolder) {
|
|
3715
4856
|
let spectSize = Math.floor(this.dftSize / 2);
|
|
3716
|
-
let chs = this.
|
|
4857
|
+
let chs = this._audioDataHolder.numberOfChannels;
|
|
3717
4858
|
let chH = h / chs;
|
|
3718
|
-
let frameLength = this.
|
|
4859
|
+
let frameLength = this._audioDataHolder.frameLen;
|
|
3719
4860
|
let framesPerPixel = frameLength / w;
|
|
3720
4861
|
let y = 0;
|
|
3721
|
-
|
|
3722
|
-
let
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
let
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
framePos =
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
sona[ch][pii] = spectr;
|
|
3741
|
-
// @ts-ignore
|
|
3742
|
-
let pMax = Math.max.apply(null, spectr);
|
|
3743
|
-
if (pMax > max) {
|
|
3744
|
-
max = pMax;
|
|
3745
|
-
}
|
|
3746
|
-
for (let s = 0; s < spectSize; s++) {
|
|
3747
|
-
let psd = (2 * Math.pow(spectr[s], 2)) / spectSize;
|
|
3748
|
-
if (psd > maxPsd) {
|
|
3749
|
-
maxPsd = psd;
|
|
4862
|
+
let audioBuffer = this._audioDataHolder.buffer;
|
|
4863
|
+
let arrayAudioBuffer = this._audioDataHolder.arrayBuffer;
|
|
4864
|
+
if (audioBuffer) {
|
|
4865
|
+
let b = new Float32Array(this.dftSize);
|
|
4866
|
+
let sona = new Array(chs);
|
|
4867
|
+
let max = 0;
|
|
4868
|
+
let maxPsd = -Infinity;
|
|
4869
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4870
|
+
let x = 0;
|
|
4871
|
+
sona[ch] = new Array(w);
|
|
4872
|
+
let chData = audioBuffer.getChannelData(ch);
|
|
4873
|
+
// TODO center buffer
|
|
4874
|
+
let framePos = 0;
|
|
4875
|
+
for (let pii = 0; pii < w; pii++) {
|
|
4876
|
+
framePos = Math.round(pii * framesPerPixel);
|
|
4877
|
+
// calculate DFT at pixel position
|
|
4878
|
+
for (let i = 0; i < this.dftSize; i++) {
|
|
4879
|
+
let chDat = chData[framePos + i];
|
|
4880
|
+
b[i] = chDat;
|
|
3750
4881
|
}
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
let framePos = 0;
|
|
3758
|
-
for (let pii = 0; pii < w; pii++) {
|
|
3759
|
-
framePos = pii * framesPerPixel;
|
|
3760
|
-
for (let y = 0; y < h; y++) {
|
|
3761
|
-
let freqIdx = Math.round(y * spectSize / h);
|
|
3762
|
-
// calculate the one sided power spectral density PSD (f, t) in Pa2/Hz
|
|
3763
|
-
// PSD(f) proportional to 2|X(f)|2 / (t2 - t1)
|
|
3764
|
-
let val = sona[ch][pii][freqIdx];
|
|
3765
|
-
let psd = (2 * Math.pow(val, 2)) / spectSize;
|
|
3766
|
-
// Calculate logarithmic
|
|
3767
|
-
let psdLog = DSPUtils.toLevelInDB(psd / maxPsd);
|
|
3768
|
-
let dynRangeInDb = 70;
|
|
3769
|
-
let scaledVal = (psdLog + dynRangeInDb) / dynRangeInDb;
|
|
3770
|
-
if (scaledVal > 1)
|
|
3771
|
-
scaledVal = 1;
|
|
3772
|
-
if (scaledVal < 0) {
|
|
3773
|
-
scaledVal = 0;
|
|
4882
|
+
let spectr = this.dft.processRealMagnitude(b);
|
|
4883
|
+
sona[ch][pii] = spectr;
|
|
4884
|
+
// @ts-ignore
|
|
4885
|
+
let pMax = Math.max.apply(null, spectr);
|
|
4886
|
+
if (pMax > max) {
|
|
4887
|
+
max = pMax;
|
|
3774
4888
|
}
|
|
3775
|
-
let
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
4889
|
+
for (let s = 0; s < spectSize; s++) {
|
|
4890
|
+
let psd = (2 * Math.pow(spectr[s], 2)) / spectSize;
|
|
4891
|
+
if (psd > maxPsd) {
|
|
4892
|
+
maxPsd = psd;
|
|
4893
|
+
}
|
|
3779
4894
|
}
|
|
3780
|
-
|
|
3781
|
-
|
|
4895
|
+
}
|
|
4896
|
+
}
|
|
4897
|
+
//console.log("max: ", max);
|
|
4898
|
+
maxPsd = (2 * Math.pow(max, 2)) / spectSize;
|
|
4899
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
4900
|
+
let framePos = 0;
|
|
4901
|
+
for (let pii = 0; pii < w; pii++) {
|
|
4902
|
+
framePos = pii * framesPerPixel;
|
|
4903
|
+
for (let y = 0; y < h; y++) {
|
|
4904
|
+
let freqIdx = Math.round(y * spectSize / h);
|
|
4905
|
+
// calculate the one sided power spectral density PSD (f, t) in Pa2/Hz
|
|
4906
|
+
// PSD(f) proportional to 2|X(f)|2 / (t2 - t1)
|
|
4907
|
+
let val = sona[ch][pii][freqIdx];
|
|
4908
|
+
let psd = (2 * Math.pow(val, 2)) / spectSize;
|
|
4909
|
+
// Calculate logarithmic
|
|
4910
|
+
let psdLog = DSPUtils.toLevelInDB(psd / maxPsd);
|
|
4911
|
+
let dynRangeInDb = 70;
|
|
4912
|
+
let scaledVal = (psdLog + dynRangeInDb) / dynRangeInDb;
|
|
4913
|
+
if (scaledVal > 1)
|
|
4914
|
+
scaledVal = 1;
|
|
4915
|
+
if (scaledVal < 0) {
|
|
4916
|
+
scaledVal = 0;
|
|
4917
|
+
}
|
|
4918
|
+
let rgbVal = (255 * scaledVal);
|
|
4919
|
+
if (rgbVal < 0) {
|
|
4920
|
+
// System.out.println("Neg RGB val: "+rgbVal);
|
|
4921
|
+
rgbVal = 0;
|
|
4922
|
+
}
|
|
4923
|
+
if (rgbVal > 255) {
|
|
4924
|
+
rgbVal = 255;
|
|
4925
|
+
}
|
|
4926
|
+
rgbVal = 255 - rgbVal;
|
|
4927
|
+
let colorStr = CSSUtils.toColorString(rgbVal, rgbVal, rgbVal);
|
|
4928
|
+
g.fillStyle = colorStr;
|
|
4929
|
+
g.fillRect(pii, chH - y, 1, 1);
|
|
3782
4930
|
}
|
|
3783
|
-
rgbVal = 255 - rgbVal;
|
|
3784
|
-
let colorStr = CSSUtils.toColorString(rgbVal, rgbVal, rgbVal);
|
|
3785
|
-
g.fillStyle = colorStr;
|
|
3786
|
-
g.fillRect(pii, chH - y, 1, 1);
|
|
3787
4931
|
}
|
|
3788
4932
|
}
|
|
4933
|
+
this.drawPlayPosition();
|
|
4934
|
+
}
|
|
4935
|
+
else if (arrayAudioBuffer) {
|
|
4936
|
+
throw Error("Redraw with array audio buffer not supported.");
|
|
3789
4937
|
}
|
|
3790
|
-
this.drawPlayPosition();
|
|
3791
4938
|
}
|
|
3792
4939
|
}
|
|
3793
4940
|
}
|
|
3794
4941
|
setData(audioData) {
|
|
3795
|
-
this.
|
|
4942
|
+
this._audioDataHolder = audioData;
|
|
3796
4943
|
this.playFramePosition = 0;
|
|
3797
|
-
//this.redraw();
|
|
3798
|
-
//this.startRender();
|
|
3799
4944
|
}
|
|
3800
4945
|
}
|
|
3801
4946
|
Sonagram.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: Sonagram, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
@@ -4020,13 +5165,13 @@ class AudioClipUIContainer extends BasicAudioCanvasLayerComponent {
|
|
|
4020
5165
|
}
|
|
4021
5166
|
currentXZoom() {
|
|
4022
5167
|
let xz = this._xZoom;
|
|
4023
|
-
if (xz == null && this.
|
|
5168
|
+
if (xz == null && this._audioDataHolder) {
|
|
4024
5169
|
let ow = this.ce.offsetWidth;
|
|
4025
5170
|
if (ow < 1) {
|
|
4026
5171
|
// at least one pixel width to avoid x-zoom zero values
|
|
4027
5172
|
ow = 1;
|
|
4028
5173
|
}
|
|
4029
|
-
xz = ow / this.
|
|
5174
|
+
xz = ow / this._audioDataHolder.duration;
|
|
4030
5175
|
}
|
|
4031
5176
|
return xz;
|
|
4032
5177
|
}
|
|
@@ -4107,7 +5252,7 @@ class AudioClipUIContainer extends BasicAudioCanvasLayerComponent {
|
|
|
4107
5252
|
layout(clear = true) {
|
|
4108
5253
|
if (this.ce && this.dc) {
|
|
4109
5254
|
const clientW = this.ce.clientWidth;
|
|
4110
|
-
if (this.
|
|
5255
|
+
if (this._audioDataHolder) {
|
|
4111
5256
|
if (this._fixFitToPanel) {
|
|
4112
5257
|
// Set the virtual canvas width to the visible width
|
|
4113
5258
|
if (this.ce.style.width != '100%') {
|
|
@@ -4118,7 +5263,7 @@ class AudioClipUIContainer extends BasicAudioCanvasLayerComponent {
|
|
|
4118
5263
|
else {
|
|
4119
5264
|
if (this._xZoom) {
|
|
4120
5265
|
// Set the virtual canvas width according to the value of the user selected xZoom value
|
|
4121
|
-
const newClW = Math.round(this._xZoom * this.
|
|
5266
|
+
const newClW = Math.round(this._xZoom * this._audioDataHolder?.duration);
|
|
4122
5267
|
this.ce.style.width = newClW + 'px';
|
|
4123
5268
|
}
|
|
4124
5269
|
else {
|
|
@@ -4130,22 +5275,22 @@ class AudioClipUIContainer extends BasicAudioCanvasLayerComponent {
|
|
|
4130
5275
|
this._layout(clear, true);
|
|
4131
5276
|
}
|
|
4132
5277
|
}
|
|
4133
|
-
set audioData(
|
|
5278
|
+
set audioData(audioDataHolder) {
|
|
4134
5279
|
this._audioClip = null;
|
|
4135
|
-
this.
|
|
4136
|
-
this.as.setData(
|
|
4137
|
-
this.so.setData(
|
|
5280
|
+
this._audioDataHolder = audioDataHolder;
|
|
5281
|
+
this.as.setData(audioDataHolder);
|
|
5282
|
+
this.so.setData(audioDataHolder);
|
|
4138
5283
|
this.layout();
|
|
4139
5284
|
}
|
|
4140
5285
|
get audioData() {
|
|
4141
|
-
return this.
|
|
5286
|
+
return this._audioDataHolder;
|
|
4142
5287
|
}
|
|
4143
5288
|
set audioClip(audioClip) {
|
|
4144
5289
|
this._audioClip = audioClip;
|
|
4145
5290
|
let audioData = null;
|
|
4146
5291
|
let sel = null;
|
|
4147
5292
|
if (audioClip) {
|
|
4148
|
-
audioData = audioClip.
|
|
5293
|
+
audioData = audioClip.audioDataHolder;
|
|
4149
5294
|
if (this._audioClip) {
|
|
4150
5295
|
this._audioClip.addSelectionObserver((clip) => {
|
|
4151
5296
|
this.selection = clip.selection;
|
|
@@ -4153,9 +5298,9 @@ class AudioClipUIContainer extends BasicAudioCanvasLayerComponent {
|
|
|
4153
5298
|
}
|
|
4154
5299
|
sel = audioClip.selection;
|
|
4155
5300
|
}
|
|
4156
|
-
this.
|
|
4157
|
-
this.as.setData(this.
|
|
4158
|
-
this.so.setData(this.
|
|
5301
|
+
this._audioDataHolder = audioData;
|
|
5302
|
+
this.as.setData(this._audioDataHolder);
|
|
5303
|
+
this.so.setData(this._audioDataHolder);
|
|
4159
5304
|
this.selecting = null;
|
|
4160
5305
|
this.selection = sel;
|
|
4161
5306
|
this.layout();
|
|
@@ -4347,7 +5492,7 @@ class AudioDisplayScrollPane {
|
|
|
4347
5492
|
let audioData = null;
|
|
4348
5493
|
let sel = null;
|
|
4349
5494
|
if (audioClip) {
|
|
4350
|
-
audioData = audioClip.
|
|
5495
|
+
audioData = audioClip.audioDataHolder;
|
|
4351
5496
|
sel = audioClip.selection;
|
|
4352
5497
|
audioClip.addSelectionObserver((clip) => {
|
|
4353
5498
|
this.zoomSelectedAction.disabled = (clip.selection == null);
|
|
@@ -4618,17 +5763,17 @@ class AudioDisplay {
|
|
|
4618
5763
|
console.log("Play started");
|
|
4619
5764
|
this.status = 'Playing...';
|
|
4620
5765
|
}
|
|
4621
|
-
set audioData(
|
|
4622
|
-
this.audioDisplayScrollPane.audioData =
|
|
5766
|
+
set audioData(audioData) {
|
|
5767
|
+
this.audioDisplayScrollPane.audioData = audioData;
|
|
4623
5768
|
if (this.playStartAction) {
|
|
4624
|
-
this.playStartAction.disabled = (
|
|
5769
|
+
this.playStartAction.disabled = (audioData == null);
|
|
4625
5770
|
}
|
|
4626
5771
|
}
|
|
4627
5772
|
set audioClip(audioClip) {
|
|
4628
5773
|
let audioData = null;
|
|
4629
5774
|
let sel = null;
|
|
4630
5775
|
if (audioClip) {
|
|
4631
|
-
audioData = audioClip.buffer;
|
|
5776
|
+
audioData = audioClip.audioDataHolder.buffer;
|
|
4632
5777
|
sel = audioClip.selection;
|
|
4633
5778
|
}
|
|
4634
5779
|
this._audioClip = audioClip;
|
|
@@ -4741,7 +5886,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
4741
5886
|
|
|
4742
5887
|
class Progress {
|
|
4743
5888
|
constructor() {
|
|
4744
|
-
this.items =
|
|
5889
|
+
this.items = undefined;
|
|
4745
5890
|
this.selectedItemIdx = 0;
|
|
4746
5891
|
this.enableDownload = false;
|
|
4747
5892
|
this.onRowSelect = new EventEmitter();
|
|
@@ -5481,7 +6626,7 @@ class Prompting {
|
|
|
5481
6626
|
constructor() {
|
|
5482
6627
|
this.promptItem = null;
|
|
5483
6628
|
this.showPrompt = false;
|
|
5484
|
-
this.items =
|
|
6629
|
+
this.items = undefined;
|
|
5485
6630
|
this.enableDownload = false;
|
|
5486
6631
|
this.audioSignalCollapsed = true;
|
|
5487
6632
|
this.displayAudioClip = null;
|
|
@@ -5792,6 +6937,7 @@ class LevelBar {
|
|
|
5792
6937
|
this._streamingMode = false;
|
|
5793
6938
|
this._staticLevelInfos = null;
|
|
5794
6939
|
this._playFramePosition = null;
|
|
6940
|
+
this._stateLoading = false;
|
|
5795
6941
|
this.warnDBLevel = DEFAULT_WARN_DB_LEVEL$1;
|
|
5796
6942
|
this.dbValues = new Array();
|
|
5797
6943
|
}
|
|
@@ -5825,17 +6971,22 @@ class LevelBar {
|
|
|
5825
6971
|
}
|
|
5826
6972
|
}
|
|
5827
6973
|
set displayLevelInfos(levelInfos) {
|
|
5828
|
-
this._staticLevelInfos = levelInfos;
|
|
5829
6974
|
if (levelInfos) {
|
|
6975
|
+
this._staticLevelInfos = levelInfos;
|
|
5830
6976
|
this.dbValues = levelInfos.bufferLevelInfos.map((li) => {
|
|
5831
6977
|
return li.powerLevelsDB();
|
|
5832
6978
|
});
|
|
5833
6979
|
}
|
|
5834
6980
|
else {
|
|
6981
|
+
this._staticLevelInfos = null;
|
|
5835
6982
|
this.dbValues = new Array();
|
|
5836
6983
|
}
|
|
5837
6984
|
this.layoutStatic();
|
|
5838
6985
|
}
|
|
6986
|
+
set stateLoading(loading) {
|
|
6987
|
+
this._stateLoading = loading;
|
|
6988
|
+
this.layoutStatic();
|
|
6989
|
+
}
|
|
5839
6990
|
set channelCount(channelCount) {
|
|
5840
6991
|
this.reset();
|
|
5841
6992
|
}
|
|
@@ -6016,6 +7167,12 @@ class LevelBar {
|
|
|
6016
7167
|
}
|
|
6017
7168
|
}
|
|
6018
7169
|
}
|
|
7170
|
+
else if (this._stateLoading) {
|
|
7171
|
+
g.strokeStyle = 'white';
|
|
7172
|
+
g.fillStyle = 'white';
|
|
7173
|
+
g.font = '20px sans-serif';
|
|
7174
|
+
g.fillText("Loading...", 10, 25);
|
|
7175
|
+
}
|
|
6019
7176
|
}
|
|
6020
7177
|
}
|
|
6021
7178
|
}
|
|
@@ -6058,7 +7215,7 @@ class LevelBar {
|
|
|
6058
7215
|
}
|
|
6059
7216
|
}
|
|
6060
7217
|
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 });
|
|
6061
|
-
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: `
|
|
7218
|
+
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: `
|
|
6062
7219
|
<div #virtualCanvas>
|
|
6063
7220
|
<canvas #levelbar></canvas>
|
|
6064
7221
|
<canvas #markerCanvas></canvas>
|
|
@@ -6115,6 +7272,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
6115
7272
|
type: Input
|
|
6116
7273
|
}], displayLevelInfos: [{
|
|
6117
7274
|
type: Input
|
|
7275
|
+
}], stateLoading: [{
|
|
7276
|
+
type: Input
|
|
6118
7277
|
}], onResize: [{
|
|
6119
7278
|
type: HostListener,
|
|
6120
7279
|
args: ['window:resize', ['$event']]
|
|
@@ -6705,47 +7864,66 @@ class PeakLevelInterceptor {
|
|
|
6705
7864
|
}
|
|
6706
7865
|
}
|
|
6707
7866
|
class LevelMeasure {
|
|
7867
|
+
//private bufferLevelInfos=new Array<LevelInfo>();
|
|
7868
|
+
//private peakLevelInfo!:LevelInfo;
|
|
6708
7869
|
constructor() {
|
|
6709
7870
|
this.worker = null;
|
|
6710
7871
|
this.workerURL = WorkerHelper.buildWorkerBlobURL(this.workerFunction);
|
|
6711
7872
|
}
|
|
6712
|
-
calcBufferLevelInfos(
|
|
7873
|
+
calcBufferLevelInfos(audioDataHolder, bufferTimeLength) {
|
|
6713
7874
|
return new Promise((resolve) => {
|
|
6714
|
-
let chs =
|
|
6715
|
-
let bufferFrameLength = Math.round(
|
|
6716
|
-
let
|
|
7875
|
+
let chs = audioDataHolder.numberOfChannels;
|
|
7876
|
+
let bufferFrameLength = Math.round(audioDataHolder.sampleRate * bufferTimeLength);
|
|
7877
|
+
let ais = audioDataHolder.audioInputStream();
|
|
7878
|
+
let audioBuffers = new Array(chs);
|
|
7879
|
+
let trBuffers = new Array(chs);
|
|
6717
7880
|
for (let ch = 0; ch < chs; ch++) {
|
|
6718
|
-
|
|
6719
|
-
let adChCopy = new Float32Array(adCh.length);
|
|
6720
|
-
adChCopy.set(adCh);
|
|
6721
|
-
buffers[ch] = adChCopy.buffer;
|
|
7881
|
+
audioBuffers[ch] = new Float32Array(bufferFrameLength);
|
|
6722
7882
|
}
|
|
7883
|
+
let bufferLevelInfos = new Array();
|
|
7884
|
+
let peakLevelInfo = new LevelInfo(chs);
|
|
6723
7885
|
this.worker = new Worker(this.workerURL);
|
|
6724
7886
|
this.worker.onmessage = (me) => {
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
7887
|
+
if (me.data.linLevelBuffers) {
|
|
7888
|
+
let linLevelArrs = new Array(chs);
|
|
7889
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
7890
|
+
linLevelArrs[ch] = new Float32Array(me.data.linLevelBuffers[ch]);
|
|
7891
|
+
}
|
|
7892
|
+
let bufferCount = Math.ceil(me.data.frameLength / me.data.bufferFrameLength);
|
|
7893
|
+
let framePos = 0;
|
|
7894
|
+
for (let bi = 0; bi < bufferCount; bi++) {
|
|
7895
|
+
let minLevels = new Array(chs);
|
|
7896
|
+
let maxLevels = new Array(chs);
|
|
7897
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
7898
|
+
let linLvlArrPos = bi * 2;
|
|
7899
|
+
minLevels[ch] = linLevelArrs[ch][linLvlArrPos];
|
|
7900
|
+
maxLevels[ch] = linLevelArrs[ch][linLvlArrPos + 1];
|
|
7901
|
+
}
|
|
7902
|
+
let bli = new LevelInfo(chs, framePos, me.data.bufferFrameLength, minLevels, maxLevels);
|
|
7903
|
+
bufferLevelInfos.push(bli);
|
|
7904
|
+
peakLevelInfo.merge(bli);
|
|
7905
|
+
}
|
|
7906
|
+
}
|
|
7907
|
+
if (me.data.eod === true) {
|
|
7908
|
+
// end of data, terminate worker and return result
|
|
7909
|
+
this.terminateWorker();
|
|
7910
|
+
resolve(new LevelInfos(bufferLevelInfos, peakLevelInfo));
|
|
7911
|
+
}
|
|
7912
|
+
else {
|
|
7913
|
+
let read = ais.read(audioBuffers);
|
|
6736
7914
|
for (let ch = 0; ch < chs; ch++) {
|
|
6737
|
-
let
|
|
6738
|
-
|
|
6739
|
-
maxLevels[ch] = linLevelArrs[ch][linLvlArrPos + 1];
|
|
7915
|
+
let copy = new Float32Array(audioBuffers[ch]);
|
|
7916
|
+
trBuffers[ch] = copy.buffer;
|
|
6740
7917
|
}
|
|
6741
|
-
|
|
6742
|
-
bufferLevelInfos.push(bli);
|
|
6743
|
-
peakLevelInfo.merge(bli);
|
|
7918
|
+
this.worker?.postMessage({ bufferFrameLength: bufferFrameLength, audioData: trBuffers, chs: chs, len: read }, trBuffers);
|
|
6744
7919
|
}
|
|
6745
|
-
this.terminateWorker();
|
|
6746
|
-
resolve(new LevelInfos(bufferLevelInfos, peakLevelInfo));
|
|
6747
7920
|
};
|
|
6748
|
-
|
|
7921
|
+
let read = ais.read(audioBuffers);
|
|
7922
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
7923
|
+
let copy = new Float32Array(audioBuffers[ch]);
|
|
7924
|
+
trBuffers[ch] = copy.buffer;
|
|
7925
|
+
}
|
|
7926
|
+
this.worker?.postMessage({ bufferFrameLength: bufferFrameLength, audioData: trBuffers, chs: chs, len: read }, trBuffers);
|
|
6749
7927
|
});
|
|
6750
7928
|
}
|
|
6751
7929
|
terminateWorker() {
|
|
@@ -6756,40 +7934,63 @@ class LevelMeasure {
|
|
|
6756
7934
|
*/
|
|
6757
7935
|
workerFunction() {
|
|
6758
7936
|
self.onmessage = function (msg) {
|
|
6759
|
-
let
|
|
7937
|
+
let len = msg.data.len;
|
|
6760
7938
|
let bufferFrameLength = msg.data.bufferFrameLength;
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
7939
|
+
if (len == -1) {
|
|
7940
|
+
// start
|
|
7941
|
+
postMessage({
|
|
7942
|
+
eod: false,
|
|
7943
|
+
bufferFrameLength: bufferFrameLength,
|
|
7944
|
+
frameLength: len
|
|
7945
|
+
});
|
|
6765
7946
|
}
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
7947
|
+
if (len == 0) {
|
|
7948
|
+
postMessage({
|
|
7949
|
+
eod: true,
|
|
7950
|
+
bufferFrameLength: bufferFrameLength,
|
|
7951
|
+
frameLength: len
|
|
7952
|
+
});
|
|
6770
7953
|
}
|
|
6771
|
-
|
|
7954
|
+
else {
|
|
7955
|
+
let chs = msg.data.chs;
|
|
7956
|
+
let audioData = new Array(chs);
|
|
7957
|
+
let linLevels = new Array(chs);
|
|
6772
7958
|
for (let ch = 0; ch < chs; ch++) {
|
|
6773
|
-
|
|
6774
|
-
for (let s = 0; s < frameLength; s++) {
|
|
6775
|
-
let bi = Math.floor(s / bufferFrameLength);
|
|
6776
|
-
let lvlArrPos = bi * 2;
|
|
6777
|
-
//let bs = s % bufferFrameLength;
|
|
6778
|
-
let chSample = chData[s];
|
|
6779
|
-
if (chSample < linLevels[ch][lvlArrPos]) {
|
|
6780
|
-
linLevels[ch][lvlArrPos] = chSample;
|
|
6781
|
-
}
|
|
6782
|
-
lvlArrPos++;
|
|
6783
|
-
if (chSample > linLevels[ch][lvlArrPos]) {
|
|
6784
|
-
linLevels[ch][lvlArrPos] = chSample;
|
|
6785
|
-
}
|
|
6786
|
-
}
|
|
7959
|
+
audioData[ch] = new Float32Array(msg.data.audioData[ch]);
|
|
6787
7960
|
}
|
|
6788
|
-
|
|
7961
|
+
//let frameLength = audioData[0].length;
|
|
7962
|
+
let bufferCount = Math.ceil(len / bufferFrameLength);
|
|
6789
7963
|
for (let ch = 0; ch < chs; ch++) {
|
|
6790
|
-
|
|
7964
|
+
linLevels[ch] = new Float32Array(bufferCount * 2);
|
|
7965
|
+
}
|
|
7966
|
+
if (audioData && chs > 0) {
|
|
7967
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
7968
|
+
let chData = audioData[ch];
|
|
7969
|
+
for (let s = 0; s < len; s++) {
|
|
7970
|
+
let bi = Math.floor(s / bufferFrameLength);
|
|
7971
|
+
let lvlArrPos = bi * 2;
|
|
7972
|
+
//let bs = s % bufferFrameLength;
|
|
7973
|
+
let chSample = chData[s];
|
|
7974
|
+
if (chSample < linLevels[ch][lvlArrPos]) {
|
|
7975
|
+
linLevels[ch][lvlArrPos] = chSample;
|
|
7976
|
+
}
|
|
7977
|
+
lvlArrPos++;
|
|
7978
|
+
if (chSample > linLevels[ch][lvlArrPos]) {
|
|
7979
|
+
linLevels[ch][lvlArrPos] = chSample;
|
|
7980
|
+
}
|
|
7981
|
+
}
|
|
7982
|
+
}
|
|
7983
|
+
const linLevelBufs = new Array(chs);
|
|
7984
|
+
for (let ch = 0; ch < chs; ch++) {
|
|
7985
|
+
linLevelBufs[ch] = linLevels[ch].buffer;
|
|
7986
|
+
}
|
|
7987
|
+
postMessage({
|
|
7988
|
+
eod: false,
|
|
7989
|
+
bufferFrameLength: bufferFrameLength,
|
|
7990
|
+
frameLength: len,
|
|
7991
|
+
linLevelBuffers: linLevelBufs
|
|
7992
|
+
}, linLevelBufs);
|
|
6791
7993
|
}
|
|
6792
|
-
postMessage({ bufferFrameLength: bufferFrameLength, frameLength: frameLength, linLevelBuffers: linLevelBufs }, linLevelBufs);
|
|
6793
7994
|
}
|
|
6794
7995
|
};
|
|
6795
7996
|
}
|
|
@@ -7161,7 +8362,7 @@ RecordingItemDisplay.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", v
|
|
|
7161
8362
|
<audio-levelbar fxFlex="1 0 1" [streamingMode]="streamingMode" [displayLevelInfos]="_displayLevelInfos"></audio-levelbar>
|
|
7162
8363
|
<spr-recordingitemcontrols fxFlex="0 0 0" [audioLoaded]="displayAudioBuffer!==null" [playStartAction]="playStartAction" [playStopAction]="playStopAction" [peakDbLvl]="peakDbLvl" [agc]="_agc" (onShowRecordingDetails)="onShowRecordingDetails.emit()"></spr-recordingitemcontrols>
|
|
7163
8364
|
</div>
|
|
7164
|
-
`, 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"] }] });
|
|
8365
|
+
`, 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"] }] });
|
|
7165
8366
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: RecordingItemDisplay, decorators: [{
|
|
7166
8367
|
type: Component,
|
|
7167
8368
|
args: [{
|
|
@@ -7207,89 +8408,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
7207
8408
|
type: Input
|
|
7208
8409
|
}] } });
|
|
7209
8410
|
|
|
7210
|
-
class Float32ArrayChunkerOutStream {
|
|
7211
|
-
constructor(outStream) {
|
|
7212
|
-
this.outStream = outStream;
|
|
7213
|
-
this.bufs = new Array();
|
|
7214
|
-
this._channels = 0;
|
|
7215
|
-
this._chunkSize = 0;
|
|
7216
|
-
this.filled = 0;
|
|
7217
|
-
this.receivedFrames = 0;
|
|
7218
|
-
this.sentFrames = 0;
|
|
7219
|
-
}
|
|
7220
|
-
createBuffers() {
|
|
7221
|
-
this.bufs = new Array(this._channels);
|
|
7222
|
-
for (let ch = 0; ch < this._channels; ch++) {
|
|
7223
|
-
this.bufs[ch] = new Float32Array(this._chunkSize);
|
|
7224
|
-
}
|
|
7225
|
-
}
|
|
7226
|
-
set chunkSize(chunkSize) {
|
|
7227
|
-
this._chunkSize = chunkSize;
|
|
7228
|
-
this.createBuffers();
|
|
7229
|
-
}
|
|
7230
|
-
get chunkSize() {
|
|
7231
|
-
return this._chunkSize;
|
|
7232
|
-
}
|
|
7233
|
-
set channels(channels) {
|
|
7234
|
-
this._channels = channels;
|
|
7235
|
-
this.createBuffers();
|
|
7236
|
-
}
|
|
7237
|
-
get channels() {
|
|
7238
|
-
return this._channels;
|
|
7239
|
-
}
|
|
7240
|
-
available() {
|
|
7241
|
-
return this._chunkSize - this.filled;
|
|
7242
|
-
}
|
|
7243
|
-
write(buffers) {
|
|
7244
|
-
let copied = 0;
|
|
7245
|
-
if (buffers.length > 0) {
|
|
7246
|
-
let buffersLen = buffers[0].length;
|
|
7247
|
-
this.receivedFrames += buffersLen;
|
|
7248
|
-
let avail = buffersLen;
|
|
7249
|
-
// Fill out buffers until all values copied
|
|
7250
|
-
while (avail > 0) {
|
|
7251
|
-
let toFill = this._chunkSize - this.filled;
|
|
7252
|
-
if (toFill > avail) {
|
|
7253
|
-
toFill = avail;
|
|
7254
|
-
}
|
|
7255
|
-
let sliceEnd = copied + toFill;
|
|
7256
|
-
// Firefox on Android sends only the first channel
|
|
7257
|
-
for (let ch = 0; ch < buffersLen; ch++) {
|
|
7258
|
-
if (buffers[ch]) {
|
|
7259
|
-
let cpPrt = buffers[ch].slice(copied, sliceEnd);
|
|
7260
|
-
let buf = this.bufs[ch];
|
|
7261
|
-
buf.set(cpPrt, this.filled);
|
|
7262
|
-
}
|
|
7263
|
-
}
|
|
7264
|
-
copied += toFill;
|
|
7265
|
-
avail -= toFill;
|
|
7266
|
-
this.filled += toFill;
|
|
7267
|
-
if (this.filled == this._chunkSize) {
|
|
7268
|
-
this.outStream.write(this.bufs);
|
|
7269
|
-
this.sentFrames += this.filled;
|
|
7270
|
-
this.filled = 0;
|
|
7271
|
-
}
|
|
7272
|
-
}
|
|
7273
|
-
}
|
|
7274
|
-
return copied;
|
|
7275
|
-
}
|
|
7276
|
-
flush() {
|
|
7277
|
-
if (this.filled > 0) {
|
|
7278
|
-
let restBufs = new Array(this._channels);
|
|
7279
|
-
for (let ch = 0; ch < this._channels; ch++) {
|
|
7280
|
-
restBufs[ch] = this.bufs[ch].slice(0, this.filled);
|
|
7281
|
-
}
|
|
7282
|
-
this.outStream.write(restBufs);
|
|
7283
|
-
this.outStream.flush();
|
|
7284
|
-
this.sentFrames += this.filled;
|
|
7285
|
-
this.filled = 0;
|
|
7286
|
-
}
|
|
7287
|
-
}
|
|
7288
|
-
close() {
|
|
7289
|
-
this.outStream.close();
|
|
7290
|
-
}
|
|
7291
|
-
}
|
|
7292
|
-
|
|
7293
8411
|
class SequenceAudioFloat32ChunkerOutStream extends Float32ArrayChunkerOutStream {
|
|
7294
8412
|
constructor(outStream, chunkDurationSeconds) {
|
|
7295
8413
|
super(outStream);
|
|
@@ -7298,11 +8416,11 @@ class SequenceAudioFloat32ChunkerOutStream extends Float32ArrayChunkerOutStream
|
|
|
7298
8416
|
this.sequenceAudioFloat32OutStream = outStream;
|
|
7299
8417
|
}
|
|
7300
8418
|
setFormat(channels, sampleRate) {
|
|
7301
|
-
console.debug("SequenceAudioFloat32ChunkerOutStream:setFormat(channels: "
|
|
8419
|
+
//console.debug("SequenceAudioFloat32ChunkerOutStream:setFormat(channels: "+channels+",sampleRate: "+sampleRate+")")
|
|
7302
8420
|
this.channels = channels;
|
|
7303
8421
|
this.sampleRate = sampleRate;
|
|
7304
8422
|
this.chunkSize = Math.round(sampleRate * this.chunkDurationSeconds);
|
|
7305
|
-
console.debug("SequenceAudioFloat32ChunkerOutStream: chunkSize: "
|
|
8423
|
+
//console.debug("SequenceAudioFloat32ChunkerOutStream: chunkSize: "+this.chunkSize);
|
|
7306
8424
|
this.sequenceAudioFloat32OutStream.setFormat(channels, sampleRate);
|
|
7307
8425
|
}
|
|
7308
8426
|
nextStream() {
|
|
@@ -7508,7 +8626,8 @@ class ChunkManager {
|
|
|
7508
8626
|
}
|
|
7509
8627
|
}
|
|
7510
8628
|
let BasicRecorder = class BasicRecorder {
|
|
7511
|
-
constructor(dialog, sessionService, uploader, config) {
|
|
8629
|
+
constructor(changeDetectorRef, dialog, sessionService, uploader, config) {
|
|
8630
|
+
this.changeDetectorRef = changeDetectorRef;
|
|
7512
8631
|
this.dialog = dialog;
|
|
7513
8632
|
this.sessionService = sessionService;
|
|
7514
8633
|
this.uploader = uploader;
|
|
@@ -7523,14 +8642,15 @@ let BasicRecorder = class BasicRecorder {
|
|
|
7523
8642
|
this._selectedDeviceId = undefined;
|
|
7524
8643
|
this._channelCount = 2;
|
|
7525
8644
|
this._session = null;
|
|
8645
|
+
this._recordingFile = null;
|
|
7526
8646
|
this.startedDate = null;
|
|
7527
8647
|
this.uploadProgress = 100;
|
|
7528
8648
|
this.uploadStatus = 'ok';
|
|
7529
8649
|
this.audioSignalCollapsed = true;
|
|
7530
8650
|
this.peakLevelInDb = MIN_DB_LEVEL;
|
|
7531
|
-
this.displayLevelInfos = null;
|
|
7532
8651
|
this.displayAudioClip = null;
|
|
7533
8652
|
this.audioFetchSubscription = null;
|
|
8653
|
+
this.audioFetching = false;
|
|
7534
8654
|
this.destroyed = false;
|
|
7535
8655
|
this.navigationDisabled = true;
|
|
7536
8656
|
// Default: Disabled chunked upload
|
|
@@ -7624,6 +8744,28 @@ let BasicRecorder = class BasicRecorder {
|
|
|
7624
8744
|
this.ac.audioOutStream = outStream;
|
|
7625
8745
|
}
|
|
7626
8746
|
}
|
|
8747
|
+
showRecording() {
|
|
8748
|
+
this._controlAudioPlayer.stop();
|
|
8749
|
+
if (this.displayAudioClip) {
|
|
8750
|
+
let dap = this.displayAudioClip;
|
|
8751
|
+
let adh = dap.audioDataHolder;
|
|
8752
|
+
if (adh) {
|
|
8753
|
+
this.levelMeasure.calcBufferLevelInfos(adh, LEVEL_BAR_INTERVALL_SECONDS).then((levelInfos) => {
|
|
8754
|
+
dap.levelInfos = levelInfos;
|
|
8755
|
+
this.changeDetectorRef.detectChanges();
|
|
8756
|
+
});
|
|
8757
|
+
}
|
|
8758
|
+
this.playStartAction.disabled = false;
|
|
8759
|
+
}
|
|
8760
|
+
else {
|
|
8761
|
+
this.playStartAction.disabled = true;
|
|
8762
|
+
// Collapse audio signal display if open
|
|
8763
|
+
if (!this.audioSignalCollapsed) {
|
|
8764
|
+
this.audioSignalCollapsed = true;
|
|
8765
|
+
}
|
|
8766
|
+
}
|
|
8767
|
+
this.changeDetectorRef.detectChanges();
|
|
8768
|
+
}
|
|
7627
8769
|
start() {
|
|
7628
8770
|
this.statusAlertType = 'info';
|
|
7629
8771
|
this.statusMsg = 'Starting session...';
|
|
@@ -7844,9 +8986,9 @@ let BasicRecorder = class BasicRecorder {
|
|
|
7844
8986
|
}
|
|
7845
8987
|
this.transportActions.startAction.disabled = true;
|
|
7846
8988
|
}
|
|
7847
|
-
postRecording(wavFile, recUrl) {
|
|
8989
|
+
postRecording(wavFile, recUrl, rf) {
|
|
7848
8990
|
let wavBlob = new Blob([wavFile], { type: 'audio/wav' });
|
|
7849
|
-
let ul = new Upload(wavBlob, recUrl);
|
|
8991
|
+
let ul = new Upload(wavBlob, recUrl, rf);
|
|
7850
8992
|
this.uploader.queueUpload(ul);
|
|
7851
8993
|
}
|
|
7852
8994
|
postAudioStreamStart() {
|
|
@@ -7888,34 +9030,339 @@ let BasicRecorder = class BasicRecorder {
|
|
|
7888
9030
|
let fd = new FormData();
|
|
7889
9031
|
fd.set('uuid', this.rfUuid);
|
|
7890
9032
|
fd.set('chunkCount', chunkCount.toString());
|
|
7891
|
-
let ul = new Upload(fd, recUrl);
|
|
9033
|
+
let ul = new Upload(fd, recUrl, this._recordingFile);
|
|
7892
9034
|
this.uploader.queueUpload(ul);
|
|
9035
|
+
console.debug("Queued for upload: " + this._recordingFile);
|
|
9036
|
+
}
|
|
9037
|
+
else {
|
|
9038
|
+
console.error("Recording file UUID not set!");
|
|
9039
|
+
}
|
|
9040
|
+
}
|
|
9041
|
+
closed() {
|
|
9042
|
+
this.statusAlertType = 'info';
|
|
9043
|
+
this.statusMsg = 'Session closed.';
|
|
9044
|
+
}
|
|
9045
|
+
error(msg = 'An unknown error occured during recording.', advice = 'Please retry.') {
|
|
9046
|
+
this.statusMsg = 'ERROR: Recording.';
|
|
9047
|
+
this.statusAlertType = 'error';
|
|
9048
|
+
this.dialog.open(MessageDialog, {
|
|
9049
|
+
data: {
|
|
9050
|
+
type: 'error',
|
|
9051
|
+
title: 'Recording error',
|
|
9052
|
+
msg: msg,
|
|
9053
|
+
advice: advice
|
|
9054
|
+
}
|
|
9055
|
+
});
|
|
9056
|
+
}
|
|
9057
|
+
};
|
|
9058
|
+
// Enable only for developemnt/debug purposes of array audio buffers !!
|
|
9059
|
+
BasicRecorder.FORCE_ARRRAY_AUDIO_BUFFER = false;
|
|
9060
|
+
BasicRecorder.DEFAULT_CHUNK_SIZE_SECONDS = 30;
|
|
9061
|
+
BasicRecorder = __decorate([
|
|
9062
|
+
__param(4, Inject(SPEECHRECORDER_CONFIG))
|
|
9063
|
+
], BasicRecorder);
|
|
9064
|
+
|
|
9065
|
+
class AudioDataHolder {
|
|
9066
|
+
constructor(_buffer, _arrayBuffer = null) {
|
|
9067
|
+
this._buffer = _buffer;
|
|
9068
|
+
this._arrayBuffer = _arrayBuffer;
|
|
9069
|
+
this._numberOfChannels = 0;
|
|
9070
|
+
this._sampleRate = 0;
|
|
9071
|
+
this._frameLen = 0;
|
|
9072
|
+
this._duration = 0;
|
|
9073
|
+
if (this._buffer && this._arrayBuffer) {
|
|
9074
|
+
throw Error('Only one of either audio buffer or array audio buffer must be set!');
|
|
9075
|
+
}
|
|
9076
|
+
if (this._buffer || this._arrayBuffer) {
|
|
9077
|
+
if (this._buffer) {
|
|
9078
|
+
this._numberOfChannels = this._buffer.numberOfChannels;
|
|
9079
|
+
this._sampleRate = this._buffer.sampleRate;
|
|
9080
|
+
this._frameLen = this._buffer.length;
|
|
9081
|
+
this._duration = this._frameLen / this._sampleRate;
|
|
9082
|
+
}
|
|
9083
|
+
else if (this._arrayBuffer) {
|
|
9084
|
+
this._numberOfChannels = this._arrayBuffer.channelCount;
|
|
9085
|
+
this._sampleRate = this._arrayBuffer.sampleRate;
|
|
9086
|
+
this._frameLen = this._arrayBuffer.frameLen;
|
|
9087
|
+
this._duration = this._frameLen / this._sampleRate;
|
|
9088
|
+
}
|
|
9089
|
+
}
|
|
9090
|
+
else {
|
|
9091
|
+
throw Error(AudioDataHolder.ONE_OF_MUST_BE_SET_ERR_MSG);
|
|
9092
|
+
}
|
|
9093
|
+
}
|
|
9094
|
+
get duration() {
|
|
9095
|
+
return this._duration;
|
|
9096
|
+
}
|
|
9097
|
+
get sampleRate() {
|
|
9098
|
+
return this._sampleRate;
|
|
9099
|
+
}
|
|
9100
|
+
get numberOfChannels() {
|
|
9101
|
+
return this._numberOfChannels;
|
|
9102
|
+
}
|
|
9103
|
+
get frameLen() {
|
|
9104
|
+
return this._frameLen;
|
|
9105
|
+
}
|
|
9106
|
+
sampleCounts() {
|
|
9107
|
+
return this._numberOfChannels * this._frameLen;
|
|
9108
|
+
}
|
|
9109
|
+
frames(framePos, frameLen, bufs) {
|
|
9110
|
+
let read = 0;
|
|
9111
|
+
if (this._buffer) {
|
|
9112
|
+
let toRead = frameLen;
|
|
9113
|
+
if (this._buffer.length < framePos + frameLen) {
|
|
9114
|
+
toRead = this._buffer.length - framePos;
|
|
9115
|
+
}
|
|
9116
|
+
for (let ch = 0; ch < bufs.length; ch++) {
|
|
9117
|
+
let chData = this._buffer.getChannelData(ch);
|
|
9118
|
+
for (let i = 0; i < toRead; i++) {
|
|
9119
|
+
bufs[ch][i] = chData[framePos + i];
|
|
9120
|
+
}
|
|
9121
|
+
}
|
|
9122
|
+
read = toRead;
|
|
9123
|
+
}
|
|
9124
|
+
else if (this._arrayBuffer) {
|
|
9125
|
+
read = this._arrayBuffer.frames(framePos, frameLen, bufs);
|
|
9126
|
+
}
|
|
9127
|
+
return read;
|
|
9128
|
+
}
|
|
9129
|
+
audioInputStream() {
|
|
9130
|
+
if (this._buffer) {
|
|
9131
|
+
return new AudioBufferInputStream(this._buffer);
|
|
9132
|
+
}
|
|
9133
|
+
if (this._arrayBuffer) {
|
|
9134
|
+
return new ArrayAudioBufferInputStream(this._arrayBuffer);
|
|
9135
|
+
}
|
|
9136
|
+
throw Error(AudioDataHolder.ONE_OF_MUST_BE_SET_ERR_MSG);
|
|
9137
|
+
}
|
|
9138
|
+
get buffer() {
|
|
9139
|
+
return this._buffer;
|
|
9140
|
+
}
|
|
9141
|
+
get arrayBuffer() {
|
|
9142
|
+
return this._arrayBuffer;
|
|
9143
|
+
}
|
|
9144
|
+
}
|
|
9145
|
+
AudioDataHolder.ONE_OF_MUST_BE_SET_ERR_MSG = 'One of either audio buffer or array audio buffer must be set!';
|
|
9146
|
+
class AudioBufferInputStream {
|
|
9147
|
+
constructor(audioBuffer) {
|
|
9148
|
+
this.audioBuffer = audioBuffer;
|
|
9149
|
+
this.framePos = 0;
|
|
9150
|
+
}
|
|
9151
|
+
close() {
|
|
9152
|
+
}
|
|
9153
|
+
skipFrames(n) {
|
|
9154
|
+
this.framePos += n;
|
|
9155
|
+
}
|
|
9156
|
+
read(buffers) {
|
|
9157
|
+
let read = 0;
|
|
9158
|
+
let toRead = buffers[0].length;
|
|
9159
|
+
if (this.framePos + toRead > this.audioBuffer.length) {
|
|
9160
|
+
toRead = this.audioBuffer.length - this.framePos;
|
|
9161
|
+
}
|
|
9162
|
+
for (let ch = 0; ch < buffers.length; ch++) {
|
|
9163
|
+
for (let i = 0; i < toRead; i++) {
|
|
9164
|
+
buffers[ch][i] = this.audioBuffer.getChannelData(ch)[this.framePos + i];
|
|
9165
|
+
}
|
|
9166
|
+
}
|
|
9167
|
+
read = toRead;
|
|
9168
|
+
this.framePos += toRead;
|
|
9169
|
+
return read;
|
|
9170
|
+
}
|
|
9171
|
+
}
|
|
9172
|
+
|
|
9173
|
+
class BasicRecFilesCache {
|
|
9174
|
+
constructor() {
|
|
9175
|
+
//public static readonly DEFAULT_MAX_SAMPLES=30*48000; // TEST 30 seconds
|
|
9176
|
+
this._sampleCount = 0;
|
|
9177
|
+
this.maxSampleCount = BasicRecFilesCache.DEFAULT_MAX_SAMPLES;
|
|
9178
|
+
this._currentRecordingFile = null;
|
|
9179
|
+
}
|
|
9180
|
+
get currentRecordingFile() {
|
|
9181
|
+
return this._currentRecordingFile;
|
|
9182
|
+
}
|
|
9183
|
+
set currentRecordingFile(value) {
|
|
9184
|
+
this._currentRecordingFile = value;
|
|
9185
|
+
this.expire();
|
|
9186
|
+
}
|
|
9187
|
+
}
|
|
9188
|
+
BasicRecFilesCache.DEBUG = false;
|
|
9189
|
+
BasicRecFilesCache.DEFAULT_MAX_SAMPLES = 10 * 60 * 48000; // 20 Minutes mono 48kHz
|
|
9190
|
+
class SprItemsCache extends BasicRecFilesCache {
|
|
9191
|
+
constructor() {
|
|
9192
|
+
super(...arguments);
|
|
9193
|
+
this._items = new Array();
|
|
9194
|
+
}
|
|
9195
|
+
get items() {
|
|
9196
|
+
return this._items;
|
|
9197
|
+
}
|
|
9198
|
+
addItem(item) {
|
|
9199
|
+
this._items.push(item);
|
|
9200
|
+
}
|
|
9201
|
+
getItem(index) {
|
|
9202
|
+
return this._items[index];
|
|
9203
|
+
}
|
|
9204
|
+
length() {
|
|
9205
|
+
return this._items.length;
|
|
9206
|
+
}
|
|
9207
|
+
tryExpire(toBeExpiredRf) {
|
|
9208
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9209
|
+
console.debug("Rec. files cache: " + toBeExpiredRf.toString() + " try expire:");
|
|
9210
|
+
if (!RecordingFileUtils.equals(toBeExpiredRf, this.currentRecordingFile)) {
|
|
9211
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9212
|
+
console.debug("Rec. files cache: " + toBeExpiredRf.toString() + " not current file...");
|
|
9213
|
+
if (toBeExpiredRf.serverPersisted) {
|
|
9214
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9215
|
+
console.debug("Rec. files cache: " + toBeExpiredRf.toString() + " is server persisted...");
|
|
9216
|
+
// expire recording files first stored to the cache
|
|
9217
|
+
let expiredAudio = RecordingFileUtils.expireAudioData(toBeExpiredRf);
|
|
9218
|
+
if (expiredAudio) {
|
|
9219
|
+
this._sampleCount -= expiredAudio.sampleCounts();
|
|
9220
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9221
|
+
console.debug("Rec. files cache: Expired: " + toBeExpiredRf.toString() + ". Cache samples now: " + this._sampleCount);
|
|
9222
|
+
}
|
|
9223
|
+
}
|
|
9224
|
+
else {
|
|
9225
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9226
|
+
console.debug("Rec. files cache: #" + toBeExpiredRf.toString() + " not yet persisted on server.");
|
|
9227
|
+
}
|
|
7893
9228
|
}
|
|
7894
9229
|
else {
|
|
7895
|
-
|
|
9230
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9231
|
+
console.debug("Rec. files cache: " + toBeExpiredRf.toString() + " is current file.");
|
|
9232
|
+
}
|
|
9233
|
+
}
|
|
9234
|
+
expire() {
|
|
9235
|
+
// expire corrected versions first
|
|
9236
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9237
|
+
console.debug("Rec. files cache: Expire? current: " + this._sampleCount + ", max: " + this.maxSampleCount);
|
|
9238
|
+
if (this._sampleCount > this.maxSampleCount) {
|
|
9239
|
+
// expire older versions of an item first
|
|
9240
|
+
for (let ii = 0; ii < this._items.length; ii++) {
|
|
9241
|
+
if (this._sampleCount <= this.maxSampleCount) {
|
|
9242
|
+
break;
|
|
9243
|
+
}
|
|
9244
|
+
let it = this._items[ii];
|
|
9245
|
+
let itRfs = it.recs;
|
|
9246
|
+
if (itRfs && itRfs.length > 1) {
|
|
9247
|
+
for (let rfi = 0; rfi < itRfs.length - 1; rfi++) {
|
|
9248
|
+
if (this._sampleCount <= this.maxSampleCount) {
|
|
9249
|
+
break;
|
|
9250
|
+
}
|
|
9251
|
+
let toBeExpiredRf = itRfs[rfi];
|
|
9252
|
+
this.tryExpire(toBeExpiredRf);
|
|
9253
|
+
}
|
|
9254
|
+
}
|
|
9255
|
+
}
|
|
9256
|
+
// if that's not sufficient expire audio data of latest versions as well
|
|
9257
|
+
for (let ii = 0; ii < this._items.length; ii++) {
|
|
9258
|
+
if (this._sampleCount <= this.maxSampleCount) {
|
|
9259
|
+
break;
|
|
9260
|
+
}
|
|
9261
|
+
let it = this._items[ii];
|
|
9262
|
+
let itRfs = it.recs;
|
|
9263
|
+
if (itRfs && itRfs.length > 0) {
|
|
9264
|
+
for (let rfi = 0; rfi < itRfs.length; rfi++) {
|
|
9265
|
+
if (this._sampleCount <= this.maxSampleCount) {
|
|
9266
|
+
break;
|
|
9267
|
+
}
|
|
9268
|
+
let toBeExpiredRf = itRfs[rfi];
|
|
9269
|
+
this.tryExpire(toBeExpiredRf);
|
|
9270
|
+
}
|
|
9271
|
+
}
|
|
9272
|
+
}
|
|
7896
9273
|
}
|
|
7897
9274
|
}
|
|
7898
|
-
|
|
7899
|
-
this.
|
|
7900
|
-
|
|
9275
|
+
addSprRecFile(item, sprRecFile) {
|
|
9276
|
+
this.expire();
|
|
9277
|
+
if (!item.recs) {
|
|
9278
|
+
item.recs = new Array();
|
|
9279
|
+
}
|
|
9280
|
+
item.recs.push(sprRecFile);
|
|
9281
|
+
this._sampleCount += RecordingFileUtils.sampleCount(sprRecFile);
|
|
9282
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9283
|
+
console.debug("Rec. files cache: Added. Cache samples: " + this._sampleCount);
|
|
7901
9284
|
}
|
|
7902
|
-
|
|
7903
|
-
this.
|
|
7904
|
-
|
|
7905
|
-
|
|
7906
|
-
|
|
7907
|
-
|
|
7908
|
-
|
|
7909
|
-
|
|
7910
|
-
|
|
9285
|
+
setSprRecFileAudioData(sprRecFile, adh) {
|
|
9286
|
+
this.expire();
|
|
9287
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9288
|
+
console.debug("Rec. files cache: Set audio data after expire. Cache samples: " + this._sampleCount);
|
|
9289
|
+
let currSampleCnt = RecordingFileUtils.sampleCount(sprRecFile);
|
|
9290
|
+
this._sampleCount -= currSampleCnt;
|
|
9291
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9292
|
+
console.debug("Rec. files cache: Set audio data subtracted curr sample count: " + currSampleCnt + ". Cache samples: " + this._sampleCount);
|
|
9293
|
+
RecordingFileUtils.setAudioData(sprRecFile, adh);
|
|
9294
|
+
let newSampleCnt = RecordingFileUtils.sampleCount(sprRecFile);
|
|
9295
|
+
this._sampleCount += newSampleCnt;
|
|
9296
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9297
|
+
console.debug("Rec. files cache: Set audio data added new sample count: " + newSampleCnt + ". Cache samples: " + this._sampleCount);
|
|
9298
|
+
let fl = adh?.frameLen;
|
|
9299
|
+
if (fl) {
|
|
9300
|
+
sprRecFile.frames = fl;
|
|
9301
|
+
}
|
|
9302
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9303
|
+
console.debug("Rec. files cache: Set audio data. Cache samples: " + this._sampleCount);
|
|
9304
|
+
}
|
|
9305
|
+
}
|
|
9306
|
+
class RecFilesCache extends BasicRecFilesCache {
|
|
9307
|
+
constructor() {
|
|
9308
|
+
super(...arguments);
|
|
9309
|
+
this._recFiles = new Array();
|
|
9310
|
+
}
|
|
9311
|
+
get recFiles() {
|
|
9312
|
+
return this._recFiles;
|
|
9313
|
+
}
|
|
9314
|
+
getRecFile(index) {
|
|
9315
|
+
return this._recFiles[index];
|
|
9316
|
+
}
|
|
9317
|
+
length() {
|
|
9318
|
+
return this._recFiles.length;
|
|
9319
|
+
}
|
|
9320
|
+
expire() {
|
|
9321
|
+
if (this._sampleCount > this.maxSampleCount) {
|
|
9322
|
+
// audio recorder list is sorted: lower index is newer
|
|
9323
|
+
for (let rfI = this._recFiles.length - 1; rfI >= 0; rfI--) {
|
|
9324
|
+
if (this._sampleCount <= this.maxSampleCount) {
|
|
9325
|
+
break;
|
|
9326
|
+
}
|
|
9327
|
+
let toBeExpiredRf = this._recFiles[rfI];
|
|
9328
|
+
if (toBeExpiredRf.serverPersisted) {
|
|
9329
|
+
if (!RecordingFileUtils.equals(toBeExpiredRf, this.currentRecordingFile)) {
|
|
9330
|
+
// expire recording files first stored to the cache
|
|
9331
|
+
let expiredAudio = RecordingFileUtils.expireAudioData(toBeExpiredRf);
|
|
9332
|
+
if (expiredAudio) {
|
|
9333
|
+
this._sampleCount -= expiredAudio.sampleCounts();
|
|
9334
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9335
|
+
console.debug("Rec. files cache: Expired #" + rfI + ". Cache samples: " + this._sampleCount);
|
|
9336
|
+
}
|
|
9337
|
+
}
|
|
9338
|
+
else {
|
|
9339
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9340
|
+
console.debug("Rec. files cache: #" + rfI + " is current file. (not expiring)");
|
|
9341
|
+
}
|
|
9342
|
+
}
|
|
9343
|
+
else {
|
|
9344
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9345
|
+
console.debug("Rec. files cache: #" + rfI + " not yet server persisted.");
|
|
9346
|
+
}
|
|
7911
9347
|
}
|
|
7912
|
-
}
|
|
9348
|
+
}
|
|
7913
9349
|
}
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
9350
|
+
addRecFile(recFile) {
|
|
9351
|
+
this.expire();
|
|
9352
|
+
this._recFiles.push(recFile);
|
|
9353
|
+
this._sampleCount += RecordingFileUtils.sampleCount(recFile);
|
|
9354
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9355
|
+
console.debug("Rec. files cache: Added. Cache samples: " + this._sampleCount);
|
|
9356
|
+
}
|
|
9357
|
+
setRecFileAudioData(recFile, adh) {
|
|
9358
|
+
this.expire();
|
|
9359
|
+
this._sampleCount -= RecordingFileUtils.sampleCount(recFile);
|
|
9360
|
+
RecordingFileUtils.setAudioData(recFile, adh);
|
|
9361
|
+
this._sampleCount += RecordingFileUtils.sampleCount(recFile);
|
|
9362
|
+
if (BasicRecFilesCache.DEBUG)
|
|
9363
|
+
console.debug("Rec. files cache: Set audio data. Cache samples: " + this._sampleCount);
|
|
9364
|
+
}
|
|
9365
|
+
}
|
|
7919
9366
|
|
|
7920
9367
|
/**
|
|
7921
9368
|
* Created by klausj on 17.06.2017.
|
|
@@ -8008,16 +9455,62 @@ class RecordingService {
|
|
|
8008
9455
|
let recUrl = recFilesUrl + '/' + encItemcode + '/' + version;
|
|
8009
9456
|
return this.audioRequest(recUrl);
|
|
8010
9457
|
}
|
|
9458
|
+
fetchRecordingFileAudioBuffer(aCtx, projectName, recordingFile) {
|
|
9459
|
+
let wobs = new Observable(observer => {
|
|
9460
|
+
let recFileId = recordingFile.recordingFileId;
|
|
9461
|
+
if (!recFileId) {
|
|
9462
|
+
recFileId = recordingFile.uuid;
|
|
9463
|
+
}
|
|
9464
|
+
if (recordingFile.session && recFileId) {
|
|
9465
|
+
let obs = this.fetchAudiofile(projectName, recordingFile.session, recFileId);
|
|
9466
|
+
obs.subscribe(resp => {
|
|
9467
|
+
// Do not use Promise version, which does not work with Safari 13 (13.0.5)
|
|
9468
|
+
if (resp.body) {
|
|
9469
|
+
aCtx.decodeAudioData(resp.body, ab => {
|
|
9470
|
+
observer.next(ab);
|
|
9471
|
+
observer.complete();
|
|
9472
|
+
}, error => {
|
|
9473
|
+
observer.error(error);
|
|
9474
|
+
observer.complete();
|
|
9475
|
+
});
|
|
9476
|
+
}
|
|
9477
|
+
else {
|
|
9478
|
+
observer.error('Fetching audio file: response has no body');
|
|
9479
|
+
}
|
|
9480
|
+
}, (error) => {
|
|
9481
|
+
if (error.status == 404) {
|
|
9482
|
+
// Interpret not as an error, the file ist not recorded yet
|
|
9483
|
+
observer.next(null);
|
|
9484
|
+
observer.complete();
|
|
9485
|
+
}
|
|
9486
|
+
else {
|
|
9487
|
+
// all other states are errors
|
|
9488
|
+
observer.error(error);
|
|
9489
|
+
observer.complete();
|
|
9490
|
+
}
|
|
9491
|
+
});
|
|
9492
|
+
}
|
|
9493
|
+
else {
|
|
9494
|
+
observer.error();
|
|
9495
|
+
}
|
|
9496
|
+
});
|
|
9497
|
+
return wobs;
|
|
9498
|
+
}
|
|
8011
9499
|
fetchAndApplyRecordingFile(aCtx, projectName, recordingFile) {
|
|
8012
9500
|
let wobs = new Observable(observer => {
|
|
8013
|
-
|
|
8014
|
-
|
|
9501
|
+
let recFileId = recordingFile.recordingFileId;
|
|
9502
|
+
if (!recFileId) {
|
|
9503
|
+
recFileId = recordingFile.uuid;
|
|
9504
|
+
}
|
|
9505
|
+
if (recordingFile.session && recFileId) {
|
|
9506
|
+
let obs = this.fetchAudiofile(projectName, recordingFile.session, recFileId);
|
|
8015
9507
|
obs.subscribe(resp => {
|
|
8016
9508
|
//console.log("Fetched audio file. HTTP response status: "+resp.status+", type: "+resp.type+", byte length: "+ resp.body.byteLength);
|
|
8017
9509
|
// Do not use Promise version, which does not work with Safari 13 (13.0.5)
|
|
8018
9510
|
if (resp.body) {
|
|
8019
9511
|
aCtx.decodeAudioData(resp.body, ab => {
|
|
8020
|
-
|
|
9512
|
+
let adh = new AudioDataHolder(ab, null);
|
|
9513
|
+
RecordingFileUtils.setAudioData(recordingFile, adh);
|
|
8021
9514
|
if (this.debugDelay > 0) {
|
|
8022
9515
|
window.setTimeout(() => {
|
|
8023
9516
|
observer.next(recordingFile);
|
|
@@ -8055,6 +9548,47 @@ class RecordingService {
|
|
|
8055
9548
|
});
|
|
8056
9549
|
return wobs;
|
|
8057
9550
|
}
|
|
9551
|
+
fetchSprRecordingFileAudioBuffer(aCtx, projectName, recordingFile) {
|
|
9552
|
+
let wobs = new Observable(observer => {
|
|
9553
|
+
if (recordingFile.session) {
|
|
9554
|
+
let obs = this.fetchSprAudiofile(projectName, recordingFile.session, recordingFile.itemCode, recordingFile.version);
|
|
9555
|
+
obs.subscribe({
|
|
9556
|
+
next: resp => {
|
|
9557
|
+
// Do not use Promise version, which does not work with Safari 13 (13.0.5)
|
|
9558
|
+
if (resp.body) {
|
|
9559
|
+
aCtx.decodeAudioData(resp.body, ab => {
|
|
9560
|
+
//RecordingFileUtils.setAudioData(recordingFile,new AudioDataHolder(ab,null));
|
|
9561
|
+
observer.next(ab);
|
|
9562
|
+
observer.complete();
|
|
9563
|
+
}, error => {
|
|
9564
|
+
observer.error(error);
|
|
9565
|
+
observer.complete();
|
|
9566
|
+
});
|
|
9567
|
+
}
|
|
9568
|
+
else {
|
|
9569
|
+
observer.error('Fetching audio file: response has no body');
|
|
9570
|
+
}
|
|
9571
|
+
},
|
|
9572
|
+
error: (error) => {
|
|
9573
|
+
if (error.status == 404) {
|
|
9574
|
+
// Interpret not as an error, the file ist not recorded yet
|
|
9575
|
+
observer.next(null);
|
|
9576
|
+
observer.complete();
|
|
9577
|
+
}
|
|
9578
|
+
else {
|
|
9579
|
+
// all other states are errors
|
|
9580
|
+
observer.error(error);
|
|
9581
|
+
observer.complete();
|
|
9582
|
+
}
|
|
9583
|
+
}
|
|
9584
|
+
});
|
|
9585
|
+
}
|
|
9586
|
+
else {
|
|
9587
|
+
observer.error();
|
|
9588
|
+
}
|
|
9589
|
+
});
|
|
9590
|
+
return wobs;
|
|
9591
|
+
}
|
|
8058
9592
|
fetchAndApplySprRecordingFile(aCtx, projectName, recordingFile) {
|
|
8059
9593
|
let wobs = new Observable(observer => {
|
|
8060
9594
|
if (recordingFile.session) {
|
|
@@ -8064,7 +9598,7 @@ class RecordingService {
|
|
|
8064
9598
|
// Do not use Promise version, which does not work with Safari 13 (13.0.5)
|
|
8065
9599
|
if (resp.body) {
|
|
8066
9600
|
aCtx.decodeAudioData(resp.body, ab => {
|
|
8067
|
-
recordingFile
|
|
9601
|
+
RecordingFileUtils.setAudioData(recordingFile, new AudioDataHolder(ab, null));
|
|
8068
9602
|
if (this.debugDelay > 0) {
|
|
8069
9603
|
window.setTimeout(() => {
|
|
8070
9604
|
observer.next(recordingFile);
|
|
@@ -8109,7 +9643,8 @@ class RecordingService {
|
|
|
8109
9643
|
// Do not use Promise version, which does not work with Safari 13
|
|
8110
9644
|
if (resp.body) {
|
|
8111
9645
|
aCtx.decodeAudioData(resp.body, ab => {
|
|
8112
|
-
let
|
|
9646
|
+
let adh = new AudioDataHolder(ab, null);
|
|
9647
|
+
let rf = new SprRecordingFile(sessId, itemcode, version, adh);
|
|
8113
9648
|
if (this.debugDelay > 0) {
|
|
8114
9649
|
window.setTimeout(() => {
|
|
8115
9650
|
observer.next(rf);
|
|
@@ -8225,14 +9760,9 @@ const DEFAULT_PRE_REC_DELAY = 1000;
|
|
|
8225
9760
|
const DEFAULT_POST_REC_DELAY = 500;
|
|
8226
9761
|
class SessionManager extends BasicRecorder {
|
|
8227
9762
|
constructor(changeDetectorRef, renderer, dialog, sessionService, recFileService, uploader, config) {
|
|
8228
|
-
super(dialog, sessionService, uploader, config);
|
|
8229
|
-
this.changeDetectorRef = changeDetectorRef;
|
|
9763
|
+
super(changeDetectorRef, dialog, sessionService, uploader, config);
|
|
8230
9764
|
this.renderer = renderer;
|
|
8231
|
-
this.dialog = dialog;
|
|
8232
|
-
this.sessionService = sessionService;
|
|
8233
9765
|
this.recFileService = recFileService;
|
|
8234
|
-
this.uploader = uploader;
|
|
8235
|
-
this.config = config;
|
|
8236
9766
|
this.enableUploadRecordings = true;
|
|
8237
9767
|
this.enableDownloadRecordings = false;
|
|
8238
9768
|
this.status = 0 /* BLOCKED */;
|
|
@@ -8266,7 +9796,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8266
9796
|
};
|
|
8267
9797
|
}
|
|
8268
9798
|
ngOnDestroy() {
|
|
8269
|
-
console.debug("Com destroy, disable wake lock.")
|
|
9799
|
+
//console.debug("Com destroy, disable wake lock.")
|
|
8270
9800
|
this.disableWakeLockCond();
|
|
8271
9801
|
this.destroyed = true;
|
|
8272
9802
|
// TODO stop capture /playback
|
|
@@ -8397,7 +9927,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8397
9927
|
progressPercentValue() {
|
|
8398
9928
|
let v = 100;
|
|
8399
9929
|
if (this.items) {
|
|
8400
|
-
v = this.promptIndex * 100 / (this.items.length - 1);
|
|
9930
|
+
v = this.promptIndex * 100 / (this.items.length() - 1);
|
|
8401
9931
|
}
|
|
8402
9932
|
return v;
|
|
8403
9933
|
}
|
|
@@ -8411,9 +9941,6 @@ class SessionManager extends BasicRecorder {
|
|
|
8411
9941
|
return ((this._session != null) && (this._session.type === 'TEST_DEF_A') && (this.audioDevices != null) && this.audioDevices.length > 0);
|
|
8412
9942
|
}
|
|
8413
9943
|
set controlAudioPlayer(controlAudioPlayer) {
|
|
8414
|
-
if (this._controlAudioPlayer) {
|
|
8415
|
-
//this._controlAudioPlayer.listener=null;
|
|
8416
|
-
}
|
|
8417
9944
|
this._controlAudioPlayer = controlAudioPlayer;
|
|
8418
9945
|
if (this._controlAudioPlayer) {
|
|
8419
9946
|
this._controlAudioPlayer.listener = this;
|
|
@@ -8498,6 +10025,8 @@ class SessionManager extends BasicRecorder {
|
|
|
8498
10025
|
this.autorecording = true;
|
|
8499
10026
|
}
|
|
8500
10027
|
if (this.ac != null) {
|
|
10028
|
+
// Hide loading hint on livelevel display
|
|
10029
|
+
this.audioFetching = false;
|
|
8501
10030
|
if (!this.ac.opened) {
|
|
8502
10031
|
if (this._selectedDeviceId) {
|
|
8503
10032
|
console.log("Open session with audio device Id: \'" + this._selectedDeviceId + "\' for " + this._channelCount + " channels");
|
|
@@ -8514,7 +10043,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8514
10043
|
}
|
|
8515
10044
|
loadScript() {
|
|
8516
10045
|
this.promptItemCount = 0;
|
|
8517
|
-
this.items = new
|
|
10046
|
+
this.items = new SprItemsCache();
|
|
8518
10047
|
let ln = 0;
|
|
8519
10048
|
//TODO randomize not supported
|
|
8520
10049
|
for (let si = 0; si < this._script.sections.length; si++) {
|
|
@@ -8528,7 +10057,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8528
10057
|
let pi = pis[piSectIdx];
|
|
8529
10058
|
let promptAsStr = PromptitemUtil.toPlainTextString(pi);
|
|
8530
10059
|
let it = new Item$1(promptAsStr, section.training, (!pi.type || pi.type === 'recording'));
|
|
8531
|
-
this.items.
|
|
10060
|
+
this.items.addItem(it);
|
|
8532
10061
|
ln++;
|
|
8533
10062
|
}
|
|
8534
10063
|
}
|
|
@@ -8569,10 +10098,10 @@ class SessionManager extends BasicRecorder {
|
|
|
8569
10098
|
}
|
|
8570
10099
|
downloadRecording() {
|
|
8571
10100
|
if (this.displayRecFile) {
|
|
8572
|
-
let ab = this.displayRecFile.
|
|
10101
|
+
let ab = this.displayRecFile.audioDataHolder;
|
|
8573
10102
|
let ww = new WavWriter();
|
|
8574
|
-
if (ab) {
|
|
8575
|
-
let wavFile = ww.writeAsync(ab, (wavFile) => {
|
|
10103
|
+
if (ab?.buffer) {
|
|
10104
|
+
let wavFile = ww.writeAsync(ab.buffer, (wavFile) => {
|
|
8576
10105
|
let blob = new Blob([wavFile], { type: 'audio/wav' });
|
|
8577
10106
|
let rfUrl = URL.createObjectURL(blob);
|
|
8578
10107
|
let dataDnlLnk = this.renderer.createElement('a');
|
|
@@ -8595,7 +10124,10 @@ class SessionManager extends BasicRecorder {
|
|
|
8595
10124
|
set displayRecFile(displayRecFile) {
|
|
8596
10125
|
this._displayRecFile = displayRecFile;
|
|
8597
10126
|
if (this._displayRecFile) {
|
|
8598
|
-
|
|
10127
|
+
if (this.items) {
|
|
10128
|
+
this.items.currentRecordingFile = this._displayRecFile;
|
|
10129
|
+
}
|
|
10130
|
+
let ab = this._displayRecFile.audioDataHolder;
|
|
8599
10131
|
if (ab) {
|
|
8600
10132
|
this.displayAudioClip = new AudioClip(ab);
|
|
8601
10133
|
this.controlAudioPlayer.audioClip = this.displayAudioClip;
|
|
@@ -8603,27 +10135,46 @@ class SessionManager extends BasicRecorder {
|
|
|
8603
10135
|
else {
|
|
8604
10136
|
// clear for now ...
|
|
8605
10137
|
this.displayAudioClip = null;
|
|
8606
|
-
this.controlAudioPlayer
|
|
10138
|
+
if (this.controlAudioPlayer) {
|
|
10139
|
+
this.controlAudioPlayer.audioClip = null;
|
|
10140
|
+
}
|
|
8607
10141
|
if (this._controlAudioPlayer && this._session) {
|
|
8608
10142
|
//... and try to fetch from server
|
|
8609
|
-
this.
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8613
|
-
|
|
8614
|
-
|
|
8615
|
-
|
|
10143
|
+
this.audioFetching = true;
|
|
10144
|
+
let rf = this._displayRecFile;
|
|
10145
|
+
this.audioFetchSubscription = this.recFileService.fetchSprRecordingFileAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
|
|
10146
|
+
next: (ab) => {
|
|
10147
|
+
this.audioFetching = false;
|
|
10148
|
+
let fabDh = null;
|
|
10149
|
+
if (ab) {
|
|
10150
|
+
if (rf && this.items) {
|
|
10151
|
+
if (SessionManager.FORCE_ARRRAY_AUDIO_BUFFER) {
|
|
10152
|
+
let aab = ArrayAudioBuffer.fromAudioBuffer(ab);
|
|
10153
|
+
fabDh = new AudioDataHolder(null, aab);
|
|
10154
|
+
}
|
|
10155
|
+
else {
|
|
10156
|
+
fabDh = new AudioDataHolder(ab);
|
|
10157
|
+
}
|
|
10158
|
+
this.items.setSprRecFileAudioData(rf, fabDh);
|
|
10159
|
+
}
|
|
10160
|
+
}
|
|
10161
|
+
else {
|
|
10162
|
+
// Should actually be handled by the error resolver
|
|
10163
|
+
this.statusMsg = 'Recording file could not be loaded.';
|
|
10164
|
+
this.statusAlertType = 'error';
|
|
10165
|
+
}
|
|
10166
|
+
if (fabDh) {
|
|
10167
|
+
// 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
|
|
10168
|
+
this.displayAudioClip = new AudioClip(fabDh);
|
|
10169
|
+
}
|
|
10170
|
+
this.controlAudioPlayer.audioClip = this.displayAudioClip;
|
|
10171
|
+
this.showRecording();
|
|
10172
|
+
}, error: err => {
|
|
10173
|
+
console.error("Could not load recording file from server: " + err);
|
|
10174
|
+
this.audioFetching = false;
|
|
10175
|
+
this.statusMsg = 'Recording file could not be loaded: ' + err;
|
|
8616
10176
|
this.statusAlertType = 'error';
|
|
8617
10177
|
}
|
|
8618
|
-
if (fab) {
|
|
8619
|
-
this.displayAudioClip = new AudioClip(fab);
|
|
8620
|
-
}
|
|
8621
|
-
this.controlAudioPlayer.audioClip = this.displayAudioClip;
|
|
8622
|
-
this.showRecording();
|
|
8623
|
-
}, err => {
|
|
8624
|
-
console.error("Could not load recording file from server: " + err);
|
|
8625
|
-
this.statusMsg = 'Recording file could not be loaded: ' + err;
|
|
8626
|
-
this.statusAlertType = 'error';
|
|
8627
10178
|
});
|
|
8628
10179
|
}
|
|
8629
10180
|
else {
|
|
@@ -8634,34 +10185,14 @@ class SessionManager extends BasicRecorder {
|
|
|
8634
10185
|
}
|
|
8635
10186
|
else {
|
|
8636
10187
|
this.displayAudioClip = null;
|
|
8637
|
-
this.controlAudioPlayer
|
|
10188
|
+
if (this.controlAudioPlayer) {
|
|
10189
|
+
this.controlAudioPlayer.audioClip = null;
|
|
10190
|
+
}
|
|
8638
10191
|
}
|
|
8639
10192
|
}
|
|
8640
10193
|
get displayRecFile() {
|
|
8641
10194
|
return this._displayRecFile;
|
|
8642
10195
|
}
|
|
8643
|
-
showRecording() {
|
|
8644
|
-
this.controlAudioPlayer.stop();
|
|
8645
|
-
if (this.displayAudioClip) {
|
|
8646
|
-
this.levelMeasure.calcBufferLevelInfos(this.displayAudioClip.buffer, LEVEL_BAR_INTERVALL_SECONDS).then((levelInfos) => {
|
|
8647
|
-
this.displayLevelInfos = levelInfos;
|
|
8648
|
-
this.changeDetectorRef.detectChanges();
|
|
8649
|
-
});
|
|
8650
|
-
this.playStartAction.disabled = false;
|
|
8651
|
-
}
|
|
8652
|
-
else {
|
|
8653
|
-
// TODO
|
|
8654
|
-
// Setting to null does not trigger a change if it was null before (happens after nextitem() in AUTOPROGRESS mode)
|
|
8655
|
-
// The level bar display does not clear, it shows the last captured stream
|
|
8656
|
-
this.displayLevelInfos = null;
|
|
8657
|
-
this.playStartAction.disabled = true;
|
|
8658
|
-
// Collapse audio signal display if open
|
|
8659
|
-
if (!this.audioSignalCollapsed) {
|
|
8660
|
-
this.audioSignalCollapsed = true;
|
|
8661
|
-
}
|
|
8662
|
-
}
|
|
8663
|
-
this.changeDetectorRef.detectChanges();
|
|
8664
|
-
}
|
|
8665
10196
|
isRecordingItem() {
|
|
8666
10197
|
return (this.promptItem != null && this.promptItem.type !== 'nonrecording');
|
|
8667
10198
|
}
|
|
@@ -8676,17 +10207,20 @@ class SessionManager extends BasicRecorder {
|
|
|
8676
10207
|
if (this.audioFetchSubscription) {
|
|
8677
10208
|
this.audioFetchSubscription.unsubscribe();
|
|
8678
10209
|
}
|
|
10210
|
+
this.audioFetching = false;
|
|
8679
10211
|
this.clearPrompt();
|
|
8680
10212
|
let isNonrecording = (this.promptItem.type === 'nonrecording');
|
|
8681
10213
|
if (isNonrecording || !this.section.promptphase || this.section.promptphase === 'IDLE') {
|
|
8682
10214
|
this.applyPrompt();
|
|
8683
10215
|
}
|
|
8684
10216
|
if (isNonrecording) {
|
|
10217
|
+
this.displayRecFile = null;
|
|
10218
|
+
this.displayRecFileVersion = 0;
|
|
8685
10219
|
this.startStopSignalState = 4 /* OFF */;
|
|
8686
10220
|
}
|
|
8687
10221
|
else {
|
|
8688
10222
|
if (this.items) {
|
|
8689
|
-
let it = this.items
|
|
10223
|
+
let it = this.items.getItem(this.promptIndex);
|
|
8690
10224
|
if (!it.recs) {
|
|
8691
10225
|
it.recs = new Array();
|
|
8692
10226
|
}
|
|
@@ -8703,13 +10237,13 @@ class SessionManager extends BasicRecorder {
|
|
|
8703
10237
|
this.displayRecFileVersion = 0;
|
|
8704
10238
|
}
|
|
8705
10239
|
}
|
|
8706
|
-
if (!temporary) {
|
|
8707
|
-
this.showRecording();
|
|
8708
|
-
}
|
|
8709
10240
|
if (!this.readonly) {
|
|
8710
10241
|
this.startStopSignalState = 0 /* IDLE */;
|
|
8711
10242
|
}
|
|
8712
10243
|
}
|
|
10244
|
+
if (!temporary) {
|
|
10245
|
+
this.showRecording();
|
|
10246
|
+
}
|
|
8713
10247
|
this.updateStartActionDisableState();
|
|
8714
10248
|
this.updateNavigationActions();
|
|
8715
10249
|
}
|
|
@@ -8747,7 +10281,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8747
10281
|
updateNavigationActions() {
|
|
8748
10282
|
let fwdNxtActionDisabled = true;
|
|
8749
10283
|
if (this.items) {
|
|
8750
|
-
let currRecs = this.items
|
|
10284
|
+
let currRecs = this.items.getItem(this._promptIndex).recs;
|
|
8751
10285
|
fwdNxtActionDisabled = !(currRecs != null && currRecs.length > 0);
|
|
8752
10286
|
}
|
|
8753
10287
|
this.transportActions.fwdNextAction.disabled = this.navigationDisabled || fwdNxtActionDisabled;
|
|
@@ -8761,10 +10295,10 @@ class SessionManager extends BasicRecorder {
|
|
|
8761
10295
|
newPrIdx = 0;
|
|
8762
10296
|
}
|
|
8763
10297
|
if (this.items != null) {
|
|
8764
|
-
let itRecs = this.items
|
|
10298
|
+
let itRecs = this.items.getItem(newPrIdx).recs;
|
|
8765
10299
|
while (itRecs != null && (itRecs.length > 0) && newPrIdx < this.promptItemCount) {
|
|
8766
10300
|
newPrIdx++;
|
|
8767
|
-
itRecs = this.items
|
|
10301
|
+
itRecs = this.items.getItem(newPrIdx).recs;
|
|
8768
10302
|
}
|
|
8769
10303
|
if (!itRecs || itRecs.length == 0) {
|
|
8770
10304
|
this.promptIndex = newPrIdx;
|
|
@@ -8785,6 +10319,23 @@ class SessionManager extends BasicRecorder {
|
|
|
8785
10319
|
}
|
|
8786
10320
|
}
|
|
8787
10321
|
started() {
|
|
10322
|
+
let ic = this.promptItem.itemcode;
|
|
10323
|
+
let rf = null;
|
|
10324
|
+
if (this._session && ic) {
|
|
10325
|
+
let sessId = this._session.sessionId;
|
|
10326
|
+
let cpIdx = this.promptIndex;
|
|
10327
|
+
if (this.items) {
|
|
10328
|
+
let it = this.items.getItem(cpIdx);
|
|
10329
|
+
if (!it.recs) {
|
|
10330
|
+
it.recs = new Array();
|
|
10331
|
+
}
|
|
10332
|
+
rf = new SprRecordingFile(sessId, ic, it.recs.length, null);
|
|
10333
|
+
//it.recs.push(rf);
|
|
10334
|
+
this.items.addSprRecFile(it, rf);
|
|
10335
|
+
this.items.currentRecordingFile = rf;
|
|
10336
|
+
}
|
|
10337
|
+
}
|
|
10338
|
+
this._recordingFile = rf;
|
|
8788
10339
|
this.status = 3 /* PRE_RECORDING */;
|
|
8789
10340
|
super.started();
|
|
8790
10341
|
this.startStopSignalState = 1 /* PRERECORDING */;
|
|
@@ -8911,13 +10462,14 @@ class SessionManager extends BasicRecorder {
|
|
|
8911
10462
|
if (rfd.recording && rfd.recording.itemcode) {
|
|
8912
10463
|
let prIdx = this.promptIndexByItemcode(rfd.recording.itemcode);
|
|
8913
10464
|
if (this.items != null && prIdx !== null) {
|
|
8914
|
-
let it = this.items
|
|
10465
|
+
let it = this.items.getItem(prIdx);
|
|
8915
10466
|
if (it && this._session) {
|
|
8916
|
-
if (!it.recs) {
|
|
8917
|
-
|
|
8918
|
-
}
|
|
10467
|
+
// if (!it.recs) {
|
|
10468
|
+
// it.recs = new Array<SprRecordingFile>();
|
|
10469
|
+
// }
|
|
8919
10470
|
let rf = new SprRecordingFile(this._session.sessionId, rfd.recording.itemcode, rfd.version, null);
|
|
8920
|
-
|
|
10471
|
+
rf.serverPersisted = true;
|
|
10472
|
+
this.items.addSprRecFile(it, rf);
|
|
8921
10473
|
}
|
|
8922
10474
|
else {
|
|
8923
10475
|
//console.debug("WARN: No recording item with code: \"" +rfd.recording.itemcode+ "\" found.");
|
|
@@ -8939,22 +10491,24 @@ class SessionManager extends BasicRecorder {
|
|
|
8939
10491
|
this.statusMsg = 'Recorded.';
|
|
8940
10492
|
this.startStopSignalState = 0 /* IDLE */;
|
|
8941
10493
|
let ad = null;
|
|
10494
|
+
let ada = null;
|
|
10495
|
+
let adh = null;
|
|
10496
|
+
let frameLen = 0;
|
|
8942
10497
|
if (this.ac != null) {
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
-
let rf = null;
|
|
8947
|
-
if (this._session && ic) {
|
|
8948
|
-
let sessId = this._session.sessionId;
|
|
8949
|
-
let cpIdx = this.promptIndex;
|
|
8950
|
-
if (this.items) {
|
|
8951
|
-
let it = this.items[cpIdx];
|
|
8952
|
-
if (!it.recs) {
|
|
8953
|
-
it.recs = new Array();
|
|
8954
|
-
}
|
|
8955
|
-
rf = new SprRecordingFile(sessId, ic, it.recs.length, ad);
|
|
8956
|
-
it.recs.push(rf);
|
|
10498
|
+
if (this.uploadChunkSizeSeconds || SessionManager.FORCE_ARRRAY_AUDIO_BUFFER) {
|
|
10499
|
+
ada = this.ac.audioBufferArray();
|
|
10500
|
+
frameLen = ada.frameLen;
|
|
8957
10501
|
}
|
|
10502
|
+
else {
|
|
10503
|
+
ad = this.ac.audioBuffer();
|
|
10504
|
+
frameLen = ad.length;
|
|
10505
|
+
}
|
|
10506
|
+
adh = new AudioDataHolder(ad, ada);
|
|
10507
|
+
}
|
|
10508
|
+
// Use an own reference since the writing of the wave file is asynchronous and this._recordingFile might already contain the next recording
|
|
10509
|
+
let rf = this._recordingFile;
|
|
10510
|
+
if (rf && rf instanceof SprRecordingFile) {
|
|
10511
|
+
this.items?.setSprRecFileAudioData(rf, adh);
|
|
8958
10512
|
if (this.enableUploadRecordings && !this.uploadChunkSizeSeconds) {
|
|
8959
10513
|
// TODO use SpeechRecorderconfig resp. RecfileService
|
|
8960
10514
|
// convert asynchronously to 16-bit integer PCM
|
|
@@ -8962,7 +10516,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8962
10516
|
// TODO duplicate conversion for manual download
|
|
8963
10517
|
//console.log("Build wav writer...");
|
|
8964
10518
|
this.processingRecording = true;
|
|
8965
|
-
if (ad
|
|
10519
|
+
if (ad) {
|
|
8966
10520
|
let ww = new WavWriter();
|
|
8967
10521
|
//new REST API URL
|
|
8968
10522
|
let apiEndPoint = '';
|
|
@@ -8975,7 +10529,7 @@ class SessionManager extends BasicRecorder {
|
|
|
8975
10529
|
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
8976
10530
|
let recUrl = sessionsUrl + '/' + rf.session + '/' + RECFILE_API_CTX + '/' + rf.itemCode;
|
|
8977
10531
|
ww.writeAsync(ad, (wavFile) => {
|
|
8978
|
-
this.postRecording(wavFile, recUrl);
|
|
10532
|
+
this.postRecording(wavFile, recUrl, rf);
|
|
8979
10533
|
this.processingRecording = false;
|
|
8980
10534
|
this.updateWakeLock();
|
|
8981
10535
|
});
|
|
@@ -8986,8 +10540,8 @@ class SessionManager extends BasicRecorder {
|
|
|
8986
10540
|
let complete = true;
|
|
8987
10541
|
if (this.items) {
|
|
8988
10542
|
// search backwards, to gain faster detection of incomplete state
|
|
8989
|
-
for (let ri = this.items.length - 1; ri >= 0; ri--) {
|
|
8990
|
-
let it = this.items
|
|
10543
|
+
for (let ri = this.items.length() - 1; ri >= 0; ri--) {
|
|
10544
|
+
let it = this.items.getItem(ri);
|
|
8991
10545
|
if (it.recording && !it.training && (!it.recs || it.recs.length == 0)) {
|
|
8992
10546
|
complete = false;
|
|
8993
10547
|
break;
|
|
@@ -9051,13 +10605,13 @@ class SessionManager extends BasicRecorder {
|
|
|
9051
10605
|
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
9052
10606
|
let recUrl = sessionsUrl + '/' + this.session?.sessionId + '/' + RECFILE_API_CTX + '/' + this.promptItem.itemcode + '/' + this.rfUuid + '/' + chunkIdx;
|
|
9053
10607
|
ww.writeAsync(audioBuffer, (wavFile) => {
|
|
9054
|
-
this.postRecording(wavFile, recUrl);
|
|
10608
|
+
this.postRecording(wavFile, recUrl, null);
|
|
9055
10609
|
this.processingRecording = false;
|
|
9056
10610
|
});
|
|
9057
10611
|
}
|
|
9058
|
-
postRecording(wavFile, recUrl) {
|
|
10612
|
+
postRecording(wavFile, recUrl, rf) {
|
|
9059
10613
|
let wavBlob = new Blob([wavFile], { type: 'audio/wav' });
|
|
9060
|
-
let ul = new Upload(wavBlob, recUrl);
|
|
10614
|
+
let ul = new Upload(wavBlob, recUrl, rf);
|
|
9061
10615
|
this.uploader.queueUpload(ul);
|
|
9062
10616
|
}
|
|
9063
10617
|
stop() {
|
|
@@ -9093,7 +10647,7 @@ SessionManager.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version
|
|
|
9093
10647
|
<app-warningbar [show]="isDefaultAudioTestSession()" warningText="This test uses default audio device! Regular sessions may require a particular audio device (microphone)!"></app-warningbar>
|
|
9094
10648
|
<app-sprprompting [projectName]="projectName"
|
|
9095
10649
|
[startStopSignalState]="startStopSignalState" [promptItem]="promptItem" [showPrompt]="showPrompt"
|
|
9096
|
-
[items]="items"
|
|
10650
|
+
[items]="items?.items"
|
|
9097
10651
|
[transportActions]="transportActions"
|
|
9098
10652
|
[selectedItemIdx]="promptIndex" (onItemSelect)="itemSelect($event)" (onNextItem)="nextItem()" (onPrevItem)="prevItem()"
|
|
9099
10653
|
[audioSignalCollapsed]="audioSignalCollapsed" [displayAudioClip]="displayAudioClip"
|
|
@@ -9107,10 +10661,10 @@ SessionManager.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version
|
|
|
9107
10661
|
|
|
9108
10662
|
|
|
9109
10663
|
<div fxLayout="row" fxLayout.xs="column" [ngStyle]="{'height.px':100,'min-height.px': 100}" [ngStyle.xs]="{'height.px':125,'min-height.px': 125}">
|
|
9110
|
-
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()" [displayLevelInfos]="
|
|
10664
|
+
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()" [displayLevelInfos]="displayAudioClip?.levelInfos" [stateLoading]="audioFetching"></audio-levelbar>
|
|
9111
10665
|
<div fxLayout="row">
|
|
9112
10666
|
<spr-recordingitemcontrols fxFlex="10 0 1"
|
|
9113
|
-
[audioLoaded]="displayAudioClip?.
|
|
10667
|
+
[audioLoaded]="displayAudioClip?.audioDataHolder!==null"
|
|
9114
10668
|
[playStartAction]="controlAudioPlayer?.startAction"
|
|
9115
10669
|
[playStopAction]="controlAudioPlayer?.stopAction"
|
|
9116
10670
|
[peakDbLvl]="peakLevelInDb"
|
|
@@ -9128,7 +10682,7 @@ SessionManager.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version
|
|
|
9128
10682
|
<div fxFlex="1 1 30%" fxLayoutAlign="start center">
|
|
9129
10683
|
<app-sprstatusdisplay fxHide.xs [statusMsg]="statusMsg" [statusAlertType]="statusAlertType" [statusWaiting]="statusWaiting"></app-sprstatusdisplay>
|
|
9130
10684
|
</div>
|
|
9131
|
-
<app-sprtransport fxFlex="10 0 30%" fxLayoutAlign="center center" [readonly]="readonly" [actions]="transportActions" [navigationEnabled]="items
|
|
10685
|
+
<app-sprtransport fxFlex="10 0 30%" fxLayoutAlign="center center" [readonly]="readonly" [actions]="transportActions" [navigationEnabled]="!items || items.length()>1"></app-sprtransport>
|
|
9132
10686
|
<div fxFlex="1 1 30%" fxLayoutAlign="end center" fxLayout="row">
|
|
9133
10687
|
<app-uploadstatus class="ricontrols" fxHide.xs fxLayoutAlign="end center" *ngIf="enableUploadRecordings" [value]="uploadProgress"
|
|
9134
10688
|
[status]="uploadStatus" [awaitNewUpload]="processingRecording"></app-uploadstatus>
|
|
@@ -9136,7 +10690,7 @@ SessionManager.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version
|
|
|
9136
10690
|
<app-readystateindicator class="ricontrols" fxLayoutAlign="end center" fxHide.xs [ready]="dataSaved && !isActive()"></app-readystateindicator>
|
|
9137
10691
|
</div>
|
|
9138
10692
|
</div>
|
|
9139
|
-
`, 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"] }] });
|
|
10693
|
+
`, 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"] }] });
|
|
9140
10694
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: SessionManager, decorators: [{
|
|
9141
10695
|
type: Component,
|
|
9142
10696
|
args: [{
|
|
@@ -9147,7 +10701,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
9147
10701
|
<app-warningbar [show]="isDefaultAudioTestSession()" warningText="This test uses default audio device! Regular sessions may require a particular audio device (microphone)!"></app-warningbar>
|
|
9148
10702
|
<app-sprprompting [projectName]="projectName"
|
|
9149
10703
|
[startStopSignalState]="startStopSignalState" [promptItem]="promptItem" [showPrompt]="showPrompt"
|
|
9150
|
-
[items]="items"
|
|
10704
|
+
[items]="items?.items"
|
|
9151
10705
|
[transportActions]="transportActions"
|
|
9152
10706
|
[selectedItemIdx]="promptIndex" (onItemSelect)="itemSelect($event)" (onNextItem)="nextItem()" (onPrevItem)="prevItem()"
|
|
9153
10707
|
[audioSignalCollapsed]="audioSignalCollapsed" [displayAudioClip]="displayAudioClip"
|
|
@@ -9161,10 +10715,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
9161
10715
|
|
|
9162
10716
|
|
|
9163
10717
|
<div fxLayout="row" fxLayout.xs="column" [ngStyle]="{'height.px':100,'min-height.px': 100}" [ngStyle.xs]="{'height.px':125,'min-height.px': 125}">
|
|
9164
|
-
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()" [displayLevelInfos]="
|
|
10718
|
+
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()" [displayLevelInfos]="displayAudioClip?.levelInfos" [stateLoading]="audioFetching"></audio-levelbar>
|
|
9165
10719
|
<div fxLayout="row">
|
|
9166
10720
|
<spr-recordingitemcontrols fxFlex="10 0 1"
|
|
9167
|
-
[audioLoaded]="displayAudioClip?.
|
|
10721
|
+
[audioLoaded]="displayAudioClip?.audioDataHolder!==null"
|
|
9168
10722
|
[playStartAction]="controlAudioPlayer?.startAction"
|
|
9169
10723
|
[playStopAction]="controlAudioPlayer?.stopAction"
|
|
9170
10724
|
[peakDbLvl]="peakLevelInDb"
|
|
@@ -9182,7 +10736,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
9182
10736
|
<div fxFlex="1 1 30%" fxLayoutAlign="start center">
|
|
9183
10737
|
<app-sprstatusdisplay fxHide.xs [statusMsg]="statusMsg" [statusAlertType]="statusAlertType" [statusWaiting]="statusWaiting"></app-sprstatusdisplay>
|
|
9184
10738
|
</div>
|
|
9185
|
-
<app-sprtransport fxFlex="10 0 30%" fxLayoutAlign="center center" [readonly]="readonly" [actions]="transportActions" [navigationEnabled]="items
|
|
10739
|
+
<app-sprtransport fxFlex="10 0 30%" fxLayoutAlign="center center" [readonly]="readonly" [actions]="transportActions" [navigationEnabled]="!items || items.length()>1"></app-sprtransport>
|
|
9186
10740
|
<div fxFlex="1 1 30%" fxLayoutAlign="end center" fxLayout="row">
|
|
9187
10741
|
<app-uploadstatus class="ricontrols" fxHide.xs fxLayoutAlign="end center" *ngIf="enableUploadRecordings" [value]="uploadProgress"
|
|
9188
10742
|
[status]="uploadStatus" [awaitNewUpload]="processingRecording"></app-uploadstatus>
|
|
@@ -9471,7 +11025,7 @@ class SpeechrecorderngComponent extends RecorderComponent {
|
|
|
9471
11025
|
this.uploadUpdate(ue);
|
|
9472
11026
|
};
|
|
9473
11027
|
window.addEventListener('beforeunload', (e) => {
|
|
9474
|
-
console.debug("Before page unload event");
|
|
11028
|
+
//console.debug("Before page unload event");
|
|
9475
11029
|
if (this.ready()) {
|
|
9476
11030
|
return;
|
|
9477
11031
|
}
|
|
@@ -9790,14 +11344,15 @@ class AudioDisplayPlayer {
|
|
|
9790
11344
|
if (this.aCtx) {
|
|
9791
11345
|
this.aCtx.decodeAudioData(data, (audioBuffer) => {
|
|
9792
11346
|
//console.debug("Audio Buffer Samplerate: ", audioBuffer.sampleRate)
|
|
9793
|
-
|
|
11347
|
+
let adh = new AudioDataHolder(audioBuffer, null);
|
|
11348
|
+
this.audioClip = new AudioClip(adh);
|
|
9794
11349
|
});
|
|
9795
11350
|
}
|
|
9796
11351
|
}
|
|
9797
|
-
set audioData(
|
|
9798
|
-
this.audioDisplayScrollPane.audioData =
|
|
9799
|
-
if (
|
|
9800
|
-
let clip = new AudioClip(
|
|
11352
|
+
set audioData(audioData) {
|
|
11353
|
+
this.audioDisplayScrollPane.audioData = audioData;
|
|
11354
|
+
if (audioData) {
|
|
11355
|
+
let clip = new AudioClip(audioData);
|
|
9801
11356
|
if (this.ap) {
|
|
9802
11357
|
this.ap.audioClip = clip;
|
|
9803
11358
|
this.playStartAction.disabled = false;
|
|
@@ -9819,7 +11374,7 @@ class AudioDisplayPlayer {
|
|
|
9819
11374
|
let audioData = null;
|
|
9820
11375
|
let sel = null;
|
|
9821
11376
|
if (audioClip) {
|
|
9822
|
-
audioData = audioClip.
|
|
11377
|
+
audioData = audioClip.audioDataHolder;
|
|
9823
11378
|
sel = audioClip.selection;
|
|
9824
11379
|
if (this._audioClip) {
|
|
9825
11380
|
this._audioClip.addSelectionObserver((ac) => {
|
|
@@ -10090,7 +11645,7 @@ class RecordingFileService {
|
|
|
10090
11645
|
// Do not use Promise version, which does not work with Safari 13
|
|
10091
11646
|
if (resp.body) {
|
|
10092
11647
|
aCtx.decodeAudioData(resp.body, ab => {
|
|
10093
|
-
recordingFile
|
|
11648
|
+
RecordingFileUtils.setAudioData(recordingFile, new AudioDataHolder(ab));
|
|
10094
11649
|
if (this.debugDelay > 0) {
|
|
10095
11650
|
window.setTimeout(() => {
|
|
10096
11651
|
observer.next(recordingFile);
|
|
@@ -10140,7 +11695,7 @@ class RecordingFileService {
|
|
|
10140
11695
|
if (resp.body) {
|
|
10141
11696
|
aCtx.decodeAudioData(resp.body, ab => {
|
|
10142
11697
|
if (rf) {
|
|
10143
|
-
rf
|
|
11698
|
+
RecordingFileUtils.setAudioData(rf, new AudioDataHolder(ab));
|
|
10144
11699
|
}
|
|
10145
11700
|
else {
|
|
10146
11701
|
observer.error('Recording file object null');
|
|
@@ -10191,7 +11746,8 @@ class RecordingFileService {
|
|
|
10191
11746
|
if (resp.body) {
|
|
10192
11747
|
aCtx.decodeAudioData(resp.body, ab => {
|
|
10193
11748
|
if (rf) {
|
|
10194
|
-
|
|
11749
|
+
let adh = new AudioDataHolder(ab);
|
|
11750
|
+
RecordingFileUtils.setAudioData(rf, adh);
|
|
10195
11751
|
}
|
|
10196
11752
|
else {
|
|
10197
11753
|
observer.error('Recording file object null');
|
|
@@ -10234,7 +11790,7 @@ class RecordingFileService {
|
|
|
10234
11790
|
// append UUID to make request URL unique to avoid localhost server caching
|
|
10235
11791
|
recUrl = recUrl + '.json?requestUUID=' + UUID.generate();
|
|
10236
11792
|
}
|
|
10237
|
-
console.log("Path request URL: "
|
|
11793
|
+
//console.log("Path request URL: "+recUrl)
|
|
10238
11794
|
return this.http.patch(recUrl, { editSampleRate: editSampleRate, editStartFrame: editStartFrame, editEndFrame: editEndFrame }, { withCredentials: this.withCredentials });
|
|
10239
11795
|
}
|
|
10240
11796
|
}
|
|
@@ -10252,6 +11808,7 @@ class RecordingFileMetaComponent {
|
|
|
10252
11808
|
constructor() {
|
|
10253
11809
|
this.sessionId = null;
|
|
10254
11810
|
this._recordingFile = null;
|
|
11811
|
+
this.stateLoading = false;
|
|
10255
11812
|
this.itemCode = null;
|
|
10256
11813
|
this.uuid = null;
|
|
10257
11814
|
}
|
|
@@ -10267,12 +11824,12 @@ class RecordingFileMetaComponent {
|
|
|
10267
11824
|
}
|
|
10268
11825
|
if (this.itemCode) {
|
|
10269
11826
|
this.uuid = null;
|
|
10270
|
-
console.debug("SprRecordingFile: "
|
|
11827
|
+
//console.debug("SprRecordingFile: "+this.itemCode+ " UUID: "+this.uuid)
|
|
10271
11828
|
}
|
|
10272
11829
|
else {
|
|
10273
11830
|
this.itemCode = null;
|
|
10274
11831
|
this.uuid = this._recordingFile?.uuid;
|
|
10275
|
-
console.debug("RecordingFile: "
|
|
11832
|
+
//console.debug("RecordingFile: "+this.itemCode+ " UUID: "+this.uuid)
|
|
10276
11833
|
}
|
|
10277
11834
|
}
|
|
10278
11835
|
else {
|
|
@@ -10289,10 +11846,11 @@ class RecordingFileMetaComponent {
|
|
|
10289
11846
|
}
|
|
10290
11847
|
}
|
|
10291
11848
|
RecordingFileMetaComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: RecordingFileMetaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10292
|
-
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: `
|
|
11849
|
+
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: `
|
|
10293
11850
|
<mat-card>
|
|
10294
11851
|
<mat-card-title>Recording file ID: {{recordingFile?.recordingFileId}}</mat-card-title>
|
|
10295
11852
|
<mat-card-content>
|
|
11853
|
+
<mat-progress-spinner *ngIf="stateLoading" mode="indeterminate" [diameter]="20"></mat-progress-spinner>
|
|
10296
11854
|
<table>
|
|
10297
11855
|
<tr *ngIf="itemCode">
|
|
10298
11856
|
<td>Itemcode:</td>
|
|
@@ -10322,7 +11880,7 @@ RecordingFileMetaComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0
|
|
|
10322
11880
|
</table>
|
|
10323
11881
|
</mat-card-content>
|
|
10324
11882
|
</mat-card>
|
|
10325
|
-
`, 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"] }] });
|
|
11883
|
+
`, 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"] }] });
|
|
10326
11884
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: RecordingFileMetaComponent, decorators: [{
|
|
10327
11885
|
type: Component,
|
|
10328
11886
|
args: [{
|
|
@@ -10331,6 +11889,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
10331
11889
|
<mat-card>
|
|
10332
11890
|
<mat-card-title>Recording file ID: {{recordingFile?.recordingFileId}}</mat-card-title>
|
|
10333
11891
|
<mat-card-content>
|
|
11892
|
+
<mat-progress-spinner *ngIf="stateLoading" mode="indeterminate" [diameter]="20"></mat-progress-spinner>
|
|
10334
11893
|
<table>
|
|
10335
11894
|
<tr *ngIf="itemCode">
|
|
10336
11895
|
<td>Itemcode:</td>
|
|
@@ -10365,6 +11924,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
10365
11924
|
}]
|
|
10366
11925
|
}], propDecorators: { sessionId: [{
|
|
10367
11926
|
type: Input
|
|
11927
|
+
}], stateLoading: [{
|
|
11928
|
+
type: Input
|
|
10368
11929
|
}], recordingFile: [{
|
|
10369
11930
|
type: Input
|
|
10370
11931
|
}] } });
|
|
@@ -10507,6 +12068,7 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
|
|
|
10507
12068
|
this.recordingFileVersion = null;
|
|
10508
12069
|
this.routedByQueryParam = false;
|
|
10509
12070
|
this.posInList = null;
|
|
12071
|
+
this.audioFetching = false;
|
|
10510
12072
|
this.naviInfoLoading = false;
|
|
10511
12073
|
this.parentE = this.eRef.nativeElement;
|
|
10512
12074
|
this.firstAction = new Action('First');
|
|
@@ -10676,18 +12238,20 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
|
|
|
10676
12238
|
this.updateActions();
|
|
10677
12239
|
let audioContext = AudioContextProvider.audioContextInstance();
|
|
10678
12240
|
if (audioContext) {
|
|
12241
|
+
this.audioFetching = true;
|
|
10679
12242
|
this.recordingFileService.fetchSprRecordingFile(audioContext, rfId).subscribe(value => {
|
|
12243
|
+
this.audioFetching = false;
|
|
10680
12244
|
this.status = 'Audio file loaded.';
|
|
10681
12245
|
let clip = null;
|
|
10682
12246
|
this.recordingFile = value;
|
|
10683
12247
|
if (this.recordingFile) {
|
|
10684
|
-
let ab = this.recordingFile.
|
|
12248
|
+
let ab = this.recordingFile.audioDataHolder;
|
|
10685
12249
|
if (ab) {
|
|
10686
12250
|
clip = new AudioClip(ab);
|
|
10687
12251
|
let esffsr = null;
|
|
10688
12252
|
let eeffsr = null;
|
|
10689
12253
|
let esr = null;
|
|
10690
|
-
if (clip.
|
|
12254
|
+
if (clip.audioDataHolder != null) {
|
|
10691
12255
|
esr = ab.sampleRate;
|
|
10692
12256
|
if (esr != null) {
|
|
10693
12257
|
esffsr = RecordingFileUtil.editStartFrameForSampleRate(this.recordingFile, esr);
|
|
@@ -10699,8 +12263,8 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
|
|
|
10699
12263
|
sel = new Selection(ab.sampleRate, esffsr, eeffsr);
|
|
10700
12264
|
}
|
|
10701
12265
|
else {
|
|
10702
|
-
let ch0 = ab.getChannelData(0);
|
|
10703
|
-
let frameLength =
|
|
12266
|
+
//let ch0 = ab.getChannelData(0);
|
|
12267
|
+
let frameLength = ab.frameLen;
|
|
10704
12268
|
sel = new Selection(esr, esffsr, frameLength);
|
|
10705
12269
|
}
|
|
10706
12270
|
}
|
|
@@ -10714,6 +12278,7 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
|
|
|
10714
12278
|
this.audioClip = clip;
|
|
10715
12279
|
this.loadedRecfile();
|
|
10716
12280
|
}, error1 => {
|
|
12281
|
+
this.audioFetching = false;
|
|
10717
12282
|
this.status = 'Error loading audio file!';
|
|
10718
12283
|
});
|
|
10719
12284
|
}
|
|
@@ -10823,7 +12388,7 @@ class RecordingFileViewComponent extends AudioDisplayPlayer {
|
|
|
10823
12388
|
for (let avRfV of avRf) {
|
|
10824
12389
|
os += avRfV.version + '/';
|
|
10825
12390
|
}
|
|
10826
|
-
console.debug(os);
|
|
12391
|
+
//console.debug(os);
|
|
10827
12392
|
}
|
|
10828
12393
|
}
|
|
10829
12394
|
this.updatePos();
|
|
@@ -10839,7 +12404,7 @@ RecordingFileViewComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0
|
|
|
10839
12404
|
|
|
10840
12405
|
<audio-display-scroll-pane #audioDisplayScrollPane></audio-display-scroll-pane>
|
|
10841
12406
|
<div class="ctrlview">
|
|
10842
|
-
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile"></app-recording-file-meta>
|
|
12407
|
+
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile" [stateLoading]="audioFetching"></app-recording-file-meta>
|
|
10843
12408
|
|
|
10844
12409
|
<audio-display-control [audioClip]="audioClip"
|
|
10845
12410
|
[playStartAction]="playStartAction"
|
|
@@ -10852,7 +12417,7 @@ RecordingFileViewComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0
|
|
|
10852
12417
|
[zoomFitToPanelAction]="zoomFitToPanelAction"></audio-display-control>
|
|
10853
12418
|
<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>
|
|
10854
12419
|
</div>
|
|
10855
|
-
`, 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"] }] });
|
|
12420
|
+
`, 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"] }] });
|
|
10856
12421
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: RecordingFileViewComponent, decorators: [{
|
|
10857
12422
|
type: Component,
|
|
10858
12423
|
args: [{
|
|
@@ -10861,7 +12426,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
10861
12426
|
|
|
10862
12427
|
<audio-display-scroll-pane #audioDisplayScrollPane></audio-display-scroll-pane>
|
|
10863
12428
|
<div class="ctrlview">
|
|
10864
|
-
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile"></app-recording-file-meta>
|
|
12429
|
+
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile" [stateLoading]="audioFetching"></app-recording-file-meta>
|
|
10865
12430
|
|
|
10866
12431
|
<audio-display-control [audioClip]="audioClip"
|
|
10867
12432
|
[playStartAction]="playStartAction"
|
|
@@ -10954,7 +12519,7 @@ class RecordingFileUI extends RecordingFileViewComponent {
|
|
|
10954
12519
|
}
|
|
10955
12520
|
applySelection() {
|
|
10956
12521
|
if (this.audioClip) {
|
|
10957
|
-
let ab = this.audioClip.
|
|
12522
|
+
let ab = this.audioClip.audioDataHolder;
|
|
10958
12523
|
let s = this.audioClip.selection;
|
|
10959
12524
|
if (ab && this.recordingFile?.recordingFileId) {
|
|
10960
12525
|
let sr = null;
|
|
@@ -10992,7 +12557,7 @@ RecordingFileUI.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", versio
|
|
|
10992
12557
|
|
|
10993
12558
|
<audio-display-scroll-pane #audioDisplayScrollPane></audio-display-scroll-pane>
|
|
10994
12559
|
<div class="ctrlview">
|
|
10995
|
-
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile"></app-recording-file-meta>
|
|
12560
|
+
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile" [stateLoading]="audioFetching"></app-recording-file-meta>
|
|
10996
12561
|
<audio-display-control [audioClip]="audioClip"
|
|
10997
12562
|
[playStartAction]="playStartAction"
|
|
10998
12563
|
[playSelectionAction]="playSelectionAction"
|
|
@@ -11006,7 +12571,7 @@ RecordingFileUI.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", versio
|
|
|
11006
12571
|
</div>
|
|
11007
12572
|
|
|
11008
12573
|
<button mat-raised-button color="accent" (click)="applySelection()" [disabled]="editSaved">{{this.applyButtonText()}}</button>
|
|
11009
|
-
`, 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"] }] });
|
|
12574
|
+
`, 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"] }] });
|
|
11010
12575
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: RecordingFileUI, decorators: [{
|
|
11011
12576
|
type: Component,
|
|
11012
12577
|
args: [{
|
|
@@ -11017,7 +12582,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
11017
12582
|
|
|
11018
12583
|
<audio-display-scroll-pane #audioDisplayScrollPane></audio-display-scroll-pane>
|
|
11019
12584
|
<div class="ctrlview">
|
|
11020
|
-
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile"></app-recording-file-meta>
|
|
12585
|
+
<app-recording-file-meta [sessionId]="sessionId" [recordingFile]="recordingFile" [stateLoading]="audioFetching"></app-recording-file-meta>
|
|
11021
12586
|
<audio-display-control [audioClip]="audioClip"
|
|
11022
12587
|
[playStartAction]="playStartAction"
|
|
11023
12588
|
[playSelectionAction]="playSelectionAction"
|
|
@@ -11074,7 +12639,8 @@ class MediaUtils {
|
|
|
11074
12639
|
|
|
11075
12640
|
class RecordingList {
|
|
11076
12641
|
constructor() {
|
|
11077
|
-
|
|
12642
|
+
//private recordingList:Array<RecordingFile>=new Array<RecordingFile>();
|
|
12643
|
+
this.recordingList = new RecFilesCache();
|
|
11078
12644
|
//cols=['index','length','samples','samplerate','action'];
|
|
11079
12645
|
this.cols = ['index', 'startedDate', 'length', 'action'];
|
|
11080
12646
|
this.selectDisabled = false;
|
|
@@ -11086,7 +12652,7 @@ class RecordingList {
|
|
|
11086
12652
|
this.buildDataSource();
|
|
11087
12653
|
}
|
|
11088
12654
|
buildDataSource() {
|
|
11089
|
-
this.recordingList.sort((a, b) => {
|
|
12655
|
+
this.recordingList.recFiles.sort((a, b) => {
|
|
11090
12656
|
let cmp = 0;
|
|
11091
12657
|
let aD = null;
|
|
11092
12658
|
let bD = null;
|
|
@@ -11107,24 +12673,35 @@ class RecordingList {
|
|
|
11107
12673
|
}
|
|
11108
12674
|
return cmp;
|
|
11109
12675
|
});
|
|
11110
|
-
this.recordingListDataSource.data = this.recordingList;
|
|
12676
|
+
this.recordingListDataSource.data = this.recordingList.recFiles;
|
|
11111
12677
|
}
|
|
11112
|
-
|
|
11113
|
-
this.recordingList.
|
|
12678
|
+
addRecFile(rf) {
|
|
12679
|
+
this.recordingList.addRecFile(rf);
|
|
11114
12680
|
this.buildDataSource();
|
|
11115
12681
|
}
|
|
12682
|
+
setRecFileAudioData(recFile, adh) {
|
|
12683
|
+
this.recordingList.setRecFileAudioData(recFile, adh);
|
|
12684
|
+
}
|
|
11116
12685
|
selectRecordingFile(rf) {
|
|
12686
|
+
this.recordingList.currentRecordingFile = rf;
|
|
11117
12687
|
this.selectedRecordingFileChanged.emit(rf);
|
|
11118
12688
|
}
|
|
11119
12689
|
selectTop() {
|
|
11120
|
-
if (this.recordingList.length > 0) {
|
|
11121
|
-
this.selectRecordingFile(this.recordingList[0]);
|
|
12690
|
+
if (this.recordingList.recFiles.length > 0) {
|
|
12691
|
+
this.selectRecordingFile(this.recordingList.recFiles[0]);
|
|
11122
12692
|
}
|
|
11123
12693
|
}
|
|
11124
12694
|
lengthTimeFormatted(rf) {
|
|
11125
12695
|
let str = '--:--:--';
|
|
11126
|
-
|
|
11127
|
-
|
|
12696
|
+
let tl = null;
|
|
12697
|
+
if (rf.timeLength) {
|
|
12698
|
+
tl = rf.timeLength;
|
|
12699
|
+
}
|
|
12700
|
+
else if (rf.frames && rf.audioDataHolder) {
|
|
12701
|
+
tl = rf.frames / rf.audioDataHolder?.sampleRate;
|
|
12702
|
+
}
|
|
12703
|
+
if (tl) {
|
|
12704
|
+
str = MediaUtils.toMediaTime(tl);
|
|
11128
12705
|
}
|
|
11129
12706
|
return str;
|
|
11130
12707
|
}
|
|
@@ -11210,8 +12787,11 @@ class RecorderCombiPane {
|
|
|
11210
12787
|
}
|
|
11211
12788
|
ngAfterViewInit() {
|
|
11212
12789
|
}
|
|
11213
|
-
|
|
11214
|
-
this.recordingListComp.
|
|
12790
|
+
addRecFile(rf) {
|
|
12791
|
+
this.recordingListComp.addRecFile(rf);
|
|
12792
|
+
}
|
|
12793
|
+
setRecFileAudioData(recFile, adh) {
|
|
12794
|
+
this.recordingListComp.setRecFileAudioData(recFile, adh);
|
|
11215
12795
|
}
|
|
11216
12796
|
selectRecordingFile(rf) {
|
|
11217
12797
|
this.selectedRecordingFileChanged.emit(rf);
|
|
@@ -11284,15 +12864,11 @@ class Item {
|
|
|
11284
12864
|
}
|
|
11285
12865
|
class AudioRecorder extends BasicRecorder {
|
|
11286
12866
|
constructor(changeDetectorRef, renderer, route, dialog, sessionService, recFileService, uploader, config) {
|
|
11287
|
-
super(dialog, sessionService, uploader, config);
|
|
11288
|
-
this.changeDetectorRef = changeDetectorRef;
|
|
12867
|
+
super(changeDetectorRef, dialog, sessionService, uploader, config);
|
|
11289
12868
|
this.renderer = renderer;
|
|
11290
12869
|
this.route = route;
|
|
11291
|
-
this.dialog = dialog;
|
|
11292
|
-
this.sessionService = sessionService;
|
|
11293
12870
|
this.recFileService = recFileService;
|
|
11294
12871
|
this.uploader = uploader;
|
|
11295
|
-
this.config = config;
|
|
11296
12872
|
this._project = null;
|
|
11297
12873
|
this.projectName = null;
|
|
11298
12874
|
this.enableUploadRecordings = true;
|
|
@@ -11475,13 +13051,15 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11475
13051
|
if (rfs) {
|
|
11476
13052
|
if (rfs instanceof Array) {
|
|
11477
13053
|
rfs.forEach((rf) => {
|
|
13054
|
+
// the list comes from the server, asssuem all recording files as server persisted
|
|
13055
|
+
rf.serverPersisted = true;
|
|
11478
13056
|
if (rf.startedDate) {
|
|
11479
13057
|
rf._startedAsDateObj = new Date(rf.startedDate);
|
|
11480
13058
|
}
|
|
11481
13059
|
if (rf.date) {
|
|
11482
13060
|
rf._dateAsDateObj = new Date(rf.date);
|
|
11483
13061
|
}
|
|
11484
|
-
this.recorderCombiPane.
|
|
13062
|
+
this.recorderCombiPane.addRecFile(rf);
|
|
11485
13063
|
});
|
|
11486
13064
|
}
|
|
11487
13065
|
else {
|
|
@@ -11535,6 +13113,7 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11535
13113
|
return this._project;
|
|
11536
13114
|
}
|
|
11537
13115
|
selectRecordingFile(rf) {
|
|
13116
|
+
this.audioFetching = false;
|
|
11538
13117
|
this.displayRecFile = rf;
|
|
11539
13118
|
}
|
|
11540
13119
|
uploadUpdate(ue) {
|
|
@@ -11556,9 +13135,6 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11556
13135
|
this.changeDetectorRef.detectChanges();
|
|
11557
13136
|
}
|
|
11558
13137
|
set controlAudioPlayer(controlAudioPlayer) {
|
|
11559
|
-
if (this._controlAudioPlayer) {
|
|
11560
|
-
//this._controlAudioPlayer.listener=null;
|
|
11561
|
-
}
|
|
11562
13138
|
this._controlAudioPlayer = controlAudioPlayer;
|
|
11563
13139
|
if (this._controlAudioPlayer) {
|
|
11564
13140
|
this._controlAudioPlayer.listener = this;
|
|
@@ -11638,6 +13214,7 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11638
13214
|
this.displayAudioClip = null;
|
|
11639
13215
|
this.showRecording();
|
|
11640
13216
|
if (this.ac) {
|
|
13217
|
+
this.audioFetching = false;
|
|
11641
13218
|
if (!this.ac.opened) {
|
|
11642
13219
|
if (this._selectedDeviceId) {
|
|
11643
13220
|
console.log("Open session with audio device Id: \'" + this._selectedDeviceId + "\' for " + this._channelCount + " channels");
|
|
@@ -11654,10 +13231,10 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11654
13231
|
}
|
|
11655
13232
|
downloadRecording() {
|
|
11656
13233
|
if (this.displayRecFile) {
|
|
11657
|
-
let ab = this.displayRecFile.
|
|
13234
|
+
let ab = this.displayRecFile.audioDataHolder;
|
|
11658
13235
|
let ww = new WavWriter();
|
|
11659
|
-
if (ab) {
|
|
11660
|
-
let wavFile = ww.writeAsync(ab, (wavFile) => {
|
|
13236
|
+
if (ab?.buffer) {
|
|
13237
|
+
let wavFile = ww.writeAsync(ab.buffer, (wavFile) => {
|
|
11661
13238
|
let blob = new Blob([wavFile], { type: 'audio/wav' });
|
|
11662
13239
|
let rfUrl = URL.createObjectURL(blob);
|
|
11663
13240
|
let dataDnlLnk = this.renderer.createElement('a');
|
|
@@ -11680,35 +13257,50 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11680
13257
|
set displayRecFile(displayRecFile) {
|
|
11681
13258
|
this._displayRecFile = displayRecFile;
|
|
11682
13259
|
if (this._displayRecFile) {
|
|
11683
|
-
let
|
|
11684
|
-
if (
|
|
11685
|
-
this.displayAudioClip = new AudioClip(
|
|
13260
|
+
let adh = this._displayRecFile.audioDataHolder;
|
|
13261
|
+
if (adh) {
|
|
13262
|
+
this.displayAudioClip = new AudioClip(adh);
|
|
13263
|
+
console.debug(" set recording file: display audio clip set");
|
|
11686
13264
|
this.controlAudioPlayer.audioClip = this.displayAudioClip;
|
|
11687
13265
|
}
|
|
11688
13266
|
else {
|
|
11689
13267
|
// clear for now ...
|
|
11690
13268
|
this.displayAudioClip = null;
|
|
13269
|
+
console.debug("set recording file: display audio clip null");
|
|
11691
13270
|
this.controlAudioPlayer.audioClip = null;
|
|
11692
13271
|
if (this._controlAudioPlayer && this._session) {
|
|
11693
13272
|
//... and try to fetch from server
|
|
11694
|
-
this.
|
|
11695
|
-
|
|
11696
|
-
|
|
11697
|
-
|
|
11698
|
-
|
|
11699
|
-
|
|
11700
|
-
|
|
13273
|
+
this.audioFetching = true;
|
|
13274
|
+
let rf = this._displayRecFile;
|
|
13275
|
+
let clip = this.displayAudioClip;
|
|
13276
|
+
this.audioFetchSubscription = this.recFileService.fetchRecordingFileAudioBuffer(this._controlAudioPlayer.context, this._session.project, rf).subscribe({
|
|
13277
|
+
next: ab => {
|
|
13278
|
+
this.audioFetching = false;
|
|
13279
|
+
let fabDh = null;
|
|
13280
|
+
if (ab) {
|
|
13281
|
+
if (rf) {
|
|
13282
|
+
fabDh = new AudioDataHolder(ab);
|
|
13283
|
+
this.recorderCombiPane.setRecFileAudioData(rf, fabDh);
|
|
13284
|
+
}
|
|
13285
|
+
}
|
|
13286
|
+
else {
|
|
13287
|
+
console.error('Recording file could not be loaded.');
|
|
13288
|
+
this.statusMsg = 'Recording file could not be loaded.';
|
|
13289
|
+
this.statusAlertType = 'error';
|
|
13290
|
+
}
|
|
13291
|
+
if (fabDh) {
|
|
13292
|
+
// 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
|
|
13293
|
+
this.displayAudioClip = new AudioClip(fabDh);
|
|
13294
|
+
//console.debug("set recording file: display audio clip from fetched audio buffer");
|
|
13295
|
+
}
|
|
13296
|
+
this.controlAudioPlayer.audioClip = this.displayAudioClip;
|
|
13297
|
+
this.showRecording();
|
|
13298
|
+
}, error: err => {
|
|
13299
|
+
console.error("Could not load recording file from server: " + err);
|
|
13300
|
+
this.audioFetching = false;
|
|
13301
|
+
this.statusMsg = 'Recording file could not be loaded: ' + err;
|
|
11701
13302
|
this.statusAlertType = 'error';
|
|
11702
13303
|
}
|
|
11703
|
-
if (fab) {
|
|
11704
|
-
this.displayAudioClip = new AudioClip(fab);
|
|
11705
|
-
}
|
|
11706
|
-
this.controlAudioPlayer.audioClip = this.displayAudioClip;
|
|
11707
|
-
this.showRecording();
|
|
11708
|
-
}, err => {
|
|
11709
|
-
console.error("Could not load recording file from server: " + err);
|
|
11710
|
-
this.statusMsg = 'Recording file could not be loaded: ' + err;
|
|
11711
|
-
this.statusAlertType = 'error';
|
|
11712
13304
|
});
|
|
11713
13305
|
}
|
|
11714
13306
|
else {
|
|
@@ -11718,6 +13310,7 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11718
13310
|
}
|
|
11719
13311
|
}
|
|
11720
13312
|
else {
|
|
13313
|
+
console.debug("recording file null");
|
|
11721
13314
|
this.displayAudioClip = null;
|
|
11722
13315
|
this.controlAudioPlayer.audioClip = null;
|
|
11723
13316
|
}
|
|
@@ -11726,28 +13319,6 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11726
13319
|
get displayRecFile() {
|
|
11727
13320
|
return this._displayRecFile;
|
|
11728
13321
|
}
|
|
11729
|
-
showRecording() {
|
|
11730
|
-
this.controlAudioPlayer.stop();
|
|
11731
|
-
if (this.displayAudioClip) {
|
|
11732
|
-
this.levelMeasure.calcBufferLevelInfos(this.displayAudioClip.buffer, LEVEL_BAR_INTERVALL_SECONDS).then((levelInfos) => {
|
|
11733
|
-
this.displayLevelInfos = levelInfos;
|
|
11734
|
-
this.changeDetectorRef.detectChanges();
|
|
11735
|
-
});
|
|
11736
|
-
this.playStartAction.disabled = false;
|
|
11737
|
-
}
|
|
11738
|
-
else {
|
|
11739
|
-
// TODO
|
|
11740
|
-
// Setting to null does not trigger a change if it was null before (happens after nextitem() in AUTOPROGRESS mode)
|
|
11741
|
-
// The level bar display does not clear, it shows the last captured stream
|
|
11742
|
-
this.displayLevelInfos = null;
|
|
11743
|
-
this.playStartAction.disabled = true;
|
|
11744
|
-
// Collapse audio signal display if open
|
|
11745
|
-
if (!this.audioSignalCollapsed) {
|
|
11746
|
-
this.audioSignalCollapsed = true;
|
|
11747
|
-
}
|
|
11748
|
-
}
|
|
11749
|
-
this.changeDetectorRef.detectChanges();
|
|
11750
|
-
}
|
|
11751
13322
|
updateStartActionDisableState() {
|
|
11752
13323
|
this.transportActions.startAction.disabled = !(this.ac);
|
|
11753
13324
|
}
|
|
@@ -11791,6 +13362,19 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11791
13362
|
super.started();
|
|
11792
13363
|
this.statusAlertType = 'info';
|
|
11793
13364
|
this.statusMsg = 'Recording...';
|
|
13365
|
+
if (!this.rfUuid) {
|
|
13366
|
+
this.rfUuid = UUID.generate();
|
|
13367
|
+
}
|
|
13368
|
+
let sessId = 0;
|
|
13369
|
+
if (this._session) {
|
|
13370
|
+
sessId = this._session.sessionId;
|
|
13371
|
+
}
|
|
13372
|
+
let rf = new RecordingFile(this.rfUuid, sessId, null);
|
|
13373
|
+
rf._startedAsDateObj = this.startedDate;
|
|
13374
|
+
if (rf._startedAsDateObj) {
|
|
13375
|
+
rf.startedDate = rf._startedAsDateObj.toString();
|
|
13376
|
+
}
|
|
13377
|
+
this._recordingFile = rf;
|
|
11794
13378
|
let maxRecordingTimeMs = MAX_RECORDING_TIME_MS;
|
|
11795
13379
|
this.maxRecTimerId = window.setTimeout(() => {
|
|
11796
13380
|
this.stopRecordingMaxRec();
|
|
@@ -11827,68 +13411,75 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11827
13411
|
this.transportActions.pauseAction.disabled = true;
|
|
11828
13412
|
this.statusAlertType = 'info';
|
|
11829
13413
|
this.statusMsg = 'Recorded.';
|
|
11830
|
-
let ad;
|
|
13414
|
+
let ad = null;
|
|
13415
|
+
let ada = null;
|
|
13416
|
+
let adh = null;
|
|
13417
|
+
let frameLen = 0;
|
|
11831
13418
|
if (this.ac) {
|
|
11832
|
-
|
|
13419
|
+
if (this.uploadChunkSizeSeconds || AudioRecorder.FORCE_ARRRAY_AUDIO_BUFFER) {
|
|
13420
|
+
ada = this.ac.audioBufferArray();
|
|
13421
|
+
frameLen = ada.frameLen;
|
|
13422
|
+
}
|
|
13423
|
+
else {
|
|
13424
|
+
ad = this.ac.audioBuffer();
|
|
13425
|
+
frameLen = ad.length;
|
|
13426
|
+
}
|
|
13427
|
+
adh = new AudioDataHolder(ad, ada);
|
|
11833
13428
|
let sessId = 0;
|
|
11834
13429
|
if (this._session) {
|
|
11835
13430
|
sessId = this._session.sessionId;
|
|
11836
13431
|
}
|
|
11837
|
-
if (
|
|
11838
|
-
this.
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
13432
|
+
if (this._recordingFile) {
|
|
13433
|
+
// Use an own reference since the writing of the wave file is asynchronous and this._recordingFile might already contain the next recording
|
|
13434
|
+
let rf = this._recordingFile;
|
|
13435
|
+
RecordingFileUtils.setAudioData(rf, adh);
|
|
13436
|
+
this.recorderCombiPane.addRecFile(rf);
|
|
13437
|
+
// Upload if upload enabled and not in chunked upload mode
|
|
13438
|
+
if (this.enableUploadRecordings && !this.uploadChunkSizeSeconds && rf != null && ad != null) {
|
|
13439
|
+
let apiEndPoint = '';
|
|
13440
|
+
if (this.config && this.config.apiEndPoint) {
|
|
13441
|
+
apiEndPoint = this.config.apiEndPoint;
|
|
13442
|
+
}
|
|
13443
|
+
if (apiEndPoint !== '') {
|
|
13444
|
+
apiEndPoint = apiEndPoint + '/';
|
|
13445
|
+
}
|
|
13446
|
+
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
13447
|
+
let recUrl = sessionsUrl + '/' + rf.session + '/' + RECFILE_API_CTX + '/' + rf.uuid;
|
|
13448
|
+
// convert asynchronously to 16-bit integer PCM
|
|
13449
|
+
// TODO could we avoid conversion to save CPU resources and transfer float PCM directly?
|
|
13450
|
+
// TODO duplicate conversion for manual download
|
|
13451
|
+
this.processingRecording = true;
|
|
13452
|
+
let ww = new WavWriter();
|
|
13453
|
+
ww.writeAsync(ad, (wavFile) => {
|
|
13454
|
+
this.postRecordingMultipart(wavFile, recUrl, rf);
|
|
13455
|
+
this.processingRecording = false;
|
|
13456
|
+
this.updateWakeLock();
|
|
13457
|
+
this.changeDetectorRef.detectChanges();
|
|
13458
|
+
});
|
|
11856
13459
|
}
|
|
11857
|
-
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
11858
|
-
let recUrl = sessionsUrl + '/' + rf.session + '/' + RECFILE_API_CTX + '/' + rf.uuid;
|
|
11859
|
-
// convert asynchronously to 16-bit integer PCM
|
|
11860
|
-
// TODO could we avoid conversion to save CPU resources and transfer float PCM directly?
|
|
11861
|
-
// TODO duplicate conversion for manual download
|
|
11862
|
-
this.processingRecording = true;
|
|
11863
|
-
let ww = new WavWriter();
|
|
11864
|
-
ww.writeAsync(ad, (wavFile) => {
|
|
11865
|
-
this.postRecordingMultipart(wavFile, rf.uuid, rf.session, rf._startedAsDateObj, recUrl);
|
|
11866
|
-
this.processingRecording = false;
|
|
11867
|
-
this.updateWakeLock();
|
|
11868
|
-
this.changeDetectorRef.detectChanges();
|
|
11869
|
-
});
|
|
11870
13460
|
}
|
|
11871
13461
|
}
|
|
13462
|
+
this.displayRecFile = this._recordingFile;
|
|
11872
13463
|
this.status = 1 /* IDLE */;
|
|
11873
13464
|
this.navigationDisabled = false;
|
|
11874
13465
|
this.updateNavigationActions();
|
|
11875
13466
|
this.updateWakeLock();
|
|
11876
13467
|
this.changeDetectorRef.detectChanges();
|
|
11877
13468
|
}
|
|
11878
|
-
postRecordingMultipart(wavFile,
|
|
13469
|
+
postRecordingMultipart(wavFile, recUrl, rf) {
|
|
11879
13470
|
let wavBlob = new Blob([wavFile], { type: 'audio/wav' });
|
|
11880
13471
|
let fd = new FormData();
|
|
11881
|
-
if (uuid) {
|
|
11882
|
-
fd.set('uuid', uuid);
|
|
13472
|
+
if (rf.uuid) {
|
|
13473
|
+
fd.set('uuid', rf.uuid);
|
|
11883
13474
|
}
|
|
11884
|
-
if (
|
|
11885
|
-
fd.set('sessionId',
|
|
13475
|
+
if (rf.session !== null) {
|
|
13476
|
+
fd.set('sessionId', rf.session.toString());
|
|
11886
13477
|
}
|
|
11887
|
-
if (
|
|
11888
|
-
fd.set('startedDate',
|
|
13478
|
+
if (rf._startedAsDateObj) {
|
|
13479
|
+
fd.set('startedDate', rf._startedAsDateObj.toJSON());
|
|
11889
13480
|
}
|
|
11890
13481
|
fd.set('audio', wavBlob);
|
|
11891
|
-
let ul = new Upload(fd, recUrl);
|
|
13482
|
+
let ul = new Upload(fd, recUrl, rf);
|
|
11892
13483
|
this.uploader.queueUpload(ul);
|
|
11893
13484
|
}
|
|
11894
13485
|
postChunkAudioBuffer(audioBuffer, chunkIdx) {
|
|
@@ -11904,8 +13495,9 @@ class AudioRecorder extends BasicRecorder {
|
|
|
11904
13495
|
}
|
|
11905
13496
|
let sessionsUrl = apiEndPoint + SessionService.SESSION_API_CTX;
|
|
11906
13497
|
let recUrl = sessionsUrl + '/' + this.session?.sessionId + '/' + RECFILE_API_CTX + '/' + this.rfUuid + '/' + chunkIdx;
|
|
13498
|
+
let rf = this._recordingFile;
|
|
11907
13499
|
ww.writeAsync(audioBuffer, (wavFile) => {
|
|
11908
|
-
this.postRecording(wavFile, recUrl);
|
|
13500
|
+
this.postRecording(wavFile, recUrl, rf);
|
|
11909
13501
|
this.processingRecording = false;
|
|
11910
13502
|
});
|
|
11911
13503
|
}
|
|
@@ -11954,11 +13546,11 @@ AudioRecorder.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version:
|
|
|
11954
13546
|
|
|
11955
13547
|
<div fxLayout="row" fxLayout.xs="column" [ngStyle]="{'height.px':100,'min-height.px': 100}"
|
|
11956
13548
|
[ngStyle.xs]="{'height.px':125,'min-height.px': 125}">
|
|
11957
|
-
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()"
|
|
11958
|
-
[displayLevelInfos]="
|
|
13549
|
+
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()" [stateLoading]="audioFetching"
|
|
13550
|
+
[displayLevelInfos]="displayAudioClip?.levelInfos"></audio-levelbar>
|
|
11959
13551
|
<div fxLayout="row">
|
|
11960
13552
|
<spr-recordingitemcontrols fxFlex="10 0 1"
|
|
11961
|
-
[audioLoaded]="displayAudioClip?.
|
|
13553
|
+
[audioLoaded]="displayAudioClip?.audioDataHolder!==null"
|
|
11962
13554
|
[playStartAction]="controlAudioPlayer?.startAction"
|
|
11963
13555
|
[playStopAction]="controlAudioPlayer?.stopAction"
|
|
11964
13556
|
[peakDbLvl]="peakLevelInDb"
|
|
@@ -11997,7 +13589,7 @@ AudioRecorder.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version:
|
|
|
11997
13589
|
[ready]="dataSaved && !isActive()"></app-readystateindicator>
|
|
11998
13590
|
</div>
|
|
11999
13591
|
</div>
|
|
12000
|
-
`, 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"] }] });
|
|
13592
|
+
`, 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"] }] });
|
|
12001
13593
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AudioRecorder, decorators: [{
|
|
12002
13594
|
type: Component,
|
|
12003
13595
|
args: [{
|
|
@@ -12020,11 +13612,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
|
|
|
12020
13612
|
|
|
12021
13613
|
<div fxLayout="row" fxLayout.xs="column" [ngStyle]="{'height.px':100,'min-height.px': 100}"
|
|
12022
13614
|
[ngStyle.xs]="{'height.px':125,'min-height.px': 125}">
|
|
12023
|
-
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()"
|
|
12024
|
-
[displayLevelInfos]="
|
|
13615
|
+
<audio-levelbar fxFlex="1 0 1" [streamingMode]="isRecording()" [stateLoading]="audioFetching"
|
|
13616
|
+
[displayLevelInfos]="displayAudioClip?.levelInfos"></audio-levelbar>
|
|
12025
13617
|
<div fxLayout="row">
|
|
12026
13618
|
<spr-recordingitemcontrols fxFlex="10 0 1"
|
|
12027
|
-
[audioLoaded]="displayAudioClip?.
|
|
13619
|
+
[audioLoaded]="displayAudioClip?.audioDataHolder!==null"
|
|
12028
13620
|
[playStartAction]="controlAudioPlayer?.startAction"
|
|
12029
13621
|
[playStopAction]="controlAudioPlayer?.stopAction"
|
|
12030
13622
|
[peakDbLvl]="peakLevelInDb"
|
|
@@ -12302,20 +13894,20 @@ class SpeechrecorderngModule {
|
|
|
12302
13894
|
}
|
|
12303
13895
|
SpeechrecorderngModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: SpeechrecorderngModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
12304
13896
|
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,
|
|
12305
|
-
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] });
|
|
12306
|
-
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]] });
|
|
13897
|
+
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] });
|
|
13898
|
+
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]] });
|
|
12307
13899
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: SpeechrecorderngModule, decorators: [{
|
|
12308
13900
|
type: NgModule,
|
|
12309
13901
|
args: [{
|
|
12310
13902
|
declarations: [AudioSignal, Sonagram, ScrollPaneHorizontal, AudioClipUIContainer, AudioDisplayScrollPane, AudioDisplay, AudioDisplayPlayer, AudioDisplayControl, LevelBar, Progress, SimpleTrafficLight, Recinstructions, Prompter, PromptContainer, PromptingContainer, Prompting, StatusDisplay,
|
|
12311
13903
|
ProgressDisplay, RecordingItemDisplay, RecordingItemControls, UploadStatus, TransportPanel, WakeLockIndicator, ReadyStateIndicator, ControlPanel, WarningBar, AudioRecorder, SessionManager, MessageDialog, SessionFinishedDialog, SpeechrecorderngComponent, AudioRecorderComponent, RecordingFileViewComponent, RecordingFileUI, ScrollIntoViewDirective, RecordingFileNaviComponent, RecordingFileMetaComponent, RecordingList, RecorderCombiPane, AudioRecorder],
|
|
12312
13904
|
exports: [MessageDialog, SpeechrecorderngComponent, ScrollPaneHorizontal, AudioClipUIContainer, AudioDisplayScrollPane, AudioDisplay, AudioDisplayPlayer, AudioDisplayControl, LevelBar, AudioRecorder],
|
|
12313
|
-
imports: [RouterModule.forChild(SPR_ROUTES), FlexLayoutModule, CommonModule, MatIconModule, MatButtonModule, MatDialogModule, MatProgressBarModule, MatProgressSpinnerModule, MatTooltipModule, HttpClientModule, MatCheckboxModule, MatCardModule, MatDividerModule, MatGridListModule, MatTableModule, MatInputModule, MatSelectModule, MatSnackBarModule],
|
|
13905
|
+
imports: [RouterModule.forChild(SPR_ROUTES), FlexLayoutModule, CommonModule, MatIconModule, MatButtonModule, MatDialogModule, MatProgressBarModule, MatProgressSpinnerModule, MatTooltipModule, HttpClientModule, MatCheckboxModule, MatCardModule, MatDividerModule, MatGridListModule, MatTableModule, MatInputModule, MatSelectModule, MatSnackBarModule, MatMenuModule],
|
|
12314
13906
|
providers: [SessionService, ProjectService, ScriptService, RecordingService, RecordingFileService, SpeechRecorderUploader]
|
|
12315
13907
|
}]
|
|
12316
13908
|
}] });
|
|
12317
13909
|
|
|
12318
|
-
const VERSION = '
|
|
13910
|
+
const VERSION = '3.0.1';
|
|
12319
13911
|
|
|
12320
13912
|
/*
|
|
12321
13913
|
* Public API Surface of speechrecorderng
|