<html>
<head>
<style>
.hmmessage P
{
margin:0px;
padding:0px
}
body.hmmessage
{
font-size: 10pt;
font-family:Verdana
}
</style>
</head>
<body class='hmmessage'>
Thanks Samuel,<br>As for the bad class design /lack of encapsulation, oh yes definitely - I'd just posted up dummy classes like this, going public for simplicity's sake.<br><br>I've also gone with the multimap as the program's main data store as I need to access objects by their position - the gameworld is a 3 dimensional grid, with objects having absolute positions.&nbsp; Initially I used a 3d array - AbstractObject[x][y][z] , but given i'm working with a large number of potential objects, using a predefined array like this eats up a *lot* of memory.<br>A multimap using one of my Coords classes , which contains x,y,z as the key allows me to quickly access members, by position, in a dynamically sized manner, and given multimaps are sorted by key, and the .find(key) func is a fairly quick Binary search, this method seems to suit.&nbsp; I'm not sure you can do this with vectors? that is, quickly access a member based on one of its atributes, without iterating through them all to check?<br><br>The boost shared pointer gives me some ideas, ta. I didn't know about it.<br>&gt;Out of the methods you listed below, Method 2 is probably more in the right direction.<br><br>...do you mean Method 1?&nbsp; If im reading your sample code correctly, it's more like a global container of some structure which links a pointer to the object, with its associated sound source, or list of sources?&nbsp; <br><br>Thanks,<br>Pingwah<br><br><br><br><br><br><br><br><br><hr id="stopSpelling">CC: openal@opensource.creative.com<br>From: space.ship.traveller@gmail.com<br>To: pingwah_leronz@hotmail.com<br>Subject: Re: [Openal] suggestions on c++ game design with openAL most welcome<br>Date: Tue, 2 Jun 2009 21:11:38 +1200<br><br><div>Hello,</div><div><br></div><div>I have a number of comments for you.</div><div><br></div>Firstly, looking at your code I would suggest you review your naming conventions.<div><br></div><div>"class classCar" is not a conventional name. If it suits you, that is fine, but it seems like you've got an incredibly verbose naming scheme which many people will find hard to look at.</div><div><br></div><div>A good scheme is to have UpperCase class names which are typically common or proper nouns. Secondly, variables don't need to include their type in the name. This is generally considered tedious and unmaintainable. For example, fltFuel might change to dblFuel. But now you have to change a lot of code. There are lots of information regarding different kinds of coding&nbsp;conventions&nbsp;available on the internet.</div><div><br></div><div>Also, you have made all your member variables public. This is also considered harmeful, for example if you change the implementation or storage of fltFuel, this now becomes a project wide change.&nbsp;The better option is to rely on encapsulation which generally means you have getters/setters for key values related to the object you are trying to represent. For example, rather than having setFuel(...) you might have a function addFuel(...) which carries out logic such as checking the maximum fuel that can be added, etc, which in my experience reduces the complexity of code elsewhere.</div><div><br></div><div>Looking at the solutions you are proposing - consider what best models what you are trying to represent.</div><div><br></div><div>For example, if you have multiple cars, each car has an engine, therefore each engine produces a sound. We can consider this the ideal world. In computer programming we need to use tricks to achieve adequate performance. So, it might be the case that you have up to 5 sources dedicated to engine sounds, and then choose the 5 engines closest to the "camera" for actually playing audio. If you have more than "x" sources close to the "camera" it may become impossible for the listener to identify individual sounds anyway, so we can limit to 5 without any loss of&nbsp;apparent&nbsp;quality.</div><div><br></div><div>I would question your use of a multimap for storing cars. It seems incredibly complex and performance heavy.</div><div><br></div><div>Consider the use of a simple std::vector. This is very fast and has guaranteed O(1) performance for all operations if you are not concerned about order. To remove an element from a vector simply use std::swap and pop:</div><div><br></div><div><div style="margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-family: Monaco; font-style: normal; font-variant: normal; font-weight: normal; font-size: 10px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none; color: rgb(195, 116, 28);"><span style="color: rgb(0, 0, 0);"><span class="EC_Apple-tab-span" style="white-space: pre;">                </span></span>/// Provides an efficient way to erase elements from a std::vector</div><div style="margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-family: Monaco; font-style: normal; font-variant: normal; font-weight: normal; font-size: 10px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none; color: rgb(41, 66, 119);"><span style="color: rgb(0, 0, 0);"><span class="EC_Apple-tab-span" style="white-space: pre;">                </span></span>template<span style="color: rgb(0, 0, 0);"> &lt;</span>typename<span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(71, 106, 151);">t</span><span style="color: rgb(0, 0, 0);">&gt;</span></div><div style="margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-family: Monaco; font-style: normal; font-variant: normal; font-weight: normal; font-size: 10px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;"><span class="EC_Apple-tab-span" style="white-space: pre;">                </span><span style="color: rgb(41, 66, 119);">bool</span> eraseElementAtIndex (<span style="color: rgb(71, 106, 151);">IndexT</span> index, <span style="color: rgb(71, 106, 151);">std</span>::<span style="color: rgb(180, 69, 0);">vector</span>&lt;<span style="color: rgb(71, 106, 151);">t</span>&gt; &amp; array)</div><div style="margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-family: Monaco; font-style: normal; font-variant: normal; font-weight: normal; font-size: 10px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;"><span class="EC_Apple-tab-span" style="white-space: pre;">                </span>{</div><div style="margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-family: Monaco; font-style: normal; font-variant: normal; font-weight: normal; font-size: 10px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;"><span class="EC_Apple-tab-span" style="white-space: pre;">                        </span><span style="color: rgb(41, 66, 119);">if</span> (array.<span style="color: rgb(71, 106, 151);">size</span>() == (index+<span style="color: rgb(41, 66, 119);">1</span>)) {</div><div style="margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-family: Monaco; font-style: normal; font-variant: normal; font-weight: normal; font-size: 10px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;"><span class="EC_Apple-tab-span" style="white-space: pre;">                                </span>array.<span style="color: rgb(71, 106, 151);">pop_back</span>();</div><div style="margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-family: Monaco; font-style: normal; font-variant: normal; font-weight: normal; font-size: 10px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none; color: rgb(41, 66, 119);"><span style="color: rgb(0, 0, 0);"><span class="EC_Apple-tab-span" style="white-space: pre;">                                </span></span>return<span style="color: rgb(0, 0, 0);"> </span>false<span style="color: rgb(0, 0, 0);">;</span></div><div style="margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-family: Monaco; font-style: normal; font-variant: normal; font-weight: normal; font-size: 10px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;"><span class="EC_Apple-tab-span" style="white-space: pre;">                        </span>} <span style="color: rgb(41, 66, 119);">else</span> {</div><div style="margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-family: Monaco; font-style: normal; font-variant: normal; font-weight: normal; font-size: 10px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;"><span class="EC_Apple-tab-span" style="white-space: pre;">                                </span>array[index] = array.<span style="color: rgb(71, 106, 151);">back</span>();</div><div style="margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-family: Monaco; font-style: normal; font-variant: normal; font-weight: normal; font-size: 10px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;"><span class="EC_Apple-tab-span" style="white-space: pre;">                                </span>array.<span style="color: rgb(71, 106, 151);">pop_back</span>();</div><div style="margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-family: Monaco; font-style: normal; font-variant: normal; font-weight: normal; font-size: 10px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none; color: rgb(41, 66, 119);"><span style="color: rgb(0, 0, 0);"><span class="EC_Apple-tab-span" style="white-space: pre;">                                </span></span>return<span style="color: rgb(0, 0, 0);"> </span>true<span style="color: rgb(0, 0, 0);">;</span></div><div style="margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-family: Monaco; font-style: normal; font-variant: normal; font-weight: normal; font-size: 10px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;"><span class="EC_Apple-tab-span" style="white-space: pre;">                        </span>}</div><div style="margin-right: 0px; margin-bottom: 0px; margin-left: 0px; font-family: Monaco; font-style: normal; font-variant: normal; font-weight: normal; font-size: 10px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none;"><span class="EC_Apple-tab-span" style="white-space: pre;">                </span>}</div></div><div><br></div><div>So we can achieve very quick storage with std::vector.</div><div><br></div><div>If you need to do space querying, for a small number of cars (&lt; 20) brute force algorithm will be fine, such as simply iterating through the list &nbsp;and choosing the closest cars, etc.</div><div><br></div><div>Finally in terms of structuring the OpenAL code the best option is to look at keeping audio completely separate from your "model".</div><div><br></div><div>Try to avoid things like:</div><div><blockquote><span class="EC_Apple-style-span" style="color: rgb(0, 0, 0); font-family: Verdana; font-size: 13px;">&nbsp;&nbsp; &nbsp; int MAX_SOUNDS = 150;<br></span></blockquote></div><div><br></div><div>This generally considered bad practice (there are specific cases where it is okay, but generally use std::vector for this kind of allocation).</div><div><br></div><div>We should consider the importance of two kinds of sounds:</div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span>- Sound that caused by specific event that occurred (crash sound).<br></div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span>- Sound that has been started and stopped by a particular object (engine sound).<br></div><div><br></div><div>These two kinds of sounds can be managed differently. For example, often with sounds based of event, my experience is that we can't tell the difference between single source and multiple source in typical cases as long as the sound is short - for example, explosion sound. So in this case you can simply have a single source which is allocated when the game starts. This is very convenient. Alternatively you can allocate a list of sources and use them in a round robin fashion if you need more realism or the sound is longer.</div><div><br></div><div>For a sound that is continuous we either have a single source (i.e. music) or multiple sources (i.e. multiple engines). This case is slightly more complex especially if we separate audio function from object model (class Car). In this case, the easiest solution is to have the audio source as part of the class Car. This is the simplest solution and means that each car has its own audio source. But this isn't efficient for a large number of cars, and increases coupling between audio and your simulation which if it is running as a server / client, obviously you don't want the server making all sorts of sounds or sound simply may not be available.</div><div><br></div><div>Therefore, I recommend you look at the following structure:</div><div><br></div><div>using boost::shared_ptr;</div><div><br></div><div>class Car {</div><div>public:</div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span>Coord getPosition ();<br></div><div>};</div><div><br></div><div>class CarsController {</div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span>typedef&nbsp;shared_ptr&lt;Car&gt; CarPtr;</div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span>std::vector&lt;CarPtr&gt; m_cars;<br></div><div><br></div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span>std::vector&lt;CarPtr&gt; findCarsClosestToPoint (Coord c, unsigned maxCars);<br></div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span>void update (float dt);</div><div>};</div><div><blockquote><span class="EC_Apple-style-span" style="color: rgb(0, 0, 0); font-family: Verdana; font-size: 13px;"></span></blockquote><br><blockquote><span class="EC_Apple-style-span" style="color: rgb(0, 0, 0); font-family: Verdana; font-size: 13px;">class AudioSource<br>{<br>&nbsp;&nbsp; ALuint intSource<br>&nbsp;<br>&nbsp;&nbsp; //funcs<br>&nbsp;&nbsp; bool AssignBufferToThis(ALbyte *filename);<br>&nbsp;&nbsp; void UpdatePosition(float x, float y, float z);<br>&nbsp;&nbsp; void Play();<br>&nbsp;&nbsp; void Stop();<br>&nbsp;&nbsp; void PitchMod(float fltMod);<br>&nbsp;&nbsp; void GainMod(float fltMod);<br>&nbsp;&nbsp; void SetLooping(bool boolLooping);<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp; etc.<br>&nbsp;<br>}<br></span></blockquote></div><div><br></div><div>class CarAudioController {</div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span>// OpenAL mixer, etc</div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span><br></div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span>struct CarSource {<br></div><div><span class="EC_Apple-tab-span" style="white-space: pre;">                </span>CarPtr car;<br></div><div><span class="EC_Apple-tab-span" style="white-space: pre;">                </span>AudioSource source;<br></div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span>}<br></div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span>std::vector&lt;CarSource&gt; m_engineSources;</div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span><br></div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span>void playEngineSound (CarsController * carsController) {</div><div><span class="EC_Apple-tab-span" style="white-space: pre;">                </span>// Step 1: Update source positions / stop sources that are no longer relevant, build a std::set of cars currently active</div><div><span class="EC_Apple-tab-span" style="white-space: pre;">                </span>// Step 2: Query for cars that are close to the listener<br></div><div><span class="EC_Apple-tab-span" style="white-space: pre;">                </span>// Step 3: For all these cars, check if they are currently in the set of active cars. If not, add it and start the appropriate engine sound.<br></div><div><span class="EC_Apple-tab-span" style="white-space: pre;">                </span>// Step 4: Profit.<br></div><div><span class="EC_Apple-tab-span" style="white-space: pre;">        </span>}<br></div><div>};</div><div><br></div><div>In terms of implementation, playEngineSound could implement a round robin scheme that is updated at set time intervals - depending on RPM, distance, etc you can update or stop the sound. There are many many options and this pseudo code is not well developed, but it should give you an idea of how to separate out the code. There are many ways to do this kind of separation - another way is using a delegate.</div><div><br></div><div>I also wrote an article you might find interesting/useful:</div><div><br></div><div><a href="http://wiki.oriontransfer.org/blog:2009:05:06:what_is_abstraction">http://wiki.oriontransfer.org/blog:2009:05:06:what_is_abstraction</a></div><div><br></div><div>I hope something here helps. The question you asked has a lot of possible solutions. Out of the methods you listed below, Method 2 is probably more in the right direction.</div><div><br></div><div>Kind regards,</div><div>Samuel</div><div><br><div><div>On 2/06/2009, at 1:59 PM, Pingwah Leronz wrote:</div><br class="EC_Apple-interchange-newline"><blockquote><span class="EC_Apple-style-span" style="border-collapse: separate; color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><div class="EC_hmmessage" style="font-size: 10pt; font-family: Verdana;">First of all, hello everyone :)<br>&nbsp;<br>&nbsp;<br>I'm working on a c++&nbsp;project that's moving into the early stages of audio design and facing what Im guessing would be a fairly common problem, and wondering if anyone has any advice or input about the best way to approach it.<br>&nbsp;<br>For those interested -<span class="EC_Apple-converted-space">&nbsp;</span><br>Let's say we have a car<br>class classCar()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;public:<br>&nbsp;&nbsp;&nbsp; classCoords coordsPosition;<br>&nbsp;&nbsp;&nbsp; classCoords coordsVelocity;<br>&nbsp;&nbsp;&nbsp; float fltFuel;<br>&nbsp;&nbsp;&nbsp; ...etc.<br>&nbsp;<br>};<br>&nbsp;<br>where classCoords is simply<br>coords<br>{<br>&nbsp; public:<br>&nbsp; float x, y, z;<br>&nbsp;<br>};<br>&nbsp;<br>and Cars are to be able to emit several sounds at once , an ambient engine roar, horn beeps, drivers yelling etc.<br><em>Also there's to be literally<span class="EC_Apple-converted-space">&nbsp;</span><u>millions</u><span class="EC_Apple-converted-space">&nbsp;</span>of cars<span class="EC_Apple-converted-space">&nbsp;</span></em>(OK, in the project itself , they're not cars :) ), so a method of culling sound emitters from the set needs to be there.&nbsp;<span class="EC_Apple-converted-space">&nbsp;</span><br>Criteria for adding and removing Cars from the audio set is simply proximity to a viewing position, and the cars themselves are stored in something like<br>&nbsp;<br>&nbsp;<br>multimap &lt;classCoord*, classCar*&gt; mapCars;<br>&nbsp;<br>(again, they're not cars- let's say the track consists of many&nbsp;discrete positions, each of which can contain many cars).<br>&nbsp;<br>I've been experimenting with two methods of handling this - the first with a global controller:<br>&nbsp;<br><strong>Method 1</strong><br><strong>---------------------------------</strong><br>class classAudioController()<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp; int MAX_SOUNDS = 150;<br>&nbsp;&nbsp;&nbsp;&nbsp; multimap &lt;classCar*, ALuint&gt; mapSounds;&nbsp;&nbsp;&nbsp;&nbsp; //where ALuint here is a ref to the standard openal source[MAX_SOURCES]<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp; //functions<br>&nbsp;&nbsp;&nbsp;&nbsp; void AddCar(classCar* newCar, ALuint* newAudioSource);<br>&nbsp;&nbsp;&nbsp;&nbsp; bool AssignBufferToSource(ALuint *intSource, ALbyte* filename);<br>&nbsp;&nbsp;&nbsp;&nbsp; void UpdateAllPositionsAndVelocities();<br>&nbsp;&nbsp;&nbsp;&nbsp; void UpdateCarsPositionAndVelocity(classCar* findCar);<br>&nbsp;&nbsp;&nbsp;&nbsp; etc.<br>&nbsp;<br>&nbsp;<br>};<br>&nbsp;<br>&nbsp;<br>and also by a more object oriented<br>&nbsp;<br><strong>Method 2</strong><br><strong>----------------------------------</strong><br>classCar<br>{<br>&nbsp;&nbsp; //position, fuel, health etc.<br>&nbsp;&nbsp; //....<br>&nbsp;&nbsp; classAudioSource *soundSource[MAX_SOURCES];&nbsp;&nbsp; //remember, each car can emit many simultaneous sounds<br>&nbsp;<br>&nbsp;<br>}<br>&nbsp;<br>where classAudioSource is<span class="EC_Apple-converted-space">&nbsp;</span><br>{<br>&nbsp;&nbsp; ALuint intSource<br>&nbsp;<br>&nbsp;&nbsp; //funcs<br>&nbsp;&nbsp; bool AssignBufferToThis(ALbyte *filename);<br>&nbsp;&nbsp; void UpdatePosition(float x, float y, float z);<br>&nbsp;&nbsp; void Play();<br>&nbsp;&nbsp; void Stop();<br>&nbsp;&nbsp; void PitchMod(float fltMod);<br>&nbsp;&nbsp; void GainMod(float fltMod);<br>&nbsp;&nbsp; void SetLooping(bool boolLooping);<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp; etc.<br>&nbsp;<br>}<br>&nbsp;<br>&nbsp;<br>&nbsp;<br>With Method 1, Cars are added and removed from the emitters map on movement events, In method 2 classAudioSources are triggered to Play/Stop based on listener proximity , again on movement events.<br>I'm running into problems with both, mainly from unfamiliarity.<br>&nbsp;<br>If anyone here has input into handling large sets of sound sources in a good OO-heavy way, or can point me to any reading that does I'd be massively grateful.<br>&nbsp;<br>Thanks,<br>Pingwah<br>&nbsp;<br>&nbsp;<br>&nbsp;<br>&nbsp;<br>&nbsp;<br><br><hr>Find car news, reviews and more<span class="EC_Apple-converted-space">&nbsp;</span><a href="http://a.ninemsn.com.au/b.aspx?URL=http://secure-au.imrworldwide.com/cgi-bin/a/ci_450304/et_2/cg_801459/pi_1004813/ai_859641&amp;_t=762955845&amp;_r=tig_OCT07&amp;_m=EXT">Looking to change your car this year?</a><span class="EC_Apple-converted-space">&nbsp;</span>_______________________________________________<br>Openal mailing list<br><a href="mailto:Openal@opensource.creative.com">Openal@opensource.creative.com</a><br><a href="http://opensource.creative.com/mailman/listinfo/openal">http://opensource.creative.com/mailman/listinfo/openal</a><br></div></span></blockquote></div><br></div><br /><hr />Make ninemsn your homepage! <a href='http://windowslive.ninemsn.com.au/article.aspx?id=813730' target='_new'>Get the latest news, goss and sport</a></body>
</html>