Quite a big update
This commit is contained in:
@ -45,11 +45,17 @@ export abstract class CsoundEngine<T = any> implements SynthEngine<T> {
|
||||
|
||||
await csound.terminateInstance();
|
||||
|
||||
const leftChannel = new Float32Array(audioBuffer.leftChannel);
|
||||
const rightChannel = new Float32Array(audioBuffer.rightChannel);
|
||||
let leftChannel = new Float32Array(audioBuffer.leftChannel);
|
||||
let rightChannel = new Float32Array(audioBuffer.rightChannel);
|
||||
|
||||
this.removeDCOffset(leftChannel, rightChannel);
|
||||
|
||||
const trimmed = this.trimToZeroCrossing(leftChannel, rightChannel, sampleRate);
|
||||
leftChannel = trimmed.left;
|
||||
rightChannel = trimmed.right;
|
||||
|
||||
// Apply short fade-in to prevent click at start
|
||||
this.applyFadeIn(leftChannel, rightChannel, sampleRate);
|
||||
this.applyFadeOut(leftChannel, rightChannel, sampleRate);
|
||||
|
||||
const peak = this.findPeak(leftChannel, rightChannel);
|
||||
if (peak > 0.001) {
|
||||
@ -218,22 +224,95 @@ e
|
||||
}
|
||||
}
|
||||
|
||||
private removeDCOffset(leftChannel: Float32Array, rightChannel: Float32Array): void {
|
||||
let leftSum = 0;
|
||||
let rightSum = 0;
|
||||
const length = leftChannel.length;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
leftSum += leftChannel[i];
|
||||
rightSum += rightChannel[i];
|
||||
}
|
||||
|
||||
const leftDC = leftSum / length;
|
||||
const rightDC = rightSum / length;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
leftChannel[i] -= leftDC;
|
||||
rightChannel[i] -= rightDC;
|
||||
}
|
||||
}
|
||||
|
||||
private trimToZeroCrossing(
|
||||
leftChannel: Float32Array,
|
||||
rightChannel: Float32Array,
|
||||
sampleRate: number
|
||||
): { left: Float32Array; right: Float32Array } {
|
||||
const maxSearchSamples = Math.min(Math.floor(sampleRate * 0.01), leftChannel.length);
|
||||
let trimIndex = 0;
|
||||
|
||||
for (let i = 1; i < maxSearchSamples; i++) {
|
||||
const prevL = leftChannel[i - 1];
|
||||
const currL = leftChannel[i];
|
||||
const prevR = rightChannel[i - 1];
|
||||
const currR = rightChannel[i];
|
||||
|
||||
if (
|
||||
(prevL <= 0 && currL >= 0) || (prevL >= 0 && currL <= 0) ||
|
||||
(prevR <= 0 && currR >= 0) || (prevR >= 0 && currR <= 0)
|
||||
) {
|
||||
trimIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (trimIndex > 0) {
|
||||
const newLeft = new Float32Array(leftChannel.length - trimIndex);
|
||||
const newRight = new Float32Array(rightChannel.length - trimIndex);
|
||||
newLeft.set(leftChannel.subarray(trimIndex));
|
||||
newRight.set(rightChannel.subarray(trimIndex));
|
||||
return { left: newLeft, right: newRight };
|
||||
}
|
||||
|
||||
return { left: leftChannel, right: rightChannel };
|
||||
}
|
||||
|
||||
private applyFadeIn(
|
||||
leftChannel: Float32Array,
|
||||
rightChannel: Float32Array,
|
||||
sampleRate: number
|
||||
): void {
|
||||
const fadeInMs = 5; // 5ms fade-in to prevent clicks
|
||||
const fadeInMs = 5;
|
||||
const fadeSamples = Math.floor((fadeInMs / 1000) * sampleRate);
|
||||
const actualFadeSamples = Math.min(fadeSamples, leftChannel.length);
|
||||
|
||||
for (let i = 0; i < actualFadeSamples; i++) {
|
||||
const gain = i / actualFadeSamples;
|
||||
const phase = i / actualFadeSamples;
|
||||
const gain = 0.5 - 0.5 * Math.cos(phase * Math.PI);
|
||||
leftChannel[i] *= gain;
|
||||
rightChannel[i] *= gain;
|
||||
}
|
||||
}
|
||||
|
||||
private applyFadeOut(
|
||||
leftChannel: Float32Array,
|
||||
rightChannel: Float32Array,
|
||||
sampleRate: number
|
||||
): void {
|
||||
const fadeOutMs = 5;
|
||||
const fadeSamples = Math.floor((fadeOutMs / 1000) * sampleRate);
|
||||
const actualFadeSamples = Math.min(fadeSamples, leftChannel.length);
|
||||
const startSample = leftChannel.length - actualFadeSamples;
|
||||
|
||||
for (let i = 0; i < actualFadeSamples; i++) {
|
||||
const sampleIndex = startSample + i;
|
||||
const phase = i / actualFadeSamples;
|
||||
const gain = 0.5 + 0.5 * Math.cos(phase * Math.PI);
|
||||
leftChannel[sampleIndex] *= gain;
|
||||
rightChannel[sampleIndex] *= gain;
|
||||
}
|
||||
}
|
||||
|
||||
protected randomRange(min: number, max: number): number {
|
||||
return min + Math.random() * (max - min);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user