comparison src/app/waveform/waveform.component.ts @ 301:fff3a4fba992

Change guard at top of renderFeatures for change in response shape + a bunch of formatting changes.
author Lucas Thompson <dev@lucas.im>
date Wed, 10 May 2017 17:45:06 +0100
parents cda9307d9eb7
children dc415a620b15
comparison
equal deleted inserted replaced
297:73beb0e970c5 301:fff3a4fba992
20 import {Subscription} from 'rxjs/Subscription'; 20 import {Subscription} from 'rxjs/Subscription';
21 import { 21 import {
22 FeatureCollection, 22 FeatureCollection,
23 SimpleResponse, 23 SimpleResponse,
24 VectorFeatures, 24 VectorFeatures,
25 MatrixFeatures, 25 MatrixFeatures
26 TrackFeature,
27 TrackFeatures
28 } from 'piper/HigherLevelUtilities'; 26 } from 'piper/HigherLevelUtilities';
29 import {toSeconds} from 'piper'; 27 import {toSeconds} from 'piper';
30 import {FeatureList, Feature} from 'piper/Feature'; 28 import {FeatureList, Feature} from 'piper/Feature';
31 import * as Hammer from 'hammerjs'; 29 import * as Hammer from 'hammerjs';
32 import {WavesSpectrogramLayer} from '../spectrogram/Spectrogram'; 30 import {WavesSpectrogramLayer} from '../spectrogram/Spectrogram';
388 element.addEventListener('touchend', () => { 386 element.addEventListener('touchend', () => {
389 if (isZooming) { 387 if (isZooming) {
390 isZooming = false; 388 isZooming = false;
391 zoomGestureJustEnded = true; 389 zoomGestureJustEnded = true;
392 } 390 }
393 }); 391 });
394 element.addEventListener('touchmove', zoom); 392 element.addEventListener('touchmove', zoom);
395 } 393 }
396 // this.timeline.createTrack(track, height/2, `wave-${this.trackIdPrefix}`); 394 // this.timeline.createTrack(track, height/2, `wave-${this.trackIdPrefix}`);
397 // this.timeline.createTrack(track, height/2, `grid-${this.trackIdPrefix}`); 395 // this.timeline.createTrack(track, height/2, `grid-${this.trackIdPrefix}`);
398 } 396 }
424 } 422 }
425 } 423 }
426 } 424 }
427 if (sample.length === 0) { 425 if (sample.length === 0) {
428 console.log('WARNING: No samples gathered, even though we hoped for ' + 426 console.log('WARNING: No samples gathered, even though we hoped for ' +
429 (m_per * w) + ' of them'); 427 (m_per * w) + ' of them');
430 return 0.0; 428 return 0.0;
431 } 429 }
432 sample.sort((a, b) => { return a - b; }); 430 sample.sort((a, b) => { return a - b; });
433 const ix = Math.floor((sample.length * percentile) / 100); 431 const ix = Math.floor((sample.length * percentile) / 100);
434 console.log('Estimating ' + percentile + '-%ile of ' + 432 console.log('Estimating ' + percentile + '-%ile of ' +
435 n + '-sample dataset (' + w + ' x ' + h + ') as value ' + ix + 433 n + '-sample dataset (' + w + ' x ' + h + ') as value ' + ix +
436 ' of sorted ' + sample.length + '-sample subset'); 434 ' of sorted ' + sample.length + '-sample subset');
437 const estimate = sample[ix]; 435 const estimate = sample[ix];
438 console.log('Estimate is: ' + estimate + ' (where min sampled value = ' + 436 console.log('Estimate is: ' + estimate + ' (where min sampled value = ' +
439 sample[0] + ' and max = ' + sample[sample.length - 1] + ')'); 437 sample[0] + ' and max = ' + sample[sample.length - 1] + ')');
440 return estimate; 438 return estimate;
441 } 439 }
442 440
443 interpolatingMapper(hexColours) { 441 interpolatingMapper(hexColours) {
444 const colours = hexColours.map(n => { 442 const colours = hexColours.map(n => {
445 const i = parseInt(n, 16); 443 const i = parseInt(n, 16);
446 return [ ((i >> 16) & 255) / 255.0, 444 return [ ((i >> 16) & 255) / 255.0,
447 ((i >> 8) & 255) / 255.0, 445 ((i >> 8) & 255) / 255.0,
448 ((i) & 255) / 255.0 ]; 446 ((i) & 255) / 255.0 ];
449 }); 447 });
450 const last = colours.length - 1; 448 const last = colours.length - 1;
451 return (value => { 449 return (value => {
452 const m = value * last; 450 const m = value * last;
453 if (m >= last) { 451 if (m >= last) {
460 const prop0 = base + 1.0 - m; 458 const prop0 = base + 1.0 - m;
461 const prop1 = m - base; 459 const prop1 = m - base;
462 const c0 = colours[base]; 460 const c0 = colours[base];
463 const c1 = colours[base + 1]; 461 const c1 = colours[base + 1];
464 return [ c0[0] * prop0 + c1[0] * prop1, 462 return [ c0[0] * prop0 + c1[0] * prop1,
465 c0[1] * prop0 + c1[1] * prop1, 463 c0[1] * prop0 + c1[1] * prop1,
466 c0[2] * prop0 + c1[2] * prop1 ]; 464 c0[2] * prop0 + c1[2] * prop1 ];
467 }); 465 });
468 } 466 }
469 467
470 iceMapper() { 468 iceMapper() {
471 const hexColours = [ 469 const hexColours = [
483 const p = v * (1 - s); 481 const p = v * (1 - s);
484 const q = v * (1 - f * s); 482 const q = v * (1 - f * s);
485 const t = v * (1 - (1 - f) * s); 483 const t = v * (1 - (1 - f) * s);
486 let r = 0, g = 0, b = 0; 484 let r = 0, g = 0, b = 0;
487 switch (i % 6) { 485 switch (i % 6) {
488 case 0: r = v; g = t; b = p; break; 486 case 0: r = v; g = t; b = p; break;
489 case 1: r = q; g = v; b = p; break; 487 case 1: r = q; g = v; b = p; break;
490 case 2: r = p; g = v; b = t; break; 488 case 2: r = p; g = v; b = t; break;
491 case 3: r = p; g = q; b = v; break; 489 case 3: r = p; g = q; b = v; break;
492 case 4: r = t; g = p; b = v; break; 490 case 4: r = t; g = p; b = v; break;
493 case 5: r = v; g = p; b = q; break; 491 case 5: r = v; g = p; b = q; break;
494 } 492 }
495 return [ r, g, b ]; 493 return [ r, g, b ];
496 } 494 }
497 495
498 greenMapper() { 496 greenMapper() {
620 if (!extracted.hasOwnProperty('features') 618 if (!extracted.hasOwnProperty('features')
621 || !extracted.hasOwnProperty('outputDescriptor')) { 619 || !extracted.hasOwnProperty('outputDescriptor')) {
622 return; 620 return;
623 } 621 }
624 if (!extracted.features.hasOwnProperty('shape') 622 if (!extracted.features.hasOwnProperty('shape')
625 || !extracted.features.hasOwnProperty('data')) { 623 || !extracted.features.hasOwnProperty('collected')) {
626 return; 624 return;
627 } 625 }
628 const features: FeatureCollection = (extracted.features as FeatureCollection); 626 const features: FeatureCollection = (extracted.features as FeatureCollection);
629 const outputDescriptor = extracted.outputDescriptor; 627 const outputDescriptor = extracted.outputDescriptor;
630 // const height = this.trackDiv.nativeElement.getBoundingClientRect().height / 2; 628 // const height = this.trackDiv.nativeElement.getBoundingClientRect().height / 2;
631 const height = this.trackDiv.nativeElement.getBoundingClientRect().height; 629 const height = this.trackDiv.nativeElement.getBoundingClientRect().height;
632 const waveTrack = this.timeline.getTrackById(`wave-${this.trackIdPrefix}`); 630 const waveTrack = this.timeline.getTrackById(`wave-${this.trackIdPrefix}`);
633 631
634 // TODO refactor all of this 632 // TODO refactor all of this
635 switch (features.shape) { 633 switch (features.shape) {
636 case 'vector': { 634 case 'vector': {
637 const collected = features.collected as VectorFeatures; 635 const collected = features.collected as VectorFeatures;
638 const stepDuration = collected.stepDuration; 636 const stepDuration = collected.stepDuration;
639 const featureData = collected.data; 637 const featureData = collected.data;
640 if (featureData.length === 0) { 638 if (featureData.length === 0) {
641 return; 639 return;
642 } 640 }
650 let max = featureData.reduce((m, f) => Math.max(m, f), -Infinity); 648 let max = featureData.reduce((m, f) => Math.max(m, f), -Infinity);
651 if (min === Infinity) { 649 if (min === Infinity) {
652 min = 0; 650 min = 0;
653 max = 1; 651 max = 1;
654 } 652 }
655 console.log("adding line layer: min = " + min + ", max = " + max); 653 console.log('adding line layer: min = ' + min + ', max = ' + max);
656 if (min !== min || max !== max) { 654 if (min !== min || max !== max) {
657 console.log("WARNING: min or max is NaN"); 655 console.log('WARNING: min or max is NaN');
658 min = 0; 656 min = 0;
659 max = 1; 657 max = 1;
660 } 658 }
661 const lineLayer = new wavesUI.helpers.LineLayer(plotData, { 659 const lineLayer = new wavesUI.helpers.LineLayer(plotData, {
662 color: colour, 660 color: colour,
663 height: height, 661 height: height,
664 yDomain: [ min, max ] 662 yDomain: [ min, max ]
665 }); 663 });
692 this.timeline.timeContext 690 this.timeline.timeContext
693 ); 691 );
694 break; 692 break;
695 } 693 }
696 case 'list': { 694 case 'list': {
697 const featureData = features.collected as FeatureList; 695 const featureData = features.collected as FeatureList;
698 if (featureData.length === 0) { 696 if (featureData.length === 0) {
699 return; 697 return;
700 } 698 }
701 // TODO look at output descriptor instead of directly inspecting features 699 // TODO look at output descriptor instead of directly inspecting features
702 const hasDuration = outputDescriptor.configured.hasDuration; 700 const hasDuration = outputDescriptor.configured.hasDuration;
704 && outputDescriptor.configured.binCount === 0 702 && outputDescriptor.configured.binCount === 0
705 && featureData[0].featureValues == null; 703 && featureData[0].featureValues == null;
706 const isRegion = hasDuration 704 const isRegion = hasDuration
707 && featureData[0].timestamp != null; 705 && featureData[0].timestamp != null;
708 console.log('Have list features: length ' + featureData.length + 706 console.log('Have list features: length ' + featureData.length +
709 ', isMarker ' + isMarker + ', isRegion ' + isRegion + 707 ', isMarker ' + isMarker + ', isRegion ' + isRegion +
710 ', hasDuration ' + hasDuration); 708 ', hasDuration ' + hasDuration);
711 // TODO refactor, this is incomprehensible 709 // TODO refactor, this is incomprehensible
712 if (isMarker) { 710 if (isMarker) {
713 const plotData = featureData.map(feature => ({ 711 const plotData = featureData.map(feature => ({
714 time: toSeconds(feature.timestamp), 712 time: toSeconds(feature.timestamp),
715 label: feature.label 713 label: feature.label
794 ); 792 );
795 } 793 }
796 break; 794 break;
797 } 795 }
798 case 'matrix': { 796 case 'matrix': {
799 const collected = features.collected as MatrixFeatures; 797 const collected = features.collected as MatrixFeatures;
800 const stepDuration = collected.stepDuration; 798 const stepDuration = collected.stepDuration;
801 // !!! + start time 799 // !!! + start time
802 const matrixData = collected.data; 800 const matrixData = collected.data;
803 801
804 if (matrixData.length === 0) { 802 if (matrixData.length === 0) {
808 console.log('matrix data length = ' + matrixData.length); 806 console.log('matrix data length = ' + matrixData.length);
809 console.log('height of first column = ' + matrixData[0].length); 807 console.log('height of first column = ' + matrixData[0].length);
810 const targetValue = this.estimatePercentile(matrixData, 95); 808 const targetValue = this.estimatePercentile(matrixData, 95);
811 const gain = (targetValue > 0.0 ? (1.0 / targetValue) : 1.0); 809 const gain = (targetValue > 0.0 ? (1.0 / targetValue) : 1.0);
812 console.log('setting gain to ' + gain); 810 console.log('setting gain to ' + gain);
813 const matrixEntity = 811 const matrixEntity = new wavesUI.utils.PrefilledMatrixEntity(
814 new wavesUI.utils.PrefilledMatrixEntity(matrixData, 812 matrixData,
815 0, // startTime 813 0, // startTime
816 stepDuration); 814 stepDuration
815 );
817 const matrixLayer = new wavesUI.helpers.MatrixLayer(matrixEntity, { 816 const matrixLayer = new wavesUI.helpers.MatrixLayer(matrixEntity, {
818 gain, 817 gain,
819 top: 0, 818 top: 0,
820 height: height, 819 height: height,
821 normalise: 'none', 820 normalise: 'none',
865 // this kinda logic should also be tested 864 // this kinda logic should also be tested
866 const mustPageForward = offsetTimestamp > visibleDuration; 865 const mustPageForward = offsetTimestamp > visibleDuration;
867 const mustPageBackward = currentTime < -currentOffset; 866 const mustPageBackward = currentTime < -currentOffset;
868 867
869 if (mustPageForward) { 868 if (mustPageForward) {
870 const hasSkippedMultiplePages = offsetTimestamp - visibleDuration > visibleDuration; 869 const hasSkippedMultiplePages = offsetTimestamp -
871 870 visibleDuration > visibleDuration;
872 this.timeline.timeContext.offset = hasSkippedMultiplePages ? 871
873 -currentTime + 0.5 * visibleDuration : 872 this.timeline.timeContext.offset = hasSkippedMultiplePages ?
874 currentOffset - visibleDuration; 873 -currentTime + 0.5 * visibleDuration :
874 currentOffset - visibleDuration;
875 this.timeline.tracks.update(); 875 this.timeline.tracks.update();
876 } 876 }
877 877
878 if (mustPageBackward) { 878 if (mustPageBackward) {
879 const hasSkippedMultiplePages = currentTime + visibleDuration < -currentOffset; 879 const hasSkippedMultiplePages = currentTime +
880 this.timeline.timeContext.offset = hasSkippedMultiplePages ? 880 visibleDuration < -currentOffset;
881 -currentTime + 0.5 * visibleDuration : 881 this.timeline.timeContext.offset = hasSkippedMultiplePages ?
882 currentOffset + visibleDuration; 882 -currentTime + 0.5 * visibleDuration :
883 currentOffset + visibleDuration;
883 this.timeline.tracks.update(); 884 this.timeline.tracks.update();
884 } 885 }
885 886
886 if (this.isPlaying) { 887 if (this.isPlaying) {
887 requestAnimationFrame(updateSeekingCursor); 888 requestAnimationFrame(updateSeekingCursor);