SquareGenerator.java
package org.hammer.audio.signal;
import org.hammer.audio.core.AudioBlock;
import org.hammer.audio.core.AudioFormatDescriptor;
/**
* Deterministic mono square-wave generator (broadcast to all channels of {@code format}).
*
* <p>Produces values of {@code +amplitude} for the first half of each period and {@code -amplitude}
* for the second half. Useful as a known harmonics-rich test signal for spectrum verification.
*
* @author refactoring
*/
public final class SquareGenerator implements SignalGenerator {
private final AudioFormatDescriptor format;
private final double frequencyHz;
private final float amplitude;
private final double phaseStep;
private double phase;
private long frameIndex;
/**
* @param format output format descriptor
* @param frequencyHz oscillator frequency in Hz; must be {@code > 0}
* @param amplitude peak amplitude
*/
public SquareGenerator(AudioFormatDescriptor format, double frequencyHz, float amplitude) {
if (!(frequencyHz > 0.0)) {
throw new IllegalArgumentException("frequencyHz must be > 0, was " + frequencyHz);
}
this.format = format;
this.frequencyHz = frequencyHz;
this.amplitude = amplitude;
this.phaseStep = 2.0 * Math.PI * frequencyHz / format.sampleRate();
this.phase = 0.0;
this.frameIndex = 0L;
}
@Override
public AudioFormatDescriptor format() {
return format;
}
@Override
public AudioBlock nextBlock(int frames) {
if (frames < 1) {
throw new IllegalArgumentException("frames must be >= 1");
}
int channels = format.channels();
float[][] samples = new float[channels][frames];
double p = phase;
final double twoPi = 2.0 * Math.PI;
for (int i = 0; i < frames; i++) {
float v = (Math.sin(p) >= 0.0) ? amplitude : -amplitude;
for (int c = 0; c < channels; c++) {
samples[c][i] = v;
}
p += phaseStep;
}
p = p % twoPi;
long index = frameIndex;
phase = p;
frameIndex += frames;
return AudioBlock.wrap(format, samples, index, System.nanoTime());
}
@Override
public void reset() {
phase = 0.0;
frameIndex = 0L;
}
/**
* @return frequency of the oscillator in Hz
*/
public double frequencyHz() {
return frequencyHz;
}
}