Logo Search packages:      
Sourcecode: csound version File versions

doppler.cpp

#include <OpcodeBase.hpp>
#include <cmath>
#include <iostream>
#include <list>
#include <vector>

// Why not use the constants already defined?
static MYFLT pi = std::atan(1.0) * MYFLT(4.0);

00010 class RCLowpassFilter
{
public:
  void initialize(MYFLT sampleRate, MYFLT cutoffHz, MYFLT initialValue)
  {
    MYFLT tau = MYFLT(1.0) / (MYFLT(2.0) * pi * cutoffHz);
    alpha = MYFLT(1.0) / (MYFLT(1.0) + (tau * sampleRate));
    value = initialValue;
  }
  MYFLT update(MYFLT inputValue)
  {
    value += alpha * (inputValue - value);
    return value;
  }
protected:
  MYFLT alpha;
  MYFLT value;
};

00029 class LinearInterpolator
{
public:
  LinearInterpolator() :
    priorValue(MYFLT(0.0)),
    currentValue(MYFLT(0.0))
  {
  }
  virtual void put(MYFLT inputValue)
  {
    priorValue = currentValue;
    currentValue = inputValue;
  }
  virtual MYFLT get(MYFLT fraction)
  {
    return priorValue + (fraction * (currentValue - priorValue));
  }
protected:
  MYFLT priorValue;
  MYFLT currentValue;
};

00051 class DelayLine : public std::vector<MYFLT>
{
public:
  MYFLT sampleRate;
  int writingFrame;
  int size_;
  void initialize(size_t sampleRate_, MYFLT maximumDelay = 10.0)
  {
    sampleRate = (MYFLT) sampleRate_;
    size_ = (int) std::ceil(maximumDelay * sampleRate);
    std::cout << "DelayLine::initialize: size: " << size_ << std::endl;
    std::cout << "DelayLine::initialize: sampleRate: " << sampleRate << std::endl;
    resize(size_);
    writingFrame = 0;
  }
  void write(MYFLT value)
  {
    while (writingFrame >= size_) {
      writingFrame -= size_;
    }
    (*this)[(size_t) writingFrame] = value;
    //std::cout << "DelayLine::write: writingFrame: " << writingFrame << std::endl;
    writingFrame++;
  }
  MYFLT delaySeconds(MYFLT delaySeconds)
  {
    int delayFrames_ = (int) (delaySeconds * sampleRate);
    return delayFrames(delayFrames_);
  }
  MYFLT delayFrames(int delayFrames_)
  {
    //std::cout << "DelayLine::delayFrames: delayFrames: " << delayFrames_ << std::endl;
    int readingFrame = writingFrame - delayFrames_;
    while (readingFrame < 0) {
      readingFrame += size_;
    }
    while (readingFrame >= size_) {
      readingFrame -= size_;
    }
    // std::cout << "DelayLine::delayFrames: readingFrame: " << readingFrame << std::endl;
    return (*this)[(size_t) readingFrame];
  }
};

std::list<RCLowpassFilter *> smoothingFilterInstances;
std::list<DelayLine *> delayLineInstances;

