AudioSampleBufferArray template class (source provided)


#1

If you like to do arithmetic on audio buffers, advancing them forward, rewinding, and what not, this class is for you. It uses a template to wrap a fixed number of audio channel buffer pointers. The class has conversions from AudioSampleBuffer, AudioSourceChannelInfo, and raw arrays, so you can do simple assignments from the common Juce types and from within standard callbacks like getNextAudioBlock().

The class is extremely lightweight, copyable,
Here it is

// lightweight object to track an adjustable array of pointers to audio data.
template <int Channels = 2>
class AudioSampleBufferArray
{
public:
  // if AudioSampleBuffer ever becomes a template, we can
  // move this typedef into the template parameters.
  typedef float Sample;

  AudioSampleBufferArray ()
    : m_numSamples (0)
  {
  }

  AudioSampleBufferArray (int numSamples, Sample* const* channels)
  {
    setFrom (numSamples, channels);
  }

  AudioSampleBufferArray (const AudioSampleBufferArray& other)
  {
    setFrom (other);
  }

  AudioSampleBufferArray (const AudioSampleBuffer& buffer, int offset = 0, int numSamples = -1)
  {
    setFrom (buffer, offset, numSamples);
  }

  AudioSampleBufferArray (const AudioSourceChannelInfo& bufferToFill)
  {
    setFrom (*bufferToFill.buffer, bufferToFill.startSample, bufferToFill.numSamples);
  }

  operator AudioSampleBuffer()
  {
    return AudioSampleBuffer (m_channels, Channels, m_numSamples);
  }

  operator const AudioSampleBuffer() const
  {
    return AudioSampleBuffer (m_channels, Channels, m_numSamples);
  }

  void setFrom (int numSamples, Sample* const* channels)
  {
    m_numSamples = numSamples;
    for (int i=0; i<Channels; i++)
      m_channels[i]=channels[i];
  }

  void setFrom (const AudioSampleBufferArray& other)
  {
    m_numSamples = other.m_numSamples;
    for (int i=0; i<Channels; i++)
      m_channels[i] = other.m_channels[i];
  }

  void setFrom (const AudioSampleBuffer& buffer, int offset = 0, int numSamples = -1)
  {
    jassert (buffer.getNumChannels() == Channels);
    jassert (offset >= 0 && offset <= buffer.getNumSamples());
    if (numSamples == -1)
      numSamples = buffer.getNumSamples() - offset;
    jassert (numSamples <= buffer.getNumSamples() - offset);
    m_numSamples = numSamples;
    for (int i = 0; i < Channels; ++i)
      m_channels[i] = buffer.getArrayOfChannels()[i] + offset;
  }

  AudioSampleBufferArray& operator= (const AudioSampleBuffer& buffer)
  {
    setFrom (buffer);
    return *this;
  }

  AudioSampleBufferArray& operator= (const AudioSampleBufferArray& other)
  {
    setFrom (other);
    return *this;
  }

  AudioSampleBufferArray& operator= (const AudioSourceChannelInfo& bufferToFill)
  {
    setFrom (bufferToFill);
    return *this;
  }

  AudioSampleBufferArray operator+ (int numSamples)
  {
    jassert (numSamples <= m_numSamples);
    Sample* channels[Channels];
    for (int i=0; i<Channels; i++)
      channels[i] = m_channels[i] + numSamples;
    return AudioSampleBufferArray (m_numSamples - numSamples, channels);
  }

  AudioSampleBufferArray operator- (int numSamples)
  {
    return operator+ (-numSamples);
  }

  AudioSampleBufferArray& operator+= (int numSamples)
  {
    *this = *this + numSamples;
    return *this;
  }

  AudioSampleBufferArray& operator-= (int numSamples)
  {
    return operator+= (-numSamples);
  }

  bool isEmpty () const
  {
    return m_numSamples <= 0;
  }

  Sample* const* pair() const
  {
    return m_channels;
  }

  operator Sample* const* () const
  {
    return m_channels;
  }

  Sample* const* operator()() const
  {
    return m_channels;
  }

  Sample* operator[] (int index)
  {
    jassert (index >= 0 && index < Channels);
    return m_channels[index];
  }

  const Sample* operator[] (int index) const
  {
    jassert (index >= 0 && index < Channels);
    return m_channels[index];
  }

  int getNumSamples () const
  {
    return m_numSamples;
  }

private:
  int m_numSamples;
  Sample* m_channels[Channels];
};

typedef AudioSampleBufferArray<2> StereoSampleBuffer;

Usage example

    void filterAudio (AudioSampleBuffer& buffer)
    {
      // conversion from AudioSampleBuffer;
      StereoSampleBuffer dest (buffer);

      // manipulate dest.getArrayOfChannels()
    }

    void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill)
    {
      // automatically respects bufferToFill.startSample and bufferToFill.numSamples
      StereoSampleBuffer outputBuffer (bufferToFill);

      int numSamplesToProcess = 64;

      // access outputBuffer.getArrayOfChannels()

      // advance outputBuffer
      outputBuffer += numSamplesToProcess;

      // conversion to AudioSampleBuffer
      filterAudio (outputBuffer);
    }

#2

AudioSampleBufferArray is now provided in the vf_audio module of VFLib. There’s also AudioSampleBufferPool and a ScopedAudioSampleBuffer for efficiently managing temporary audio buffers in your AudioDeviceIOCallback: