Mercurial > hg > ugly-duckling
comparison src/app/waveform/waveform.component.ts @ 341:684619d3fad5
Allow interacting with highlight layer regardless of whether playback / seeking is supported. Also remove cursor layer when component seeking disabled.
author | Lucas Thompson <dev@lucas.im> |
---|---|
date | Fri, 19 May 2017 16:18:34 +0100 |
parents | 097d93b11445 |
children | b5f2ee789fb3 |
comparison
equal
deleted
inserted
replaced
338:2b374217d8a0 | 341:684619d3fad5 |
---|---|
155 if (isPlaying) { | 155 if (isPlaying) { |
156 this.animate(); | 156 this.animate(); |
157 } | 157 } |
158 }); | 158 }); |
159 } else { | 159 } else { |
160 if (this.cursorLayer && this.waveTrack) { | |
161 this.waveTrack.remove(this.cursorLayer); | |
162 } | |
160 if (this.playingStateSubscription) { | 163 if (this.playingStateSubscription) { |
161 this.playingStateSubscription.unsubscribe(); | 164 this.playingStateSubscription.unsubscribe(); |
162 } | 165 } |
163 if (this.seekedSubscription) { | 166 if (this.seekedSubscription) { |
164 this.seekedSubscription.unsubscribe(); | 167 this.seekedSubscription.unsubscribe(); |
195 private onAudioDataSubscription: Subscription; | 198 private onAudioDataSubscription: Subscription; |
196 private zoomOnMouseDown: number; | 199 private zoomOnMouseDown: number; |
197 private offsetOnMouseDown: number; | 200 private offsetOnMouseDown: number; |
198 private hasShot: boolean; | 201 private hasShot: boolean; |
199 private isLoading: boolean; | 202 private isLoading: boolean; |
203 private waveTrack: Track; | |
200 | 204 |
201 private static changeColour(layer: Layer, colour: string): void { | 205 private static changeColour(layer: Layer, colour: string): void { |
202 const butcherShapes = (shape) => { | 206 const butcherShapes = (shape) => { |
203 shape.install({color: () => colour}); | 207 shape.install({color: () => colour}); |
204 shape.params.color = colour; | 208 shape.params.color = colour; |
253 this.timeline.visibleWidth = width; | 257 this.timeline.visibleWidth = width; |
254 } | 258 } |
255 } else { | 259 } else { |
256 this.timeline = new wavesUI.core.Timeline(pixelsPerSecond, width); | 260 this.timeline = new wavesUI.core.Timeline(pixelsPerSecond, width); |
257 } | 261 } |
258 const waveTrack = this.timeline.createTrack( | 262 this.waveTrack = this.timeline.createTrack( |
259 track, | 263 track, |
260 height, | 264 height, |
261 `wave-${this.trackIdPrefix}` | 265 `wave-${this.trackIdPrefix}` |
262 ); | 266 ); |
263 if (isInitialRender && hasExistingTimeline) { | 267 if (isInitialRender && hasExistingTimeline) { |
264 // time axis | 268 // time axis |
265 const timeAxis = new wavesUI.helpers.TimeAxisLayer({ | 269 const timeAxis = new wavesUI.helpers.TimeAxisLayer({ |
266 height: height, | 270 height: height, |
267 color: '#b0b0b0' | 271 color: '#b0b0b0' |
268 }); | 272 }); |
269 this.addLayer(timeAxis, waveTrack, this.timeline.timeContext, true); | 273 this.addLayer(timeAxis, this.waveTrack, this.timeline.timeContext, true); |
270 this.cursorLayer = new wavesUI.helpers.CursorLayer({ | 274 this.cursorLayer = new wavesUI.helpers.CursorLayer({ |
271 height: height, | 275 height: height, |
272 color: '#c33c54' | 276 color: '#c33c54' |
273 }); | 277 }); |
274 this.addLayer(this.cursorLayer, waveTrack, this.timeline.timeContext); | 278 this.addLayer( |
279 this.cursorLayer, | |
280 this.waveTrack, | |
281 this.timeline.timeContext | |
282 ); | |
275 } | 283 } |
276 if ('ontouchstart' in window) { | 284 if ('ontouchstart' in window) { |
277 interface Point { | 285 interface Point { |
278 x: number; | 286 x: number; |
279 y: number; | 287 y: number; |
540 } | 548 } |
541 } | 549 } |
542 } | 550 } |
543 | 551 |
544 renderWaveform(buffer: AudioBuffer): void { | 552 renderWaveform(buffer: AudioBuffer): void { |
545 // const height: number = this.trackDiv.nativeElement.getBoundingClientRect().height / 2; | 553 const height = this.trackDiv.nativeElement.getBoundingClientRect().height; |
546 const height: number = this.trackDiv.nativeElement.getBoundingClientRect().height; | |
547 const waveTrack = this.timeline.getTrackById(`wave-${this.trackIdPrefix}`); | |
548 if (this.timeline) { | 554 if (this.timeline) { |
549 // resize | 555 // resize |
550 const width = this.trackDiv.nativeElement.getBoundingClientRect().width; | 556 const width = this.trackDiv.nativeElement.getBoundingClientRect().width; |
551 | 557 |
552 this.clearTimeline(); | 558 this.clearTimeline(); |
553 | 559 |
554 this.timeline.visibleWidth = width; | 560 this.timeline.visibleWidth = width; |
555 this.timeline.pixelsPerSecond = width / buffer.duration; | 561 this.timeline.pixelsPerSecond = width / buffer.duration; |
556 waveTrack.height = height; | 562 this.waveTrack.height = height; |
557 } else { | 563 } else { |
558 this.renderTimeline(buffer.duration); | 564 this.renderTimeline(buffer.duration); |
559 } | 565 } |
560 this.timeline.timeContext.offset = 0.5 * this.timeline.timeContext.visibleDuration; | 566 this.timeline.timeContext.offset = 0.5 * this.timeline.timeContext.visibleDuration; |
561 | 567 |
562 // time axis | 568 // time axis |
563 const timeAxis = new wavesUI.helpers.TimeAxisLayer({ | 569 const timeAxis = new wavesUI.helpers.TimeAxisLayer({ |
564 height: height, | 570 height: height, |
565 color: '#b0b0b0' | 571 color: '#b0b0b0' |
566 }); | 572 }); |
567 this.addLayer(timeAxis, waveTrack, this.timeline.timeContext, true); | 573 this.addLayer(timeAxis, this.waveTrack, this.timeline.timeContext, true); |
568 | 574 |
569 const nchannels = buffer.numberOfChannels; | 575 const nchannels = buffer.numberOfChannels; |
570 const totalWaveHeight = height * 0.9; | 576 const totalWaveHeight = height * 0.9; |
571 const waveHeight = totalWaveHeight / nchannels; | 577 const waveHeight = totalWaveHeight / nchannels; |
572 | 578 |
576 top: (height - totalWaveHeight) / 2 + waveHeight * ch, | 582 top: (height - totalWaveHeight) / 2 + waveHeight * ch, |
577 height: waveHeight, | 583 height: waveHeight, |
578 color: '#0868ac', | 584 color: '#0868ac', |
579 channel: ch | 585 channel: ch |
580 }); | 586 }); |
581 this.addLayer(waveformLayer, waveTrack, this.timeline.timeContext); | 587 this.addLayer(waveformLayer, this.waveTrack, this.timeline.timeContext); |
582 } | 588 } |
583 | 589 |
584 this.cursorLayer = new wavesUI.helpers.CursorLayer({ | 590 this.cursorLayer = new wavesUI.helpers.CursorLayer({ |
585 height: height, | 591 height: height, |
586 color: '#c33c54' | 592 color: '#c33c54' |
587 }); | 593 }); |
588 this.addLayer(this.cursorLayer, waveTrack, this.timeline.timeContext); | 594 this.addLayer(this.cursorLayer, this.waveTrack, this.timeline.timeContext); |
589 this.timeline.state = new wavesUI.states.CenteredZoomState(this.timeline); | 595 this.timeline.state = new wavesUI.states.CenteredZoomState(this.timeline); |
590 waveTrack.render(); | 596 this.waveTrack.render(); |
591 waveTrack.update(); | 597 this.waveTrack.update(); |
592 | 598 |
593 this.isLoading = false; | 599 this.isLoading = false; |
594 this.ref.markForCheck(); | 600 this.ref.markForCheck(); |
595 this.animate(); | 601 this.animate(); |
596 } | 602 } |
639 min = 0; | 645 min = 0; |
640 max = 1; | 646 max = 1; |
641 } | 647 } |
642 | 648 |
643 const height = this.trackDiv.nativeElement.getBoundingClientRect().height; | 649 const height = this.trackDiv.nativeElement.getBoundingClientRect().height; |
644 const waveTrack = this.timeline.getTrackById(`wave-${this.trackIdPrefix}`); | |
645 | 650 |
646 // Now add a line layer for each vector feature | 651 // Now add a line layer for each vector feature |
647 const lineLayers = features.map(feature => { | 652 const lineLayers = features.map(feature => { |
648 | 653 |
649 let duration = 0; | 654 let duration = 0; |
667 height: height, | 672 height: height, |
668 yDomain: [ min, max ] | 673 yDomain: [ min, max ] |
669 }); | 674 }); |
670 this.addLayer( | 675 this.addLayer( |
671 lineLayer, | 676 lineLayer, |
672 waveTrack, | 677 this.waveTrack, |
673 this.timeline.timeContext | 678 this.timeline.timeContext |
674 ); | 679 ); |
675 | 680 |
676 // Set start and duration so that the highlight layer can use | 681 // Set start and duration so that the highlight layer can use |
677 // them to determine which line to draw values from | 682 // them to determine which line to draw values from |
689 height: height, | 694 height: height, |
690 yDomain: [ min, max ] | 695 yDomain: [ min, max ] |
691 }); | 696 }); |
692 this.addLayer( | 697 this.addLayer( |
693 scaleLayer, | 698 scaleLayer, |
694 waveTrack, | 699 this.waveTrack, |
695 this.timeline.timeContext | 700 this.timeline.timeContext |
696 ); | 701 ); |
697 | 702 |
698 // And a single highlight layer which uses all of the line layers | 703 // And a single highlight layer which uses all of the line layers |
699 // as its source material | 704 // as its source material |
705 yDomain: [ min, max ], | 710 yDomain: [ min, max ], |
706 unit | 711 unit |
707 }); | 712 }); |
708 this.addLayer( | 713 this.addLayer( |
709 this.highlightLayer, | 714 this.highlightLayer, |
710 waveTrack, | 715 this.waveTrack, |
711 this.timeline.timeContext | 716 this.timeline.timeContext |
712 ); | 717 ); |
713 } | 718 } |
714 | 719 |
715 // TODO refactor - this doesn't belong here | 720 // TODO refactor - this doesn't belong here |
728 return; | 733 return; |
729 } | 734 } |
730 const features: FeatureCollection = (extracted.features as FeatureCollection); | 735 const features: FeatureCollection = (extracted.features as FeatureCollection); |
731 const outputDescriptor = extracted.outputDescriptor; | 736 const outputDescriptor = extracted.outputDescriptor; |
732 const height = this.trackDiv.nativeElement.getBoundingClientRect().height; | 737 const height = this.trackDiv.nativeElement.getBoundingClientRect().height; |
733 const waveTrack = this.timeline.getTrackById(`wave-${this.trackIdPrefix}`); | |
734 | 738 |
735 let unit = ''; | 739 let unit = ''; |
736 if (outputDescriptor.configured.hasOwnProperty('unit')) { | 740 if (outputDescriptor.configured.hasOwnProperty('unit')) { |
737 unit = outputDescriptor.configured.unit; | 741 unit = outputDescriptor.configured.unit; |
738 } | 742 } |
776 labelPosition: 'bottom', | 780 labelPosition: 'bottom', |
777 shadeSegments: true | 781 shadeSegments: true |
778 }); | 782 }); |
779 this.addLayer( | 783 this.addLayer( |
780 featureLayer, | 784 featureLayer, |
781 waveTrack, | 785 this.waveTrack, |
782 this.timeline.timeContext | 786 this.timeline.timeContext |
783 ); | 787 ); |
784 break; | 788 break; |
785 case 'regions': | 789 case 'regions': |
786 this.renderRegions( | 790 this.renderRegions( |
787 featureData, | 791 featureData, |
788 outputDescriptor, | 792 outputDescriptor, |
789 waveTrack, | 793 this.waveTrack, |
790 height, | 794 height, |
791 colour | 795 colour |
792 ); | 796 ); |
793 break; | 797 break; |
794 case 'notes': | 798 case 'notes': |
808 notes, | 812 notes, |
809 {height: height, color: colour, yDomain: [min, max] } | 813 {height: height, color: colour, yDomain: [min, max] } |
810 ); | 814 ); |
811 this.addLayer( | 815 this.addLayer( |
812 pianoRollLayer, | 816 pianoRollLayer, |
813 waveTrack, | 817 this.waveTrack, |
814 this.timeline.timeContext | 818 this.timeline.timeContext |
815 ); | 819 ); |
816 break; | 820 break; |
817 } | 821 } |
818 } catch (e) { | 822 } catch (e) { |
847 normalise: 'none', | 851 normalise: 'none', |
848 mapper: this.iceMapper() | 852 mapper: this.iceMapper() |
849 }); | 853 }); |
850 this.addLayer( | 854 this.addLayer( |
851 matrixLayer, | 855 matrixLayer, |
852 waveTrack, | 856 this.waveTrack, |
853 this.timeline.timeContext | 857 this.timeline.timeContext |
854 ); | 858 ); |
855 break; | 859 break; |
856 } | 860 } |
857 default: | 861 default: |
876 const updateSeekingCursor = () => { | 880 const updateSeekingCursor = () => { |
877 const currentTime = this.audioService.getCurrentTime(); | 881 const currentTime = this.audioService.getCurrentTime(); |
878 this.cursorLayer.currentPosition = currentTime; | 882 this.cursorLayer.currentPosition = currentTime; |
879 this.cursorLayer.update(); | 883 this.cursorLayer.update(); |
880 | 884 |
881 if (typeof(this.highlightLayer) !== 'undefined') { | 885 if (this.highlightLayer) { |
882 this.highlightLayer.currentPosition = currentTime; | 886 this.highlightLayer.currentPosition = currentTime; |
883 this.highlightLayer.update(); | 887 this.highlightLayer.update(); |
884 } | 888 } |
885 | 889 |
886 const currentOffset = this.timeline.timeContext.offset; | 890 const currentOffset = this.timeline.timeContext.offset; |
1047 } | 1051 } |
1048 | 1052 |
1049 seek(x: number): void { | 1053 seek(x: number): void { |
1050 if (this.timeline) { | 1054 if (this.timeline) { |
1051 const timeContext: any = this.timeline.timeContext; | 1055 const timeContext: any = this.timeline.timeContext; |
1056 const timeX = timeContext.timeToPixel.invert(x) - timeContext.offset; | |
1052 if (this.isSeeking) { | 1057 if (this.isSeeking) { |
1053 this.audioService.seekTo( | 1058 this.audioService.seekTo(timeX); |
1054 timeContext.timeToPixel.invert(x) - timeContext.offset | 1059 } else { |
1055 ); | 1060 if (this.highlightLayer) { |
1061 this.highlightLayer.currentPosition = timeX; | |
1062 this.highlightLayer.update(); | |
1063 } | |
1056 } | 1064 } |
1057 } | 1065 } |
1058 } | 1066 } |
1059 } | 1067 } |
1060 | 1068 |