From: <kla...@us...> - 2010-03-24 16:58:43
|
Revision: 12753 http://vegastrike.svn.sourceforge.net/vegastrike/?rev=12753&view=rev Author: klaussfreire Date: 2010-03-24 16:58:33 +0000 (Wed, 24 Mar 2010) Log Message: ----------- Lots of fixes and some new tests: - Streaming fixes to account for broken OpenAL implementations that don't support setting AL_SEC_OFFSET - Streaming tests now measure time drift. I'm measuring some weird jitter, though... that might be a problem with movie playback - Complex scene test now uses a quicker tick, to test the scene manager's efficiency with many sources - which seems good for now :-D - New test for streaming the same track twice - concurrently. Will be interesting to know if Windows can handle that (windows has some weird file sharing rules - ie: opening a file twice). o While doing that, I noticed we didn't have a generic API for playing a stream from a position other than the beginning. Fixed that. - Warning fixes (initialization order) Modified Paths: -------------- branches/audio/vegastrike/src/audio/RenderableSource.cpp branches/audio/vegastrike/src/audio/RenderableSource.h branches/audio/vegastrike/src/audio/SceneManager.cpp branches/audio/vegastrike/src/audio/SimpleSource.cpp branches/audio/vegastrike/src/audio/Source.cpp branches/audio/vegastrike/src/audio/Source.h branches/audio/vegastrike/src/audio/codecs/FFStream.cpp branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALHelpers.cpp branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALHelpers.h branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableSource.cpp branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableSource.h branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableStreamingSource.cpp branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableStreamingSource.h branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderer.cpp branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALStreamingSound.cpp branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALStreamingSound.h branches/audio/vegastrike/src/audio/test.cpp Modified: branches/audio/vegastrike/src/audio/RenderableSource.cpp =================================================================== --- branches/audio/vegastrike/src/audio/RenderableSource.cpp 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/RenderableSource.cpp 2010-03-24 16:58:33 UTC (rev 12753) @@ -60,5 +60,11 @@ updateImpl(flags, sceneListener); } catch(Exception e) {} } + + void RenderableSource::seek(Timestamp time) + throw(Exception) + { + seekImpl(time); + } }; Modified: branches/audio/vegastrike/src/audio/RenderableSource.h =================================================================== --- branches/audio/vegastrike/src/audio/RenderableSource.h 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/RenderableSource.h 2010-03-24 16:58:33 UTC (rev 12753) @@ -74,6 +74,16 @@ /** Get the attached source */ Source* getSource() const throw() { return source; } + /** Seek to the specified position + * @note It may not be supported by the renderer on all sources. + * Streaming sources are guaranteed to perform a rough seek on a best effort + * basis, meaning the effective time after the seek may be off a bit, and + * the process may be costly. + * Seeking in non-streaming sources may not be supported at all. + * @throws EndOfStreamException if you try to seek past the end + */ + void seek(Timestamp time) throw(Exception); + /** Update the underlying API with dirty attributes * @param flags You may specify which attributes to update. Not all attributes are * equally costly, so you'll want to ease up on some, pump up some others. @@ -108,6 +118,9 @@ /** @see update. */ virtual void updateImpl(int flags, const Listener& sceneListener) throw(Exception) = 0; + + /** @see seek. */ + virtual void seekImpl(Timestamp time) throw(Exception) = 0; }; }; Modified: branches/audio/vegastrike/src/audio/SceneManager.cpp =================================================================== --- branches/audio/vegastrike/src/audio/SceneManager.cpp 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/SceneManager.cpp 2010-03-24 16:58:33 UTC (rev 12753) @@ -12,6 +12,7 @@ #include "SimpleSource.h" #include "SimpleScene.h" #include "Sound.h" +#include "SourceListener.h" #include <limits> #include <assert.h> @@ -88,10 +89,11 @@ Duration activationFrequency; SceneManagerData() : + rootListener(new Listener()), + maxSources(16), minGain(1.0 / 16384.0), maxDistance(std::numeric_limits<double>::infinity()), - rootListener(new Listener()), lastPositionUpdateTime(-std::numeric_limits<Timestamp>::infinity()), lastAttributeUpdateTime(-std::numeric_limits<Timestamp>::infinity()), @@ -438,8 +440,8 @@ SourcePriorityRef(SimpleScene::SourceIterator itr, const Listener &listener, SimpleScene *scn) : iter(itr), - gain( estimateGain(**iter, listener) ), - scene(scn) + scene(scn), + gain( estimateGain(**iter, listener) ) { } @@ -478,6 +480,11 @@ sit != send; ++sit) { + if ( (*sit)->getSourceListener().get() ) { + // Must invoke the listener to get updated positions + (*sit)->getSourceListener()->onUpdate(**sit, RenderableSource::UPDATE_LOCATION); + } + if (listener.getPosition().distanceSquared((*sit)->getPosition()) < maxDistanceSq) { SourcePriorityRef ref(sit, listener, scene); if (ref.gain > data->minGain) { Modified: branches/audio/vegastrike/src/audio/SimpleSource.cpp =================================================================== --- branches/audio/vegastrike/src/audio/SimpleSource.cpp 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/SimpleSource.cpp 2010-03-24 16:58:33 UTC (rev 12753) @@ -13,8 +13,8 @@ SimpleSource::SimpleSource(SharedPtr<Sound> sound, bool looping) throw() : Source(sound, looping), - scene(0), - playing(false) + playing(false), + scene(0) { } Modified: branches/audio/vegastrike/src/audio/Source.cpp =================================================================== --- branches/audio/vegastrike/src/audio/Source.cpp 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/Source.cpp 2010-03-24 16:58:33 UTC (rev 12753) @@ -13,18 +13,23 @@ Source::Source(SharedPtr<Sound> sound, bool _looping) throw() : soundPtr(sound), + + // Some safe defaults + position(0,0,0), + direction(0,0,1), + velocity(0,0,0), + cosAngleRange(-1,-1), + + radius(1), + pfRadiusRatios(1,1), referenceFreqs(250,5000), + gain(1), + lastKnownPlayingTime(0), - lastKnownPlayingTimeTime( getRealTime() ), - - // Some safe defaults - position(0,0,0), - direction(0,0,1), - velocity(0,0,0), - radius(1) + lastKnownPlayingTimeTime( getRealTime() ) { // Some default flags setLooping(_looping); @@ -43,10 +48,10 @@ return timestamp; } - void Source::startPlaying() throw(Exception) + void Source::startPlaying(Timestamp start) throw(Exception) { dirty.setAll(); - startPlayingImpl( setLastKnownPlayingTime(0) ); + startPlayingImpl( setLastKnownPlayingTime(start) ); } void Source::stopPlaying() throw() @@ -199,5 +204,15 @@ if (sourceListenerPtr.get() != 0 && sourceListenerPtr->wantAttachEvents()) sourceListenerPtr->onPostAttach(*this, ptr.get() != 0); } + + void Source::seek(Timestamp time) + throw(Exception) + { + if (rendererDataPtr.get() && isPlaying() && isActive()) { + rendererDataPtr->seek(time); + } else { + setLastKnownPlayingTime(time); + } + } }; Modified: branches/audio/vegastrike/src/audio/Source.h =================================================================== --- branches/audio/vegastrike/src/audio/Source.h 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/Source.h 2010-03-24 16:58:33 UTC (rev 12753) @@ -197,10 +197,11 @@ void setRelative(bool relative) throw() { flags.relative = relative ? 1 : 0; dirty.attributes = 1; } /** Play the source + * @param start an optional timestamp to start playing from. * @remarks Rewind and play from the beginning. If the source is playing, it is reset. * May not take effect immediately. */ - void startPlaying() throw(Exception); + void startPlaying(Timestamp start = 0) throw(Exception); /** Stop a playing source * @remarks If the source is playing, stop it. Otherwise, do nothing. @@ -274,6 +275,16 @@ */ void updateRenderable(int flags, const Listener& sceneListener) throw(); + /** Seek to the specified position + * @note It may not be supported by the renderer on all sources. + * Streaming sources are guaranteed to perform a rough seek on a best effort + * basis, meaning the effective time after the seek may be off a bit, and + * the process may be costly. + * Seeking in non-streaming sources may not be supported at all. + * @throws EndOfStreamException if you try to seek past the end + */ + void seek(Timestamp time) throw(Exception); + protected: /** Set the last known playing time, update the measurement timestamp as well. * @return the parameter, for chaining. Modified: branches/audio/vegastrike/src/audio/codecs/FFStream.cpp =================================================================== --- branches/audio/vegastrike/src/audio/codecs/FFStream.cpp 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/codecs/FFStream.cpp 2010-03-24 16:58:33 UTC (rev 12753) @@ -71,6 +71,9 @@ size_t sampleBufferAlloc; // in bytes uint64_t sampleBufferStart; // in samples + std::string filepath; + VSFileSystem::VSFileType filetype; + int audioStreamIndex; FFData(const std::string &path, VSFileSystem::VSFileType type, Format &fmt, int streamIdx) throw(Exception) : pFormatCtx(0), @@ -79,7 +82,10 @@ pStream(0), packetBuffer(0), packetBufferSize(0), - sampleBufferBase(0) + sampleBufferBase(0), + filepath(path), + filetype(type), + audioStreamIndex(streamIdx) { packet.data = 0; @@ -173,6 +179,11 @@ av_close_input_file(pFormatCtx); } + bool saneTimeStamps() const throw() + { + return pCodecCtx->time_base.num != 0; + } + int64_t timeToPts(double time) const throw() { return int64_t(floor(time * pCodecCtx->time_base.den / pCodecCtx->time_base.num)); @@ -290,10 +301,22 @@ ffData->sampleBufferStart += advance; ffData->sampleBufferSize -= advance; } else { - // rough seek - avcodec_flush_buffers(ffData->pCodecCtx); - av_seek_frame(ffData->pFormatCtx, ffData->streamIndex, ffData->timeToPts(position), AVSEEK_FLAG_BACKWARD); - ffData->syncPts(); + if (ffData->saneTimeStamps()) { + // rough seek + avcodec_flush_buffers(ffData->pCodecCtx); + av_seek_frame(ffData->pFormatCtx, ffData->streamIndex, ffData->timeToPts(position), + (targetSample < ffData->sampleBufferStart + ffData->sampleBufferSize) ? AVSEEK_FLAG_BACKWARD : 0); + ffData->syncPts(); + } else if (targetSample < ffData->sampleBufferStart) { + // cannot seek but have to seek backwards, so... + // ...close the file and reopen (yack) + std::string path = ffData->filepath; + VSFileSystem::VSFileType type = ffData->filetype; + int streamIndex = ffData->audioStreamIndex; + + delete ffData; + ffData = new __impl::FFData(path, type, getFormatInternal(), streamIndex); + } // just skip data (big steps) do { Modified: branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALHelpers.cpp =================================================================== --- branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALHelpers.cpp 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALHelpers.cpp 2010-03-24 16:58:33 UTC (rev 12753) @@ -17,10 +17,9 @@ namespace __impl { namespace OpenAL { - void _checkAlErrorAt(const char *filename, int lineno) + void _checkAlErrorAt(ALenum error, const char *filename, int lineno) throw (Exception) { - ALenum error = alGetError(); switch(error) { case AL_NO_ERROR : return; default: Modified: branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALHelpers.h =================================================================== --- branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALHelpers.h 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALHelpers.h 2010-03-24 16:58:33 UTC (rev 12753) @@ -4,14 +4,15 @@ #include "../../Exceptions.h" #include "al.h" -#define checkAlError() Audio::__impl::OpenAL::_checkAlErrorAt(__FILE__, __LINE__) +#define checkAlErrorCode(error) Audio::__impl::OpenAL::_checkAlErrorAt((error), __FILE__, __LINE__) +#define checkAlError() Audio::__impl::OpenAL::_checkAlErrorAt(alGetError(), __FILE__, __LINE__) #define clearAlError() Audio::__impl::OpenAL::_clearAlError(); namespace Audio { namespace __impl { namespace OpenAL { - void _checkAlErrorAt(const char *filename, int lineno) throw (Exception); + void _checkAlErrorAt(ALenum error, const char *filename, int lineno) throw (Exception); void _clearAlError() throw(); ALenum asALFormat(const Format &format) throw(); Modified: branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableSource.cpp =================================================================== --- branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableSource.cpp 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableSource.cpp 2010-03-24 16:58:33 UTC (rev 12753) @@ -50,9 +50,10 @@ clearAlError(); ALuint als = getALSource(); alSourcePlay(als); + checkAlError(); + if (start != 0) - alSourcef(als, AL_SEC_OFFSET, start); - checkAlError(); + seekImpl(start); } } @@ -156,5 +157,25 @@ checkAlError(); } } + + void OpenALRenderableSource::seekImpl(Timestamp time) + throw(Exception) + { + // Tell the AL to jump to the specified position + // NOTE: lots of implementations don't support it + // but according to OpenAL 1.1 specs they should + clearAlError(); + ALuint als = getALSource(); + alSourcef(als, AL_SEC_OFFSET, time); + + ALenum error = alGetError(); + if (error == ALC_INVALID_ENUM) { + // This version of the AL does not support seeking + // fail silently + // TODO: must log the fact to console as a warning + } else { + checkAlErrorCode(error); + } + } }; Modified: branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableSource.h =================================================================== --- branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableSource.h 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableSource.h 2010-03-24 16:58:33 UTC (rev 12753) @@ -46,6 +46,9 @@ /** @see RenderableSource::updateImpl. */ virtual void updateImpl(int flags, const Listener& sceneListener) throw(Exception); + /** @see RenderableSource::seekImpl. */ + virtual void seekImpl(Timestamp time) throw(Exception); + /** Derived classes may use the underlying AL source handle to set additional attributes */ ALuint getALSource() const { return alSource; } Modified: branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableStreamingSource.cpp =================================================================== --- branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableStreamingSource.cpp 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableStreamingSource.cpp 2010-03-24 16:58:33 UTC (rev 12753) @@ -89,6 +89,14 @@ return Timestamp(offs); } + void OpenALRenderableStreamingSource::seekImpl(Timestamp time) + throw(Exception) + { + // Seek the stream to the specified position + dynamic_cast<OpenALStreamingSound*>(getSource()->getSound().get()) + ->seek(time); + } + void OpenALRenderableStreamingSource::updateImpl(int flags, const Listener& sceneListener) throw(Exception) { Modified: branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableStreamingSource.h =================================================================== --- branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableStreamingSource.h 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderableStreamingSource.h 2010-03-24 16:58:33 UTC (rev 12753) @@ -45,6 +45,9 @@ /** @see RenderableSource::updateImpl. */ virtual void updateImpl(int flags, const Listener& sceneListener) throw(Exception); + /** @see RenderableSource::seekImpl. */ + virtual void seekImpl(Timestamp time) throw(Exception); + /** Derived classes may use the underlying AL source handle to set additional attributes */ ALuint getALSource() const { return alSource; } Modified: branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderer.cpp =================================================================== --- branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderer.cpp 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALRenderer.cpp 2010-03-24 16:58:33 UTC (rev 12753) @@ -4,9 +4,6 @@ #include "OpenALRenderer.h" #include "BorrowedOpenALRenderer.h" -#include "OpenALRenderableListener.h" -#include "OpenALRenderableSource.h" -#include "OpenALRenderableStreamingSource.h" #include "OpenALHelpers.h" #include "config.h" @@ -17,7 +14,12 @@ #include "../../Listener.h" #include "OpenALSimpleSound.h" +#include "OpenALStreamingSound.h" +#include "OpenALRenderableListener.h" +#include "OpenALRenderableSource.h" +#include "OpenALRenderableStreamingSource.h" + namespace Audio { namespace __impl { @@ -245,19 +247,16 @@ { checkContext(); SharedPtr<Sound> sound = data->lookupSound(type,name); - if (!sound.get() || (!streaming && sound->isStreaming())) { - // If a pre-existing sound is streaming, and we're required - // to load the sound in non-streaming fashion, we have to - // to load a new version of it, and forget about the old one. - // When all references to the streaming version are lost, - // resources will be freed automatically. + if (!sound.get() || streaming) { if (streaming) { - /* + // Streaming sounds cannot be cached, so if a streaming sound + // is in the cache, it must be evicted and re-created + sound.reset(); data->addSound( + type, + name, sound = SharedPtr<Sound>(new OpenALStreamingSound(name,type)) ); - */ - throw NotImplementedException("OpenAL Streaming"); } else { data->addSound( type, Modified: branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALStreamingSound.cpp =================================================================== --- branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALStreamingSound.cpp 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALStreamingSound.cpp 2010-03-24 16:58:33 UTC (rev 12753) @@ -29,7 +29,7 @@ OpenALStreamingSound::OpenALStreamingSound(const std::string& name, VSFileSystem::VSFileType type, unsigned int _bufferSamples) throw() : - SimpleSound(name, type, false), + SimpleSound(name, type, true), bufferSamples(_bufferSamples) { for (size_t i=0; i < NUM_BUFFERS; ++i) Modified: branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALStreamingSound.h =================================================================== --- branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALStreamingSound.h 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/renderers/OpenAL/OpenALStreamingSound.h 2010-03-24 16:58:33 UTC (rev 12753) @@ -1,8 +1,8 @@ // // C++ Interface: Audio::OpenALSimpleSound // -#ifndef __AUDIO_OPENALSIMPLESOUND_H__INCLUDED__ -#define __AUDIO_OPENALSIMPLESOUND_H__INCLUDED__ +#ifndef __AUDIO_OPENALSTREAMINGSOUND_H__INCLUDED__ +#define __AUDIO_OPENALSTREAMINGSOUND_H__INCLUDED__ #include "../../Exceptions.h" #include "../../Types.h" @@ -102,4 +102,4 @@ }; -#endif//__AUDIO_SIMPLESOUND_H__INCLUDED__ +#endif//__AUDIO_OPENALSTREAMINGSOUND_H__INCLUDED__ Modified: branches/audio/vegastrike/src/audio/test.cpp =================================================================== --- branches/audio/vegastrike/src/audio/test.cpp 2010-03-23 00:28:39 UTC (rev 12752) +++ branches/audio/vegastrike/src/audio/test.cpp 2010-03-24 16:58:33 UTC (rev 12753) @@ -18,6 +18,7 @@ #include <iostream> #include <string> +#include <limits> #include "utils.h" @@ -66,6 +67,12 @@ sleep(100); } + void smQuickTick() + { + SceneManager::getSingleton()->commit(); + sleep(10); + } + void testRendererless() { // Test clearing and creating scenes repeatedly @@ -245,12 +252,13 @@ class EngParticleListener : public UpdateSourceListener { const vector<LVector3> &engPaths; // x=phase, y=speed, z=wobble - double worldSize; + + public: + double time; public: EngParticleListener(const vector<LVector3> &engpaths, double worldsize) : - engPaths(engpaths), - worldSize(worldsize) + engPaths(engpaths) { } @@ -259,18 +267,16 @@ assert(which >= 0 && which < (long)engPaths.size()); double phase = engPaths[which].x + phaseOffset; - double wobble = engPaths[which].z; - double wobbleFreq = 23 * 2 * M_PI * which; + double speed = engPaths[which].y; + double radii = engPaths[which].z; LVector3 vBase = LVector3( - cos(phase) * worldSize, - -sin(phase) * worldSize, + cos(phase + time * speed) * radii, + -sin(phase + time * speed) * radii, 0 ); - LVector3 vWobble = vBase * (sin(phase*wobbleFreq) * wobble); - - return vBase + vWobble; + return vBase; } LVector3 computeVelocity(long which, double phaseOffset=0.0) const @@ -278,25 +284,16 @@ assert(which >= 0 && which < (long)engPaths.size()); double phase = engPaths[which].x + phaseOffset; - double wobble = engPaths[which].z; - double wobbleFreq = 23 * 2 * M_PI * sin(which); + double speed = engPaths[which].y; + double radii = engPaths[which].z; LVector3 dvBase = LVector3( - -sin(phase) * worldSize, - -cos(phase) * worldSize, + -sin(phase + time * speed) * radii * speed, + -cos(phase + time * speed) * radii * speed, 0 ); - LVector3 vBase = LVector3( - cos(phase) * worldSize, - -sin(phase) * worldSize, - 0 - ); - - LVector3 dvWobble = vBase * (cos(phase*wobbleFreq) * wobble * wobbleFreq) - + dvBase * (sin(phase*wobbleFreq) * wobble); - - return dvBase + dvWobble; + return dvBase; } /** @@ -318,13 +315,14 @@ } }; - void testComplexScene() + void testComplexScene(bool doppler) { cerr << " Complex scene" << endl; clearScene(); int i; + double t; SceneManager *sm = SceneManager::getSingleton(); @@ -352,7 +350,15 @@ // distance (forcing sources on/off) const size_t nengs = 100; + const double worldsize = 500.0; + // Set scene manager settings for test + sm->setMaxSources(10); + sm->setMaxDistance(worldsize/4); + sm->getRenderer()->setDopplerFactor(doppler ? 0.25 : 0.0); + sm->getRenderer()->setMeterDistance(1.0); + + cerr << " Creating resources" << endl; cerr << " looking up templates..." << flush; SharedPtr<SourceTemplate> abtpl = TemplateManager::getSingleton()->getSourceTemplate( @@ -383,8 +389,6 @@ vector<LVector3> engpaths; // x=phase, y=speed, z=wobble // Fill in engpaths - const double worldsize = 100.0; - SharedPtr<SourceListener> englistener( new EngParticleListener(engpaths,worldsize) ); @@ -392,16 +396,18 @@ { const double phase_step = 2.0 * M_PI / nengs; for (size_t i = 0; i < nengs; ++i) { - double phase = (i + rand() / double(RAND_MAX)) * phase_step; - double speed = phase_step * ( double(rand() + RAND_MAX/2) / RAND_MAX ); - double wobble = 7 * sin(13*i) * speed * worldsize * 0.01; + double phase = i * phase_step; + double speed = 2.0 * phase_step * ( double(rand() + RAND_MAX/2) / RAND_MAX ); + double radii = worldsize * ( 1.0 + 0.25 * double(rand() - RAND_MAX/2) / RAND_MAX ); - engpaths.push_back(LVector3(phase, speed, wobble)); + engpaths.push_back(LVector3(phase, speed, radii)); SharedPtr<Source> src = sm->createSource(engtpl); src->setUserDataLong(i); src->setSourceListener(englistener); engsources.push_back(src); + + spcscene->add(src); } } @@ -410,13 +416,38 @@ cerr << " playing out scene..." << flush; + absource->setGain(0.01); absource->startPlaying(); - { for (vector<SharedPtr<Source> >::iterator i = engsources.begin(); i != engsources.end(); ++i) - (*i)->startPlaying(); } + { + for (vector<SharedPtr<Source> >::iterator i = engsources.begin(); i != engsources.end(); ++i) + (*i)->startPlaying(); + } - for (i=0; i<100; ++i) // 10s = 100 ticks - smTick(); + for (t=getRealTime(); (getRealTime()-t) < 20.0; ) { // 20s = 200 ticks + const double phase_step = 2.0 * M_PI / 20; + double phase = (getRealTime()-t) * phase_step; + double speed = phase_step; + + LVector3 pos = LVector3( + cos(phase) * worldsize, + -sin(phase) * worldsize, + 0 + ); + + LVector3 dpos = LVector3( + -sin(phase) * worldsize * speed, + -cos(phase) * worldsize * speed, + 0 + ); + + spcscene->getListener().setOrientation( dpos, Vector3(0,1,0) ); + spcscene->getListener().setPosition( pos ); + + dynamic_cast<EngParticleListener*>(englistener.get())->time = (getRealTime()-t) / 20.0; + + smQuickTick(); + } absource->stopPlaying(); { for (vector<SharedPtr<Source> >::iterator i = engsources.begin(); i != engsources.end(); ++i) @@ -435,6 +466,7 @@ clearScene(); int i; + double timeDelta = 0.0; SceneManager *sm = SceneManager::getSingleton(); @@ -470,14 +502,34 @@ cerr << " playing out scene..." << flush; + double startPlayingTime = getRealTime(); musicsource->startPlaying(); - for (i=0; i<200; ++i) // 20s = 200 ticks + for (i=0; i<200; ++i) { // 20s = 200 ticks smTick(); + + // Track drift + double realTime = getRealTime(); + double curPlayingTime = musicsource->getPlayingTime(); + double shouldPlayingTime = realTime - startPlayingTime; + double delta = fabs(curPlayingTime - shouldPlayingTime); + if (delta > timeDelta) + timeDelta = delta; + + // Resync supposed start time to account for systematic + // drift (which isn't that bad, and quite normal in fact) + startPlayingTime = realTime - curPlayingTime; + + cerr << "Time delta: " << int(delta * 1000) << "ms (max " << int(timeDelta * 1000) << "ms)\t\r" << flush; + } musicsource->stopPlaying(); for (i=0; i<10; ++i) // 1s = 10 ticks smTick(); + if (timeDelta > (1.0 / 30.0)) + cerr << "\nWARNING: Poor time tracking resolution\n"; + cerr << " Time drift at " << int(timeDelta*1000) << "ms" << endl; + cerr << " ok" << endl; } @@ -488,6 +540,7 @@ clearScene(); int i; + double timeDelta = 0.0; SceneManager *sm = SceneManager::getSingleton(); @@ -536,10 +589,26 @@ cerr << " playing out scene..." << flush; + double startPlayingTime = getRealTime(); musicsource->startPlaying(); musicsource2->startPlaying(); - for (i=0; i<200; ++i) // 20s = 200 ticks + for (i=0; i<200; ++i) { // 20s = 200 ticks smTick(); + + // Track drift + double realTime = getRealTime(); + double curPlayingTime = musicsource->getPlayingTime(); + double shouldPlayingTime = realTime - startPlayingTime; + double delta = fabs(curPlayingTime - shouldPlayingTime); + if (delta > timeDelta) + timeDelta = delta; + + // Resync supposed start time to account for systematic + // drift (which isn't that bad, and quite normal in fact) + startPlayingTime = realTime - curPlayingTime; + + cerr << "Time delta: " << int(delta * 1000) << "ms (max " << int(timeDelta * 1000) << "ms)\t\r" << flush; + } musicsource->stopPlaying(); for (i=0; i<50; ++i) // 5s = 50 ticks @@ -549,10 +618,106 @@ for (i=0; i<10; ++i) // 1s = 10 ticks smTick(); + if (timeDelta > (1.0 / 30.0)) + cerr << "\nWARNING: Poor time tracking resolution\n"; + cerr << " Time drift at " << int(timeDelta*1000) << "ms" << endl; + cerr << " ok" << endl; } + void testMultiStreaming2() + { + cerr << " Multiple streaming (stream one music track - twice - from different positions)" << endl; + + clearScene(); + + int i; + double timeDelta = 0.0; + + SceneManager *sm = SceneManager::getSingleton(); + + // Create (and verify that) a test scene + SharedPtr<Scene> scene = sm->createScene("testScene"); + sm->getScene("testScene"); + sm->setSceneActive("testScene",true); + + // Multi streaming test scene: + // 1. Two streaming music tracks playing simultaneously + cerr << " Creating resources" << endl; + cerr << " creating sounds..." << flush; + SharedPtr<Sound> music = sm->getRenderer()->getSound( + "SonOfSandFleaRemix.ogg", VSFileSystem::MusicFile, true); + SharedPtr<Sound> music2 = sm->getRenderer()->getSound( + "SonOfSandFleaRemix.ogg", VSFileSystem::MusicFile, true); + cerr << " ok" << endl; + cerr << " loading sounds..." << flush; + music->load(); + music2->load(); + cerr << " ok" << endl; + + cerr << " setting up listener..." << flush; + scene->getListener().setOrientation( Vector3(0,0,1), Vector3(0,1,0) ); + scene->getListener().setPosition( LVector3(0,0,0) ); + cerr << " ok" << endl; + + cerr << " creating sources..." << flush; + + SharedPtr<Source> musicsource = sm->createSource(music); + musicsource->setPosition(Vector3(0,0,0)); + musicsource->setGain(1.0f); + musicsource->setAttenuated(false); + musicsource->setRelative(true); + + SharedPtr<Source> musicsource2 = sm->createSource(music2); + musicsource2->setPosition(Vector3(0,0,0)); + musicsource2->setGain(1.0f); + musicsource2->setAttenuated(false); + musicsource2->setRelative(true); + + scene->add(musicsource); + scene->add(musicsource2); + + cerr << " ok" << endl; + + cerr << " playing out scene..." << flush; + + double startPlayingTime = getRealTime(); + musicsource->startPlaying(); + musicsource2->startPlaying(60.0); + for (i=0; i<200; ++i) { // 20s = 200 ticks + smTick(); + + // Track drift + double realTime = getRealTime(); + double curPlayingTime = musicsource->getPlayingTime(); + double shouldPlayingTime = realTime - startPlayingTime; + double delta = fabs(curPlayingTime - shouldPlayingTime); + if (delta > timeDelta) + timeDelta = delta; + + // Resync supposed start time to account for systematic + // drift (which isn't that bad, and quite normal in fact) + startPlayingTime = realTime - curPlayingTime; + + cerr << "Time delta: " << int(delta * 1000) << "ms (max " << int(timeDelta * 1000) << "ms)\t\r" << flush; + } + + musicsource->stopPlaying(); + for (i=0; i<50; ++i) // 5s = 50 ticks + smTick(); + + musicsource2->stopPlaying(); + for (i=0; i<10; ++i) // 1s = 10 ticks + smTick(); + + if (timeDelta > (1.0 / 30.0)) + cerr << "\nWARNING: Poor time tracking resolution\n"; + cerr << " Time drift at " << int(timeDelta*1000) << "ms" << endl; + + cerr << " ok" << endl; + } + void initALRenderer() { cerr << " Initializing renderer..." << endl; @@ -590,12 +755,14 @@ testSimpleSceneWFileTemplates(); // Now more complex scenes... - testComplexScene(); - testComplexScene(); // Test replay ability + testComplexScene(false); + testComplexScene(false); // Test replay ability + testComplexScene(true); // Streaming tests testStreaming(); testMultiStreaming(); + testMultiStreaming2(); // Tidy close closeRenderer(); |