fix: round interpolated MIDI values to integers to deduplicate repeated consecutive values
This commit is contained in:
@@ -140,6 +140,30 @@ describe('KGAudioInterface preroll playback', () => {
|
||||
expect(scheduledTimes).toContain(0.5);
|
||||
});
|
||||
|
||||
it('skips redundant scheduled pitch bend events when interpolated values round to the same MIDI value', () => {
|
||||
const region = createMockMidiRegion({
|
||||
pitchBends: [
|
||||
createMockMidiPitchBend({ id: 'bend-1', beat: 0, value: MIDI_PITCH_BEND_CENTER }),
|
||||
createMockMidiPitchBend({ id: 'bend-2', beat: 1, value: MIDI_PITCH_BEND_CENTER + 1 }),
|
||||
],
|
||||
});
|
||||
const track = createMockMidiTrack({ id: 1, regions: [region] });
|
||||
const project = createMockProject({ tracks: [track] });
|
||||
const audio = KGAudioInterface.instance();
|
||||
const audioBus = {
|
||||
resetLiveMidiPitchBend: vi.fn(),
|
||||
setLiveMidiPitchBend: vi.fn(),
|
||||
scheduleLiveMidiPitchBend: vi.fn(),
|
||||
shouldPlayWithSolo: vi.fn().mockReturnValue(true),
|
||||
};
|
||||
|
||||
;(audio as unknown as { trackAudioBuses: Map<string, unknown> }).trackAudioBuses.set('1', audioBus);
|
||||
audio.preparePlayback(project, 0);
|
||||
|
||||
const scheduledTimes = MockTransport.schedule.mock.calls.map(([, time]) => time);
|
||||
expect(scheduledTimes).toEqual([0.25]);
|
||||
});
|
||||
|
||||
it('computes the initial interpolated bend for non-zero playback starts', () => {
|
||||
const region = createMockMidiRegion({
|
||||
pitchBends: [
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { applyOfflinePitchBendAutomation, encodeWav, getOfflineTrackGain, getOfflineTrackVolumeDb } from './KGOfflineRenderer';
|
||||
import { bakeMidiAutomationPointsInWindow } from '../../util/midiAutomationUtil';
|
||||
|
||||
/**
|
||||
* Create a minimal AudioBuffer-like object for testing.
|
||||
@@ -192,4 +193,38 @@ describe('offline pitch bend automation', () => {
|
||||
expect(calls[0][1]).toBe(0.5);
|
||||
expect(calls[0][0]).toBeCloseTo(Math.pow(2, -2 / 12), 5);
|
||||
});
|
||||
|
||||
it('applies only distinct quantized pitch bend transitions from a shallow ramp', () => {
|
||||
const source = {
|
||||
playbackRate: {
|
||||
value: 1,
|
||||
setValueAtTime: (..._args: unknown[]) => undefined,
|
||||
},
|
||||
} as unknown as Parameters<typeof applyOfflinePitchBendAutomation>[0];
|
||||
|
||||
const calls: Array<[number, number]> = [];
|
||||
source.playbackRate.setValueAtTime = ((value: number, time: number) => {
|
||||
calls.push([value, time]);
|
||||
return source.playbackRate as never;
|
||||
}) as typeof source.playbackRate.setValueAtTime;
|
||||
|
||||
const baked = bakeMidiAutomationPointsInWindow(
|
||||
[
|
||||
{ beat: 0, value: 8192 },
|
||||
{ beat: 1, value: 8193 },
|
||||
],
|
||||
0,
|
||||
1,
|
||||
{
|
||||
maxIntervalMs: 20,
|
||||
bpm: 120,
|
||||
defaultValue: 8192,
|
||||
}
|
||||
);
|
||||
|
||||
applyOfflinePitchBendAutomation(source, 1, baked.filter(point => point.beat > 0), 0, 0.5);
|
||||
|
||||
expect(calls).toHaveLength(1);
|
||||
expect(calls[0][1]).toBe(0.26);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user