diff options
Diffstat (limited to 'src/client/views/AudioWaveform.tsx')
-rw-r--r-- | src/client/views/AudioWaveform.tsx | 137 |
1 files changed, 22 insertions, 115 deletions
diff --git a/src/client/views/AudioWaveform.tsx b/src/client/views/AudioWaveform.tsx index 8a3c3c319..525c0ce5a 100644 --- a/src/client/views/AudioWaveform.tsx +++ b/src/client/views/AudioWaveform.tsx @@ -1,16 +1,26 @@ import React = require("react"); import axios from "axios"; -import { action, computed, reaction, IReactionDisposer } from "mobx"; +import { action, computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; import Waveform from "react-audio-waveform"; import { Doc } from "../../fields/Doc"; import { List } from "../../fields/List"; import { listSpec } from "../../fields/Schema"; -import { Cast, NumCast } from "../../fields/Types"; +import { Cast } from "../../fields/Types"; import { numberRange } from "../../Utils"; import "./AudioWaveform.scss"; import { Colors } from "./global/globalEnums"; -import Color = require("color"); + + +/** + * AudioWaveform + * + * Used in CollectionStackedTimeline to render a canvas with a visual of an audio waveform for AudioBox and VideoBox documents. + * Uses react-audio-waveform package. + * Bins the audio data into audioBuckets which are passed to package to render the lines. + * Calculates new buckets each time a new zoom factor or new set of trim bounds is created and stores it in a field on the layout doc with a title indicating the bounds and zoom for that list (see audioBucketField) + */ + export interface AudioWaveformProps { duration: number; // length of media clip @@ -26,19 +36,24 @@ export interface AudioWaveformProps { @observer export class AudioWaveform extends React.Component<AudioWaveformProps> { - public static NUMBER_OF_BUCKETS = 100; + public static NUMBER_OF_BUCKETS = 100; // number of buckets data is divided into to draw waveform lines + _disposer: IReactionDisposer | undefined; + @computed get waveHeight() { return Math.max(50, this.props.PanelHeight); } + @computed get clipStart() { return this.props.clipStart; } @computed get clipEnd() { return this.props.clipEnd; } @computed get zoomFactor() { return this.props.zoomFactor; } - @computed get audioBuckets() { return Cast(this.props.layoutDoc[this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor)], listSpec("number"), []); } + @computed get audioBuckets() { return Cast(this.props.layoutDoc[this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor)], listSpec("number"), []); } audioBucketField = (start: number, end: number, zoomFactor: number) => "audioBuckets/" + "/" + start.toFixed(2).replace(".", "_") + "/" + end.toFixed(2).replace(".", "_") + "/" + (zoomFactor * 10); + componentWillUnmount() { this._disposer?.(); } + componentDidMount() { this._disposer = reaction(() => ({ clipStart: this.clipStart, clipEnd: this.clipEnd, fieldKey: this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor), zoomFactor: this.props.zoomFactor }), ({ clipStart, clipEnd, fieldKey, zoomFactor }) => { @@ -49,7 +64,6 @@ export class AudioWaveform extends React.Component<AudioWaveformProps> { setTimeout(() => this.createWaveformBuckets(fieldKey, clipStart, clipEnd, zoomFactor)); } }, { fireImmediately: true }); - } // decodes the audio file into peaks for generating the waveform @@ -86,16 +100,10 @@ export class AudioWaveform extends React.Component<AudioWaveformProps> { } ); } + render() { return ( <div className="audioWaveform"> - {/* <Waveform - barWidth={2} - width={() => this.props.PanelWidth} - height={this.props.PanelHeight} - peaks={this.audioBuckets} - color={Colors.MEDIUM_BLUE} - /> */} <Waveform color={Colors.MEDIUM_BLUE_ALT} height={this.waveHeight} @@ -108,105 +116,4 @@ export class AudioWaveform extends React.Component<AudioWaveformProps> { </div> ); } -} - - -export interface WaveformProps { - barWidth: number; - width: () => number; - height: () => number; - peaks: number[]; - color: string; -} - -// @observer -// export class Waveform extends React.Component<WaveformProps> { -// private _canvas: HTMLCanvasElement | null = null; - -// get width() { return this.props.width(); } -// get height() { return this.props.height(); } -// get peaks() { return this.props.peaks; } - -// componentDidMount() { -// this.drawBars(); -// } - -// drawBars() { -// const waveCanvasCtx = this._canvas?.getContext("2d"); - -// if (waveCanvasCtx) { -// const pixelRatio = window.devicePixelRatio; -// console.log(pixelRatio); - -// const displayWidth = Math.round(this.width); -// const displayHeight = Math.round(this.height); -// waveCanvasCtx.canvas.width = this.width; -// waveCanvasCtx.canvas.height = this.height; -// waveCanvasCtx.canvas.style.width = `${displayWidth}px`; -// waveCanvasCtx.canvas.style.height = `${displayHeight}px`; - -// waveCanvasCtx.clearRect(0, 0, this.width, this.height); - -// const hasMinVals = [].some.call(this.peaks, (val) => val < 0); -// let filteredPeaks = this.peaks; -// if (hasMinVals) { -// // If the first value is negative, add 1 to the filtered indices -// let indexOffset = 0; -// if (this.peaks[0] < 0) { -// indexOffset = 1; -// } -// filteredPeaks = [].filter.call( -// this.peaks, -// (_, index) => (index + indexOffset) % 2 == 0 -// ); -// } - -// const $ = 0.5; -// const height = this.height; -// const offsetY = 0; -// const halfH = this.height / 2; -// const length = filteredPeaks.length; -// const bar = this.props.barWidth; -// const gap = 2; -// const step = bar + gap; - -// let absmax = 1; -// absmax = this.absMax(filteredPeaks); - -// const scale = length / this.width; - -// waveCanvasCtx.fillStyle = this.props.color; - -// for (let i = 0; i < this.width; i += step) { -// let h = Math.round(filteredPeaks[Math.floor(i * scale)] / absmax * halfH) -// if (h === 0) { -// h = 1 -// } -// waveCanvasCtx.fillRect(i + $, halfH - h + offsetY, bar + $, h * 2) -// } -// } -// } - -// absMax = (values: number[]) => { -// let max = -Infinity; -// for (const i in values) { -// const num = Math.abs(values[i]); -// if (num > max) { -// max = num; -// } -// } - -// return max; -// } - - -// render() { -// return this.props.peaks ? ( -// <canvas -// ref={(instance) => { -// this._canvas = instance; -// }} -// /> -// ) : null -// } -// }
\ No newline at end of file +}
\ No newline at end of file |