Maximum number of sources? (python-ogre)

cradle

23-03-2007 11:21:01

Is there a maximum number of sources that you are allowed to create for any given soundcard? If so, how do I get around it? (or is it a limited number of buffers, does OgreAL share sources with the same filename... how would I do that myself if it doesn't?)


The details...

Not sure whether to post here or the python-ogre forums... anyway.

I'm using OgreAL (through its wrapper in python-ogre, latest version [0.90a]) and it works like a charm, except sometimes...

When a certain number of audio sources are created, my Audio code crashes; the two errors I'm experiencing are..

There is no current context in OgreAL::Sound::createAndBindSource

and

The specified source name is not valid in OgreAL::Sound::initSource

Both of which occur at this line in my code...

self.sounds[gun] = self.soundManager.createSound(gun + "-" + name, gun + ".wav", False)

...where 'gun' is a unique name for the gun, and 'name' is the unique name for the player.

The code that I use to initialise the engine is...

self.soundManager = OgreAL.SoundManager()

So, how I can reproduce this (it seems to be different on every machine I try, hence my soundcard theory) is by joining "x" number of players to a game, and once a certain number of players join, some of the computers will crash out with errors akin to the ones above. All up I'm probably using about 15 or so unique sounds, all very small 'wav' files.

The no context was thrown by a card registering as a "NVIDIA(R) nForce(TM) Audio" with OgreAL, whereas the other error was thrown by a card which was using "Generic Hardware" (presumable through the wrapper).

So, I guess my question is, is my theory correct, there there are only a certain number of sources you can create? (not sure why I'm getting two different errors though) Or is there something else I may not be aware of? How do people get around the limited number of sources issue? Can you share a buffer (?) between sources? I'd rather not have to share a source between different objects... ideas? What am I missing?

- Glenn

cradle

23-03-2007 13:29:39

Ok... I did search this forum for answers, but I didn't search the developers forum, in which I found http://www.ogre3d.org/phpBB2/viewtopic.php?t=18753&view=previous&sid=66e380ba5e34080034028300176fdd7b (yay for google :D)

So, now that I know that, what are people's strategies for playing lots of sounds? (lots of bullets, explosions, footsteps, ricochets, etc...)

Just play the sound if there are sources left? Removing old sources when they are finished and recreating them again when needed? Or is there a smarter way...?

- Glenn

CaseyB

23-03-2007 16:44:31

There is a lot going into the next release. It may take a while but I'll announce changes as they come up. Anyway, one of the bits of functionality we are looking to add is something like a particle system. There would be a sound emitter which would instantiate short lived sounds like footsteps, bullets, etc.

cradle

24-03-2007 00:47:44

Ah, I see. Cool.

Just fyi, I've implemented a rather simplistic 'particle' sounds system as a stand in for a better one... here's how it goes.

class SFX(object):
def __init__(self, soundManager):
self.soundNum = 0
self.soundManager = soundManager
self.sounds = []
self.maxSounds = soundManager.maxSources()
print "Maximum Sound Sources:", self.maxSounds

def play(self, soundFile, position, refDistance = 2.0, rolloffFactor = 0.1, maxDistance = 200.0):
for s in self.sounds[:]:
if s.isStopped():
self.soundManager.destroySound(s)
self.sounds.remove(s)
if len(self.sounds) < self.maxSounds:
s = self.soundManager.createSound("sfx%i" % self.soundNum, soundFile, False)
self.soundNum += 1
s.setPosition(position)
s.setMaxDistance(maxDistance)
s.setRolloffFactor(rolloffFactor)
s.setReferenceDistance(refDistance)
s.play()
self.sounds.append(s)


As far as I can tell it works, it just has a very brutal contingency plan once the maximum number of sounds are playing (32 on mine): it doesn't play any more.

Nice work on OgreAL, it's very useful.

- Glenn

cradle

24-03-2007 01:17:59

Iiinteresting... seems that the machine that was crashing (the one with the Nforce2), was reporting as having 0 maxSources()... investigate I will.

- Glenn

CaseyB

24-03-2007 02:55:23

That is odd. Do you have the OpenAL redistributable installed on that machine?

cradle

24-03-2007 04:33:47

Yeah, I do. I tried bundling the OpenAL wrapper and dll with it, I tried (removing the bundled version) and using the Creative OpenAL installer, then tried using the Creative installer with EAX. All reported the maxSources as 0. However, on a hunch I rolled back the Nforce audio driver to a 2003 version of a Realtek driver (which correspondingly meant it chose Generic Hardware over the NVidia OpenAL dll) and it reported the max sources as 32 and worked properly. Not sure why exactly that was happening, maybe the NVidia dll does funny stuff?

On a similar note, is there any way I can select which of the enumerated devices that OgreAL should use? I would like to be able to see if selecting Generic Hardware, or Generic Software would make that machine work with the NVidia drivers for the souncard installed.

- Glenn

CaseyB

24-03-2007 05:10:08

On a similar note, is there any way I can select which of the enumerated devices that OgreAL should use?Not yet. That is something that I would really love to add in, but I can't find a good reference on how to choose a certain device, all I see is how to create the "Default Device." I'll have another look and see what I can find though.

Samir

27-03-2007 19:02:19

A large number of sources is a must in the game I'm developing as it's an RTS game...and I was expecting that OgreAL would take care of that...it didn't... :( ...now I see it's planned for the next release...so...anything I can do to help out?...It's only a matter of managing buffers...I can do that :-)...

CaseyB

27-03-2007 19:33:16

If you want to give it a shot and submit a patch that would be most welcome! There are actually two sides to this issue. The first is managing buffers, which is not so bad and there is already a bit of that in place now. The second part is much less trivial and that is managing sources. As it stands now each Sound owns it's source and can do with it what it wants. In order to play many sounds at once then the sound would need to have some kind of a transparent object that looks like a source, but doesn't always have to be the OpenAL Source. It would then try to get the source when it is played. and should do something intelligent when there are too many sources. It's a really tough problem to solve in a nice, clean way. That's why I haven't tackled it yet, I've been thinking about what's best. Feel free to give it a go though! I'd love to see what you come up with!

Samir

27-03-2007 21:14:30

If you want to give it a shot and submit a patch that would be most welcome!

I intended to, but wanted to make sure nobody started already, or see if you already have some idea about how to go about implementing it, and if not, discuss my ideas before giving it a shot.

There are actually two sides to this issue. The first is managing buffers, which is not so bad and there is already a bit of that in place now.

Oh...ok...good you cleared that out...but there is something I don't get...why is managing buffers so different from managing sources?...don't both have a limited number?...of course buffers have the thing where a file already loaded shouldn't be loaded again...but sill...not sure where the difference in managing them is...


The second part is much less trivial and that is managing sources. As it stands now each Sound owns it's source and can do with it what it wants. In order to play many sounds at once then the sound would need to have some kind of a transparent object that looks like a source, but doesn't always have to be the OpenAL Source. It would then try to get the source when it is played. and should do something intelligent when there are too many sources. It's a really tough problem to solve in a nice, clean way. That's why I haven't tackled it yet, I've been thinking about what's best. Feel free to give it a go though! I'd love to see what you come up with!


Here is what I was thinking.

- Sound object would not be permanently associated with an OpenAL source, instead, each time they want to play, they request an OpenAL source from the manager.
- On the manager's side, a heap holding structs such as:

struct Source {
ALunit source;
int usage_count;
bool operator<(Source const & s1, Source const & s2) const {
return s1.usage_count > s2.usage_count;
}
Source & operator++() {
++usage_count;
return *this;
}
};

and each time a Sound wants to play, the Source object in the heap would be increased, and if it doesn't exist, the top of the heap would be given to the requesting Sound to use as its source (that would be the one least used).
- For those who don't want the extra overhead of inserting into a heap (which is not much considering Sounds are not played all that often compared to other events happening every frame), an option could be added to disable that functionality and throw a well explained exception when the maximum limit of Sounds is used, suggesting the enabling of that option.

Hope I explained myself clearly enough...

So...what do you think of the idea?...is it worth a shot, or do you have a better one?...

CaseyB

30-03-2007 16:07:09

That sounds almost exactly like what I was thinking! The only comment that I have is that you may want to hide the complexity in an OgreAL::Source class and the OgreAL::Sound can own an instance of one. But yeah, sounds good!

Samir

30-03-2007 16:13:15

That sounds almost exactly like what I was thinking!

HA HA...Cool...so if 2 people thought of the same idea separately...it must be the best :D

The only comment that I have is that you may want to hide the complexity in an OgreAL::Source class and the OgreAL::Sound can own an instance of one.

OK.

But yeah, sounds good!

Cool...I'll keep you posted whenever I make a significant progress.

t0tAl_mElTd0wN

30-03-2007 18:01:21

I haven't worked on OgreAL in a bit, but it's still there in the back of my mind and I expect I'll start doing a /lot/ more with it once we get to that point in the game I'm developing. If someone could figure out how to mix sounds in software and "bundle" them together into a single source, I'll definitely include that in the scripts. 'Sound Particles' seem to be an important feature that has come up more than a few times here, so if I (or someone else?) can figure out how to do software mixing of sounds then I'll allow for sounds to be dynamically generated from one (or many) sound files, pieced together with a script, and attached to a single source.

Samir

02-04-2007 08:16:09

I have successfully created and used 30 Sounds out of only 7 Sources on my Sound Card... :D

There are still things remaining to be done though, including:

  1. 1- Take into consideration the case when all physical sources are playing.[/list:u]
    1. 2- Allow the management of part of the physical sources only, the other would part be permanently assigned to their sound, especially useful for background music. (This has been partially done).[/list:u]
      1. 3- Cleaner code design: Currently, the communication between the SourceManager class and the Sound class is not very clean, I'm considering moving all the source related private members from the Sound class to the Source struct (and maybe that would become a class too).[/list:u]

        Let me know of any suggestions you might have...

CaseyB

02-04-2007 09:00:55

I have successfully created and used 30 Sounds out of only 7 Sources on my Sound Card... :DVERY COOL!!

I'm considering moving all the source related private members from the Sound class to the Source struct (and maybe that would become a class too)I think that's a good idea, that way it will be possible to change the implementation of the source management without affecting the Sound class. Looks like you're well on you way though! This is something people have been begging for! I can't wait to see your implementation!

Samir

02-04-2007 09:29:54

VERY COOL!!
:D :D :D

I'm considering moving all the source related private members from the Sound class to the Source struct (and maybe that would become a class too)I think that's a good idea, that way it will be possible to change the implementation of the source management without affecting the Sound class.


Yes...but I'm not sure which ones to move and which ones not to move...
First of all, should the Sound class have access to the SourceRef (i.e. ALuint) of OpenAL?...if it does, then implementation is not very separated...and if it doesn't, updating of the position and velocity would have to be done in the Source class...and what use would the Sound class have then?...

Currently, the Source class requests a SourceRef from the SourceManager class by passing it's own mSource by reference when play() is called, which the SourceManager modifies when needed...

Looks like you're well on you way though! This is something people have been begging for! I can't wait to see your implementation!


He he...OK...I'll show it when it's clean enough for me not to be embarrassed by it :)

syedhs

14-04-2007 06:51:05

Samir,

Mind sharing your code here regarding increasing the sound source to 30? :) I am going to tackle this problem, as some computers only have max 12 source. In my scene, there are times when there are 30 AI vehicles (and therefore 30 sounds) + the player vehicle (4).

