Mercurial > hg > ugly-duckling
comparison src/app/waveform/waveform.component.ts @ 54:5fb857f8553b
Add a number of ad-hoc workarounds for bugs / quirks with waves-ui - regarding removing layers and avoiding ghost listeners. Still work to be done here.
author | Lucas Thompson <dev@lucas.im> |
---|---|
date | Thu, 08 Dec 2016 15:09:03 +0000 |
parents | ccfbce214751 |
children | 214e41418460 |
comparison
equal
deleted
inserted
replaced
53:ccfbce214751 | 54:5fb857f8553b |
---|---|
8 import {FeatureExtractionService} from "../services/feature-extraction/feature-extraction.service"; | 8 import {FeatureExtractionService} from "../services/feature-extraction/feature-extraction.service"; |
9 import {Subscription} from "rxjs"; | 9 import {Subscription} from "rxjs"; |
10 import {toSeconds} from "piper"; | 10 import {toSeconds} from "piper"; |
11 | 11 |
12 type Timeline = any; // TODO what type actually is it.. start a .d.ts for waves-ui? | 12 type Timeline = any; // TODO what type actually is it.. start a .d.ts for waves-ui? |
13 type Layer = any; | |
14 type Track = any; | |
13 | 15 |
14 @Component({ | 16 @Component({ |
15 selector: 'app-waveform', | 17 selector: 'app-waveform', |
16 templateUrl: './waveform.component.html', | 18 templateUrl: './waveform.component.html', |
17 styleUrls: ['./waveform.component.css'] | 19 styleUrls: ['./waveform.component.css'] |
18 }) | 20 }) |
19 export class WaveformComponent implements OnInit, AfterViewInit, OnDestroy { | 21 export class WaveformComponent implements OnInit, AfterViewInit, OnDestroy { |
20 | 22 |
21 @ViewChild('track') trackDiv: ElementRef; | 23 @ViewChild('track') trackDiv: ElementRef; |
22 | 24 |
23 private _audioBuffer: AudioBuffer = undefined; | 25 private _audioBuffer: AudioBuffer; |
24 private timeline: Timeline = undefined; | 26 private timeline: Timeline; |
25 private cursorLayer: any = undefined; | 27 private cursorLayer: any; |
28 private disposableLayers: Layer[]; | |
26 | 29 |
27 @Input() | 30 @Input() |
28 set audioBuffer(buffer: AudioBuffer) { | 31 set audioBuffer(buffer: AudioBuffer) { |
29 this._audioBuffer = buffer || undefined; | 32 this._audioBuffer = buffer || undefined; |
30 if (this.audioBuffer) | 33 if (this.audioBuffer) |
41 private isPlaying: boolean; | 44 private isPlaying: boolean; |
42 | 45 |
43 constructor(private audioService: AudioPlayerService, | 46 constructor(private audioService: AudioPlayerService, |
44 private piperService: FeatureExtractionService, | 47 private piperService: FeatureExtractionService, |
45 public ngZone: NgZone) { | 48 public ngZone: NgZone) { |
49 this.disposableLayers = []; | |
50 this._audioBuffer = undefined; | |
51 this.timeline = undefined; | |
52 this.cursorLayer = undefined; | |
46 this.isPlaying = false; | 53 this.isPlaying = false; |
47 this.featureExtractionSubscription = piperService.featuresExtracted$.subscribe( | 54 this.featureExtractionSubscription = piperService.featuresExtracted$.subscribe( |
48 features => { | 55 features => { |
49 this.renderFeatures(features); | 56 this.renderFeatures(features); |
50 }); | 57 }); |
74 const width: number = track.getBoundingClientRect().width; | 81 const width: number = track.getBoundingClientRect().width; |
75 const pixelsPerSecond = width / duration; | 82 const pixelsPerSecond = width / duration; |
76 const timeline = new wavesUI.core.Timeline(pixelsPerSecond, width); | 83 const timeline = new wavesUI.core.Timeline(pixelsPerSecond, width); |
77 timeline.timeContext.offset = 0.5 * timeline.timeContext.visibleDuration; | 84 timeline.timeContext.offset = 0.5 * timeline.timeContext.visibleDuration; |
78 timeline.createTrack(track, height, 'main'); | 85 timeline.createTrack(track, height, 'main'); |
79 | 86 return timeline; |
87 } | |
88 | |
89 renderWaveform(buffer: AudioBuffer): void { | |
90 const height: number = this.trackDiv.nativeElement.getBoundingClientRect().height; | |
91 const mainTrack = this.timeline.getTrackById('main'); | |
92 if (this.timeline) { | |
93 // resize | |
94 const width = this.trackDiv.nativeElement.getBoundingClientRect().width; | |
95 // loop through layers and remove them, waves-ui provides methods for this but it seems to not work properly | |
96 for (let i = 0; i < this.disposableLayers.length; ++i) { | |
97 let layer = this.disposableLayers.pop(); | |
98 mainTrack.remove(layer); | |
99 layer.destroy(); | |
100 } | |
101 this.timeline.visibleWidth = width; | |
102 this.timeline.pixelsPerSecond = width / buffer.duration; | |
103 mainTrack.height = height; | |
104 } else { | |
105 this.timeline = this.renderTimeline(buffer.duration) | |
106 } | |
80 // time axis | 107 // time axis |
81 const timeAxis = new wavesUI.helpers.TimeAxisLayer({ | 108 const timeAxis = new wavesUI.helpers.TimeAxisLayer({ |
82 height: height, | 109 height: height, |
83 color: 'gray' | 110 color: 'gray' |
84 }); | 111 }); |
85 | 112 this.addLayer(timeAxis, mainTrack, this.timeline.timeContext, true); |
86 timeline.addLayer(timeAxis, 'main', 'default', true); | 113 |
87 return timeline; | |
88 } | |
89 | |
90 renderWaveform(buffer: AudioBuffer): void { | |
91 const height: number = this.trackDiv.nativeElement.getBoundingClientRect().height; | |
92 this.timeline = this.renderTimeline(buffer.duration); | |
93 const waveformLayer = new wavesUI.helpers.WaveformLayer(buffer, { | 114 const waveformLayer = new wavesUI.helpers.WaveformLayer(buffer, { |
94 top: 10, | 115 top: 10, |
95 height: height * 0.9, | 116 height: height * 0.9, |
96 color: 'darkblue' | 117 color: 'darkblue' |
97 }); | 118 }); |
98 (this.timeline as any).addLayer(waveformLayer, 'main'); | 119 this.addLayer(waveformLayer, mainTrack, this.timeline.timeContext); |
99 | 120 |
100 this.cursorLayer = new wavesUI.helpers.CursorLayer({ | 121 this.cursorLayer = new wavesUI.helpers.CursorLayer({ |
101 height: height | 122 height: height |
102 }); | 123 }); |
103 this.timeline.addLayer(this.cursorLayer, 'main'); | 124 this.addLayer(this.cursorLayer, mainTrack, this.timeline.timeContext); |
104 this.timeline.state = new wavesUI.states.CenteredZoomState(this.timeline); | 125 this.timeline.state = new wavesUI.states.CenteredZoomState(this.timeline); |
126 mainTrack.render(); | |
127 mainTrack.update(); | |
105 this.animate(); | 128 this.animate(); |
106 } | 129 } |
107 | 130 |
108 // TODO refactor - this doesn't belong here | 131 // TODO refactor - this doesn't belong here |
109 private renderFeatures(features: FeatureList): void { | 132 private renderFeatures(features: FeatureList): void { |
111 return { | 134 return { |
112 cx: toSeconds(feature.timestamp), | 135 cx: toSeconds(feature.timestamp), |
113 cy: feature.featureValues[0] | 136 cy: feature.featureValues[0] |
114 }; | 137 }; |
115 }); | 138 }); |
116 this.timeline.addLayer( | 139 this.addLayer( |
117 new wavesUI.helpers.BreakpointLayer(plotData, {color: 'green'}), | 140 new wavesUI.helpers.BreakpointLayer(plotData, {color: 'green'}), |
118 'main' | 141 this.timeline.getTrackById('main'), |
142 this.timeline.timeContext | |
119 ); | 143 ); |
120 } | 144 } |
121 | 145 |
122 private animate(): void { | 146 private animate(): void { |
123 this.ngZone.runOutsideAngular(() => { | 147 this.ngZone.runOutsideAngular(() => { |
159 }; | 183 }; |
160 updateSeekingCursor(); | 184 updateSeekingCursor(); |
161 }); | 185 }); |
162 } | 186 } |
163 | 187 |
188 private addLayer(layer: Layer, track: Track, timeContext: any, isAxis: boolean = false): void { | |
189 timeContext.zoom = 1.0; | |
190 if (!layer.timeContext) { | |
191 layer.setTimeContext(isAxis ? | |
192 timeContext : new wavesUI.core.LayerTimeContext(timeContext)); | |
193 } | |
194 this.disposableLayers.push(layer); | |
195 track.add(layer); | |
196 layer.render(); | |
197 layer.update(); | |
198 } | |
199 | |
164 ngOnDestroy(): void { | 200 ngOnDestroy(): void { |
165 this.featureExtractionSubscription.unsubscribe(); | 201 this.featureExtractionSubscription.unsubscribe(); |
166 this.playingStateSubscription.unsubscribe(); | 202 this.playingStateSubscription.unsubscribe(); |
167 this.seekedSubscription.unsubscribe(); | 203 this.seekedSubscription.unsubscribe(); |
168 } | 204 } |