tone 15.5.49 → 15.5.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -616,6 +616,50 @@ describe("TickSource", () => {
616
616
  }
617
617
  source.dispose();
618
618
  });
619
+
620
+ it("does not skip the boundary tick when started between ticks (#1500)", () => {
621
+ const block = 128 / 48000;
622
+ const source = new TickSource(384);
623
+ const start = 2 * block + 0.12;
624
+ source.start(start);
625
+ const fired: number[] = [];
626
+ const boundary = (2 + 70) * block + 0.1;
627
+ source.forEachTickBetween(start, boundary, (_, tick) =>
628
+ fired.push(tick)
629
+ );
630
+ source.forEachTickBetween(boundary, boundary + 0.05, (_, tick) =>
631
+ fired.push(tick)
632
+ );
633
+ expect(fired).to.include(
634
+ 64,
635
+ "tick 64 at the window boundary was skipped"
636
+ );
637
+ source.dispose();
638
+ });
639
+
640
+ it("does not fire a tick twice when started more than half a tick past an integer tick (#1500)", () => {
641
+ const source = new TickSource(2);
642
+ const start = 0.35;
643
+ source.start(start);
644
+ const tickCount = new Map<number, number>();
645
+ const record = (_: number, tick: number) => {
646
+ tickCount.set(tick, (tickCount.get(tick) ?? 0) + 1);
647
+ };
648
+ const eps = 1e-10;
649
+ let windowStart = start;
650
+ for (let n = 1; n <= 8; n++) {
651
+ const windowEnd = start + n * 0.5 + eps;
652
+ source.forEachTickBetween(windowStart, windowEnd, record);
653
+ windowStart = windowEnd;
654
+ }
655
+ for (const [tick, count] of tickCount) {
656
+ expect(count).to.equal(
657
+ 1,
658
+ `tick ${tick} fired ${count} times instead of once`
659
+ );
660
+ }
661
+ source.dispose();
662
+ });
619
663
  });
620
664
 
621
665
  context("Seconds", () => {
@@ -5,7 +5,6 @@ import {
5
5
  import { Seconds, Ticks, Time } from "../type/Units.js";
6
6
  import { optionsFromArguments } from "../util/Defaults.js";
7
7
  import { readOnly } from "../util/Interface.js";
8
- import { EQ } from "../util/Math.js";
9
8
  import {
10
9
  PlaybackState,
11
10
  StateTimeline,
@@ -413,43 +412,24 @@ export class TickSource<
413
412
  let error: Error | null = null;
414
413
 
415
414
  if (lastStateEvent?.state === "started") {
416
- const maxStartTime = Math.max(lastStateEvent.time, startTime);
417
- // Figure out how far past the last whole-tick boundary maxStartTime
418
- // sits, so we can compute the time of the next tick at or after it.
419
- const startTicks = this.frequency.getTicksAtTime(maxStartTime);
420
- const ticksAtStart = this.frequency.getTicksAtTime(
421
- lastStateEvent.time
415
+ const origin = this.frequency.getTicksAtTime(lastStateEvent.time);
416
+ const endTicks = this.frequency.getTicksAtTime(endTime) - origin;
417
+ const tick = Math.ceil(
418
+ this.frequency.getTicksAtTime(
419
+ Math.max(lastStateEvent.time, startTime)
420
+ ) - origin
422
421
  );
423
- const diff = startTicks - ticksAtStart;
424
- const offset = Math.ceil(diff) - diff;
425
- // Guard against floating-point issues: when startTicks is just barely
426
- // above an integer tick boundary (offset ≈ 1), snap back to that integer
427
- const firstTick = EQ(offset, 1)
428
- ? Math.floor(startTicks)
429
- : startTicks + offset;
430
- let nextTickTime = this.frequency.getTimeOfTick(firstTick);
431
- // Advance past any ticks that land before the start of this window
432
- // to avoid any tick that was already processed.
433
- if (nextTickTime < maxStartTime) {
434
- nextTickTime += this.frequency.getDurationOfTicks(
435
- 1,
436
- nextTickTime
437
- );
438
- }
439
- while (nextTickTime < endTime) {
422
+ for (let t = tick; t < endTicks; t++) {
423
+ const time = this.frequency.getTimeOfTick(origin + t);
440
424
  try {
441
- callback(
442
- nextTickTime,
443
- Math.round(this.getTicksAtTime(nextTickTime))
444
- );
425
+ callback(time, Math.round(this.getTicksAtTime(time)));
445
426
  } catch (e) {
446
427
  error = e as Error;
447
428
  break;
448
429
  }
449
- nextTickTime += this.frequency.getDurationOfTicks(
450
- 1,
451
- nextTickTime
452
- );
430
+ if (this.disposed) {
431
+ break;
432
+ }
453
433
  }
454
434
  }
455
435
 
package/Tone/version.ts CHANGED
@@ -1 +1 @@
1
- export const version: string = "15.5.49";
1
+ export const version: string = "15.5.51";