00098 class Doppler : public OpcodeBase<Doppler>
{
public:
  // Csound opcode outputs.
  MYFLT *audioOutput;
  // Csound opcode inputs.
  MYFLT *audioInput;
  MYFLT *kSourcePosition;     // usually meters
  MYFLT *kMicPosition;        // usually meters
  MYFLT *jSpeedOfSound;       // usually meters/second
  MYFLT *jUpdateFilterCutoff; // Hz
  // Doppler internal state.
  MYFLT speedOfSound;         // usually meters/second
  MYFLT smoothingFilterCutoff;   // Hz
  MYFLT sampleRate;           // Hz
  MYFLT samplesPerDistance;   // usually samples/meter
  MYFLT blockRate;            // Hz
  int blockSize;              // samples
  RCLowpassFilter *smoothingFilter;
  LinearInterpolator *audioInterpolator;
  std::list< std::vector<MYFLT> *> *audioBufferQueue;
  std::list<MYFLT> *sourcePositionQueue;
  int relativeIndex;
  int currentIndex;

  int init(CSOUND *csound)
  {
    sampleRate = csound->GetSr(csound);
    blockSize = csound->GetKsmps(csound);
    blockRate = sampleRate / blockSize;
    // Take care of default values.
    if (*jSpeedOfSound == MYFLT(-1.0)) {
      *jSpeedOfSound = MYFLT(340.29);
    }
    speedOfSound = *jSpeedOfSound;
    if (*jUpdateFilterCutoff == MYFLT(-1.0)) {
//    MYFLT blockRateNyquist = blockRate / MYFLT(2.0);
//    *jUpdateFilterCutoff = blockRateNyquist / MYFLT(2.0);
      *jUpdateFilterCutoff = MYFLT(6.0); // very conservative
    }
    smoothingFilterCutoff = *jUpdateFilterCutoff;
    samplesPerDistance = sampleRate / speedOfSound;
    audioInterpolator = new LinearInterpolator;
    smoothingFilter = NULL;
    audioBufferQueue = new std::list< std::vector<MYFLT> *>;
    sourcePositionQueue = new std::list<MYFLT>;
    currentIndex = 0;
    relativeIndex = 0;
    return OK;
  }
  int kontrol(CSOUND *csound)
  {
    MYFLT sourcePosition = *kSourcePosition;
    MYFLT micPosition = *kMicPosition;

    std::vector<MYFLT> *sourceBuffer = new std::vector<MYFLT>;
    sourceBuffer->resize(blockSize);
    for (size_t inputFrame = 0; inputFrame < blockSize; inputFrame++) {
      (*sourceBuffer)[inputFrame] = audioInput[inputFrame];
    }
    audioBufferQueue->push_back(sourceBuffer);
    sourcePositionQueue->push_back(sourcePosition);

    std::vector<MYFLT> *currentBuffer = audioBufferQueue->front();
    MYFLT targetPosition = sourcePositionQueue->front() - micPosition;

    // The smoothing filter cannot be initialized at i-time,
    // because it must be initialized from a k-rate variable.
    if (!smoothingFilter) {
      smoothingFilter = new RCLowpassFilter();
      smoothingFilter->initialize(sampleRate, smoothingFilterCutoff, targetPosition);
      log(csound, "Doppler::kontrol: sizeof(MYFLT):         %10d\n", sizeof(MYFLT));
      log(csound, "Doppler::kontrol: PI:                    %10.3f\n", pi);
      log(csound, "Doppler::kontrol: this:                  %10p\n", this);
      log(csound, "Doppler::kontrol: sampleRate:            %10.3f\n", sampleRate);
      log(csound, "Doppler::kontrol: blockSize:             %10.3f\n", blockSize);
      log(csound, "Doppler::kontrol: blockRate:             %10.3f\n", blockRate);
      log(csound, "Doppler::kontrol: speedOfSound:          %10.3f\n", speedOfSound);
      log(csound, "Doppler::kontrol: samplesPerDistance:    %10.3f\n", samplesPerDistance);
      log(csound, "Doppler::kontrol: smoothingFilterCutoff: %10.3f\n", smoothingFilterCutoff);
      log(csound, "Doppler::kontrol: kMicPosition:          %10.3f\n", *kMicPosition);
      log(csound, "Doppler::kontrol: kSourcePosition:       %10.3f\n", *kSourcePosition);
    }

    for (size_t outputFrame = 0; outputFrame < blockSize; outputFrame++) {
      MYFLT position = smoothingFilter->update(targetPosition);
      MYFLT distance = std::fabs(position);
      MYFLT sourceTime = relativeIndex - (distance * samplesPerDistance);
      int targetIndex = int(sourceTime);
      MYFLT fraction = sourceTime - targetIndex;
      relativeIndex++;
      for ( ; targetIndex >= currentIndex; currentIndex++) {
        if (currentIndex >= blockSize) {
          relativeIndex -= blockSize;
          currentIndex -= blockSize;
          targetIndex -= blockSize;
                delete audioBufferQueue->front();
          audioBufferQueue->pop_front();
          sourcePositionQueue->pop_front();
          currentBuffer = audioBufferQueue->front();
          targetPosition = sourcePositionQueue->front() - micPosition;
        }
        audioInterpolator->put((*currentBuffer)[currentIndex]);
      }
      MYFLT currentSample = audioInterpolator->get(fraction);
      audioOutput[outputFrame] = currentSample;
    }
    return OK;
  }
};

