Mercurial > hg > ugly-duckling
changeset 129:161af71c80d4
Module for spectrogram stuff. Consume the WavesSpectrogramLayer in Waveform... of course.
author | Lucas Thompson <dev@lucas.im> |
---|---|
date | Thu, 16 Mar 2017 10:35:53 +0000 |
parents | 576e7e0246cb |
children | 8aa1ff061503 e50248f9cda3 |
files | src/app/spectrogram/Spectrogram.ts src/app/waveform/waveform.component.ts |
diffstat | 2 files changed, 95 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/spectrogram/Spectrogram.ts Thu Mar 16 10:35:53 2017 +0000 @@ -0,0 +1,92 @@ +/** + * Created by lucast on 16/03/2017. + */ +import {RealFft, KissRealFft} from "piper/fft/RealFft"; +import {hann} from "piper/FftUtilities"; +import {Framing} from "piper"; +import Waves from 'waves-ui'; + +class SpectrogramEntity extends Waves.utils.MatrixEntity { + + private samples: Float32Array; + private framing: Framing; + private fft: RealFft; + private real: Float32Array; + private nCols: number; + private window: Float32Array; + + constructor(samples: Float32Array, options: Framing & Object) { + super(); + this.samples = samples; + this.framing = options; + this.real = new Float32Array(this.framing.blockSize); + this.nCols = Math.floor(this.samples.length / this.framing.stepSize); //!!! not correct + this.fft = new KissRealFft(this.framing.blockSize); + this.window = hann(this.framing.blockSize); + } + + getColumnCount(): number { + return this.nCols; + } + + getColumnHeight(): number { + return Math.floor(this.framing.blockSize * 0.5) + 1; + } + + getColumn(n: number): Float32Array { + + const startSample = n * this.framing.stepSize; + const sz = this.framing.blockSize; + + this.real.fill(0); + + let available = sz; + if (startSample + sz >= this.samples.length) { + available = this.samples.length - startSample; + } + + for (let i = 0; i < available; ++i) { + this.real[i] = this.samples[startSample + i] * this.window[i]; + } + + const complex = this.fft.forward(this.real); + + const h = this.getColumnHeight(); + const col = new Float32Array(h); + + for (let i = 0; i < h; ++i) { + const real: number = complex[i * 2]; + const imaginary: number = complex[i * 2 + 1]; + col[i] = real * real + imaginary * imaginary; + } + + return col; + } +} + +export class WavesSpectrogramLayer extends Waves.core.Layer { + constructor(buffer: AudioBuffer, + options: Framing & Object) { + + const defaults = { + normalise: 'hybrid', + gain: 40.0, + channel: 0, + stepSize: 512, + blockSize: 1024 + }; + + const mergedOptions: Framing & Object & {channel: number} = + Object.assign({}, defaults, options); + + super('entity', + new SpectrogramEntity( + buffer.getChannelData(mergedOptions.channel), + mergedOptions + ), + mergedOptions + ); + + this.configureShape(Waves.shapes.Matrix, {}, mergedOptions); + } +}
--- a/src/app/waveform/waveform.component.ts Thu Mar 16 10:34:38 2017 +0000 +++ b/src/app/waveform/waveform.component.ts Thu Mar 16 10:35:53 2017 +0000 @@ -15,6 +15,7 @@ import {toSeconds} from "piper"; import {FeatureList, Feature} from "piper/Feature"; import * as Hammer from 'hammerjs'; +import {WavesSpectrogramLayer} from "../spectrogram/Spectrogram"; type Timeline = any; // TODO what type actually is it.. start a .d.ts for waves-ui? type Layer = any; @@ -379,11 +380,11 @@ const height: number = this.trackDiv.nativeElement.getBoundingClientRect().height / 2; const gridTrack = this.timeline.getTrackById('grid'); - const spectrogramLayer = new wavesUI.helpers.SpectrogramLayer(buffer, { + const spectrogramLayer = new WavesSpectrogramLayer(buffer, { top: height * 0.05, height: height * 0.9, stepSize: 512, - fftSize: 1024, + blockSize: 1024, normalise: 'none', mapper: this.sunsetMapper() });