Samir

14-04-2007 07:46:07

Of course...I'd be happy to share it...:D...but I've been meaning to clean it up a bit before I submit a patch...unfortunately, I had too many exams at the same time lately and did not have much time to do that...I'll try to clean it up as soon as I can an submit the patch.

syedhs

14-04-2007 09:11:57

Wow... a nice suprise... since you replied quite fast as this thread has been idle for quite sometimes... well thanks... but mind telling me a bit about the algo?

Samir

14-04-2007 11:08:39

I've explained the algorithm a bit above. Basically, hardware sources are requested dynamically by objects of class Source from a SourceManager. The SourceManager class returns either the same source already used, or if that hardware source is now being used by another Source object, it will return the hardware source least used. To keep track of which hardware source is least used, source usage count is stored in a heap.

Also, the SoundManager class allows a number of hardware sources to be excluded from the heap and bound permanently to their Source object. These would be useful for playing sound streams in the background. But currently, I have been unable to play sound streams.

So if you want to play only normal sounds, I can give you the patch in its current state so you can get by with it until I fix everything.

syedhs

14-04-2007 11:41:43

Okay thanks. I should have paid more attention while reading this thread :). Well if you are free, then you are more than welcomed to provide the file here.

Btw, did you consider source distance to the listener as one of the factors to remove sound from the SoundManager?

