/** * The rules of a Knob (#378): where a value sits on the turn, and what a drag and the wheel make of it. */ import { describe, expect, it } from 'vitest'; import { draggedValue, KNOB_TRAVEL, knobOrigin, knobPosition, knobValue, wheeledValue, } from '../../src/ui/knob'; const threshold = { min: -100, max: 0, step: 0.5 }; const attack = { min: 0, max: 1, step: 0.001, taper: 3 }; const makeup = { min: -24, max: 24, step: 0.5 }; describe('a knob', () => { it('turns evenly without a taper, and gives the low end more of the turn with one', () => { expect(knobPosition(-50, threshold)).toBeCloseTo(0.5, 9); expect(knobValue(0.5, threshold)).toBe(-50); // An attack of 3 ms is an eighth of the way round, not three thousandths. expect(knobPosition(0.003, attack)).toBeCloseTo(0.144, 3); expect(knobValue(knobPosition(0.003, attack), attack)).toBe(0.003); expect(knobValue(-1, attack)).toBe(0); expect(knobValue(2, attack)).toBe(1); }); it('turns up as it is dragged up, a tenth as far with Shift', () => { expect(draggedValue(-50, -KNOB_TRAVEL / 2, false, threshold)).toBe(0); expect(draggedValue(-50, KNOB_TRAVEL / 4, false, threshold)).toBe(-75); expect(draggedValue(-50, -KNOB_TRAVEL / 2, true, threshold)).toBe(-45); expect(draggedValue(-50, KNOB_TRAVEL * 10, false, threshold)).toBe(-100); }); it('moves at least one step, however short the drag', () => { expect(draggedValue(-50, -1, true, threshold)).toBe(-49.5); expect(draggedValue(-50, 1, true, threshold)).toBe(-50.5); expect(draggedValue(0, -1, true, threshold)).toBe(0); expect(draggedValue(-50, 0, false, threshold)).toBe(-50); }); it('notches up on the wheel turned up, and down on it turned down', () => { expect(wheeledValue(-50, -100, threshold)).toBe(-48); expect(wheeledValue(-50, 100, threshold)).toBe(-52); expect(wheeledValue(0.003, -100, attack)).toBeGreaterThan(0.003); }); it('has 0 straight up on a bipolar range, and gives the small numbers either way most of the turn (#386)', () => { const slide = { min: -2000, max: 2000, step: 1, taper: 3, bipolar: true }; expect(knobPosition(0, slide)).toBe(0.5); expect(knobPosition(2000, slide)).toBe(1); expect(knobPosition(-2000, slide)).toBe(0); // 250 st/s, an eighth of the reach, is halfway up the right half; even it would be at 0.5625. expect(knobPosition(250, slide)).toBeCloseTo(0.75, 9); expect(knobPosition(-250, slide)).toBeCloseTo(0.25, 9); expect(knobValue(0.75, slide)).toBe(250); expect(knobValue(0.5, slide)).toBe(0); for (const value of [-1200, -7, 0, 3, 640]) expect(knobValue(knobPosition(value, slide), slide)).toBe(value); expect(knobOrigin(slide)).toBe(0.5); expect(draggedValue(0, -1, true, slide)).toBe(1); }); it('fills its arc from 0 when the range has it inside, else from the low end', () => { expect(knobOrigin(makeup)).toBeCloseTo(0.5, 9); expect(knobOrigin(threshold)).toBe(0); expect(knobOrigin(attack)).toBe(0); }); });