Skip to content

Commit

Permalink
Merge pull request #53 from h39s/jat-103
Browse files Browse the repository at this point in the history
JAT-103 Add more filter types
  • Loading branch information
selinali2010 authored Oct 8, 2023
2 parents 357c189 + d354130 commit 449015a
Show file tree
Hide file tree
Showing 15 changed files with 294 additions and 103 deletions.
1 change: 1 addition & 0 deletions src/__tests__/cucumber_tests/shared_steps/equalizerApo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const givenCanWriteToAquaConfig = (given: DefineStepFunction) => {
isEnabled: false,
isAutoPreAmpOn: false,
isGraphViewOn: false,
isCaseSensitiveFs: false,
preAmp: 0,
filters: { unique_id: getDefaultFilterWithId() },
};
Expand Down
112 changes: 112 additions & 0 deletions src/__tests__/unit_tests/FrequencyBand.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
<AQUA: System-wide parametric audio equalizer interface>
Copyright (C) <2023> <AQUA Dev Team>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import '@testing-library/jest-dom';
import { screen } from '@testing-library/react';
import {
FilterTypeEnum,
NO_GAIN_FILTER_TYPES,
getDefaultFilterWithId,
} from 'common/constants';
import FrequencyBand from 'renderer/components/FrequencyBand';
import { AquaProviderWrapper } from 'renderer/utils/AquaContext';
import defaultAquaContext from '__tests__/utils/mockAquaProvider';
import { setup } from '../utils/userEventUtils';

describe('FrequencyBand', () => {
const filter = getDefaultFilterWithId();
const filterTypeDropdownLabel = `${filter.frequency}-filter-type`;
const filterGainNumberLabel = `${filter.frequency}-gain-number`;
const filterGainRangeLabel = `${filter.frequency}-gain-range`;
const trashIconLabel = 'Trash Icon';
const handleSubmit = jest.fn();

beforeEach(() => {
handleSubmit.mockClear();
});

it('should render with name', () => {
setup(
<AquaProviderWrapper value={defaultAquaContext}>
<FrequencyBand filter={filter} isMinSliderCount={false} />
</AquaProviderWrapper>
);
expect(screen.getByLabelText(filterTypeDropdownLabel)).toBeInTheDocument();
expect(screen.getByLabelText(trashIconLabel)).not.toHaveAttribute(
'aria-disabled',
'true'
);
});

it('should enable gain when filter type is affected by gain', () => {
setup(
<AquaProviderWrapper value={defaultAquaContext}>
{Object.values(FilterTypeEnum)
.filter(
(filterType) =>
!NO_GAIN_FILTER_TYPES.some(
(noGainFilterType) => noGainFilterType === filterType
)
)
.map((filterType) => {
return (
<FrequencyBand
key={filterType}
filter={{ ...filter, type: filterType }}
isMinSliderCount={false}
/>
);
})}
</AquaProviderWrapper>
);
const gainNumberInputs = screen.getAllByLabelText(filterGainNumberLabel);
gainNumberInputs.forEach((input) => expect(input).not.toBeDisabled());
const gainRangeInputs = screen.getAllByLabelText(filterGainRangeLabel);
gainRangeInputs.forEach((input) => expect(input).not.toBeDisabled());
});

it('should disable gain when filter type is not affected by gain', () => {
setup(
<AquaProviderWrapper value={defaultAquaContext}>
{NO_GAIN_FILTER_TYPES.map((filterType) => (
<FrequencyBand
key={filterType}
filter={{ ...filter, type: filterType }}
isMinSliderCount={false}
/>
))}
</AquaProviderWrapper>
);
const gainNumberInputs = screen.getAllByLabelText(filterGainNumberLabel);
gainNumberInputs.forEach((input) => expect(input).toBeDisabled());
const gainRangeInputs = screen.getAllByLabelText(filterGainRangeLabel);
gainRangeInputs.forEach((input) => expect(input).toBeDisabled());
});

it('should prevent deleting when min slider count is met', () => {
setup(
<AquaProviderWrapper value={defaultAquaContext}>
<FrequencyBand filter={filter} isMinSliderCount />
</AquaProviderWrapper>
);
expect(screen.getByLabelText(trashIconLabel)).toHaveAttribute(
'aria-disabled',
'true'
);
});
});
3 changes: 3 additions & 0 deletions src/__tests__/unit_tests/NumberInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@ describe('NumberInput', () => {
const input = screen.getByLabelText(id);
expect(input).toHaveValue(`${testValue}`);
expect(input).toBeDisabled();

fireEvent.wheel(input, { deltaY: -100 });
expect(handleSubmit).not.toHaveBeenCalled();
});

