breakfastquay / rubberband

Official mirror of Rubber Band Library, an audio time-stretching and pitch-shifting library.
http://breakfastquay.com/rubberband/
GNU General Public License v2.0
566 stars 91 forks source link

Segmentation fault #44

Closed FadyQJ closed 3 years ago

FadyQJ commented 3 years ago

Due to lack of enough documentation, I'm stuck at a simple task. I am using Un4seen Bass and I want to use rubberband to change the tempo of my channel data. My channel data is interleaved so I am using this code but I get segmentation fault at the process function. I may be missing some trivial thing here but I am trying to understand how to use the library.

std::vector<float> Source::_setTempo(std::vector<float> data, double range, double targetRange) {
  double rangePerc = (range / targetRange);
  stretcher.setTimeRatio(rangePerc);

  std::vector<float *> processData(2); // @todo channel count
  processData[0] = new float[data.size() / 2];
  processData[1] = new float[data.size() / 2];
  for (int i = 0; i < data.size(); ++i) { // data here is the interleaved data from Bass library
    if (i % 2 == 0) {
      processData[0][i/2] = data[i];
    } else {
      processData[1][i/2] = data[i];
    }
  }

  float *const *samples;
  stretcher.process(processData.data(), 44100, false);
  int size = stretcher.retrieve(samples, 44100);

  std::vector<float> result(size * 2);
  for (int i = 0; i < result.size(); ++i) {
    if (i % 2 == 0) {
      result[i] = samples[0][i/2];
    } else {
      result[i] = samples[1][i/2];
    }
  }

  return result;
}
FadyQJ commented 3 years ago

stretcher.process(processData.data(), 44100, false); -> second argument is not sample rate but buffer length same for retreive The code ended up looking like this

std::vector<float> Source::_setTempo(std::vector<float> data, double range, double targetRange) {
  std::lock_guard<std::mutex> guard(_mutex);

  _stretcher.reset();
  _stretcher.setTimeRatio(ratio);
  int len = data.size() / 2;

  float **processData = new float*[2]; // @todo channel count
  processData[0] = new float[len];
  processData[1] = new float[len];
  for (int i = 0; i < data.size(); ++i) {
    if (i % 2 == 0) {
      processData[0][i/2] = data[i];
    } else {
      processData[1][i/2] = data[i];
    }
  }
  _stretcher.process(processData, len , false);

  float **samples = new float*[2]; // @todo channel count
  samples[0] = new float[len];
  samples[1] = new float[len];

  long processedLen = 0;
  while (_stretcher.available() != 0) {
    long lenOutput = _stretcher.available();
    if (processedLen + lenOutput >= len) {
      lenOutput = len - processedLen;
    }

    if (lenOutput <= 0) {
      break;
    }

    // we need to provide to _stretcher.retrieve a pointer to the offset of output location
    float **lenOutputPtrs = new float*[2]; // @todo channel count
    lenOutputPtrs[0] = samples[0] + processedLen;
    lenOutputPtrs[1] = samples[1] + processedLen;

    _stretcher.retrieve(lenOutputPtrs, lenOutput);
    processedLen += lenOutput;
  }

  std::vector<float> result(data.size());
  for (int i = 0; i < len; i++) {
    result[i * 2] = samples[0][i];
    result[i * 2 + 1] = samples[1][i];
  }

  delete samples[0];
  delete samples[1];
  delete samples;
  return result;
}