Samir

14-04-2007 12:18:01

Well if you are free, then you are more than welcomed to provide the file here.
Well...I'm not exactly free...but I have enough time to paste you a patch of what I have so far here :D


Btw, did you consider source distance to the listener as one of the factors to remove sound from the SoundManager?

That's a greate idea! :D I don't know why I did not think of that...I will consider adding it to the patch later...

Sorry for having to paste the patch here...don't want to submit it before it's bug free...


Index: include/OgreALOggSound.h
===================================================================
--- include/OgreALOggSound.h (revision 62)
+++ include/OgreALOggSound.h (working copy)
@@ -69,7 +69,7 @@
* @param soundFile The name of the file to load
* @param loop Should the sound loop once it has played
*/
- OggSound(const Ogre::String& name, const Ogre::String& soundFile, bool loop, AudioFormat format);
+ OggSound(const Ogre::String& name, const Ogre::String& soundFile, bool loop, AudioFormat format, bool const isDynamic);

public:
/** Standard Destructor. */
Index: include/OgreALSound.h
===================================================================
--- include/OgreALSound.h (revision 62)
+++ include/OgreALSound.h (working copy)
@@ -61,9 +61,9 @@
/** Default Constructor. */
Sound();
/** Normal Constructor. Should not be called directly! Use SoundManager::createSound */
- Sound(const Ogre::String& name, const Ogre::String& fileName);
+ Sound(const Ogre::String& name, const Ogre::String& fileName, bool const isDynamic);
/** Constructor to be called if BufferRef exists */
- Sound(BufferRef buffer, const Ogre::String& name, const Ogre::String& fileName, bool loop = false);
+ Sound(BufferRef buffer, const Ogre::String& name, const Ogre::String& fileName, bool loop = false, bool const isDynamic = true);

public:
/** Standard Destructor */
@@ -271,7 +271,11 @@

/// Updates the sound if need be
virtual bool _updateSound();
-
+
+ /** Returns whether this sources uses a fixed hardware source
+ or whether it requests an available hardware source dynamically
+ when needed */
+ bool isDynamic() const { return mIsDynamic; }
protected:
/// Creates the source and binds the buffer
void createAndBindSource();
@@ -311,6 +315,7 @@
ALboolean mLoop;
mutable bool mLocalTransformDirty;