it('should not accept bad inputs for float input', async () => {
Expand Down
4 changes: 4 additions & 0 deletions src/__tests__/unit_tests/RangeInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -241,5 +241,9 @@ describe('RangeInput', () => {
expect(upArrow).toHaveAttribute('aria-disabled', 'true');
await user.click(upArrow);
expect(handleChange).not.toHaveBeenCalled();

const slider = screen.getByLabelText(`${name}`);
fireEvent.wheel(slider, { deltaY: -100 });
expect(handleChange).not.toHaveBeenCalled();
});
});
24 changes: 16 additions & 8 deletions src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ export const MIN_NUM_FILTERS = 1;
// Need to use LSC and HSC to allow users to adjust quality for low/high shelf filters
export enum FilterTypeEnum {
PK = 'PK', // Peak ["PK",True,True]
// LPQ = 'LPQ', // Low Pass ["LPQ",False,True]
// HPQ = 'HPQ', // High Pass ["HPQ",False,True]
// BP = 'BP', // Band Pass ["BP",False,True]
// NO = 'NO', // Notch ["NO",False,True]
// AP = 'AP', // All Pass ["AP",False,True]
NO = 'NO', // Notch ["NO",False,True]
LSC = 'LSC', // Low Shelf ["LSC",True,True]
HSC = 'HSC', // High Shelf ["HSC",True,True]
LPQ = 'LPQ', // Low Pass ["LPQ",False,True]
HPQ = 'HPQ', // High Pass ["HPQ",False,True]
BP = 'BP', // Band Pass ["BP",False,True]
// AP = 'AP', // All Pass ["AP",False,True]
// BWLP = 'BWLP', // Butterworth Low Pass ["BWLP",False,True]
// BWHP = 'BWHP', // Butterworth High Pass ["BWHP",False,True]
// LRLP = 'LRLP', // Linkwitz Riley Low Pass ["LRLP",False,True]
Expand All @@ -52,13 +52,21 @@ export enum FilterTypeEnum {

export const FilterTypeToLabelMap: Record<FilterTypeEnum, string> = {
[FilterTypeEnum.PK]: 'Peak Filter',
// [FilterTypeEnum.LPQ]: 'Low Pass Filter',
// [FilterTypeEnum.HPQ]: 'High Pass Filter',
[FilterTypeEnum.NO]: 'Notch Filter',
[FilterTypeEnum.LSC]: 'Low Shelf Filter',
[FilterTypeEnum.HSC]: 'High Shelf Filter',
// [FilterTypeEnum.NO]: 'Notch Filter',
[FilterTypeEnum.LPQ]: 'Low Pass Filter',
[FilterTypeEnum.HPQ]: 'High Pass Filter',
[FilterTypeEnum.BP]: 'Band Pass Filter',
};

export const NO_GAIN_FILTER_TYPES = [
FilterTypeEnum.BP,
FilterTypeEnum.LPQ,
FilterTypeEnum.HPQ,
FilterTypeEnum.NO,
];

export const WINDOW_WIDTH = 1428;
export const WINDOW_HEIGHT = 625;
export const WINDOW_HEIGHT_EXPANDED = 1036;
Expand Down
8 changes: 8 additions & 0 deletions src/renderer/components/FrequencyBand.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
MIN_FREQUENCY,
MIN_GAIN,
MIN_QUALITY,
NO_GAIN_FILTER_TYPES,
} from 'common/constants';
import IconButton, { IconName } from 'renderer/widgets/IconButton';
import {
Expand Down Expand Up @@ -193,6 +194,12 @@ const FrequencyBand = forwardRef(
}
};

const isGainDisabled = useMemo(
() =>
NO_GAIN_FILTER_TYPES.some((filterType) => filterType === filter.type),
[filter.type]
);

const onRemoveEqualizerSlider = async () => {
if (isRemoveDisabled) {
return;
Expand Down Expand Up @@ -258,6 +265,7 @@ const FrequencyBand = forwardRef(
value={filter.gain}
sliderHeight={sliderHeight}
setValue={handleGainSubmit}
isDisabled={isGainDisabled}
/>
</div>
<NumberInput
Expand Down
6 changes: 4 additions & 2 deletions src/renderer/components/Slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ interface ISliderProps {
min: number;
max: number;
value: number;
isDisabled?: boolean;
sliderHeight?: string;
label?: string;
setValue: (newValue: number) => Promise<void>;
Expand All @@ -39,6 +40,7 @@ const Slider = ({
value,
sliderHeight = '150px',
label,
isDisabled = false,
setValue,
}: ISliderProps) => {
const { globalError } = useAquaContext();
Expand Down Expand Up @@ -73,7 +75,7 @@ const Slider = ({
height={sliderHeight}
handleChange={handleInput}
handleMouseUp={handleInput}
isDisabled={!!globalError}
isDisabled={isDisabled || !!globalError}
incrementPrecision={0}
displayPrecision={2}
/>
Expand All @@ -84,7 +86,7 @@ const Slider = ({
min={min}
max={max}
handleSubmit={handleInput}
isDisabled={!!globalError}
isDisabled={isDisabled || !!globalError}
floatPrecision={2}
showArrows
/>
Expand Down
34 changes: 28 additions & 6 deletions src/renderer/graph/Chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,31 @@ const Chart = ({ data = [], dimensions }: IChartProps) => {
[height, margins]
);

const padding = {
left: 50,
top: 0,
right: 0,
bottom: 30,
};
const padding = useMemo(() => {
return {
left: 50,
top: 0,
right: 0,
bottom: 30,
};
}, []);

const chartWidth = useMemo(
() =>
Math.max(
width - margins.left - margins.right - padding.left - padding.right,
0
),
[width, margins, padding]
);
const chartHeight = useMemo(
() =>
Math.max(
height - margins.top - margins.bottom - padding.top - padding.bottom,
0
),
[height, margins, padding]
);

const { xTickFormat, yTickFormat, xScaleFreq, yScaleGain } = useController({
data,
Expand Down Expand Up @@ -102,6 +121,9 @@ const Chart = ({ data = [], dimensions }: IChartProps) => {
{data.map((e: IChartCurveData) => (
<Curve key={e.id} data={e} xScale={xScaleFreq} yScale={yScaleGain} />
))}
<clipPath id="chart-clip-path">
<rect x={padding.left} width={chartWidth} height={chartHeight} />
</clipPath>
<Axis
type="left"
scale={yScaleGain}
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/graph/FrequencyResponseChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@ const FrequencyResponseChart = () => {
}, [autoPreAmpValue, isAutoPreAmpOn, isLoading, setPreAmp]);

const ref = useRef<HTMLDivElement>(null);
const [width, setWidth] = useState<number>(1396);
const [height, setHeight] = useState<number>(380);
const [width, setWidth] = useState<number>(0);
const [height, setHeight] = useState<number>(0);

const updateDimensions = useCallback(() => {
const newWidth = ref.current?.clientWidth;
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/graph/Line.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ const Line = ({

// Set initial path attribute
const initRender = useCallback(() => {
d3.select(ref.current).attr('d', d);
d3.select(ref.current)
.attr('d', d)
.attr('clip-path', 'url(#chart-clip-path)');
}, [d]);

// Handle animation for the initial render
Expand Down
61 changes: 31 additions & 30 deletions src/renderer/graph/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const getTFCoefficients = (filter: IFilter) => {
quality: userQuality,
} = filter;

// TODO: add additional shelf filter cases when/if we add them in
// Handle these filter types differently:
// 'peak', 'low-shelf-fixed', 'high-shelf-fixed', 'low-shelf-q', 'high-shelf-q', 'low-shelf-db', 'high-shelf-db'
const specialFilters = new Set([
Expand All @@ -77,7 +78,7 @@ const getTFCoefficients = (filter: IFilter) => {

const shelfFilters = new Set([FilterTypeEnum.HSC, FilterTypeEnum.LSC]);
if (shelfFilters.has(filterType)) {
// TODO: add additional shelf filter cases when /if we add them in
// TODO: add additional shelf filter cases when/if we add them in
// if (filterType in {'low-shelf-fixed', 'high-shelf-fixed'}){
// quality = 0.9
// } else
Expand Down Expand Up @@ -122,35 +123,35 @@ const getTFCoefficients = (filter: IFilter) => {
a0 = 1 + alpha / gain;
a1 = -2 * cosine;
a2 = 1 - alpha / gain;
// TODO: Add these filters back in when we re-enable the filter types
// } else if ( filterType === FilterTypeEnum.NO){
// b0 = 1
// b1 = -2*cosine
// b2 = 1
// a0 = 1+alpha
// a1 = -2*cosine
// a2 = 1-alpha
// } else if (filterType === FilterTypeEnum.LPQ){
// b0 = (1-cosine)/2
// b1 = 1-cosine
// b2 = (1-cosine)/2
// a0 = 1+alpha;
// a1 = -2*cosine;
// a2 = 1-alpha;
// } else if (filterType === FilterTypeEnum.HPQ){
// b0 = (1+cosine)/2
// b1 = -(1+cosine)
// b2 = (1+cosine) /2
// a0 = 1+alpha
// a1 = -2*cosine
// a2 = 1-alpha
// } else if (filterType === FilterTypeEnum.BP){
// b0 = alpha
// b1 = 0
// b2 = -alpha
// a0 = 1+alpha
// a1 = -2*cosine
// a2 = 1-alpha
} else if (filterType === FilterTypeEnum.NO) {
b0 = 1;
b1 = -2 * cosine;
b2 = 1;
a0 = 1 + alpha;
a1 = -2 * cosine;
a2 = 1 - alpha;
} else if (filterType === FilterTypeEnum.LPQ) {
b0 = (1 - cosine) / 2;
b1 = 1 - cosine;
b2 = (1 - cosine) / 2;
a0 = 1 + alpha;
a1 = -2 * cosine;
a2 = 1 - alpha;
} else if (filterType === FilterTypeEnum.HPQ) {
b0 = (1 + cosine) / 2;
b1 = -(1 + cosine);
b2 = (1 + cosine) / 2;
a0 = 1 + alpha;
a1 = -2 * cosine;
a2 = 1 - alpha;
} else if (filterType === FilterTypeEnum.BP) {
b0 = alpha;
b1 = 0;
b2 = -alpha;
a0 = 1 + alpha;
a1 = -2 * cosine;
a2 = 1 - alpha;
// TODO: Add this filter back in when/if we decide to add all pass filter
// } else if ( filterType === FilterTypeEnum.AP){
// b0 = 1-alpha
// b1 = -2*cosine
Expand Down
Loading

0 comments on commit 449015a

Please sign in to comment.