feat: add independent full-band activity workflow
This commit is contained in:
@@ -4,7 +4,8 @@ const DIXON_2006_URL =
|
||||
"https://www.dafx.de/paper-archive/2006/papers/p_133.pdf";
|
||||
const BOECK_KREBS_SCHEDL_2012_URL =
|
||||
"https://www.cp.jku.at/research/papers/Boeck_etal_ISMIR_2012.pdf";
|
||||
const DEFAULT_MAXIMUM_OUTPUT_BYTES = 64 * 1024 * 1024;
|
||||
export const DEFAULT_MAXIMUM_SPECTRAL_FLUX_OUTPUT_BYTES =
|
||||
64 * 1024 * 1024;
|
||||
|
||||
function requireConfigurationObject(value, label) {
|
||||
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
||||
@@ -92,6 +93,90 @@ function checkedByteCount(elementCount, bytesPerElement, label) {
|
||||
return byteCount;
|
||||
}
|
||||
|
||||
export function estimateDixonSpectralFluxWorkload(options) {
|
||||
const configuration = requireConfigurationObject(options, "options");
|
||||
const sampleCount = requireNonNegativeSafeInteger(
|
||||
requireOwn(configuration, "sampleCount"),
|
||||
"sampleCount",
|
||||
);
|
||||
const fftSize = requirePowerOfTwo(
|
||||
requireOwn(configuration, "fftSize"),
|
||||
"fftSize",
|
||||
);
|
||||
const hopSize = requireNonNegativeSafeInteger(
|
||||
requireOwn(configuration, "hopSize"),
|
||||
"hopSize",
|
||||
);
|
||||
if (hopSize < 1 || hopSize > fftSize) {
|
||||
throw new RangeError("hopSize must be between 1 and fftSize, inclusive.");
|
||||
}
|
||||
const maximumOutputBytes =
|
||||
configuration.maximumOutputBytes ??
|
||||
DEFAULT_MAXIMUM_SPECTRAL_FLUX_OUTPUT_BYTES;
|
||||
if (!Number.isSafeInteger(maximumOutputBytes) || maximumOutputBytes <= 0) {
|
||||
throw new RangeError("maximumOutputBytes must be a positive safe integer.");
|
||||
}
|
||||
const frameCount = sampleCount < fftSize
|
||||
? 0
|
||||
: 1 + Math.floor((sampleCount - fftSize) / hopSize);
|
||||
const binCount = fftSize;
|
||||
const positiveDifferenceElements =
|
||||
checkedElementCount(frameCount, binCount);
|
||||
const positiveDifferenceBytes = checkedByteCount(
|
||||
positiveDifferenceElements,
|
||||
Float64Array.BYTES_PER_ELEMENT,
|
||||
"positiveDifferences",
|
||||
);
|
||||
const rawOdfBytes = checkedByteCount(
|
||||
frameCount,
|
||||
Float64Array.BYTES_PER_ELEMENT,
|
||||
"rawOdf",
|
||||
);
|
||||
const frameTimingBytes = checkedByteCount(
|
||||
frameCount * 3,
|
||||
Float64Array.BYTES_PER_ELEMENT,
|
||||
"frame timing",
|
||||
);
|
||||
const outputBytes =
|
||||
positiveDifferenceBytes + rawOdfBytes + frameTimingBytes;
|
||||
if (!Number.isSafeInteger(outputBytes)) {
|
||||
throw new RangeError(
|
||||
"spectral-flux output byte count exceeds safe integer range.",
|
||||
);
|
||||
}
|
||||
if (outputBytes > maximumOutputBytes) {
|
||||
throw new RangeError(
|
||||
`spectral flux requires ${outputBytes.toLocaleString()} output bytes; ` +
|
||||
`maximumOutputBytes is ${maximumOutputBytes.toLocaleString()}.`,
|
||||
);
|
||||
}
|
||||
const workspaceElements = frameCount === 0 ? 0 : fftSize * 4;
|
||||
const workspaceBytes = checkedByteCount(
|
||||
workspaceElements,
|
||||
Float64Array.BYTES_PER_ELEMENT,
|
||||
"spectral-flux workspace",
|
||||
);
|
||||
const estimatedPeakTypedArrayBytes = outputBytes + workspaceBytes;
|
||||
if (!Number.isSafeInteger(estimatedPeakTypedArrayBytes)) {
|
||||
throw new RangeError(
|
||||
"spectral-flux peak typed-array byte count exceeds safe integer range.",
|
||||
);
|
||||
}
|
||||
return Object.freeze({
|
||||
sampleCount,
|
||||
frameCount,
|
||||
binCount,
|
||||
positiveDifferenceElements,
|
||||
positiveDifferenceBytes,
|
||||
rawOdfBytes,
|
||||
frameTimingBytes,
|
||||
outputBytes,
|
||||
maximumOutputBytes,
|
||||
workspaceBytes,
|
||||
estimatedPeakTypedArrayBytes,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute Simon Dixon's 2006 magnitude spectral-flux onset detection function.
|
||||
*
|
||||
@@ -123,51 +208,24 @@ export function computeDixonSpectralFlux(options) {
|
||||
if (typeof channelId !== "string" || channelId.length === 0) {
|
||||
throw new TypeError("channelId must be a non-empty string.");
|
||||
}
|
||||
const maximumOutputBytes = configuration.maximumOutputBytes ?? DEFAULT_MAXIMUM_OUTPUT_BYTES;
|
||||
if (!Number.isSafeInteger(maximumOutputBytes) || maximumOutputBytes <= 0) {
|
||||
throw new RangeError("maximumOutputBytes must be a positive safe integer.");
|
||||
}
|
||||
|
||||
const frameCount = samples.length < fftSize
|
||||
? 0
|
||||
: 1 + Math.floor((samples.length - fftSize) / hopSize);
|
||||
const binCount = fftSize;
|
||||
const positiveDifferenceElements = checkedElementCount(frameCount, binCount);
|
||||
const positiveDifferenceBytes = checkedByteCount(
|
||||
positiveDifferenceElements,
|
||||
Float64Array.BYTES_PER_ELEMENT,
|
||||
"positiveDifferences",
|
||||
);
|
||||
const rawOdfBytes = checkedByteCount(
|
||||
const workload = estimateDixonSpectralFluxWorkload({
|
||||
sampleCount: samples.length,
|
||||
fftSize,
|
||||
hopSize,
|
||||
maximumOutputBytes: configuration.maximumOutputBytes,
|
||||
});
|
||||
const {
|
||||
frameCount,
|
||||
Float64Array.BYTES_PER_ELEMENT,
|
||||
"rawOdf",
|
||||
);
|
||||
const frameTimingBytes = checkedByteCount(
|
||||
frameCount * 3,
|
||||
Float64Array.BYTES_PER_ELEMENT,
|
||||
"frame timing",
|
||||
);
|
||||
const outputBytes = positiveDifferenceBytes + rawOdfBytes + frameTimingBytes;
|
||||
if (!Number.isSafeInteger(outputBytes)) {
|
||||
throw new RangeError("spectral-flux output byte count exceeds safe integer range.");
|
||||
}
|
||||
if (outputBytes > maximumOutputBytes) {
|
||||
throw new RangeError(
|
||||
`spectral flux requires ${outputBytes.toLocaleString()} output bytes; ` +
|
||||
`maximumOutputBytes is ${maximumOutputBytes.toLocaleString()}.`,
|
||||
);
|
||||
}
|
||||
const workspaceElements = frameCount === 0 ? 0 : fftSize * 4;
|
||||
const workspaceBytes = checkedByteCount(
|
||||
workspaceElements,
|
||||
Float64Array.BYTES_PER_ELEMENT,
|
||||
"spectral-flux workspace",
|
||||
);
|
||||
const estimatedPeakTypedArrayBytes = outputBytes + workspaceBytes;
|
||||
if (!Number.isSafeInteger(estimatedPeakTypedArrayBytes)) {
|
||||
throw new RangeError("spectral-flux peak typed-array byte count exceeds safe integer range.");
|
||||
}
|
||||
binCount,
|
||||
positiveDifferenceElements,
|
||||
positiveDifferenceBytes,
|
||||
rawOdfBytes,
|
||||
frameTimingBytes,
|
||||
outputBytes,
|
||||
maximumOutputBytes,
|
||||
workspaceBytes,
|
||||
estimatedPeakTypedArrayBytes,
|
||||
} = workload;
|
||||
|
||||
const positiveDifferences = new Float64Array(positiveDifferenceElements);
|
||||
const rawOdf = new Float64Array(frameCount);
|
||||
|
||||
Reference in New Issue
Block a user