+ const bool mIsDynamic;
SourceRef mSource;
BufferFormat mFormat;
Size mFreq;
Index: include/OgreALSoundManager.h
===================================================================
--- include/OgreALSoundManager.h (revision 62)
+++ include/OgreALSoundManager.h (working copy)
@@ -76,7 +76,7 @@
typedef std::map<Ogre::String, Sound*> SoundMap;
typedef std::map<AudioFormat, FormatData*> FormatMap;
typedef Ogre::MapIterator<FormatMap> FormatMapIterator;
-
+ class SourceManager;
/**
* SoundManager.
* @remark This class is responsible for creating and managing all of the
@@ -107,9 +107,10 @@
* @param fileName The name of the sound file to load
* @param loop Should the sound be looped once it has finished playing
* @param format This allows you to use a non-default AudioFormat, this is needed in order for sounds that are encoded as multi-channel to play properly
+ * @param isDynamic This makes the sound request an available hardware source dynamicly which alows the use of more sources than is directly supported by the hardware. Most sounds should be dynamic except sound streams.
* @return Returns a pointer to the newly created sound
*/
- virtual Sound* createSound(const Ogre::String& name, const Ogre::String& fileName, bool loop = false, AudioFormat format = DEFAULT);
+ virtual Sound* createSound(const Ogre::String& name, const Ogre::String& fileName, bool loop = false, AudioFormat format = DEFAULT, bool const isDynamic = true);
/**
* Creates a sound stream. This is the only way sound streams should be instantiated
* @param name The name used to refer to the sound stream
@@ -185,6 +186,7 @@
static const Ogre::String SOUND;
static const Ogre::String STREAM;
static const Ogre::String AUDIO_FORMAT;
+ static const Ogre::String IS_DYNAMIC;

static const BufferFormat xRamAuto;
static const BufferFormat xRamHardware;
@@ -200,6 +202,7 @@

SoundFactory *mSoundFactory;
ListenerFactory *mListenerFactory;
+ SourceManager *mSourceManager;
Ogre::NameValuePairList mFileTypePair;
Ogre::ResourceGroupManager *mResourceGroupManager;

Index: include/OgreALSource.h
===================================================================
--- include/OgreALSource.h (revision 0)
+++ include/OgreALSource.h (revision 0)
@@ -0,0 +1,70 @@
+/*---------------------------------------------------------------------------*\
+** This source file is part of OgreAL **
+** an OpenAL plugin for the Ogre Rendering Engine. **
+** **
+** Copyright 2006 Casey Borders **
+** **
+** OgreAL 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 2, or (at your option) any later **
+** version. **
+** **
+** The developer really likes screenshots and while he recognises that the **
+** fact that this is an AUDIO plugin means that the fruits of his labor will **
+** never been seen in these images he would like to kindly ask that you send **
+** screenshots of your application using his library to **
+** screenshots@mooproductions.org **
+** **
+** Please bear in mind that the sending of these screenshots means that you **
+** are agreeing to allow the developer to display them in the media of his **
+** choice. They will, however, be fully credited to the person sending the **
+** email or, if you wish them to be credited differently, please state that **
+** in the body of the email. **
+** **
+** OgreAL 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 OgreAL; see the file LICENSE. If not, write to the **
+** Free Software Foundation, Inc., **
+** 59 Temple Place - Suite 330, **
+** Boston, MA 02111-1307, USA. **
+\*---------------------------------------------------------------------------*/
+
+#ifndef _OGRE_AL_SOURCE_H_
+#define _OGRE_AL_SOURCE_H_
+
+#include "OgreALPrereqs.h"
+
+namespace OgreAL {
+
+ class Sound;
+ struct Source
+ {
+ Source() :
+ sound(0),
+ source(UINT_MAX),
+ buffer(UINT_MAX),
+ usageCount(0) { }
+ // This constructor is only used to create
+ // a Source constant for comparison.
+ Source(Sound * const snd) :
+ sound(snd) { }
+ bool operator<(Source const &rhs) const
+ {
+ return usageCount > rhs.usageCount;
+ }
+ bool operator==(Source const &rhs) const
+ {
+ return sound == rhs.sound;
+ }
+ Sound *sound;
+ SourceRef source;
+ BufferRef buffer;
+ int usageCount;
+ };
+}
+
+#endif
Index: include/OgreALSourceManager.h
===================================================================
--- include/OgreALSourceManager.h (revision 0)
+++ include/OgreALSourceManager.h (revision 0)
@@ -0,0 +1,77 @@
+/*---------------------------------------------------------------------------*\
+** This source file is part of OgreAL **
+** an OpenAL plugin for the Ogre Rendering Engine. **
+** **
+** Copyright 2006 Casey Borders **
+** **
+** OgreAL 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 2, or (at your option) any later **
+** version. **
+** **
+** The developer really likes screenshots and while he recognises that the **
+** fact that this is an AUDIO plugin means that the fruits of his labor will **
+** never been seen in these images he would like to kindly ask that you send **
+** screenshots of your application using his library to **
+** screenshots@mooproductions.org **
+** **
+** Please bear in mind that the sending of these screenshots means that you **
+** are agreeing to allow the developer to display them in the media of his **
+** choice. They will, however, be fully credited to the person sending the **
+** email or, if you wish them to be credited differently, please state that **
+** in the body of the email. **
+** **
+** OgreAL 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 OgreAL; see the file LICENSE. If not, write to the **
+** Free Software Foundation, Inc., **
+** 59 Temple Place - Suite 330, **
+** Boston, MA 02111-1307, USA. **
+\*---------------------------------------------------------------------------*/
+
+#ifndef _OGRE_AL_SOURCE_MANAGER_H_
+#define _OGRE_AL_SOURCE_MANAGER_H_
+
+#include "OgreALPrereqs.h"
+#include "OgreALSource.h"
+
+#include <OgreSingleton.h>
+
+#include <vector>
+
+namespace OgreAL {
+
+ class SourceManager : public Ogre::Singleton<SourceManager>
+ {
+ public:
+ SourceManager();
+ /** Standard Destructor. */
+ virtual ~SourceManager();
+ /** Returns the SourceManager singleton object */
+ static SourceManager& getSingleton();
+ /** Returns a pointer to the SourceManager singleton object */
+ static SourceManager* getSingletonPtr();
+ unsigned int getDynamicSourcesCount() const { return mDynamicSources.size(); }
+ unsigned int getFixedSourcesCount() const { return mFixedSources.size(); }
+ /** Set the number of fixed sources. These should mostly be used
+ to create stream sounds.
+ By default, 3/4 of the available hardware sources can be used dynamically
+ and the rest can be used as a fixed source */
+ void setFixedSourcesCount(unsigned int const num);
+ /** This is used by dynamic Sound objects to retrieve an available sound source */
+ void getDynamicSource(Sound * const sound, SourceRef & source, BufferRef const buffer);
+ SourceRef getFixedSource();
+ private:
+ std::vector<Source> mDynamicSources;
+ std::vector<SourceRef> mFixedSources;
+ std::vector<Source>::size_type mUsedDynamicSources;
+ std::vector<SourceRef>::size_type mUsedFixedSources;
+ };
+
+}
+
+#endif
Index: include/OgreALWavSound.h
===================================================================
--- include/OgreALWavSound.h (revision 62)
+++ include/OgreALWavSound.h (working copy)
@@ -66,7 +66,7 @@
* @param soundFile The name of the file to load
* @param loop Should the sound loop once it has played
*/
- WavSound(const Ogre::String& name, const Ogre::String& soundFile, bool loop, AudioFormat format);
+ WavSound(const Ogre::String& name, const Ogre::String& soundFile, bool loop, AudioFormat format, bool const isDynamic);

