thestk / stk

The Synthesis ToolKit in C++ (STK) is a set of open source audio signal processing and algorithmic synthesis classes written in the C++ programming language.
https://ccrma.stanford.edu/software/stk/
Other
1.02k stars 180 forks source link

Add StkFrames constructor that wraps pointer to existing buffer #108

Closed vuki closed 3 years ago

vuki commented 3 years ago

Adds new constructor to StkFrames class that takes a pointer to an existing StkFloat buffer and wraps it into the StkFrames object. This is useful in frameworks that provide a buffer that needs to be filled with samples. Wrapping the buffer pointer in StkFrames class allows sending the buffer directly into Stk objects, without need for data copying. A single tick invocation is needed to fill the buffer instead of calling tick for each sample.

For example, the callback function in crtsine.cpp may be written as:

int tick( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
         double streamTime, RtAudioStreamStatus status, void *dataPointer )
{
  SineWave *sine = (SineWave *) dataPointer;
  register StkFloat *samples = (StkFloat *) outputBuffer;

#if 1 // new version
  StkFrames wrapper(samples, nBufferFrames, 1);
  sine->tick(wrapper);
#else // original version
  for ( unsigned int i=0; i<nBufferFrames; i++ )
    *samples++ = sine->tick();
#endif

  return 0;
}

Test code:

#include <iostream>
#include "Stk.h"

void main() {
  // data buffer
  StkFloat buffer[10];
  // wrap the buffer in StkFrames structure
  StkFrames* wrapper = new StkFrames(buffer, 10);
  // write to the wrapper
  (*wrapper)[0] = 1.1;
  std::cout << buffer[0] << " " << (*wrapper)[0] << std::endl;
  // write to the original buffer
  buffer[1] = 2.2;
  std::cout << buffer[1] << " " << (*wrapper)[1] << std::endl;
  // delete the wrapper
  delete wrapper;
  // verify the buffer
  std::cout << buffer[0] << " " << buffer[1] << std::endl;
}

Result:

1.1 1.1
2.2 2.2
1.1 2.2
garyscavone commented 3 years ago

There is some danger here, since we are unable to know if the buffer pointer is valid and of the specified length.

Off the top of my head, what about using some sort of static routines that achieve the same thing?

vuki commented 3 years ago

Sure, there is some danger, but it is programmer's responsibility to provide correct data. If the length and channel number provided in the constructor are valid and the pointer is not deallocated somewhere else, I think it is safe. I made this PR with intention of creating short-time wrappers, mostly for use in callbacks, such as the one required by RtAudio. I don't know how to achieve the same effect other way, without unnecessary data copying..