dev@10: import { dev@31: Component, OnInit, ViewChild, ElementRef, Input, AfterViewInit, NgZone dev@10: } from '@angular/core'; dev@39: import {AudioPlayerService} from "../services/audio-player/audio-player.service"; dev@36: import wavesUI from 'waves-ui'; dev@8: dev@20: type Timeline = any; // TODO what type actually is it.. start a .d.ts for waves-ui? dev@6: dev@6: @Component({ dev@6: selector: 'app-waveform', dev@6: templateUrl: './waveform.component.html', dev@6: styleUrls: ['./waveform.component.css'] dev@6: }) dev@20: export class WaveformComponent implements OnInit, AfterViewInit { dev@20: dev@8: @ViewChild('track') trackDiv: ElementRef; dev@6: dev@16: private _audioBuffer: AudioBuffer = undefined; dev@16: dev@16: @Input() dev@16: set audioBuffer(buffer: AudioBuffer) { dev@16: this._audioBuffer = buffer || undefined; dev@20: if (this.audioBuffer) dev@20: this.renderWaveform(this.audioBuffer); dev@16: } dev@16: dev@16: get audioBuffer(): AudioBuffer { dev@16: return this._audioBuffer; dev@16: } dev@16: dev@31: constructor(private audioService: AudioPlayerService, dev@31: public ngZone: NgZone) {} dev@10: ngOnInit() {} dev@10: dev@10: ngAfterViewInit(): void { dev@20: this.renderTimeline(); dev@20: } dev@20: dev@20: renderTimeline(duration: number = 1.0): Timeline { dev@18: const track: HTMLElement = this.trackDiv.nativeElement; dev@20: track.innerHTML = ""; dev@18: const height: number = track.getBoundingClientRect().height; dev@18: const width: number = track.getBoundingClientRect().width; dev@18: const pixelsPerSecond = width / duration; dev@18: const timeline = new wavesUI.core.Timeline(pixelsPerSecond, width); dev@33: timeline.timeContext.offset = 0.5 * timeline.timeContext.visibleDuration; dev@18: timeline.createTrack(track, height, 'main'); dev@18: dev@18: // time axis dev@18: const timeAxis = new wavesUI.helpers.TimeAxisLayer({ dev@18: height: height, dev@18: color: 'gray' dev@18: }); dev@18: dev@18: timeline.addLayer(timeAxis, 'main', 'default', true); dev@20: return timeline; dev@16: } dev@16: dev@20: renderWaveform(buffer: AudioBuffer): void { dev@20: const height: number = this.trackDiv.nativeElement.getBoundingClientRect().height; dev@20: const timeline: Timeline = this.renderTimeline(buffer.duration); dev@20: const waveformLayer = new wavesUI.helpers.WaveformLayer(buffer, { dev@10: top: 10, dev@20: height: height * 0.9, dev@16: color: 'darkblue' dev@16: }); dev@20: (timeline as any).addLayer(waveformLayer, 'main'); dev@31: dev@31: const cursorLayer = new wavesUI.helpers.CursorLayer({ dev@31: height: height dev@31: }); dev@31: timeline.addLayer(cursorLayer, 'main'); dev@31: timeline.state = new wavesUI.states.CenteredZoomState(timeline); dev@31: this.ngZone.runOutsideAngular(() => { dev@31: // listen for time passing... dev@31: // TODO this gets the fans going on large files... worth fixing? or waiting to write a better component? dev@31: // or, can this be updated in a more efficient manner? dev@31: const updateSeekingCursor = () => { dev@31: cursorLayer.currentPosition = this.audioService.getCurrentTime(); dev@31: cursorLayer.update(); dev@34: if (timeline.timeContext.offset + this.audioService.getCurrentTime() >= timeline.timeContext.visibleDuration) { dev@33: timeline.timeContext.offset -= timeline.timeContext.visibleDuration; dev@34: timeline.tracks.update(); dev@34: } dev@34: if (-this.audioService.getCurrentTime() > timeline.timeContext.offset) { dev@33: timeline.timeContext.offset += timeline.timeContext.visibleDuration; dev@34: timeline.tracks.update(); dev@34: } dev@31: requestAnimationFrame(updateSeekingCursor); dev@31: }; dev@31: updateSeekingCursor(); dev@31: }); dev@6: } dev@16: dev@6: }