1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192 |
- import * as audio from '../audio';
- export class WaveForm {
- ctx: CanvasRenderingContext2D;
- overlayCtx: CanvasRenderingContext2D;
- track: audio.FileTrack | null = null;
- data: Float32Array | null = null;
- stride: number = 0;
- currentSection: number = -1;
- constructor(
- readonly canvas: HTMLCanvasElement,
- readonly overlay: HTMLCanvasElement,
- readonly setTime: (time: number) => void
- ) {
- canvas.height = canvas.clientHeight;
- canvas.width = canvas.clientWidth;
- overlay.height = overlay.clientHeight;
- overlay.width = overlay.clientWidth;
- this.ctx = canvas.getContext('2d')!;
- this.overlayCtx = overlay.getContext('2d')!;
- this.ctx.fillStyle = 'forestgreen';
- this.overlayCtx.fillStyle = 'rgba(255, 0, 0, 0.5)';
- this.overlay.addEventListener('click', (event: MouseEvent) => {
- let pos = event.clientX - this.overlay.offsetLeft;
- let percentage = pos / this.overlay.width;
- let time = this.currentSection * 5 + percentage * 5;
- this.setTime(time);
- });
- }
- clear(): void {
- this.track = null;
- }
- setTrack(track: audio.FileTrack): void {
- this.track = track;
- this.stride = Math.floor(
- (this.track.buffer.sampleRate / this.canvas.width) * 5
- );
- this.currentSection = -1;
- }
- timeToX(time: number): number {
- return ((time - this.currentSection * 5) / 5) * this.canvas.width;
- }
- update(times: number[]): void {
- const section = Math.floor(this.track!.getTime() / 5);
- const height = this.canvas.height;
- const midPoint = Math.floor(height / 2);
- this.ctx.fillRect(0, midPoint, this.canvas.width, 1);
- if (this.currentSection != section) {
- this.data = this.track!.buffer.getChannelData(0);
- this.ctx.clearRect(0, 0, this.canvas.width, height);
- let offset = section * this.canvas.width * this.stride;
- for (let i = 0; i < this.canvas.width; ++i) {
- let index = offset + i * this.stride;
- let max = -1;
- let min = 1;
- for (let j = index; j < index + this.stride; ++j) {
- const value = this.data[j];
- max = Math.max(value, max);
- min = Math.min(value, min);
- }
- let positiveHeight = midPoint + Math.round(midPoint * max);
- let negativeHeight = midPoint + Math.round(midPoint * min);
- const barHeight = Math.max(1, positiveHeight - negativeHeight);
- this.ctx.fillRect(i, negativeHeight, 1, barHeight);
- }
- this.currentSection = section;
- }
- let marker = this.timeToX(this.track!.getTime());
- this.overlayCtx.clearRect(0, 0, this.canvas.width, height);
- this.overlayCtx.fillRect(0, 0, marker, height);
- times.forEach((time) => {
- if (time > section * 5 && time <= section * 5 + 5) {
- let x = this.timeToX(time);
- this.overlayCtx.beginPath();
- this.overlayCtx.moveTo(x, 0);
- this.overlayCtx.lineTo(x, height);
- this.overlayCtx.stroke();
- }
- });
- }
- }
|