diff options
Diffstat (limited to 'src/engine/BufferFactory.cpp')
-rw-r--r-- | src/engine/BufferFactory.cpp | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/engine/BufferFactory.cpp b/src/engine/BufferFactory.cpp new file mode 100644 index 00000000..63fd31ae --- /dev/null +++ b/src/engine/BufferFactory.cpp @@ -0,0 +1,124 @@ +/* This file is part of Ingen. + * Copyright (C) 2007-2009 Dave Robillard <http://drobilla.net> + * + * Ingen 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. + * + * Ingen 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., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <algorithm> +#include <iostream> +#include "shared/LV2URIMap.hpp" +#include "AudioBuffer.hpp" +#include "EventBuffer.hpp" +#include "ObjectBuffer.hpp" +#include "BufferFactory.hpp" +#include "Engine.hpp" +#include "AudioDriver.hpp" +#include "ThreadManager.hpp" + +namespace Ingen { + +using namespace Shared; + +BufferFactory::BufferFactory(Engine& engine, SharedPtr<Shared::LV2URIMap> map) + : _engine(engine) + , _map(map) +{ +} + +struct BufferDeleter { + BufferDeleter(BufferFactory& bf) : _factory(bf) {} + void operator()(void* ptr) { + _factory.recycle((Buffer*)ptr); + } + BufferFactory& _factory; +}; + + +SharedPtr<Buffer> +BufferFactory::get(Shared::DataType type, size_t size) +{ + Raul::AtomicPtr<Buffer>& head_ptr = free_list(type); + Buffer* try_head; + Buffer* next; + do { + try_head = head_ptr.get(); + if (!try_head) + break; + next = try_head->_next; + } while (!head_ptr.compare_and_exchange(try_head, next)); + + if (!try_head) { + if (ThreadManager::current_thread_id() != THREAD_PROCESS) { + return create(type, size); + } else { + cerr << "ERROR: Failed to obtain buffer" << endl; + return SharedPtr<Buffer>(); + } + } + + try_head->_next = NULL; + return SharedPtr<Buffer>(try_head, BufferDeleter(*this)); +} + + +SharedPtr<Buffer> +BufferFactory::create(Shared::DataType type, size_t size) +{ + assert(ThreadManager::current_thread_id() != THREAD_PROCESS); + + Buffer* buffer = NULL; + + if (type.is_control()) { + if (size == 0) + size = sizeof(LV2_Object) + sizeof(float); + AudioBuffer* ret = new AudioBuffer(type, size); + ret->object()->type = _map->object_class_vector; + ((LV2_Vector_Body*)ret->object()->body)->elem_type = _map->object_class_float32; + buffer = ret; + } else if (type.is_audio()) { + if (size == 0) + size = sizeof(LV2_Object) + sizeof(LV2_Vector_Body) + + _engine.audio_driver()->buffer_size() * sizeof(float); + AudioBuffer* ret = new AudioBuffer(type, size); + ret->object()->type = _map->object_class_float32; + buffer = ret; + } else if (type.is_events()) { + if (size == 0) + size = _engine.audio_driver()->buffer_size() * 4; // FIXME + buffer = new EventBuffer(size); + } else if (type.is_value()) { + if (size == 0) + size = 32; // FIXME + buffer = new ObjectBuffer(std::max(size, sizeof(LV2_Object) + sizeof(void*))); + } else { + cout << "ERROR: Failed to create buffer of unknown type" << endl; + return SharedPtr<Buffer>(); + } + + return SharedPtr<Buffer>(buffer, BufferDeleter(*this)); +} + +void +BufferFactory::recycle(Buffer* buf) +{ + Raul::AtomicPtr<Buffer>& head_ptr = free_list(buf->type()); + Buffer* try_head; + do { + try_head = head_ptr.get(); + buf->_next = try_head; + } while (!head_ptr.compare_and_exchange(try_head, buf)); +} + + +} // namespace Ingen |