I'm trying to make a vibrato effect on nodejs:

const INTERPOLATOR_MARGIN = 3
const ADDITIONAL_DELAY = 3
const BASE_DELAY_SEC = 0.002
const VIBRATO_FREQUENCY_DEFAULT_HZ = 2
const VIBRATO_FREQUENCY_MAX_HZ = 14
const VIBRATO_DEPTH_DEFAULT_PERCENT = 50

class ChannelProcessor {
  constructor(data, type) {
    this.type = type

    switch (type) {
      case constants.filtering.types.equalizer: {
        this.history = new Array(constants.filtering.equalizerBands * 6).fill(0)
        this.bandMultipliers = data
        this.current = 0
        this.minus1 = 2
        this.minus2 = 1

        break
      }
      case constants.filtering.types.tremolo: {
        this.frequency = data.frequency
        this.depth = data.depth
        this.phase = 0

        break
      }
      case constants.filtering.types.rotationHz: {
        this.phase = 0
        this.rotationStep = (constants.circunferece.diameter * data.rotationHz) / constants.opus.samplingRate

        break
      }
      case constants.filtering.types.vibrato: {
        this.lfoPhase = 0;
        this.lfoFrequency = data.frequency || VIBRATO_FREQUENCY_DEFAULT_HZ;
        this.depth = data.depth || 0.5; // Already normalized between 0 and 1.
        this.baseDelaySamples = BASE_DELAY_SEC * constants.opus.samplingRate;
        this.bufferSize = Math.ceil(this.baseDelaySamples) + ADDITIONAL_DELAY + INTERPOLATOR_MARGIN;
        this.delayBufferL = new Float32Array(this.bufferSize);
        this.delayBufferR = new Float32Array(this.bufferSize);
        this.writeIndex = 0;
        break;
      }
// …rest of the filter types…
    }
  }

  processEqualizer(band) {
    let processedBand = band * 0.25

    for (let bandIndex = 0; bandIndex < constants.filtering.equalizerBands; bandIndex++) {
      const coefficient = constants.sampleRate.coefficients[bandIndex]

      const x = bandIndex * 6
      const y = x + 3

      const bandResult = coefficient.alpha * (band - this.history[x + this.minus2]) + coefficient.gamma * this.history[y + this.minus1] - coefficient.beta * this.history[y + this.minus2]

      this.history[x + this.current] = band
      this.history[y + this.current] = bandResult

      processedBand += bandResult * this.bandMultipliers[bandIndex]
    }

    return processedBand * 4
  }

  processTremolo(sample) {
    const lfo = Math.sin(constants.circunferece.diameter * this.frequency * this.phase / constants.opus.samplingRate)
    const newAmplitude = sample * ((1 - this.depth) + this.depth * lfo)

    if (this.phase >= constants.opus.samplingRate / this.frequency) this.phase = 0
    else this.phase += 1

    return newAmplitude
  }

  processRotationHz(leftSample, rightSample) {
    const panning = Math.sin(this.phase)
  
    const leftMultiplier = panning <= 0 ? 1 : 1 - panning
    const rightMultiplier = panning >= 0 ? 1 : 1 + panning
  
    this.phase += this.rotationStep
    if (this.phase > constants.circunferece.diameter)
      this.phase -= constants.circunferece.diameter
  
    return {
      left: leftSample * leftMultiplier,
      right: rightSample * rightMultiplier
    }
  }

  applyVibrato(sample, delayBuffer) {
    // Store the incoming sample in the delay buffer
    delayBuffer[this.writeIndex] = sample;

    // Calculate the delay for the current sample
    const lfoValue = Math.sin(this.lfoPhase * 2 * Math.PI * this.lfoFrequency / this.sampleRate);
    this.lfoPhase += (1 / this.sampleRate);
    if (this.lfoPhase > 1) this.lfoPhase -= 1;
    const currentDelay = this.baseDelaySamples + ADDITIONAL_DELAY + (lfoValue * this.depth * this.baseDelaySamples);

    // Calculate read position
    let readPos = this.writeIndex - Math.floor(currentDelay);
    if (readPos < 0) readPos += this.bufferSize; // wraparound for negative indices
    const fracDelay = currentDelay % 1; // the fractional part of the delay

    // Interpolation
    const interpolatedSample = this.hermiteInterpolate(delayBuffer, readPos, fracDelay);

    // Advance the write index for the next call
    this.writeIndex = (this.writeIndex + 1) % this.bufferSize;

    // Return the interpolated sample
    return interpolatedSample;
  }

