resampleFutoTrace function

Float32List resampleFutoTrace(
  1. List<FutoSwipePoint> trace
)

Converts a touch trace to the encoder's features input, [2, 64].

This reproduces the NumPy preprocessing used for the published validation: linear interpolation in time to about 60 Hz, then by index to 64 samples. A trace with no duration skips the 60 Hz stage. The arithmetic follows numpy.linspace and numpy.interp so float32 results match exactly.

Implementation

Float32List resampleFutoTrace(List<FutoSwipePoint> trace) {
  final count = trace.length;
  final origin = trace.first.time.inMicroseconds;
  final times = Float64List(count);
  final xs = Float64List(count);
  final ys = Float64List(count);
  for (var i = 0; i < count; i++) {
    times[i] = (trace[i].time.inMicroseconds - origin) / 1000;
    xs[i] = trace[i].x;
    ys[i] = trace[i].y;
  }

  var stageX = xs;
  var stageY = ys;
  final duration = times[count - 1];
  if (duration > 1e-3) {
    final samples = math.max(2, _roundHalfEven(duration / (1000 / 60)) + 1);
    final grid = _linspace(0, duration, samples);
    stageX = _interp(grid, times, xs);
    stageY = _interp(grid, times, ys);
  }

  final positions = Float64List(stageX.length);
  for (var i = 0; i < positions.length; i++) {
    positions[i] = i.toDouble();
  }
  final index = _linspace(
    0,
    (stageX.length - 1).toDouble(),
    futoSwipeTraceSamples,
  );
  final x = _interp(index, positions, stageX);
  final y = _interp(index, positions, stageY);
  return Float32List(futoSwipeTraceSamples * 2)
    ..setAll(0, x)
    ..setAll(futoSwipeTraceSamples, y);
}