ladish/grauph/src/libs/engine/Buffer.cpp

298 lines
7.4 KiB
C++

/* This file is part of Om. Copyright (C) 2006 Dave Robillard.
*
* Om is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* Om is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Buffer.h"
#include <iostream>
#include <cassert>
#include <stdlib.h>
#include "MidiMessage.h"
using std::cerr; using std::endl;
/* TODO: Be sure these functions are vectorized by GCC when it's vectorizer
* stops sucking. Probably a good idea to inline them as well */
namespace Om {
template <typename T>
Buffer<T>::Buffer(size_t size)
: m_size(size),
m_filled_size(0),
m_is_joined(false),
m_state(OK),
m_set_value(0),
m_data(NULL),
m_local_data(NULL)
{
assert(m_size > 0);
allocate();
}
template Buffer<sample>::Buffer(size_t size);
template Buffer<MidiMessage>::Buffer(size_t size);
/** Allocate and use a locally managed buffer (data).
*/
template<typename T>
void
Buffer<T>::allocate()
{
assert(!m_is_joined);
assert(m_data == NULL);
assert(m_local_data == NULL);
assert(m_size > 0);
const int ret = posix_memalign((void**)&m_local_data, 16, m_size * sizeof(T));
if (ret != 0) {
cerr << "[Buffer] Failed to allocate buffer. Aborting." << endl;
exit(EXIT_FAILURE);
}
assert(ret == 0);
assert(m_local_data != NULL);
m_data = m_local_data;
set(0, 0, m_size-1);
}
template void Buffer<sample>::allocate();
template void Buffer<MidiMessage>::allocate();
/** Free locally allocated buffer.
*/
template<typename T>
void
Buffer<T>::deallocate()
{
assert(!m_is_joined);
free(m_local_data);
if (m_data == m_local_data)
m_data = NULL;
m_local_data = NULL;
}
template void Buffer<sample>::deallocate();
template void Buffer<MidiMessage>::deallocate();
/** Empty (ie zero) the buffer.
*/
template<typename T>
void
Buffer<T>::clear()
{
set(0, 0, m_size-1);
m_state = OK;
m_filled_size = 0;
}
template void Buffer<sample>::clear();
template void Buffer<MidiMessage>::clear();
/** Set value of buffer to @a val after @a start_sample.
*
* The Buffer will handle setting the intial portion of the buffer to the
* value on the next cycle automatically (if @a start_sample is > 0), as
* long as pre_process() is called every cycle.
*/
template <typename T>
void
Buffer<T>::set(T val, size_t start_sample)
{
assert(start_sample < m_size);
set(val, start_sample, m_size-1);
if (start_sample > 0)
m_state = HALF_SET_CYCLE_1;
m_set_value = val;
}
template void Buffer<sample>::set(sample val, size_t start_sample);
template void Buffer<MidiMessage>::set(MidiMessage val, size_t start_sample);
/** Set a block of buffer to @a val.
*
* @a start_sample and @a end_sample define the inclusive range to be set.
*/
template <typename T>
void
Buffer<T>::set(T val, size_t start_sample, size_t end_sample)
{
assert(start_sample >= 0);
assert(end_sample >= start_sample);
assert(end_sample < m_size);
assert(m_data != NULL);
for (size_t i=start_sample; i <= end_sample; ++i)
m_data[i] = val;
}
template void Buffer<sample>::set(sample val, size_t start_sample, size_t end_sample);
template void Buffer<MidiMessage>::set(MidiMessage val, size_t start_sample, size_t end_sample);
/** Scale a block of buffer by @a val.
*
* @a start_sample and @a end_sample define the inclusive range to be set.
*/
template <typename T>
void
Buffer<T>::scale(T val, size_t start_sample, size_t end_sample)
{
assert(start_sample >= 0);
assert(end_sample >= start_sample);
assert(end_sample < m_size);
assert(m_data != NULL);
for (size_t i=start_sample; i <= end_sample; ++i)
m_data[i] *= val;
}
template void Buffer<sample>::scale(sample val, size_t start_sample, size_t end_sample);
/** Copy a block of @a src into buffer.
*
* @a start_sample and @a end_sample define the inclusive range to be set.
* This function only copies the same range in one buffer to another.
*/
template <typename T>
void
Buffer<T>::copy(const Buffer<T>* src, size_t start_sample, size_t end_sample)
{
assert(start_sample >= 0);
assert(end_sample >= start_sample);
assert(end_sample < m_size);
assert(src != NULL);
assert(src->data() != NULL);
assert(m_data != NULL);
const T* const src_data = src->data();
for (size_t i=start_sample; i <= end_sample; ++i)
m_data[i] = src_data[i];
}
template void Buffer<sample>::copy(const Buffer<sample>* const src, size_t start_sample, size_t end_sample);
template void Buffer<MidiMessage>::copy(const Buffer<MidiMessage>* const src, size_t start_sample, size_t end_sample);
/** Accumulate a block of @a src into @a dst.
*
* @a start_sample and @a end_sample define the inclusive range to be accumulated.
* This function only adds the same range in one buffer to another.
*/
template <typename T>
void
Buffer<T>::accumulate(const Buffer<T>* const src, size_t start_sample, size_t end_sample)
{
assert(start_sample >= 0);
assert(end_sample >= start_sample);
assert(end_sample < m_size);
assert(src != NULL);
assert(src->data() != NULL);
assert(m_data != NULL);
const T* const src_data = src->data();
for (size_t i=start_sample; i <= end_sample; ++i)
m_data[i] += src_data[i];
}
template void Buffer<sample>::accumulate(const Buffer<sample>* const src, size_t start_sample, size_t end_sample);
/** Use another buffer's data instead of the local one.
*
* This buffer will essentially be identical to @a buf after this call.
*/
template<typename T>
void
Buffer<T>::join(Buffer<T>* buf)
{
assert(buf->size() == m_size);
m_data = buf->m_data;
m_filled_size = buf->filled_size();
m_is_joined = true;
assert(m_filled_size <= m_size);
}
template void Buffer<sample>::join(Buffer<sample>* buf);
template void Buffer<MidiMessage>::join(Buffer<MidiMessage>* buf);
template<typename T>
void
Buffer<T>::unjoin()
{
m_is_joined = false;
m_data = m_local_data;
}
template void Buffer<sample>::unjoin();
template void Buffer<MidiMessage>::unjoin();
template<>
void
Buffer<sample>::prepare(samplecount nframes)
{
// FIXME: nframes parameter doesn't actually work,
// writing starts from 0 every time
assert(m_size == 1 || nframes == m_size);
switch (m_state) {
case HALF_SET_CYCLE_1:
m_state = HALF_SET_CYCLE_2;
break;
case HALF_SET_CYCLE_2:
set(m_set_value, 0, m_size-1);
m_state = OK;
break;
default:
break;
}
}
////// DriverBuffer ////////
template <typename T>
DriverBuffer<T>::DriverBuffer(size_t size)
: Buffer<T>(size)
{
Buffer<T>::deallocate(); // FIXME: allocate then immediately deallocate, dirty
Buffer<T>::m_data = NULL;
}
template DriverBuffer<sample>::DriverBuffer(size_t size);
template DriverBuffer<MidiMessage>::DriverBuffer(size_t size);
/** Set the buffer (data) used.
*
* This is only to be used by Drivers (to provide zero-copy processing).
*/
template<typename T>
void
DriverBuffer<T>::set_data(T* data)
{
assert(!m_is_joined);
m_data = data;
}
template void DriverBuffer<sample>::set_data(sample* data);
template void DriverBuffer<MidiMessage>::set_data(MidiMessage* data);
} // namespace Om