SyntheticCalibrationFixture.java
package org.hammer.audio.experimental.acoustic.calibration;
import java.util.Objects;
import org.hammer.audio.core.AudioBlock;
import org.hammer.audio.core.AudioFormatDescriptor;
/** Deterministic single-pulse audio fixtures for calibration tests and offline experiments. */
public final class SyntheticCalibrationFixture {
private SyntheticCalibrationFixture() {
throw new UnsupportedOperationException("Utility class");
}
/**
* Generates one common pulse observed with an explicit non-negative delay per channel.
*
* @param format multichannel audio format
* @param frameIndex absolute nominal start frame
* @param timestampNanos nominal block timestamp
* @param frames block length
* @param pulseFrame undelayed pulse frame inside the block
* @param channelDelaysSamples per-channel delay from the common pulse
* @return immutable deterministic calibration block
*/
public static AudioBlock pulseBlock(
AudioFormatDescriptor format,
long frameIndex,
long timestampNanos,
int frames,
int pulseFrame,
int[] channelDelaysSamples) {
Objects.requireNonNull(format, "format");
Objects.requireNonNull(channelDelaysSamples, "channelDelaysSamples");
if (frames < 1) {
throw new IllegalArgumentException("frames must be >= 1");
}
if (pulseFrame < 0 || pulseFrame >= frames) {
throw new IllegalArgumentException("pulseFrame must be inside the block");
}
if (channelDelaysSamples.length != format.channels()) {
throw new IllegalArgumentException("channel delays must match the format channel count");
}
float[][] samples = new float[format.channels()][frames];
for (int channel = 0; channel < channelDelaysSamples.length; channel++) {
int delay = channelDelaysSamples[channel];
int observedFrame = pulseFrame + delay;
if (delay < 0 || observedFrame >= frames) {
throw new IllegalArgumentException("channel delay places the pulse outside the block");
}
samples[channel][observedFrame] = 1.0f;
}
return AudioBlock.wrap(format, samples, frameIndex, timestampNanos);
}
}