summaryrefslogtreecommitdiffstats
path: root/src/engine/Buffer.cpp
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2006-06-09 15:07:31 +0000
committerDavid Robillard <d@drobilla.net>2006-06-09 15:07:31 +0000
commitacbda29f838280ba98cf9e9e539e9d8a6e8fc6ad (patch)
treee31b37a2456e6d1e564c9a7146c88be259d338b0 /src/engine/Buffer.cpp
downloadingen-acbda29f838280ba98cf9e9e539e9d8a6e8fc6ad.tar.gz
ingen-acbda29f838280ba98cf9e9e539e9d8a6e8fc6ad.tar.bz2
ingen-acbda29f838280ba98cf9e9e539e9d8a6e8fc6ad.zip
Added Om aka Graph aka god knows what
git-svn-id: http://svn.drobilla.net/lad/grauph@9 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/engine/Buffer.cpp')
-rw-r--r--src/engine/Buffer.cpp297
1 files changed, 297 insertions, 0 deletions
diff --git a/src/engine/Buffer.cpp b/src/engine/Buffer.cpp
new file mode 100644
index 00000000..963b14a5
--- /dev/null
+++ b/src/engine/Buffer.cpp
@@ -0,0 +1,297 @@
+/* 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