annotate src/app/waveform/waveform.component.ts @ 31:f6ea31a3b1a3

Encapsulate audio playing and decoding logic in a ng2 service, provided by the root module.
author Lucas Thompson <dev@lucas.im>
date Wed, 30 Nov 2016 10:21:27 +0000
parents aabfa7a693dc
children 7e155ee93db3
rev   line source
dev@10 1 import {
dev@31 2 Component, OnInit, ViewChild, ElementRef, Input, AfterViewInit, NgZone
dev@10 3 } from '@angular/core';
dev@31 4 import {AudioPlayerService} from "../services/audio-player.service";
dev@8 5
dev@16 6 declare var wavesUI: any; // TODO non-global app scope import
dev@20 7 type Timeline = any; // TODO what type actually is it.. start a .d.ts for waves-ui?
dev@6 8
dev@6 9 @Component({
dev@6 10 selector: 'app-waveform',
dev@6 11 templateUrl: './waveform.component.html',
dev@6 12 styleUrls: ['./waveform.component.css']
dev@6 13 })
dev@20 14 export class WaveformComponent implements OnInit, AfterViewInit {
dev@20 15
dev@8 16 @ViewChild('track') trackDiv: ElementRef;
dev@6 17
dev@16 18 private _audioBuffer: AudioBuffer = undefined;
dev@16 19
dev@16 20 @Input()
dev@16 21 set audioBuffer(buffer: AudioBuffer) {
dev@16 22 this._audioBuffer = buffer || undefined;
dev@20 23 if (this.audioBuffer)
dev@20 24 this.renderWaveform(this.audioBuffer);
dev@16 25 }
dev@16 26
dev@16 27 get audioBuffer(): AudioBuffer {
dev@16 28 return this._audioBuffer;
dev@16 29 }
dev@16 30
dev@31 31 constructor(private audioService: AudioPlayerService,
dev@31 32 public ngZone: NgZone) {}
dev@10 33 ngOnInit() {}
dev@10 34
dev@10 35 ngAfterViewInit(): void {
dev@20 36 this.renderTimeline();
dev@20 37 }
dev@20 38
dev@20 39 renderTimeline(duration: number = 1.0): Timeline {
dev@18 40 const track: HTMLElement = this.trackDiv.nativeElement;
dev@20 41 track.innerHTML = "";
dev@18 42 const height: number = track.getBoundingClientRect().height;
dev@18 43 const width: number = track.getBoundingClientRect().width;
dev@18 44 const pixelsPerSecond = width / duration;
dev@18 45 const timeline = new wavesUI.core.Timeline(pixelsPerSecond, width);
dev@18 46 timeline.createTrack(track, height, 'main');
dev@18 47
dev@18 48 // time axis
dev@18 49 const timeAxis = new wavesUI.helpers.TimeAxisLayer({
dev@18 50 height: height,
dev@18 51 color: 'gray'
dev@18 52 });
dev@18 53
dev@18 54 timeline.addLayer(timeAxis, 'main', 'default', true);
dev@20 55 return timeline;
dev@16 56 }
dev@16 57
dev@20 58 renderWaveform(buffer: AudioBuffer): void {
dev@20 59 const height: number = this.trackDiv.nativeElement.getBoundingClientRect().height;
dev@20 60 const timeline: Timeline = this.renderTimeline(buffer.duration);
dev@20 61 const waveformLayer = new wavesUI.helpers.WaveformLayer(buffer, {
dev@10 62 top: 10,
dev@20 63 height: height * 0.9,
dev@16 64 color: 'darkblue'
dev@16 65 });
dev@20 66 (timeline as any).addLayer(waveformLayer, 'main');
dev@31 67
dev@31 68 const cursorLayer = new wavesUI.helpers.CursorLayer({
dev@31 69 height: height
dev@31 70 });
dev@31 71 timeline.addLayer(cursorLayer, 'main');
dev@31 72 timeline.state = new wavesUI.states.CenteredZoomState(timeline);
dev@31 73 this.ngZone.runOutsideAngular(() => {
dev@31 74 // listen for time passing...
dev@31 75 // TODO this gets the fans going on large files... worth fixing? or waiting to write a better component?
dev@31 76 // or, can this be updated in a more efficient manner?
dev@31 77 const updateSeekingCursor = () => {
dev@31 78 cursorLayer.currentPosition = this.audioService.getCurrentTime();
dev@31 79 cursorLayer.update();
dev@31 80 requestAnimationFrame(updateSeekingCursor);
dev@31 81 };
dev@31 82 updateSeekingCursor();
dev@31 83 });
dev@6 84 }
dev@16 85
dev@6 86 }