public:
/** Standard Destructor. */
Index: OgreAL.sln
===================================================================
--- OgreAL.sln (revision 62)
+++ OgreAL.sln (working copy)
@@ -1,6 +1,6 @@

Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual Studio 2005
+# Visual C++ Express 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Doppler_Demo", "Demos\Doppler_Demo\Doppler_Demo.vcproj", "{BCE6FFBF-EC38-48C7-9BE1-470EA3A364E4}"
ProjectSection(ProjectDependencies) = postProject
{AB7B6FEF-01F2-44D0-BEEB-6FCD173FB3B0} = {AB7B6FEF-01F2-44D0-BEEB-6FCD173FB3B0}
@@ -23,6 +23,8 @@
{AB7B6FEF-01F2-44D0-BEEB-6FCD173FB3B0} = {AB7B6FEF-01F2-44D0-BEEB-6FCD173FB3B0}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MultiSource_Demo", "Demos\MultiSource_Demo\MultiSource_Demo.vcproj", "{B5DCD2AB-A679-4B30-96A2-9299EAAF493B}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -49,6 +51,10 @@
{DAAEC9A1-355F-418A-A015-0575C171AA5B}.Debug|Win32.Build.0 = Debug|Win32
{DAAEC9A1-355F-418A-A015-0575C171AA5B}.Release|Win32.ActiveCfg = Release|Win32
{DAAEC9A1-355F-418A-A015-0575C171AA5B}.Release|Win32.Build.0 = Release|Win32
+ {B5DCD2AB-A679-4B30-96A2-9299EAAF493B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B5DCD2AB-A679-4B30-96A2-9299EAAF493B}.Debug|Win32.Build.0 = Debug|Win32
+ {B5DCD2AB-A679-4B30-96A2-9299EAAF493B}.Release|Win32.ActiveCfg = Release|Win32
+ {B5DCD2AB-A679-4B30-96A2-9299EAAF493B}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Index: OgreAL/OgreAL.vcproj
===================================================================
--- OgreAL/OgreAL.vcproj (revision 62)
+++ OgreAL/OgreAL.vcproj (working copy)
@@ -48,7 +48,7 @@
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
- DebugInformationFormat="4"
+ DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -208,6 +208,10 @@
>
</File>
<File
+ RelativePath="..\src\OgreALSourceManager.cpp"
+ >
+ </File>
+ <File
RelativePath="..\src\OgreALWavSound.cpp"
>
</File>
@@ -250,6 +254,14 @@
>
</File>
<File
+ RelativePath="..\include\OgreALSource.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\OgreALSourceManager.h"
+ >
+ </File>
+ <File
RelativePath="..\include\OgreALWavSound.h"
>
</File>
Index: src/OgreALOggSound.cpp
===================================================================
--- src/OgreALOggSound.cpp (revision 62)
+++ src/OgreALOggSound.cpp (working copy)
@@ -37,8 +37,8 @@
#include "OgreALSoundManager.h"

