copy the remaining files from trunk
authorCampbell Barton <ideasman42@gmail.com>
Thu, 1 Sep 2011 07:51:20 +0000 (07:51 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 1 Sep 2011 07:51:20 +0000 (07:51 +0000)
intern/audaspace/intern/AUD_IHandle.h [new file with mode: 0644]
intern/audaspace/intern/AUD_JOSResampleFactory.h [new file with mode: 0644]
intern/audaspace/intern/AUD_JOSResampleReader.cpp [new file with mode: 0644]
intern/audaspace/intern/AUD_SequencerEntry.cpp [new file with mode: 0644]
intern/audaspace/intern/AUD_SequencerHandle.cpp [new file with mode: 0644]

diff --git a/intern/audaspace/intern/AUD_IHandle.h b/intern/audaspace/intern/AUD_IHandle.h
new file mode 100644 (file)
index 0000000..5b86951
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Copyright 2009-2011 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * Audaspace 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.
+ *
+ * AudaSpace 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 more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Audaspace; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file audaspace/intern/AUD_IHandle.h
+ *  \ingroup audaspaceintern
+ */
+
+#ifndef AUD_IHANDLE
+#define AUD_IHANDLE
+
+//#include "AUD_Space.h"
+//#include "AUD_Reference.h"
+
+typedef void (*stopCallback)(void*);
+
+/**
+ * This class represents a playback handles for specific devices.
+ */
+class AUD_IHandle
+{
+public:
+       /**
+        * Destroys the handle.
+        */
+       virtual ~AUD_IHandle() {}
+
+       /**
+        * Pauses a played back sound.
+        * \return
+        *        - true if the sound has been paused.
+        *        - false if the sound isn't playing back or the handle is invalid.
+        */
+       virtual bool pause()=0;
+
+       /**
+        * Resumes a paused sound.
+        * \return
+        *        - true if the sound has been resumed.
+        *        - false if the sound isn't paused or the handle is invalid.
+        */
+       virtual bool resume()=0;
+
+       /**
+        * Stops a played back or paused sound. The handle is definitely invalid
+        * afterwards.
+        * \return
+        *        - true if the sound has been stopped.
+        *        - false if the handle is invalid.
+        */
+       virtual bool stop()=0;
+
+       /**
+        * Gets the behaviour of the device for a played back sound when the sound
+        * doesn't return any more samples.
+        * \return
+        *        - true if the source will be paused when it's end is reached
+        *        - false if the handle won't kept or is invalid.
+        */
+       virtual bool getKeep()=0;
+
+       /**
+        * Sets the behaviour of the device for a played back sound when the sound
+        * doesn't return any more samples.
+        * \param keep True when the source should be paused and not deleted.
+        * \return
+        *        - true if the behaviour has been changed.
+        *        - false if the handle is invalid.
+        */
+       virtual bool setKeep(bool keep)=0;
+
+       /**
+        * Seeks in a played back sound.
+        * \param position The new position from where to play back, in seconds.
+        * \return
+        *        - true if the handle is valid.
+        *        - false if the handle is invalid.
+        * \warning Whether the seek works or not depends on the sound source.
+        */
+       virtual bool seek(float position)=0;
+
+       /**
+        * Retrieves the current playback position of a sound.
+        * \return The playback position in seconds, or 0.0 if the handle is
+        *         invalid.
+        */
+       virtual float getPosition()=0;
+
+       /**
+        * Returns the status of a played back sound.
+        * \return
+        *        - AUD_STATUS_INVALID if the sound has stopped or the handle is
+        *.         invalid
+        *        - AUD_STATUS_PLAYING if the sound is currently played back.
+        *        - AUD_STATUS_PAUSED if the sound is currently paused.
+        * \see AUD_Status
+        */
+       virtual AUD_Status getStatus()=0;
+
+       /**
+        * Retrieves the volume of a playing sound.
+        * \return The volume.
+        */
+       virtual float getVolume()=0;
+
+       /**
+        * Sets the volume of a playing sound.
+        * \param volume The volume.
+        * \return
+        *        - true if the handle is valid.
+        *        - false if the handle is invalid.
+        */
+       virtual bool setVolume(float volume)=0;
+
+       /**
+        * Retrieves the pitch of a playing sound.
+        * \return The pitch.
+        */
+       virtual float getPitch()=0;
+
+       /**
+        * Sets the pitch of a playing sound.
+        * \param pitch The pitch.
+        * \return
+        *        - true if the handle is valid.
+        *        - false if the handle is invalid.
+        */
+       virtual bool setPitch(float pitch)=0;
+
+       /**
+        * Retrieves the loop count of a playing sound.
+        * A negative value indicates infinity.
+        * \return The remaining loop count.
+        */
+       virtual int getLoopCount()=0;
+
+       /**
+        * Sets the loop count of a playing sound.
+        * A negative value indicates infinity.
+        * \param count The new loop count.
+        * \return
+        *        - true if the handle is valid.
+        *        - false if the handle is invalid.
+        */
+       virtual bool setLoopCount(int count)=0;
+
+       /**
+        * Sets the callback function that's called when the end of a playing sound
+        * is reached.
+        * \param callback The callback function.
+        * \param data The data that should be passed to the callback function.
+        * \return
+        *        - true if the handle is valid.
+        *        - false if the handle is invalid.
+        */
+       virtual bool setStopCallback(stopCallback callback = 0, void* data = 0)=0;
+};
+
+#endif //AUD_IHandle
diff --git a/intern/audaspace/intern/AUD_JOSResampleFactory.h b/intern/audaspace/intern/AUD_JOSResampleFactory.h
new file mode 100644 (file)
index 0000000..90a5df5
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Copyright 2009-2011 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * Audaspace 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.
+ *
+ * AudaSpace 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 more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Audaspace; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file audaspace/intern/AUD_JOSResampleFactory.h
+ *  \ingroup audaspaceintern
+ */
+
+
+#ifndef AUD_JOSRESAMPLEFACTORY
+#define AUD_JOSRESAMPLEFACTORY
+
+#include "AUD_MixerFactory.h"
+
+/**
+ * This factory creates a resampling reader that does Julius O. Smith's resampling algorithm.
+ */
+class AUD_JOSResampleFactory : public AUD_MixerFactory
+{
+private:
+       // hide copy constructor and operator=
+       AUD_JOSResampleFactory(const AUD_JOSResampleFactory&);
+       AUD_JOSResampleFactory& operator=(const AUD_JOSResampleFactory&);
+
+public:
+       /**
+        * Creates a new factory.
+        * \param factory The input factory.
+        * \param specs The target specifications.
+        */
+       AUD_JOSResampleFactory(AUD_Reference<AUD_IFactory> factory, AUD_DeviceSpecs specs);
+
+       virtual AUD_Reference<AUD_IReader> createReader();
+};
+
+#endif //AUD_JOSRESAMPLEFACTORY
diff --git a/intern/audaspace/intern/AUD_JOSResampleReader.cpp b/intern/audaspace/intern/AUD_JOSResampleReader.cpp
new file mode 100644 (file)
index 0000000..8da3d55
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Copyright 2009-2011 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * Audaspace 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.
+ *
+ * AudaSpace 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 more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Audaspace; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file audaspace/intern/AUD_JOSResampleReader.cpp
+ *  \ingroup audaspaceintern
+ */
+
+#include "AUD_JOSResampleReader.h"
+
+#include "AUD_JOSResampleReaderCoeff.cpp"
+
+#include <cmath>
+#include <cstring>
+#include <iostream>
+
+/* MSVC does not have lrint */
+#ifdef _MSC_VER
+#ifdef _M_X64
+#include <emmintrin.h>
+static inline int lrint(double d)
+{
+               return _mm_cvtsd_si32(_mm_load_sd(&d));
+}
+#else
+static inline int lrint(double d)
+{
+       int i;
+
+       _asm{
+               fld d
+               fistp i
+       };
+
+       return i;
+}
+#endif
+#endif
+
+#define CC m_channels + channel
+
+#define AUD_RATE_MAX 256
+#define SHIFT_BITS 12
+#define double_to_fp(x) (lrint(x * double(1 << SHIFT_BITS)))
+#define int_to_fp(x) (x << SHIFT_BITS)
+#define fp_to_int(x) (x >> SHIFT_BITS)
+#define fp_to_double(x) (x * 1.0/(1 << SHIFT_BITS))
+#define fp_rest(x) (x & ((1 << SHIFT_BITS) - 1))
+#define fp_rest_to_double(x) fp_to_double(fp_rest(x))
+
+AUD_JOSResampleReader::AUD_JOSResampleReader(AUD_Reference<AUD_IReader> reader, AUD_Specs specs) :
+       AUD_ResampleReader(reader, specs.rate),
+       m_channels(AUD_CHANNELS_INVALID),
+       m_n(0),
+       m_P(0),
+       m_cache_valid(0),
+       m_last_factor(0)
+{
+}
+
+void AUD_JOSResampleReader::reset()
+{
+       m_cache_valid = 0;
+       m_n = 0;
+       m_P = 0;
+       m_last_factor = 0;
+}
+
+void AUD_JOSResampleReader::updateBuffer(int size, double factor, int samplesize)
+{
+       unsigned int len;
+       double num_samples = double(m_len) / double(m_L);
+       // first calculate what length we need right now
+       if(factor >= 1)
+               len = ceil(num_samples);
+       else
+               len = (unsigned int)(ceil(num_samples / factor));
+
+       // then check if afterwards the length is enough for the maximum rate
+       if(len + size < num_samples * AUD_RATE_MAX)
+               len = num_samples * AUD_RATE_MAX - size;
+
+       if(m_n > len)
+       {
+               sample_t* buf = m_buffer.getBuffer();
+               len = m_n - len;
+               memmove(buf, buf + len * m_channels, (m_cache_valid - len) * samplesize);
+               m_n -= len;
+               m_cache_valid -= len;
+       }
+
+       m_buffer.assureSize((m_cache_valid + size) * samplesize, true);
+}
+
+#define RESAMPLE_METHOD(name, left, right) void AUD_JOSResampleReader::name(double target_factor, int length, sample_t* buffer)\
+{\
+       sample_t* buf = m_buffer.getBuffer();\
+\
+       int P, l, end, channel, i;\
+       double eta, v, f_increment, factor;\
+\
+       m_sums.assureSize(m_channels * sizeof(double));\
+       double* sums = reinterpret_cast<double*>(m_sums.getBuffer());\
+       sample_t* data;\
+       const float* coeff = m_coeff;\
+\
+       unsigned int P_increment;\
+\
+       for(unsigned int t = 0; t < length; t++)\
+       {\
+               factor = (m_last_factor * (length - t - 1) + target_factor * (t + 1)) / length;\
+\
+               memset(sums, 0, sizeof(double) * m_channels);\
+\
+               if(factor >= 1)\
+               {\
+                       P = double_to_fp(m_P * m_L);\
+\
+                       end = floor(m_len / double(m_L) - m_P) - 1;\
+                       if(m_n < end)\
+                               end = m_n;\
+\
+                       data = buf + (m_n - end) * m_channels;\
+                       l = fp_to_int(P);\
+                       eta = fp_rest_to_double(P);\
+                       l += m_L * end;\
+\
+                       for(i = 0; i <= end; i++)\
+                       {\
+                               v = coeff[l] + eta * (coeff[l+1] - coeff[l]);\
+                               l -= m_L;\
+                               left\
+                       }\
+\
+                       P = int_to_fp(m_L) - P;\
+\
+                       end = floor((m_len - 1) / double(m_L) + m_P) - 1;\
+                       if(m_cache_valid - m_n - 2 < end)\
+                               end = m_cache_valid - m_n - 2;\
+\
+                       data = buf + (m_n + 2 + end) * m_channels - 1;\
+                       l = fp_to_int(P);\
+                       eta = fp_rest_to_double(P);\
+                       l += m_L * end;\
+\
+                       for(i = 0; i <= end; i++)\
+                       {\
+                               v = coeff[l] + eta * (coeff[l+1] - coeff[l]);\
+                               l -= m_L;\
+                               right\
+                       }\
+\
+                       for(channel = 0; channel < m_channels; channel++)\
+                       {\
+                               *buffer = sums[channel];\
+                               buffer++;\
+                       }\
+               }\
+               else\
+               {\
+                       f_increment = factor * m_L;\
+                       P_increment = double_to_fp(f_increment);\
+                       P = double_to_fp(m_P * f_increment);\
+\
+                       end = (int_to_fp(m_len) - P) / P_increment - 1;\
+                       if(m_n < end)\
+                               end = m_n;\
+\
+                       P += P_increment * end;\
+                       data = buf + (m_n - end) * m_channels;\
+                       l = fp_to_int(P);\
+\
+                       for(i = 0; i <= end; i++)\
+                       {\
+                               eta = fp_rest_to_double(P);\
+                               v = coeff[l] + eta * (coeff[l+1] - coeff[l]);\
+                               P -= P_increment;\
+                               l = fp_to_int(P);\
+                               left\
+                       }\
+\
+                       P = -P;\
+\
+                       end = (int_to_fp(m_len) - P) / P_increment - 1;\
+                       if(m_cache_valid - m_n - 2 < end)\
+                               end = m_cache_valid - m_n - 2;\
+\
+                       P += P_increment * end;\
+                       data = buf + (m_n + 2 + end) * m_channels - 1;\
+                       l = fp_to_int(P);\
+\
+                       for(i = 0; i <= end; i++)\
+                       {\
+                               eta = fp_rest_to_double(P);\
+                               v = coeff[l] + eta * (coeff[l+1] - coeff[l]);\
+                               P -= P_increment;\
+                               l = fp_to_int(P);\
+                               right\
+                       }\
+\
+                       for(channel = 0; channel < m_channels; channel++)\
+                       {\
+                               *buffer = f_increment / m_L * sums[channel];\
+                               buffer++;\
+                       }\
+               }\
+\
+               m_P += fmod(1.0 / factor, 1.0);\
+               m_n += floor(1.0 / factor);\
+\
+               if(m_P >= 1.0)\
+               {\
+                       m_P -= 1.0;\
+                       m_n++;\
+               }\
+       }\
+}
+
+RESAMPLE_METHOD(resample, {
+                               channel = 0;
+                               do
+                               {
+                                       sums[channel] += *data * v;
+                                       channel++;
+                                       data++;
+                               }
+                               while(channel < m_channels);
+}, {
+                               channel = m_channels;
+                               do
+                               {
+                                       channel--;
+                                       sums[channel] += *data * v;
+                                       data--;
+                               }
+                               while(channel);
+})
+
+RESAMPLE_METHOD(resample_mono, {
+                               *sums += *data * v;
+                               data++;
+}, {
+                               *sums += *data * v;
+                               data--;
+})
+
+RESAMPLE_METHOD(resample_stereo, {
+                               sums[0] += data[0] * v;
+                               sums[1] += data[1] * v;
+                               data+=2;
+}, {
+                               data-=2;
+                               sums[0] += data[1] * v;
+                               sums[1] += data[2] * v;
+})
+
+void AUD_JOSResampleReader::seek(int position)
+{
+       position = floor(position * double(m_reader->getSpecs().rate) / double(m_rate));
+       m_reader->seek(position);
+       reset();
+}
+
+int AUD_JOSResampleReader::getLength() const
+{
+       return floor(m_reader->getLength() * double(m_rate) / double(m_reader->getSpecs().rate));
+}
+
+int AUD_JOSResampleReader::getPosition() const
+{
+       return floor((m_reader->getPosition() + double(m_P))
+                                * m_rate / m_reader->getSpecs().rate);
+}
+
+AUD_Specs AUD_JOSResampleReader::getSpecs() const
+{
+       AUD_Specs specs = m_reader->getSpecs();
+       specs.rate = m_rate;
+       return specs;
+}
+
+void AUD_JOSResampleReader::read(int& length, bool& eos, sample_t* buffer)
+{
+       if(length == 0)
+               return;
+
+       AUD_Specs specs = m_reader->getSpecs();
+
+       int samplesize = AUD_SAMPLE_SIZE(specs);
+       double target_factor = double(m_rate) / double(specs.rate);
+       eos = false;
+       int len;
+       double num_samples = double(m_len) / double(m_L);
+
+       // check for channels changed
+       if(specs.channels != m_channels)
+       {
+               m_channels = specs.channels;
+               reset();
+
+               switch(m_channels)
+               {
+               case AUD_CHANNELS_MONO:
+                       m_resample = &AUD_JOSResampleReader::resample_mono;
+                       break;
+               case AUD_CHANNELS_STEREO:
+                       m_resample = &AUD_JOSResampleReader::resample_stereo;
+                       break;
+               default:
+                       m_resample = &AUD_JOSResampleReader::resample;
+                       break;
+               }
+       }
+
+       if(m_last_factor == 0)
+               m_last_factor = target_factor;
+
+       if(target_factor == 1 && m_last_factor == 1 && (m_P == 0))
+       {
+               // can read directly!
+
+               len = length - (m_cache_valid - m_n);
+
+               updateBuffer(len, target_factor, samplesize);
+               sample_t* buf = m_buffer.getBuffer();
+
+               m_reader->read(len, eos, buf + m_cache_valid * m_channels);
+               m_cache_valid += len;
+
+               length = m_cache_valid - m_n;
+
+               if(length > 0)
+               {
+                       memcpy(buffer, buf + m_n * m_channels, length * samplesize);
+                       m_n += length;
+               }
+
+               return;
+       }
+
+       // use minimum for the following calculations
+       double factor = AUD_MIN(target_factor, m_last_factor);
+
+       if(factor >= 1)
+               len = (m_n - m_cache_valid) + int(ceil(length / factor)) + ceil(num_samples);
+       else
+               len = (m_n - m_cache_valid) + int(ceil(length / factor) + ceil(num_samples / factor));
+
+       if(len > 0)
+       {
+               int should = len;
+
+               updateBuffer(len, factor, samplesize);
+
+               m_reader->read(len, eos, m_buffer.getBuffer() + m_cache_valid * m_channels);
+               m_cache_valid += len;
+
+               if(len < should)
+               {
+                       if(len == 0 && eos)
+                               length = 0;
+                       else
+                       {
+                               // use maximum for the following calculations
+                               factor = AUD_MAX(target_factor, m_last_factor);
+
+                               if(eos)
+                               {
+                                       // end of stream, let's check how many more samples we can produce
+                                       len = floor((m_cache_valid - m_n) * factor);
+                                       if(len < length)
+                                               length = len;
+                               }
+                               else
+                               {
+                                       // not enough data available yet, so we recalculate how many samples we can calculate
+                                       if(factor >= 1)
+                                               len = floor((num_samples + m_cache_valid - m_n) * factor);
+                                       else
+                                               len = floor((num_samples * factor + m_cache_valid - m_n) * factor);
+                                       if(len < length)
+                                               length = len;
+                               }
+                       }
+               }
+       }
+
+       (this->*m_resample)(target_factor, length, buffer);
+
+       m_last_factor = target_factor;
+
+       if(m_n > m_cache_valid)
+       {
+               m_n = m_cache_valid;
+       }
+
+       eos = eos && ((m_n == m_cache_valid) || (length == 0));
+}
diff --git a/intern/audaspace/intern/AUD_SequencerEntry.cpp b/intern/audaspace/intern/AUD_SequencerEntry.cpp
new file mode 100644 (file)
index 0000000..c5112f9
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Copyright 2009-2011 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * Audaspace 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.
+ *
+ * AudaSpace 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 more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Audaspace; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file audaspace/intern/AUD_SequencerEntry.cpp
+ *  \ingroup audaspaceintern
+ */
+
+
+#include "AUD_SequencerEntry.h"
+#include "AUD_SequencerReader.h"
+
+#include <cmath>
+#include <limits>
+
+AUD_SequencerEntry::AUD_SequencerEntry(AUD_Reference<AUD_IFactory> sound, float begin, float end, float skip, int id) :
+       m_status(0),
+       m_pos_status(1),
+       m_sound_status(0),
+       m_id(id),
+       m_sound(sound),
+       m_begin(begin),
+       m_end(end),
+       m_skip(skip),
+       m_muted(false),
+       m_relative(true),
+       m_volume_max(1.0f),
+       m_volume_min(0),
+       m_distance_max(std::numeric_limits<float>::max()),
+       m_distance_reference(1.0f),
+       m_attenuation(1.0f),
+       m_cone_angle_outer(360),
+       m_cone_angle_inner(360),
+       m_cone_volume_outer(0),
+       m_location(3),
+       m_orientation(4)
+{
+       AUD_Quaternion q;
+       m_orientation.write(q.get());
+       float f = 1;
+       m_volume.write(&f);
+       m_pitch.write(&f);
+
+       pthread_mutexattr_t attr;
+       pthread_mutexattr_init(&attr);
+       pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+
+       pthread_mutex_init(&m_mutex, &attr);
+
+       pthread_mutexattr_destroy(&attr);
+}
+
+AUD_SequencerEntry::~AUD_SequencerEntry()
+{
+       pthread_mutex_destroy(&m_mutex);
+}
+
+void AUD_SequencerEntry::lock()
+{
+       pthread_mutex_lock(&m_mutex);
+}
+
+void AUD_SequencerEntry::unlock()
+{
+       pthread_mutex_unlock(&m_mutex);
+}
+
+void AUD_SequencerEntry::setSound(AUD_Reference<AUD_IFactory> sound)
+{
+       lock();
+
+       if(m_sound.get() != sound.get())
+       {
+               m_sound = sound;
+               m_sound_status++;
+       }
+
+       unlock();
+}
+
+void AUD_SequencerEntry::move(float begin, float end, float skip)
+{
+       lock();
+
+       if(m_begin != begin || m_skip != skip || m_end != end)
+       {
+               m_begin = begin;
+               m_skip = skip;
+               m_end = end;
+               m_pos_status++;
+       }
+
+       unlock();
+}
+
+void AUD_SequencerEntry::mute(bool mute)
+{
+       lock();
+
+       m_muted = mute;
+
+       unlock();
+}
+
+int AUD_SequencerEntry::getID() const
+{
+       return m_id;
+}
+
+AUD_AnimateableProperty* AUD_SequencerEntry::getAnimProperty(AUD_AnimateablePropertyType type)
+{
+       switch(type)
+       {
+       case AUD_AP_VOLUME:
+               return &m_volume;
+       case AUD_AP_PITCH:
+               return &m_pitch;
+       case AUD_AP_PANNING:
+               return &m_panning;
+       case AUD_AP_LOCATION:
+               return &m_location;
+       case AUD_AP_ORIENTATION:
+               return &m_orientation;
+       default:
+               return NULL;
+       }
+}
+
+void AUD_SequencerEntry::updateAll(float volume_max, float volume_min, float distance_max,
+                                                                  float distance_reference, float attenuation, float cone_angle_outer,
+                                                                  float cone_angle_inner, float cone_volume_outer)
+{
+       lock();
+
+       if(volume_max != m_volume_max)
+       {
+               m_volume_max = volume_max;
+               m_status++;
+       }
+
+       if(volume_min != m_volume_min)
+       {
+               m_volume_min = volume_min;
+               m_status++;
+       }
+
+       if(distance_max != m_distance_max)
+       {
+               m_distance_max = distance_max;
+               m_status++;
+       }
+
+       if(distance_reference != m_distance_reference)
+       {
+               m_distance_reference = distance_reference;
+               m_status++;
+       }
+
+       if(attenuation != m_attenuation)
+       {
+               m_attenuation = attenuation;
+               m_status++;
+       }
+
+       if(cone_angle_outer != m_cone_angle_outer)
+       {
+               m_cone_angle_outer = cone_angle_outer;
+               m_status++;
+       }
+
+       if(cone_angle_inner != m_cone_angle_inner)
+       {
+               m_cone_angle_inner = cone_angle_inner;
+               m_status++;
+       }
+
+       if(cone_volume_outer != m_cone_volume_outer)
+       {
+               m_cone_volume_outer = cone_volume_outer;
+               m_status++;
+       }
+
+       unlock();
+}
+
+bool AUD_SequencerEntry::isRelative()
+{
+       return m_relative;
+}
+
+void AUD_SequencerEntry::setRelative(bool relative)
+{
+       lock();
+
+       if(m_relative != relative)
+       {
+               m_relative = relative;
+               m_status++;
+       }
+
+       unlock();
+}
+
+float AUD_SequencerEntry::getVolumeMaximum()
+{
+       return m_volume_max;
+}
+
+void AUD_SequencerEntry::setVolumeMaximum(float volume)
+{
+       lock();
+
+       m_volume_max = volume;
+       m_status++;
+
+       unlock();
+}
+
+float AUD_SequencerEntry::getVolumeMinimum()
+{
+       return m_volume_min;
+}
+
+void AUD_SequencerEntry::setVolumeMinimum(float volume)
+{
+       lock();
+
+       m_volume_min = volume;
+       m_status++;
+
+       unlock();
+}
+
+float AUD_SequencerEntry::getDistanceMaximum()
+{
+       return m_distance_max;
+}
+
+void AUD_SequencerEntry::setDistanceMaximum(float distance)
+{
+       lock();
+
+       m_distance_max = distance;
+       m_status++;
+
+       unlock();
+}
+
+float AUD_SequencerEntry::getDistanceReference()
+{
+       return m_distance_reference;
+}
+
+void AUD_SequencerEntry::setDistanceReference(float distance)
+{
+       lock();
+
+       m_distance_reference = distance;
+       m_status++;
+
+       unlock();
+}
+
+float AUD_SequencerEntry::getAttenuation()
+{
+       return m_attenuation;
+}
+
+void AUD_SequencerEntry::setAttenuation(float factor)
+{
+       lock();
+
+       m_attenuation = factor;
+       m_status++;
+
+       unlock();
+}
+
+float AUD_SequencerEntry::getConeAngleOuter()
+{
+       return m_cone_angle_outer;
+}
+
+void AUD_SequencerEntry::setConeAngleOuter(float angle)
+{
+       lock();
+
+       m_cone_angle_outer = angle;
+       m_status++;
+
+       unlock();
+}
+
+float AUD_SequencerEntry::getConeAngleInner()
+{
+       return m_cone_angle_inner;
+}
+
+void AUD_SequencerEntry::setConeAngleInner(float angle)
+{
+       lock();
+
+       m_cone_angle_inner = angle;
+       m_status++;
+
+       unlock();
+}
+
+float AUD_SequencerEntry::getConeVolumeOuter()
+{
+       return m_cone_volume_outer;
+}
+
+void AUD_SequencerEntry::setConeVolumeOuter(float volume)
+{
+       lock();
+
+       m_cone_volume_outer = volume;
+       m_status++;
+
+       unlock();
+}
diff --git a/intern/audaspace/intern/AUD_SequencerHandle.cpp b/intern/audaspace/intern/AUD_SequencerHandle.cpp
new file mode 100644 (file)
index 0000000..c9cf46c
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Copyright 2009-2011 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * Audaspace 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.
+ *
+ * AudaSpace 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 more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Audaspace; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file audaspace/intern/AUD_SequencerHandle.cpp
+ *  \ingroup audaspaceintern
+ */
+
+
+#include "AUD_SequencerHandle.h"
+#include "AUD_ReadDevice.h"
+
+AUD_SequencerHandle::AUD_SequencerHandle(AUD_Reference<AUD_SequencerEntry> entry, AUD_ReadDevice& device) :
+       m_entry(entry),
+       m_status(0),
+       m_pos_status(0),
+       m_sound_status(0),
+       m_device(device)
+{
+       if(!entry->m_sound.isNull())
+       {
+               m_handle = device.play(entry->m_sound, true);
+               m_3dhandle = AUD_Reference<AUD_I3DHandle>(m_handle);
+       }
+}
+
+AUD_SequencerHandle::~AUD_SequencerHandle()
+{
+       stop();
+}
+
+int AUD_SequencerHandle::compare(AUD_Reference<AUD_SequencerEntry> entry) const
+{
+       if(m_entry->getID() < entry->getID())
+               return -1;
+       else if(m_entry->getID() == entry->getID())
+               return 0;
+       return 1;
+}
+
+void AUD_SequencerHandle::stop()
+{
+       if(!m_handle.isNull())
+               m_handle->stop();
+}
+
+void AUD_SequencerHandle::update(float position, float frame)
+{
+       if(!m_handle.isNull())
+       {
+               m_entry->lock();
+               if(position >= m_entry->m_end && m_entry->m_end >= 0)
+                       m_handle->pause();
+               else if(position >= m_entry->m_begin)
+                       m_handle->resume();
+
+               if(m_sound_status != m_entry->m_sound_status)
+               {
+                       if(!m_handle.isNull())
+                               m_handle->stop();
+
+                       if(!m_entry->m_sound.isNull())
+                       {
+                               m_handle = m_device.play(m_entry->m_sound, true);
+                               m_3dhandle = AUD_Reference<AUD_I3DHandle>(m_handle);
+                       }
+
+                       m_sound_status = m_entry->m_sound_status;
+                       m_pos_status--;
+                       m_status--;
+               }
+
+               if(m_pos_status != m_entry->m_pos_status)
+               {
+                       seek(position);
+
+                       m_pos_status = m_entry->m_pos_status;
+               }
+
+               if(m_status != m_entry->m_status)
+               {
+                       m_3dhandle->setRelative(m_entry->m_relative);
+                       m_3dhandle->setVolumeMaximum(m_entry->m_volume_max);
+                       m_3dhandle->setVolumeMinimum(m_entry->m_volume_min);
+                       m_3dhandle->setDistanceMaximum(m_entry->m_distance_max);
+                       m_3dhandle->setDistanceReference(m_entry->m_distance_reference);
+                       m_3dhandle->setAttenuation(m_entry->m_attenuation);
+                       m_3dhandle->setConeAngleOuter(m_entry->m_cone_angle_outer);
+                       m_3dhandle->setConeAngleInner(m_entry->m_cone_angle_inner);
+                       m_3dhandle->setConeVolumeOuter(m_entry->m_cone_volume_outer);
+
+                       m_status = m_entry->m_status;
+               }
+
+               float value;
+
+               m_entry->m_volume.read(frame, &value);
+               m_handle->setVolume(value);
+               m_entry->m_pitch.read(frame, &value);
+               m_handle->setPitch(value);
+               m_entry->m_panning.read(frame, &value);
+               AUD_SoftwareDevice::setPanning(m_handle.get(), value);
+
+               AUD_Vector3 v, v2;
+               AUD_Quaternion q;
+
+               m_entry->m_orientation.read(frame, q.get());
+               m_3dhandle->setSourceOrientation(q);
+               m_entry->m_location.read(frame, v.get());
+               m_3dhandle->setSourceLocation(v);
+               m_entry->m_location.read(frame + 1, v2.get());
+               v2 -= v;
+               m_3dhandle->setSourceVelocity(v2);
+
+               if(m_entry->m_muted)
+                       m_handle->setVolume(0);
+               m_entry->unlock();
+       }
+}
+
+void AUD_SequencerHandle::seek(float position)
+{
+       if(!m_handle.isNull())
+       {
+               m_entry->lock();
+               if(position >= m_entry->m_end && m_entry->m_end >= 0)
+               {
+                       m_handle->pause();
+                       m_entry->unlock();
+                       return;
+               }
+
+               float seekpos = position - m_entry->m_begin;
+               if(seekpos < 0)
+                       seekpos = 0;
+               seekpos += m_entry->m_skip;
+               m_handle->seek(seekpos);
+               if(position < m_entry->m_begin)
+                       m_handle->pause();
+               else
+                       m_handle->resume();
+               m_entry->unlock();
+       }
+}