From 86fc34b924e281ee9273c44c024434bdd6e3f7f2 Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Mon, 2 Aug 2010 18:22:34 +0000 Subject: [PATCH] Audaspace: * Added a stopCallback function that is called when the end of a sound is reached. * Fixed the scrubbing not working. * Minor SoundActuator cleanup. --- intern/audaspace/OpenAL/AUD_OpenALDevice.cpp | 35 +++++++-- intern/audaspace/OpenAL/AUD_OpenALDevice.h | 1 + intern/audaspace/intern/AUD_C-API.cpp | 27 +++++++ intern/audaspace/intern/AUD_C-API.h | 8 ++ intern/audaspace/intern/AUD_IDevice.h | 14 ++++ intern/audaspace/intern/AUD_NULLDevice.cpp | 5 ++ intern/audaspace/intern/AUD_NULLDevice.h | 1 + .../audaspace/intern/AUD_SilenceFactory.cpp | 37 ++++++++++ intern/audaspace/intern/AUD_SilenceFactory.h | 50 +++++++++++++ intern/audaspace/intern/AUD_SilenceReader.cpp | 74 +++++++++++++++++++ intern/audaspace/intern/AUD_SilenceReader.h | 71 ++++++++++++++++++ .../audaspace/intern/AUD_SoftwareDevice.cpp | 23 ++++++ intern/audaspace/intern/AUD_SoftwareDevice.h | 1 + source/blender/blenkernel/intern/sound.c | 4 + source/blender/makesdna/DNA_scene_types.h | 1 + source/gameengine/Ketsji/KX_SoundActuator.h | 2 - 16 files changed, 347 insertions(+), 7 deletions(-) create mode 100644 intern/audaspace/intern/AUD_SilenceFactory.cpp create mode 100644 intern/audaspace/intern/AUD_SilenceFactory.h create mode 100644 intern/audaspace/intern/AUD_SilenceReader.cpp create mode 100644 intern/audaspace/intern/AUD_SilenceReader.h diff --git a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp index 88e48ff20ba..f69a2e5d805 100644 --- a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp +++ b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp @@ -68,6 +68,12 @@ struct AUD_OpenALHandle : AUD_Handle /// The loop count of the source. int loopcount; + + /// The stop callback. + stopCallback stop; + + /// Stop callback data. + void* stop_data; }; struct AUD_OpenALBufferedFactory @@ -131,13 +137,9 @@ void AUD_OpenALDevice::updateStreams() { // for all sounds - AUD_HandleIterator it = m_playingSounds->begin(); - while(it != m_playingSounds->end()) + for(AUD_HandleIterator it = m_playingSounds->begin(); it != m_playingSounds->end(); it++) { sound = *it; - // increment the iterator to make sure it's valid, - // in case the sound gets deleted after stopping - ++it; // is it a streamed sound? if(!sound->isBuffered) @@ -227,12 +229,21 @@ void AUD_OpenALDevice::updateStreams() // if it really stopped if(sound->data_end) { + if(sound->stop) + sound->stop(sound->stop_data); + + // increment the iterator to the next value, + // because the sound gets deleted in the list here. + ++it; // pause or if(sound->keep) pause(sound); // stop else stop(sound); + // decrement again, so that we get the next sound in the + // next loop run + --it; } // continue playing else @@ -1012,6 +1023,20 @@ bool AUD_OpenALDevice::setLoopCount(AUD_Handle* handle, int count) return result; } +bool AUD_OpenALDevice::setStopCallback(AUD_Handle* handle, stopCallback callback, void* data) +{ + lock(); + bool result = isValid(handle); + if(result) + { + AUD_OpenALHandle* h = (AUD_OpenALHandle*)handle; + h->stop = callback; + h->stop_data = data; + } + unlock(); + return result; +} + /* AUD_XXX Temorary disabled bool AUD_OpenALDevice::bufferFactory(void *value) diff --git a/intern/audaspace/OpenAL/AUD_OpenALDevice.h b/intern/audaspace/OpenAL/AUD_OpenALDevice.h index 37a5b886882..985954fc20b 100644 --- a/intern/audaspace/OpenAL/AUD_OpenALDevice.h +++ b/intern/audaspace/OpenAL/AUD_OpenALDevice.h @@ -160,6 +160,7 @@ public: virtual bool setPitch(AUD_Handle* handle, float pitch); virtual int getLoopCount(AUD_Handle* handle); virtual bool setLoopCount(AUD_Handle* handle, int count); + virtual bool setStopCallback(AUD_Handle* handle, stopCallback callback = NULL, void* data = NULL); virtual AUD_Vector3 getListenerLocation() const; virtual void setListenerLocation(const AUD_Vector3& location); diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp index 5e0364c618c..b9926b85a48 100644 --- a/intern/audaspace/intern/AUD_C-API.cpp +++ b/intern/audaspace/intern/AUD_C-API.cpp @@ -60,6 +60,7 @@ bool g_pyinitialized = false; #include "AUD_ReadDevice.h" #include "AUD_IReader.h" #include "AUD_SequencerFactory.h" +#include "AUD_SilenceFactory.h" #ifdef WITH_SDL #include "AUD_SDLDevice.h" @@ -845,6 +846,32 @@ float* AUD_readSoundBuffer(const char* filename, float low, float high, return result; } +static void pauseSound(AUD_Channel* handle) +{ + assert(AUD_device); + + AUD_device->pause(handle); +} + +AUD_Channel* AUD_pauseAfter(AUD_Channel* handle, float seconds) +{ + assert(AUD_device); + + AUD_SilenceFactory silence; + AUD_LimiterFactory limiter(&silence, 0, seconds); + + try + { + AUD_Channel* channel = AUD_device->play(&limiter); + AUD_device->setStopCallback(channel, (stopCallback)pauseSound, handle); + return channel; + } + catch(AUD_Exception&) + { + return NULL; + } +} + AUD_Sound* AUD_createSequencer(void* data, AUD_volumeFunction volume) { /* AUD_XXX should be this: but AUD_createSequencer is called before the device diff --git a/intern/audaspace/intern/AUD_C-API.h b/intern/audaspace/intern/AUD_C-API.h index f73e658d5b1..de2d8465d18 100644 --- a/intern/audaspace/intern/AUD_C-API.h +++ b/intern/audaspace/intern/AUD_C-API.h @@ -463,6 +463,14 @@ extern float* AUD_readSoundBuffer(const char* filename, float low, float high, float sthreshold, int samplerate, int* length); +/** + * Pauses a playing sound after a specific amount of time. + * \param handle The handle to the sound. + * \param time The time in seconds. + * \return The silence handle. + */ +extern AUD_Channel* AUD_pauseAfter(AUD_Channel* handle, float seconds); + extern AUD_Sound* AUD_createSequencer(void* data, AUD_volumeFunction volume); extern void AUD_destroySequencer(AUD_Sound* sequencer); diff --git a/intern/audaspace/intern/AUD_IDevice.h b/intern/audaspace/intern/AUD_IDevice.h index bb2d65cde74..d0925f6f647 100644 --- a/intern/audaspace/intern/AUD_IDevice.h +++ b/intern/audaspace/intern/AUD_IDevice.h @@ -34,6 +34,8 @@ struct AUD_Handle { }; +typedef void (*stopCallback)(void*); + /** * This class represents an output device for sound sources. * Output devices may be several backends such as plattform independand like @@ -225,6 +227,18 @@ public: * - false if the handle is invalid. */ virtual bool setLoopCount(AUD_Handle* handle, int count)=0; + + /** + * Sets the callback function that's called when the end of a playing sound + * is reached. + * \param handle The sound handle. + * \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(AUD_Handle* handle, stopCallback callback = 0, void* data = 0)=0; }; #endif //AUD_IDevice diff --git a/intern/audaspace/intern/AUD_NULLDevice.cpp b/intern/audaspace/intern/AUD_NULLDevice.cpp index ec9e02ef28f..272e1e4b5b2 100644 --- a/intern/audaspace/intern/AUD_NULLDevice.cpp +++ b/intern/audaspace/intern/AUD_NULLDevice.cpp @@ -133,3 +133,8 @@ bool AUD_NULLDevice::setLoopCount(AUD_Handle* handle, int count) { return false; } + +bool AUD_NULLDevice::setStopCallback(AUD_Handle* handle, stopCallback callback, void* data) +{ + return false; +} diff --git a/intern/audaspace/intern/AUD_NULLDevice.h b/intern/audaspace/intern/AUD_NULLDevice.h index c6261854803..a1ffdba201a 100644 --- a/intern/audaspace/intern/AUD_NULLDevice.h +++ b/intern/audaspace/intern/AUD_NULLDevice.h @@ -59,6 +59,7 @@ public: virtual bool setPitch(AUD_Handle* handle, float pitch); virtual int getLoopCount(AUD_Handle* handle); virtual bool setLoopCount(AUD_Handle* handle, int count); + virtual bool setStopCallback(AUD_Handle* handle, stopCallback callback = 0, void* data = 0); }; #endif //AUD_NULLDEVICE diff --git a/intern/audaspace/intern/AUD_SilenceFactory.cpp b/intern/audaspace/intern/AUD_SilenceFactory.cpp new file mode 100644 index 00000000000..4e59d7486d5 --- /dev/null +++ b/intern/audaspace/intern/AUD_SilenceFactory.cpp @@ -0,0 +1,37 @@ +/* + * $Id$ + * + * ***** BEGIN LGPL LICENSE BLOCK ***** + * + * Copyright 2009 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 Lesser General Public License as published by + * the Free Software Foundation, either version 3 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with AudaSpace. If not, see . + * + * ***** END LGPL LICENSE BLOCK ***** + */ + +#include "AUD_SilenceFactory.h" +#include "AUD_SilenceReader.h" +#include "AUD_Space.h" + +AUD_SilenceFactory::AUD_SilenceFactory() +{ +} + +AUD_IReader* AUD_SilenceFactory::createReader() const +{ + return new AUD_SilenceReader(); +} diff --git a/intern/audaspace/intern/AUD_SilenceFactory.h b/intern/audaspace/intern/AUD_SilenceFactory.h new file mode 100644 index 00000000000..bc8a5b92727 --- /dev/null +++ b/intern/audaspace/intern/AUD_SilenceFactory.h @@ -0,0 +1,50 @@ +/* + * $Id$ + * + * ***** BEGIN LGPL LICENSE BLOCK ***** + * + * Copyright 2009 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 Lesser General Public License as published by + * the Free Software Foundation, either version 3 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with AudaSpace. If not, see . + * + * ***** END LGPL LICENSE BLOCK ***** + */ + +#ifndef AUD_SILENCEFACTORY +#define AUD_SILENCEFACTORY + +#include "AUD_IFactory.h" + +/** + * This factory creates a reader that plays a sine tone. + */ +class AUD_SilenceFactory : public AUD_IFactory +{ +private: + // hide copy constructor and operator= + AUD_SilenceFactory(const AUD_SilenceFactory&); + AUD_SilenceFactory& operator=(const AUD_SilenceFactory&); + +public: + /** + * Creates a new silence factory. + */ + AUD_SilenceFactory(); + + virtual AUD_IReader* createReader() const; +}; + +#endif //AUD_SILENCEFACTORY diff --git a/intern/audaspace/intern/AUD_SilenceReader.cpp b/intern/audaspace/intern/AUD_SilenceReader.cpp new file mode 100644 index 00000000000..5243286c5e4 --- /dev/null +++ b/intern/audaspace/intern/AUD_SilenceReader.cpp @@ -0,0 +1,74 @@ +/* + * $Id$ + * + * ***** BEGIN LGPL LICENSE BLOCK ***** + * + * Copyright 2009 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 Lesser General Public License as published by + * the Free Software Foundation, either version 3 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with AudaSpace. If not, see . + * + * ***** END LGPL LICENSE BLOCK ***** + */ + +#include "AUD_SilenceReader.h" + +#include + +AUD_SilenceReader::AUD_SilenceReader() : + m_position(0) +{ +} + +bool AUD_SilenceReader::isSeekable() const +{ + return true; +} + +void AUD_SilenceReader::seek(int position) +{ + m_position = position; +} + +int AUD_SilenceReader::getLength() const +{ + return -1; +} + +int AUD_SilenceReader::getPosition() const +{ + return m_position; +} + +AUD_Specs AUD_SilenceReader::getSpecs() const +{ + AUD_Specs specs; + specs.rate = AUD_RATE_44100; + specs.channels = AUD_CHANNELS_MONO; + return specs; +} + +void AUD_SilenceReader::read(int & length, sample_t* & buffer) +{ + // resize if necessary + if(m_buffer.getSize() < length * sizeof(sample_t)) + { + m_buffer.resize(length * sizeof(sample_t)); + memset(m_buffer.getBuffer(), 0, m_buffer.getSize()); + } + + buffer = m_buffer.getBuffer(); + m_position += length; +} diff --git a/intern/audaspace/intern/AUD_SilenceReader.h b/intern/audaspace/intern/AUD_SilenceReader.h new file mode 100644 index 00000000000..a8b959b5309 --- /dev/null +++ b/intern/audaspace/intern/AUD_SilenceReader.h @@ -0,0 +1,71 @@ +/* + * $Id$ + * + * ***** BEGIN LGPL LICENSE BLOCK ***** + * + * Copyright 2009 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 Lesser General Public License as published by + * the Free Software Foundation, either version 3 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with AudaSpace. If not, see . + * + * ***** END LGPL LICENSE BLOCK ***** + */ + +#ifndef AUD_SILENCEREADER +#define AUD_SILENCEREADER + +#include "AUD_IReader.h" +#include "AUD_Buffer.h" + +/** + * This class is used for sine tone playback. + * The output format is in the 16 bit format and stereo, the sample rate can be + * specified. + * As the two channels both play the same the output could also be mono, but + * in most cases this will result in having to resample for output, so stereo + * sound is created directly. + */ +class AUD_SilenceReader : public AUD_IReader +{ +private: + /** + * The current position in samples. + */ + int m_position; + + /** + * The playback buffer. + */ + AUD_Buffer m_buffer; + + // hide copy constructor and operator= + AUD_SilenceReader(const AUD_SilenceReader&); + AUD_SilenceReader& operator=(const AUD_SilenceReader&); + +public: + /** + * Creates a new reader. + */ + AUD_SilenceReader(); + + virtual bool isSeekable() const; + virtual void seek(int position); + virtual int getLength() const; + virtual int getPosition() const; + virtual AUD_Specs getSpecs() const; + virtual void read(int & length, sample_t* & buffer); +}; + +#endif //AUD_SILENCEREADER diff --git a/intern/audaspace/intern/AUD_SoftwareDevice.cpp b/intern/audaspace/intern/AUD_SoftwareDevice.cpp index 1f063e636f1..757f31fc15d 100644 --- a/intern/audaspace/intern/AUD_SoftwareDevice.cpp +++ b/intern/audaspace/intern/AUD_SoftwareDevice.cpp @@ -45,6 +45,12 @@ struct AUD_SoftwareHandle : AUD_Handle /// The loop count of the source. int loopcount; + + /// The stop callback. + stopCallback stop; + + /// Stop callback data. + void* stop_data; }; typedef std::list::iterator AUD_HandleIterator; @@ -151,6 +157,9 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length) // in case the end of the sound is reached if(pos < length) { + if(sound->stop) + sound->stop(sound->stop_data); + if(sound->keep) pause(sound); else @@ -488,3 +497,17 @@ bool AUD_SoftwareDevice::setLoopCount(AUD_Handle* handle, int count) unlock(); return result; } + +bool AUD_SoftwareDevice::setStopCallback(AUD_Handle* handle, stopCallback callback, void* data) +{ + lock(); + bool result = isValid(handle); + if(result) + { + AUD_SoftwareHandle* h = (AUD_SoftwareHandle*)handle; + h->stop = callback; + h->stop_data = data; + } + unlock(); + return result; +} diff --git a/intern/audaspace/intern/AUD_SoftwareDevice.h b/intern/audaspace/intern/AUD_SoftwareDevice.h index c14b5356c6b..93b0f165c7a 100644 --- a/intern/audaspace/intern/AUD_SoftwareDevice.h +++ b/intern/audaspace/intern/AUD_SoftwareDevice.h @@ -132,6 +132,7 @@ public: virtual bool setPitch(AUD_Handle* handle, float pitch); virtual int getLoopCount(AUD_Handle* handle); virtual bool setLoopCount(AUD_Handle* handle, int count); + virtual bool setStopCallback(AUD_Handle* handle, stopCallback callback = NULL, void* data = NULL); }; #endif //AUD_SOFTWAREDEVICE diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 17ff6615ee7..264bae31089 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -438,6 +438,10 @@ void sound_seek_scene(struct bContext *C) else AUD_seek(scene->sound_scene_handle, CFRA / FPS); AUD_resume(scene->sound_scene_handle); + if(AUD_getStatus(scene->sound_scrub_handle) != AUD_STATUS_INVALID) + AUD_seek(scene->sound_scrub_handle, 0); + else + scene->sound_scrub_handle = AUD_pauseAfter(scene->sound_scene_handle, 1 / FPS); } else { diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 984aa5a6705..d0d9d21e0bd 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -797,6 +797,7 @@ typedef struct Scene { void *sound_scene; void *sound_scene_handle; + void *sound_scrub_handle; void *fps_info; /* (runtime) info/cache used for presenting playback framerate info to the user */ diff --git a/source/gameengine/Ketsji/KX_SoundActuator.h b/source/gameengine/Ketsji/KX_SoundActuator.h index ce7612d4bcb..c175a184a15 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.h +++ b/source/gameengine/Ketsji/KX_SoundActuator.h @@ -107,14 +107,12 @@ public: static int pyattr_set_audposition(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static int pyattr_set_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static int pyattr_set_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_rollOffFactor(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static int pyattr_set_type(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_3d_property(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_audposition(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_rollOffFactor(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_type(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); #endif // DISABLE_PYTHON