  hermiteInterpolate(buffer, position, fractional) {
    // Define local function to handle wrapping of indices
    const wrapIndex = (i) => (i + this.bufferSize) % this.bufferSize;

    // Get surrounding samples for interpolation, taking into account buffer wrap
    const xm1 = buffer[wrapIndex(position - 1)];
    const x0 = buffer[position]; // current sample
    const x1 = buffer[wrapIndex(position + 1)];
    const x2 = buffer[wrapIndex(position + 2)];

    // Compute Hermite coefficients
    const c0 = x0;
    const c1 = 0.5 * (x1 - xm1);
    const c2 = xm1 - (2.5 * x0) + (2 * x1) - (0.5 * x2);
    const c3 = 0.5 * (x2 - xm1) + (1.5 * (x0 - x1));

    // The interpolation polynomial
    return (((c3 * fractional + c2) * fractional + c1) * fractional + c0);
  }

  process(samples) {
    const bytes = constants.pcm.bytes

    for (let i = 0; i < samples.length - bytes; i += bytes * 2) {
      const sample = samples.readInt16LE(i)
      let result = null
      
      switch (this.type) {
        case constants.filtering.types.equalizer: {
          result = this.processEqualizer(sample)

          if (this.current++ == 3) this.current = 0
          if (this.minus1++ == 3) this.minus1 = 0
          if (this.minus2++ == 3) this.minus2 = 0

          break
        }
        case constants.filtering.types.tremolo: {
          result = this.processTremolo(sample)

          break
        }
        case constants.filtering.types.rotationHz: {
          const rightSample = samples.readInt16LE(i + 2)
          const { left, right } = this.processRotationHz(sample, rightSample)

          samples.writeInt16LE(clamp16Bit(left), i)
          samples.writeInt16LE(clamp16Bit(right), i + 2)

          break
        }
        case constants.filtering.types.vibrato: {
          const sampleL = samples.readInt16LE(i);
          const sampleR = samples.readInt16LE(i + 2);

          const processedSampleL = this.applyVibrato(sampleL, this.delayBufferL);
          const processedSampleR = this.applyVibrato(sampleR, this.delayBufferR);

      samples.writeInt16LE(clamp16Bit(processedSampleL), i);
      samples.writeInt16LE(clamp16Bit(processedSampleR), i + 2);

          break
        }
      }

      if (this.type != constants.filtering.types.rotationHz && this.type != constants.filtering.types.vibrato)
        samples.writeInt16LE(clamp16Bit(result), i)
    }

    return samples
  }
}

Based on a java code:

package com.github.natanbc.lavadsp.vibrato;

import com.github.natanbc.lavadsp.Converter;

public class VibratoConverter implements Converter {
    private static final int ADDITIONAL_DELAY = 3;
    private static final float BASE_DELAY_SEC = 0.002f; // 2 ms
    private static final float VIBRATO_FREQUENCY_DEFAULT_HZ = 2;
    private static final float VIBRATO_FREQUENCY_MAX_HZ = 14;
    private static final float VIBRATO_DEPTH_DEFAULT_PERCENT = 50;
    
    private final float sampleRate;
    private final Lfo lfo;
    private final RingBuffer buffer;
    private float depth = VIBRATO_DEPTH_DEFAULT_PERCENT / 100;
    
    public VibratoConverter(int sampleRate) {
        if(sampleRate < 1) {
            throw new IllegalArgumentException("Sample rate < 1");
        }
        this.sampleRate = sampleRate;
        this.lfo = new Lfo(sampleRate);
        this.buffer = new RingBuffer((int)(BASE_DELAY_SEC * sampleRate * 2));
    }
    
