From 008c5ff7056eb6f4228fd6521374d17a4db06d03 Mon Sep 17 00:00:00 2001 From: Tarek Date: Fri, 8 Mar 2024 15:03:25 +0100 Subject: [PATCH] outsource melscale to different file --- src/lenses/SpectrogramLens/MelScale.tsx | 68 +++++++++++++++++++++++ src/lenses/SpectrogramLens/index.tsx | 72 ++----------------------- 2 files changed, 73 insertions(+), 67 deletions(-) create mode 100644 src/lenses/SpectrogramLens/MelScale.tsx diff --git a/src/lenses/SpectrogramLens/MelScale.tsx b/src/lenses/SpectrogramLens/MelScale.tsx new file mode 100644 index 00000000..471364da --- /dev/null +++ b/src/lenses/SpectrogramLens/MelScale.tsx @@ -0,0 +1,68 @@ +import * as d3 from 'd3'; + +interface MelScale { + (value: number): number; + toMelScale(value: number): number; + fromMelScale(frequency: number): number; + domain(): number[]; + domain(domain: number[]): MelScale; + range(): number[]; + range(range: number[]): MelScale; + copy(): MelScale; + invert(value: number): number; + ticks(count?: number): number[]; + tickFormat(count?: number, specifier?: string): (d: number) => string; +} + +const melScale = (): MelScale => { + // Create the base log scale + const linearScale = d3.scaleLinear(); + const logScale = d3.scaleLog(); + + // Our custom scale function + const scale: MelScale = ((value: number) => { + return linearScale(value); + }) as MelScale; + + scale.toMelScale = (frequency: number): number => { + return 2595 * Math.log10(1 + frequency / 700); + }; + + scale.fromMelScale = (mel: number): number => { + return 700 * (Math.pow(10, mel / 2595) - 1); + }; + + // Copy methods from the log scale + // eslint-disable-next-line @typescript-eslint/no-explicit-any + scale.domain = (domain?: number[]): any => { + if (domain === undefined) { + return linearScale.domain().map((d) => scale.toMelScale(d)); + } + logScale.domain(domain); + return domain ? (linearScale.domain(domain), scale) : linearScale.domain(); + }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + scale.range = (range?: number[]): any => { + if (range) logScale.range(range); + return range ? (linearScale.range(range), scale) : linearScale.range(); + }; + scale.copy = () => { + return melScale().domain(scale.domain()).range(scale.range()); + }; + scale.invert = (value: number): number => { + return scale.fromMelScale(linearScale.invert(value)); + }; + + scale.ticks = (count?: number): number[] => { + const ticks = logScale.ticks(count).map((val) => { + return scale.toMelScale(val); + }); + if (!count) return ticks; + + return [ticks[0]].concat(ticks.slice(ticks.length - count, ticks.length)); + }; + + return scale; +}; + +export default melScale; diff --git a/src/lenses/SpectrogramLens/index.tsx b/src/lenses/SpectrogramLens/index.tsx index 4ee705a0..cf7197bc 100644 --- a/src/lenses/SpectrogramLens/index.tsx +++ b/src/lenses/SpectrogramLens/index.tsx @@ -10,6 +10,7 @@ import { ColorsState, useColors } from '../../stores/colors'; import { Lens } from '../../types'; import useSetting from '../useSetting'; import MenuBar from './MenuBar'; +import melScale from './MelScale'; import { fixWindow, freqType, unitType, amplitudeToDb } from './Spectrogram'; const Container = tw.div`flex flex-col w-full h-full items-stretch justify-center`; @@ -25,69 +26,6 @@ interface WebAudio_ extends WebAudio { const DOMAIN_LOWER_LIMIT = 10; const FFT_SAMPLES = 1024; -interface MelScale { - (value: number): number; - domain(): number[]; - domain(domain: number[]): MelScale; - range(): number[]; - range(range: number[]): MelScale; - copy(): MelScale; - invert(value: number): number; - ticks(count?: number): number[]; - tickFormat(count?: number, specifier?: string): (d: number) => string; -} - -function toMelScale(frequency: number): number { - return 2595 * Math.log10(1 + frequency / 700); -} - -function fromMelScale(mel: number): number { - return 700 * (Math.pow(10, mel / 2595) - 1); -} - -function melScale(): MelScale { - // Create the base log scale - const linearScale = d3.scaleLinear(); - const logScale = d3.scaleLog(); - - // Our custom scale function - const scale: MelScale = ((value: number) => { - return linearScale(value); - }) as MelScale; - - // Copy methods from the log scale - // eslint-disable-next-line @typescript-eslint/no-explicit-any - scale.domain = (domain?: number[]): any => { - if (domain === undefined) { - return linearScale.domain().map((d) => toMelScale(d)); - } - logScale.domain(domain); - return domain ? (linearScale.domain(domain), scale) : linearScale.domain(); - }; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - scale.range = (range?: number[]): any => { - if (range) logScale.range(range); - return range ? (linearScale.range(range), scale) : linearScale.range(); - }; - scale.copy = () => { - return melScale().domain(scale.domain()).range(scale.range()); - }; - scale.invert = (value: number): number => { - return fromMelScale(linearScale.invert(value)); - }; - - scale.ticks = (count?: number): number[] => { - const ticks = logScale.ticks(count).map((val) => { - return toMelScale(val); - }); - if (!count) return ticks; - - return [ticks[0]].concat(ticks.slice(ticks.length - count, ticks.length)); - }; - - return scale; -} - /* * Redraws the scale for resized spectrogram */ @@ -138,8 +76,8 @@ const drawScale = ( .ticks(numTicks) .tickFormat( (x: number) => - `${freqType(fromMelScale(x).valueOf()).toFixed(1)} ${unitType( - fromMelScale(x).valueOf() + `${freqType(scale.fromMelScale(x).valueOf()).toFixed(1)} ${unitType( + scale.fromMelScale(x).valueOf() )}` ); } else { @@ -352,7 +290,7 @@ const SpectrogramLens: Lens = ({ columns, urls, values }) => { value = heightScale(height - y); } else if (freqScale === 'mel') { const scaleFunc = melScale() - .domain([DOMAIN_LOWER_LIMIT, toMelScale(upperLimit)]) + .domain([DOMAIN_LOWER_LIMIT, melScale().toMelScale(upperLimit)]) .range(range); heightScale = d3.scaleLinear([0, upperLimit], [0, FFT_SAMPLES / 2]); value = heightScale(scaleFunc.invert(height - y)); @@ -475,7 +413,7 @@ const SpectrogramLens: Lens = ({ columns, urls, values }) => { const domain: [number, number] = [ DOMAIN_LOWER_LIMIT, - toMelScale(upperLimit), + melScale().toMelScale(upperLimit), ]; const range: [number, number] = [0, height];