namespace OgreAL {
- OggSound::OggSound(const Ogre::String& name, const Ogre::String& soundFile, bool loop, AudioFormat format) :
- Sound(name, soundFile),
+ OggSound::OggSound(const Ogre::String& name, const Ogre::String& soundFile, bool loop, AudioFormat format, bool const isDynamic) :
+ Sound(name, soundFile, isDynamic),
mOggFile(0),
mVorbisInfo(0),
mVorbisComment(0)
Index: src/OgreALOggSoundStream.cpp
===================================================================
--- src/OgreALOggSoundStream.cpp (revision 62)
+++ src/OgreALOggSoundStream.cpp (working copy)
@@ -35,6 +35,7 @@

#include "OgreALOggSoundStream.h"
#include "OgreALSoundManager.h"
+#include "OgreALSourceManager.h"

namespace OgreAL {
OggSoundStream::OggSoundStream(const Ogre::String& name, const Ogre::String& soundFile, bool loop, AudioFormat format) :
@@ -69,7 +70,8 @@
mLoop = loop;

alGenBuffers(2, mBuffers);
- alGenSources(1, &mSource);
+ //alGenSources(1, &mSource);
+ mSource = SourceManager::getSingleton().getFixedSource();
checkError(__FUNCTION__);

if(SoundManager::getSingleton().xRamSupport())
@@ -88,7 +90,7 @@
alSourceQueueBuffers(mSource, 2, mBuffers);
checkError(__FUNCTION__);

- initSource();
+ //initSource();

// There is an issue with looping Ogg streams in OpenAL
// so we'll do it manually in the update method
Index: src/OgreALSound.cpp
===================================================================
--- src/OgreALSound.cpp (revision 62)
+++ src/OgreALSound.cpp (working copy)
@@ -35,6 +35,7 @@

#include "OgreALSound.h"
#include "OgreALSoundManager.h"
+#include "OgreALSourceManager.h"
#include "OgrePrerequisites.h"

namespace OgreAL {
@@ -55,12 +56,15 @@
mFileName(""),
mSourceRelative(AL_FALSE),
mDerivedPosition(Ogre::Vector3::ZERO),
- mDerivedDirection(Ogre::Vector3::NEGATIVE_UNIT_Z)
+ mDerivedDirection(Ogre::Vector3::NEGATIVE_UNIT_Z),
+ mIsDynamic(false),
+ mSource(0),
+ mBuffer(0)
{
mParentNode = NULL;
}

- Sound::Sound(const Ogre::String &name, const Ogre::String& fileName) :
+ Sound::Sound(const Ogre::String &name, const Ogre::String& fileName, bool const isDynamic) :
MovableObject(name),
mPitch(1.0), mGain(1.0),
mMaxGain(1.0),
@@ -77,13 +81,16 @@
mFileName(fileName),
mSourceRelative(AL_FALSE),
mDerivedPosition(Ogre::Vector3::ZERO),
- mDerivedDirection(Ogre::Vector3::NEGATIVE_UNIT_Z)
+ mDerivedDirection(Ogre::Vector3::NEGATIVE_UNIT_Z),
+ mIsDynamic(isDynamic),
+ mSource(0),
+ mBuffer(0)
{
mParentNode = NULL;
}


- Sound::Sound(BufferRef buffer, const Ogre::String& name, const Ogre::String& fileName, bool loop) :
+ Sound::Sound(BufferRef buffer, const Ogre::String& name, const Ogre::String& fileName, bool loop, bool const isDynamic) :
MovableObject(name),
mBuffer(buffer),
mLoop(loop?AL_TRUE:AL_FALSE),
@@ -101,7 +108,9 @@
mFileName(fileName),
mSourceRelative(AL_FALSE),
mDerivedPosition(Ogre::Vector3::ZERO),
- mDerivedDirection(Ogre::Vector3::NEGATIVE_UNIT_Z)
+ mDerivedDirection(Ogre::Vector3::NEGATIVE_UNIT_Z),
+ mIsDynamic(isDynamic),
+ mSource(0)
{
mParentNode = NULL;

@@ -110,17 +119,34 @@

Sound::~Sound()
{
- alSourceStop(mSource);
+ /*alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
alDeleteSources(1, &mSource);
- checkError(__FUNCTION__);
+ checkError(__FUNCTION__);*/
}

bool Sound::play()
{
- if(isPlaying()) return true;
+ if(mIsDynamic)
+ {
+ SourceRef const oldSource = mSource;
+ SourceManager::getSingleton().getDynamicSource(this, mSource, mBuffer);
+ if(isPlaying()) return true;
+ if(oldSource != mSource) {
+ alGetError();
+ initSource();
+ //checkError(__FUNCTION__);
+ alGetError();
+ }
+ alSourcePlay(mSource);
+ alGetError();
+ }
+ else
+ {
+ if(isPlaying()) return true;

- alSourcePlay(mSource);
+ alSourcePlay(mSource);
+ }
return true;
}

@@ -343,13 +369,22 @@
{
SoundManager::getSingleton().eaxSetBufferMode(1, &mBuffer, SoundManager::xRamHardware);
}
+
+ if(!mIsDynamic)
+ {
+ mSource = SourceManager::getSingleton().getFixedSource();
+ initSource();
+ checkError(__FUNCTION__);

- alGenSources(1, &mSource);
- initSource();
- checkError(__FUNCTION__);
+ alSourcei(mSource, AL_BUFFER, mBuffer);
+ checkError(__FUNCTION__);
+ }
+ //alGenSources(1, &mSource);
+ //initSource();
+ //checkError(__FUNCTION__);

- alSourcei(mSource, AL_BUFFER, mBuffer);
- checkError(__FUNCTION__);
+ //alSourcei(mSource, AL_BUFFER, mBuffer);
+ //checkError(__FUNCTION__);
}

void Sound::initSource()
@@ -369,7 +404,8 @@
alSource3f(mSource, AL_DIRECTION, mDerivedDirection.x, mDerivedDirection.y, mDerivedDirection.z);
alSourcei (mSource, AL_SOURCE_RELATIVE, mSourceRelative);
alSourcei (mSource, AL_LOOPING, mLoop);
- checkError(__FUNCTION__);
+ //checkError(__FUNCTION__);
+ alGetError();
}

void Sound::checkError(const Ogre::String& source) const
@@ -466,19 +502,20 @@
bool loop = Ogre::StringConverter::parseBool(params->find(SoundManager::LOOP_STATE)->second);
AudioFormat audioFormat = static_cast<AudioFormat>
(Ogre::StringConverter::parseInt(params->find(SoundManager::AUDIO_FORMAT)->second));
+ bool isDynamic = Ogre::StringConverter::parseBool(params->find(SoundManager::IS_DYNAMIC)->second);

BufferMap::iterator bufferItr = mBufferMap.find(fileName);
if(bufferItr != mBufferMap.end())
{
// We have this buffer loaded already!
- return new Sound((BufferRef)bufferItr->second, name, fileName, loop);
+ return new Sound((BufferRef)bufferItr->second, name, fileName, loop, isDynamic);
}

if(inType.compare(SoundManager::OGG) == 0)
{
if(outType.compare(SoundManager::SOUND) == 0)
{
- Sound *sound = new OggSound(name, fileName, loop, audioFormat);
+ Sound *sound = new OggSound(name, fileName, loop, audioFormat, isDynamic);
// Save the reference to this buffer so we can point to it again later
mBufferMap[fileName] = sound->getBufferRef();
return sound;
@@ -497,7 +534,7 @@
{
if(outType.compare(SoundManager::SOUND) == 0)
{
- Sound *sound = new WavSound(name, fileName, loop, audioFormat);
+ Sound *sound = new WavSound(name, fileName, loop, audioFormat, isDynamic);
// Save the reference to this buffer so we can point to it again later
mBufferMap[fileName] = sound->getBufferRef();
return sound;
Index: src/OgreALSoundManager.cpp
===================================================================
--- src/OgreALSoundManager.cpp (revision 62)
+++ src/OgreALSoundManager.cpp (working copy)
@@ -34,6 +34,7 @@
\*---------------------------------------------------------------------------*/

#include "OgreALSoundManager.h"
+#include "OgreALSourceManager.h"

template<> OgreAL::SoundManager* Ogre::Singleton<OgreAL::SoundManager>::ms_Singleton = 0;

@@ -47,12 +48,14 @@
const Ogre::String SoundManager::SOUND = "SoundOut";
const Ogre::String SoundManager::STREAM = "StreamOut";
const Ogre::String SoundManager::AUDIO_FORMAT = "AudioFormat";
+ const Ogre::String SoundManager::IS_DYNAMIC = "IsDynamic";

const ALenum SoundManager::xRamAuto = alGetEnumValue("AL_STORAGE_AUTO");
const ALenum SoundManager::xRamHardware = alGetEnumValue("AL_STORAGE_HARDWARE");
const ALenum SoundManager::xRamAccessible = alGetEnumValue("AL_STORAGE_ACCESSIBLE");

SoundManager::SoundManager() :
+ mSourceManager(0),
mEAXSupport(false),
mEAXVersion(0),
mXRAMSupport(false),
@@ -180,6 +183,11 @@
Ogre::Root::getSingleton().removeMovableObjectFactory(mSoundFactory);
Ogre::Root::getSingleton().removeMovableObjectFactory(mListenerFactory);

+ if(mSourceManager)
+ {
+ delete mSourceManager;
+ mSourceManager = 0;
+ }
delete mListenerFactory;
delete mSoundFactory;

@@ -207,11 +215,12 @@
}

Sound* SoundManager::createSound(const Ogre::String& name,
- const Ogre::String& fileName, bool loop, AudioFormat format)
+ const Ogre::String& fileName, bool loop, AudioFormat format, bool const isDynamic)
{
mFileTypePair.clear();
mFileTypePair[OUTPUT_TYPE] = SOUND;
mFileTypePair[AUDIO_FORMAT] = Ogre::StringConverter::toString(format);
+ mFileTypePair[IS_DYNAMIC] = Ogre::StringConverter::toString(isDynamic);

return _createSound(name, fileName, loop);
}
@@ -222,12 +231,16 @@
mFileTypePair.clear();
mFileTypePair[OUTPUT_TYPE] = STREAM;
mFileTypePair[AUDIO_FORMAT] = Ogre::StringConverter::toString(format);
-
+ mFileTypePair[IS_DYNAMIC] = Ogre::StringConverter::toString(false);
+
return _createSound(name, fileName, loop);
}

Sound* SoundManager::_createSound(const Ogre::String& name, const Ogre::String& fileName, bool loop)
{
+ if(!mSourceManager)
+ mSourceManager = new SourceManager();
+
Ogre::String path = "";
Ogre::String group = mResourceGroupManager->findGroupContainingResource(fileName);
Ogre::FileInfoListPtr resourceList = mResourceGroupManager->listResourceFileInfo(group);
Index: src/OgreALSoundStream.cpp
===================================================================
--- src/OgreALSoundStream.cpp (revision 62)
+++ src/OgreALSoundStream.cpp (working copy)
@@ -41,7 +41,7 @@
{}

SoundStream::SoundStream(const Ogre::String& name, const Ogre::String& fileName) :
- Sound(name, fileName)
+ Sound(name, fileName, false)
{}

SoundStream::~SoundStream()
Index: src/OgreALSourceManager.cpp
===================================================================
--- src/OgreALSourceManager.cpp (revision 0)
+++ src/OgreALSourceManager.cpp (revision 0)
@@ -0,0 +1,171 @@
+#include "OgreALSourceManager.h"
+#include "OgreALSoundManager.h"
+
+template<> OgreAL::SourceManager* Ogre::Singleton<OgreAL::SourceManager>::ms_Singleton = 0;
+
+#include <sstream>
+using namespace std;
+
+namespace OgreAL {
+
+ Ogre::String errorToString(int error)
+ {
+ switch(error)
+ {
+ case AL_INVALID_VALUE:
+ return Ogre::String("The value pointer given is not valid");
+ break;
+ case AL_INVALID_ENUM:
+ return Ogre::String("The specified parameter is not valid");
+ break;
+ case AL_INVALID_NAME:
+ return Ogre::String("The specified source name is not valid");
+ break;
+ case AL_INVALID_OPERATION:
+ return Ogre::String("There is no current context");
+ break;
+ default:
+ return Ogre::String("Unknown Error");
+ break;
+ }
+ }
+
+ void checkError(const Ogre::String& source)
+ {
+ int error = alGetError();
+
+ if(error != AL_NO_ERROR)
+ {
+ throw Ogre::Exception(3, "OpenAL Error: " + errorToString(error), source);
+ }
+ }
+
+
+
+ SourceManager::SourceManager() :
+ mDynamicSources(3 * SoundManager::getSingleton().maxSources() / 4),
+ mFixedSources(SoundManager::getSingleton().maxSources() / 4),
+ mUsedDynamicSources(0),
+ mUsedFixedSources(0)
+ {
+ vector<SourceRef> sources(SoundManager::getSingleton().maxSources());
+ alGetError();
+ alGenSources(sources.size(), &sources[0]);
+ checkError(__FUNCTION__);
+ for(int s = 0; s < mDynamicSources.size(); ++s)
+ mDynamicSources[s].source = sources[s];
+ for(int s = 0; s < mFixedSources.size(); ++s)
+ mFixedSources[s] = sources[mDynamicSources.size() + s];
+ }
+
+ SourceManager::~SourceManager()
+ {
+ }
+
+ SourceManager* SourceManager::getSingletonPtr(void)
+ {
+ return ms_Singleton;
+ }
+
+ SourceManager& SourceManager::getSingleton(void)
+ {
+ assert( ms_Singleton ); return (*ms_Singleton);
+ }
+
+ void SourceManager::setFixedSourcesCount(unsigned int const num)
+ {
+ if(num == mFixedSources.size())
+ return;
+ if(num > mFixedSources.size())
+ {
+ if(num > mDynamicSources.size() - mUsedDynamicSources)
+ {
+ ostringstream error;
+ error << "Cannot set fixed sources count to "
+ << num
+ << " because total sources count is equal to "
+ << mDynamicSources.size() + mFixedSources.size()
+ << " and dynamicly used sources are equal to "
+ << mUsedDynamicSources
+ << " which means there are only "
+ << mDynamicSources.size() - mUsedDynamicSources
+ << " unused dynamic sources to make available as fixed sources";
+ throw Ogre::Exception(7, error.str(),"OgreAL::SourceManager::setFixedSourcesCount");
+ }
+ for(std::vector<SourceRef>::size_type s = 0; s < num; ++s)
+ {
+ mFixedSources.push_back(mDynamicSources.back().source);
+ mDynamicSources.pop_back();
+ }
+ }
+ else
+ {
+ if(num <= mUsedFixedSources)
+ {
+ ostringstream error;
+ error << "Cannot set fixed sources count to "
+ << num
+ << " there are currently "
+ << mFixedSources.size()
+ << " in use.";
+ throw Ogre::Exception(7, error.str(),"OgreAL::SourceManager::setFixedSourcesCount");
+ }
+ Source source;
+ for(std::vector<Source>::size_type s = 0; s < num; ++s)
+ {
+ source.source = mFixedSources.back();
+ mDynamicSources.push_back(source);
+ mFixedSources.pop_back();
+ }
+ }
+ }
+
+ void SourceManager::getDynamicSource(Sound * const sound, SourceRef & source, BufferRef const buffer)
+ {
+ vector<Source>::iterator heapSource = find(mDynamicSources.begin(), mDynamicSources.begin() + mUsedDynamicSources, Source(sound));
+ if(heapSource == mDynamicSources.begin() + mUsedDynamicSources)
+ {
+ if(mUsedDynamicSources == mDynamicSources.size())
+ {
+ pop_heap(mDynamicSources.begin(), mDynamicSources.end());
+ source = mDynamicSources.back().source;
+ mDynamicSources.back().sound = sound;
+ mDynamicSources.back().buffer = buffer;
+ mDynamicSources.back().usageCount = 1;
+ }
+ else
+ {
+ source = (mDynamicSources.begin() + mUsedDynamicSources)->source;
+ (mDynamicSources.begin() + mUsedDynamicSources)->sound = sound;
+ (mDynamicSources.begin() + mUsedDynamicSources)->buffer = buffer;
+ (mDynamicSources.begin() + mUsedDynamicSources)->usageCount = 1;
+ ++mUsedDynamicSources;
+ }
+ alGetError();
+ alSourcei(source, AL_BUFFER, buffer);
+ //checkError(__FUNCTION__);
+ alGetError();
+ push_heap(mDynamicSources.begin(), mDynamicSources.begin() + mUsedDynamicSources);
+ }
+ else
+ {
+ ++(heapSource->usageCount);
+ source = heapSource->source;
+ make_heap(mDynamicSources.begin(), mDynamicSources.begin() + mUsedDynamicSources);
+ }
+ }
+ SourceRef SourceManager::getFixedSource()
+ {
+ if(mUsedFixedSources >= mFixedSources.size())
+ {
+ ostringstream error;
+ error << "Cannot get anymore fixed sources. Fixed sources count of "
+ << mFixedSources.size()
+ << " exceeded. Try using OgreAL::SourceManager::setFixedSourcesCount() to increase this value.";
+ throw Ogre::Exception(8, error.str(), "OgreAL::SourceManager::getFixedSource()");
+ }
+ ++mUsedFixedSources;
+ return mFixedSources[mUsedFixedSources - 1];
+
+ }
+}
Index: src/OgreALWavSound.cpp
===================================================================
--- src/OgreALWavSound.cpp (revision 62)
+++ src/OgreALWavSound.cpp (working copy)
@@ -37,8 +37,8 @@
#include "OgreALSoundManager.h"

namespace OgreAL {
- WavSound::WavSound(const Ogre::String& name, const Ogre::String& soundFile, bool loop, AudioFormat format) :
- Sound(name, soundFile)
+ WavSound::WavSound(const Ogre::String& name, const Ogre::String& soundFile, bool loop, AudioFormat format, bool const isDynamic) :
+ Sound(name, soundFile, isDynamic)
{
alGenBuffers(1, &mBuffer);
checkError(__FUNCTION__);

syedhs

14-04-2007 13:36:14

That is very kind of you. Thanks! :D

Samir

14-04-2007 13:39:08

That is very kind of you. Thanks! :D
Sure...no problem... :D

Let me know if you find any bugs... (other than the fact that you can't play streams)

Night Elf

30-04-2007 19:35:01

I was wondering if there are any news regarding this topic. We're using OgreAL for our project and we'd need a solution for this problem as soon as possible... Any idea when this will be integrated into the library?

(Sorry, I don't want to sound like I'm making any demands. I would just like to know if there's any ETA on the next version of OgreAL as we're running quite short on time.)

Vectrex

01-05-2007 14:57:44

In relation to this I'd keep in mind that sometimes you want a new sound to cut off an old one, so some way to use the same channel would be good (eg I'm retriggering a cylinder firing sample 15,000 times a minute for my engine :) )

CaseyB

02-05-2007 01:41:29

(Sorry, I don't want to sound like I'm making any demands. I would just like to know if there's any ETA on the next version of OgreAL as we're running quite short on time.)It's ok, I know that I'm running way behind on things and I apologize! Things are pretty hectic right now outside of coding! I am going to be moving in a few weeks and I will be working from home (instead of having an hour commute each way!) so I should be able to have some more free time to work on this. I can't give an ETA though as I am really at a loss for why this is happening, hopefully it's something stupid that I am doing and it will be cleared up quickly.