diff options
Diffstat (limited to 'flow/datahandle_impl.cpp')
-rw-r--r-- | flow/datahandle_impl.cpp | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/flow/datahandle_impl.cpp b/flow/datahandle_impl.cpp new file mode 100644 index 0000000..ae13a75 --- /dev/null +++ b/flow/datahandle_impl.cpp @@ -0,0 +1,499 @@ + /* + + Copyright (C) 2002 Hans Meine + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + */ + +#include <gsl/gsldatahandle.h> +#include <gsl/gslloader.h> +#include <gsl/gslwaveosc.h> +#include "artsflow.h" +#include "stdsynthmodule.h" +#include "debug.h" +#include <algorithm> +#include <cstring> +#include <gslpp/datahandle.h> + +using namespace std; + +namespace Arts { + +static GSL::DataHandle getDHandle(DataHandle handle); + +class DataHandle_impl : virtual public DataHandle_skel +{ +protected: + GSL::DataHandle dhandle_; + long errno_; + friend GSL::DataHandle getDHandle(DataHandle handle); + +public: + DataHandle_impl(GSL::DataHandle dhandle = GSL::DataHandle::null()) + : dhandle_(dhandle) + { + errno_ = dhandle_.isNull() ? 0 : dhandle_.open(); + } + + ~DataHandle_impl() + { + if(dhandle_.isOpen()) + dhandle_.close(); + } + + long valueCount() + { + return dhandle_.valueCount(); + } + + long bitDepth() + { + return dhandle_.bitDepth(); + } + + long channelCount() + { + return dhandle_.channelCount(); + } + + long errorNo() + { + return errno_; + } + + GSL::DataHandle createCropped(long headCutValueCount, + long tailCutValueCount) + { + return dhandle_.createCropped(headCutValueCount, tailCutValueCount); + } + + GSL::DataHandle createCut(long cutOffset, + long cutValueCount) + { + return dhandle_.createCut(cutOffset, cutValueCount); + } + + GSL::DataHandle createReversed() + { + return dhandle_.createReversed(); + } +}; + +class ReversedDataHandle_impl : virtual public DataHandle_impl, + virtual public ReversedDataHandle_skel +{ + void init(DataHandle sourceHandle) + { + DataHandle_impl *impl = dynamic_cast<DataHandle_impl *>(sourceHandle._base()); + dhandle_ = impl->createReversed(); + } +}; + +class CroppedDataHandle_impl : virtual public DataHandle_impl, + virtual public CroppedDataHandle_skel +{ + void init(DataHandle sourceHandle, + long headCutValueCount, + long tailCutValueCount) + { + DataHandle_impl *impl = dynamic_cast<DataHandle_impl *>(sourceHandle._base()); + dhandle_ = impl->createCropped(headCutValueCount, tailCutValueCount); + } +}; + +class CutDataHandle_impl : virtual public DataHandle_impl, + virtual public CutDataHandle_skel +{ + void init(DataHandle sourceHandle, + long cutOffset, + long cutValueCount) + { + DataHandle_impl *impl = dynamic_cast<DataHandle_impl *>(sourceHandle._base()); + dhandle_ = impl->createCut(cutOffset, cutValueCount); + } +}; + +static GSL::DataHandle getDHandle(DataHandle handle) +{ + DataHandle_impl *impl = dynamic_cast<DataHandle_impl *>(handle._base()); + if(impl) + return impl->dhandle_; + return GSL::DataHandle::null(); +} + +GslWaveChunk* const_wchunk_from_freq(gpointer wchunk_data, gfloat) +{ + return (GslWaveChunk*)wchunk_data; +} + +// FIXME: Think about whether this is needed as a parameter like mixerFrequency +#define OSCILLATOR_FREQUENCY 440.0f + +class DataHandlePlay_impl : virtual public DataHandlePlay_skel, + virtual public StdSynthModule +{ +protected: + DataHandle dhandle_; + + GSL::DataHandle gslDHandle_; + int errno_; + GslWaveChunk *wchunk_; + GslErrorType wchunkError_; + GslWaveOscData *wosc_; + + float mixerFrequency_; + unsigned short channelIndex_; + float speed_; + unsigned long pos_; + bool finished_; + bool paused_; + +public: + DataHandlePlay_impl() + : dhandle_(DataHandle::null()), + gslDHandle_(GSL::DataHandle::null()), + wchunk_(NULL), + wosc_(NULL), + mixerFrequency_(0), // FIXME: doc says soundserver's freq + channelIndex_(0), + speed_(1.0f), + pos_(0), + finished_(false), + paused_(false) + {} + + ~DataHandlePlay_impl() + { + handle(DataHandle::null()); + } + + DataHandle handle() + { + return dhandle_; + } + + void handle(DataHandle handle) + { + deleteWaveChunk(); + + if(!gslDHandle_.isNull() && !errno_) + gslDHandle_.close(); + + dhandle_ = handle; + + if(handle.isNull()) + gslDHandle_ = GSL::DataHandle::null(); + else + { + gslDHandle_ = getDHandle(dhandle_); + + if(gslDHandle_.isNull()) + { + arts_debug("ERROR: could not get internal GSL::DataHandle!"); + finished(true); // FIXME: can this happen? + } + else + { + errno_ = gslDHandle_.open(); + if(errno_) + arts_debug("DataHandlePlay got error from GSL::DataHandle.open(): '%s'", + strerror(errno_)); + } + } + } + + void streamInit() + { + if(!gslDHandle_.isNull() && !wosc_) + { + if(!wchunk_) + createWaveChunk(); + configureWaveOsc(); + } + } + + float mixerFrequency() { return wosc_ ? wosc_->mix_freq : 0; } + void mixerFrequency(float f) + { + if(wchunk_) + arts_warning("DataHandlePlay: cannot change mixerFrequency after start of sound processing!"); + + if(mixerFrequency() != f) + { + mixerFrequency_ = f; + mixerFrequency_changed(f); + } + } + + long channelIndex() { return channelIndex_; } + void channelIndex(long ci) + { + if(channelIndex_ != ci) + { + channelIndex_ = ci; + if(wosc_) + { + GslWaveOscConfig config = wosc_->config; + config.channel = ci; + gsl_wave_osc_config(wosc_, &config); + } + channelIndex_changed(ci); + } + } + + float speed() { return speed_; } + void speed(float s) + { + if(speed_ != s) + { + speed_ = s; + if(wosc_) + { + GslWaveOscConfig config = wosc_->config; + config.cfreq = OSCILLATOR_FREQUENCY * speed(); + gsl_wave_osc_config(wosc_, &config); + } + speed_changed(s); + } + } + + long pos() { return wosc_ ? wosc_->block.offset : 0; } + void pos(long p) + { + if(pos() != p) + { + GslWaveOscConfig config = wosc_->config; + config.start_offset = p; + gsl_wave_osc_config(wosc_, &config); + pos_changed(p); + } + } + + bool finished() { return finished_; } + void finished(bool f) + { + if(finished_ != f) + { + finished_ = f; + finished_changed(f); + } + } + + bool paused() { return paused_; } + void paused(bool p) + { + paused_ = p; + } + + void deleteWaveChunk() + { + deleteWaveOsc(); + + if(wchunk_) + { + arts_debug("DataHandlePlay_impl: close()ing gsl_wave_chunk"); + gsl_wave_chunk_close(wchunk_); + gsl_wave_chunk_unref(wchunk_); + wchunk_ = NULL; + } + } + + void createWaveChunk() + { + deleteWaveChunk(); + + if(!gslDHandle_.isNull() && gslDHandle_.isOpen()) + { + GslDataCache *dcache = gslDHandle_.createGslDataCache(); + if(!dcache) + { + arts_debug("FATAL: creating data cache failed!"); + finished(true); // FIXME: can this happen? + } + else + { + wchunk_ = + gsl_wave_chunk_new(dcache, + OSCILLATOR_FREQUENCY, + mixerFrequency_, + GSL_WAVE_LOOP_NONE, + 0, 0, 0); + arts_debug("DataHandlePlay_impl: open()ing gsl_wave_chunk"); + wchunkError_ = gsl_wave_chunk_open(wchunk_); + gsl_data_cache_unref(dcache); + } + } + } + + void deleteWaveOsc() + { + if(wosc_) + { + gsl_wave_osc_shutdown(wosc_); + delete wosc_; + wosc_ = NULL; + } + } + + void configureWaveOsc() + { + if(wchunk_) + { + GslWaveOscConfig config; + memset(&config, 0, sizeof (GslWaveOscConfig)); + config.start_offset = 0; + config.play_dir = 1; + config.wchunk_data = (gpointer)wchunk_; + config.wchunk_from_freq = &const_wchunk_from_freq; + config.channel = channelIndex(); + config.cfreq = OSCILLATOR_FREQUENCY * speed(); + + if(!wosc_) + { + wosc_ = new GslWaveOscData(); + gsl_wave_osc_init(wosc_); + } + + gsl_wave_osc_config(wosc_, &config); + } + } + + void calculateBlock(unsigned long samples) + { + if(!paused_ && wchunk_) + { + if (!gsl_wave_osc_process(wosc_, samples, 0, 0, 0, outvalue)) + arts_debug("gsl_wave_osc_process failed."); + finished(wosc_->done); + } + else + for(unsigned long i = 0; i < samples; i++) + outvalue[i] = 0.f; + /* + unsigned long haveSamples = 0; + + while(haveSamples != samples) + { + long n = min(gslDHandle_.valueCount() - pos_, samples - haveSamples); + long got = gslDHandle_.isNull() ? + 0 : gslDHandle_.read(pos_, n, &outvalue[haveSamples]); + if(got <= 0) + { + for(unsigned long i = haveSamples; i < samples; i++) + outvalue[i] = 0.f; + break; + } + pos_ += got; + haveSamples += got; + } + finished(pos_ >= gslDHandle_.valueCount()); + */ + } + + DataHandlePlay clone() + { + arts_debug("DataHandlePlay_impl: clone()ing myself"); + DataHandlePlay_impl *result = new DataHandlePlay_impl(); + + result->dhandle_ = dhandle_; + result->gslDHandle_ = gslDHandle_; + result->errno_ = errno_; + + createWaveChunk(); + if(wchunk_) + { + result->wchunk_ = wchunk_; + gsl_wave_chunk_ref(wchunk_); + result->wchunkError_ = gsl_wave_chunk_open(wchunk_); + } + else + result->wchunkError_ = wchunkError_; + + result->mixerFrequency_ = mixerFrequency_; + result->channelIndex_ = channelIndex_; + result->speed_ = speed_; + result->pos_ = pos_; + result->finished_ = finished_; + result->paused_ = paused_; + + return DataHandlePlay::_from_base(result); + } +}; + +class WaveDataHandle_impl : virtual public DataHandle_impl, + virtual public WaveDataHandle_skel +{ + GSL::WaveDataHandle wdhandle_; + +public: + WaveDataHandle_impl() : wdhandle_(GSL::WaveDataHandle::null()) {} + + float mixerFrequency() + { + return wdhandle_.mixerFrequency(); + } + + float oscillatorFrequency() + { + return wdhandle_.oscillatorFrequency(); + } + + bool load(const string& filename) + { + return load(filename, 0, 0); + } + + bool load(const string& filename, + long waveIndex, + long chunkIndex) + { + wdhandle_ = GSL::WaveDataHandle(filename, waveIndex, chunkIndex); + if(dhandle_.isOpen()) + dhandle_.close(); + dhandle_ = wdhandle_; + errno_ = dhandle_.isNull() ? 0 : dhandle_.open(); + return isLoaded(); + } + + bool isLoaded() + { + if(wdhandle_.isNull()) + return false; + + return !wdhandle_.error(); + } + + DataHandlePlay createPlayer() + { + DataHandlePlay_impl *result= new DataHandlePlay_impl(); + + result->mixerFrequency(mixerFrequency()); + result->handle(WaveDataHandle::_from_base(this->_copy())); + + return DataHandlePlay::_from_base(result); + } +}; + +REGISTER_IMPLEMENTATION(DataHandlePlay_impl); +REGISTER_IMPLEMENTATION(DataHandle_impl); +REGISTER_IMPLEMENTATION(CroppedDataHandle_impl); +REGISTER_IMPLEMENTATION(CutDataHandle_impl); +REGISTER_IMPLEMENTATION(ReversedDataHandle_impl); +REGISTER_IMPLEMENTATION(WaveDataHandle_impl); + +} |