    public void setDepth(float depth) {
        if(depth <= 0) {
            throw new IllegalArgumentException("Depth <= 0");
        }
        if(depth > 1) {
            throw new IllegalArgumentException("Depth > 1");
        }
        this.depth = depth;
    }
    
    public void setFrequency(float frequency) {
        if(frequency <= 0) {
            throw new IllegalArgumentException("Frequency <= 0");
        }
        if(frequency > VIBRATO_FREQUENCY_MAX_HZ) {
            throw new IllegalArgumentException("Frequency > max (" + VIBRATO_FREQUENCY_MAX_HZ + ")");
        }
        lfo.frequency = frequency;
    }
    
    @Override
    public void process(float[] input, int inputOffset, float[] output, int outputOffset, int samples) {
        for(int i = 0; i < samples; i++) {
            float lfoValue = lfo.getValue();
            int maxDelay = (int)(BASE_DELAY_SEC * sampleRate);
    
            float delay = lfoValue * depth * maxDelay + ADDITIONAL_DELAY;
    
            output[outputOffset + i] = buffer.getHermiteAt(delay);
    
            buffer.writeMargined(input[inputOffset + i]);
        }
    }
    
    private static class Lfo {
        private final float sampleRate;
        float frequency = VIBRATO_FREQUENCY_DEFAULT_HZ;
        float phase;
    
        Lfo(float sampleRate) {
            this.sampleRate = sampleRate;
        }
        
        float getValue() {
            float dp = 2 * (float)Math.PI * frequency / sampleRate;
            float value = (float)((Math.sin(phase) + 1) * 0.5);
            phase += dp;
            while(phase > 2 * Math.PI) {
                phase -= 2 * Math.PI;
            }
            return value;
        }
    }
    
    private static class RingBuffer {
        private static final int INTERPOLATOR_MARGIN = 3;
        
        private final float[] buffer;
        private final int size;
        private int writeIndex;
        
        RingBuffer(int size) {
            this.buffer = new float[size + INTERPOLATOR_MARGIN];
            this.size = size;
        }
        
        void writeMargined(float sample) {
            buffer[writeIndex] = sample;
    
            if(writeIndex < INTERPOLATOR_MARGIN) {
                buffer[size + writeIndex] = sample;
            }
    
            writeIndex++;
            if(writeIndex == size){
                writeIndex = 0;
            }
        }
    
        float getHermiteAt(float delay) {
            float fReadIndex = writeIndex - 1 - delay;
            while(fReadIndex < 0) {
                fReadIndex += size;
            }
            while(fReadIndex >= size) {
                fReadIndex -= size;
            }
        
            int iPart = (int)fReadIndex; // integer part of the delay
            float fPart = fReadIndex - iPart; // fractional part of the delay
    
            return getSampleHermite4p3o(fPart, buffer, iPart);
        }
        
        // Hermite polynomial interpolation
        // 4-point, 3rd-order Hermite (x-form)
        private static float getSampleHermite4p3o(float x, float[] buffer, int offset) {
            float y0 = buffer[offset];
            float y1 = buffer[offset + 1];
            float y2 = buffer[offset + 2];
            float y3 = buffer[offset + 3];
        
            //c0 = y[1];
            //c1 = (1.0/2.0)*(y[2]-y[0]);
            float c1 = (1f / 2f) * (y2 - y0);
            //c2 = (y[0] - (5.0/2.0)*y[1]) + (2.0*y[2] - (1.0/2.0)*y[3]);
            float c2 = (y0 - (5f / 2f) * y1) + (2f * y2 - (1f / 2f) * y3);
            //c3 = (1.0/2.0)*(y[3]-y[0]) + (3.0/2.0)*(y[1]-y[2]);
            float c3 = (1f / 2f) * (y3 - y0) + (3f / 2f) * (y1 - y2);
            return ((c3 * x + c2) * x + c1) * x + y1;
        }
    }
}

However, it doesn't end up having the same effect, it's way different, could you help me make it the same?