#ifdef NEVER
struct Doppler2 : public OpcodeBase<Doppler2>
{
  // Csound opcode outputs.
  MYFLT *audioOutput;
  // Csound opcode inputs.
  MYFLT *audioInput;
  MYFLT *kSourcePosition;
  MYFLT *kMicPosition;
  MYFLT *jSpeedOfSound;
  MYFLT *jUpdateFilterCutoff;
  // Doppler internal state.
  MYFLT speedOfSound;
  MYFLT smoothingFilterCutoff;
  MYFLT sampleRate;
  MYFLT samplesPerDistance;
  MYFLT blockSize;
  MYFLT blockRate;
  RCLowpassFilter *smoothingFilter;
  LinearInterpolator *audioInterpolator;
  DelayLine *delayLine;
  int init(CSOUND *csound)
  {
    sampleRate = csound->GetSr(csound);
    blockSize = csound->GetKsmps(csound);
    blockRate = sampleRate / blockSize;
    // Take care of default values.
    if (*jSpeedOfSound == MYFLT(-1.0)) {
      *jSpeedOfSound = MYFLT(340.29);
    }
    speedOfSound = *jSpeedOfSound;
    if (*jUpdateFilterCutoff == MYFLT(-1.0)) {
      MYFLT blockRateNyquist = blockRate / MYFLT(2.0);
      *jUpdateFilterCutoff = blockRateNyquist / MYFLT(2.0);
    }
    smoothingFilterCutoff = *jUpdateFilterCutoff;
    samplesPerDistance = sampleRate / speedOfSound;
    audioInterpolator = new LinearInterpolator;
    // The smoothing filter cannot be initialized at i-time,
    // because it must be initialized from a k-rate variable.
    smoothingFilter = 0;
    delayLine = new DelayLine;
    return OK;
  }
  int kontrol(CSOUND *csound)
  {
    MYFLT sourcePosition = *kSourcePosition;
    MYFLT micPosition = *kMicPosition;
    MYFLT position = sourcePosition - micPosition;
    // On the very first block only, initialize the smoothing filter.
    if (!smoothingFilter) {
      smoothingFilter = new RCLowpassFilter();
      smoothingFilter->initialize(sampleRate, smoothingFilterCutoff, *kSourcePosition);
      log(csound, "Doppler::kontrol: sizeof(MYFLT):                  %10d\n", sizeof(MYFLT));
      log(csound, "Doppler::kontrol: PI:                             %10.3f\n", pi);
      log(csound, "Doppler::kontrol: this:                           %10p\n", this);
      log(csound, "Doppler::kontrol: sampleRate:                       %10.3f\n", sampleRate);
      log(csound, "Doppler::kontrol: blockSize:                 %10.3f\n", blockSize);
      log(csound, "Doppler::kontrol: blockRate:                       %10.3f\n", blockRate);
      log(csound, "Doppler::kontrol: speedOfSound:           %10.3f\n", speedOfSound);
      log(csound, "Doppler::kontrol: samplesPerDistance:                 %10.3f\n", samplesPerDistance);
      log(csound, "Doppler::kontrol: smoothingFilterCutoff:  %10.3f\n", smoothingFilterCutoff);
      log(csound, "Doppler::kontrol: kMicPosition:             %10.3f\n", *kMicPosition);
      log(csound, "Doppler::kontrol: kSourcePosition:          %10.3f\n", *kSourcePosition);
      delayLine->initialize(sampleRate, 10.0);
    }
    for (size_t frame = 0; frame < blockSize; frame++) {
      delayLine->write(audioInput[frame]);
      MYFLT distance = std::fabs(position);
      MYFLT delayFrames = distance * samplesPerDistance;
      MYFLT delayFramesFloor = int(delayFrames);
      MYFLT fraction = delayFrames - delayFramesFloor;
      MYFLT currentValue = delayLine->delayFrames((int) delayFrames);
      audioInterpolator->put(currentValue);
      currentValue = audioInterpolator->get(fraction);
      position = smoothingFilter->update(position);
      audioOutput[frame] = currentValue;
    }
    return OK;
  }
};
#endif


extern "C"
{
  OENTRY oentries[] =
    {
      {
        (char*)"doppler",
        sizeof(Doppler),
        3,
        (char*)"a",
        (char*)"akkjj",
        (SUBR) Doppler::init_,
        (SUBR) Doppler::kontrol_,
        0,
      },
#ifdef NEVER
      {
        (char*)"doppler2",
        sizeof(Doppler2),
        3,
        (char*)"a",
        (char*)"akkjj",
        (SUBR) Doppler2::init_,
        (SUBR) Doppler2::kontrol_,
        0,
      },
#endif
      {
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
      }
    };

  PUBLIC int csoundModuleCreate(CSOUND *csound)
  {
    return 0;
  }

  PUBLIC int csoundModuleInit(CSOUND *csound)
  {
    int status = 0;
    for(OENTRY *oentry = &oentries[0]; oentry->opname; oentry++)
      {
        status |= csound->AppendOpcode(csound, oentry->opname,
                                       oentry->dsblksiz, oentry->thread,
                                       oentry->outypes, oentry->intypes,
                                       (int (*)(CSOUND*,void*)) oentry->iopadr,
                                       (int (*)(CSOUND*,void*)) oentry->kopadr,
                                       (int (*)(CSOUND*,void*)) oentry->aopadr);
      }
    return status;
  }

  PUBLIC int csoundModuleDestroy(CSOUND *csound)
  {
    //csound->Message(csound, "Deleting C++ objects from doppler...\n");
    for (std::list<RCLowpassFilter *>::iterator it = smoothingFilterInstances.begin();
         it != smoothingFilterInstances.end();
         ++it) {
      delete *it;
    }
    smoothingFilterInstances.clear();
    for (std::list<DelayLine *>::iterator it = delayLineInstances.begin();
         it != delayLineInstances.end();
         ++it) {
      delete *it;
    }
    delayLineInstances.clear();
    return 0;
  }
}


Generated by  Doxygen 1.6.0   Back to index