0
0

Hello,

I have been learning FMOD for couple of weeks now and have tested, remade some of the examples (c#). I guess I am familiar with the platform to the extent to dare to start asking questions (passed the homework phase).

Appologies if this is obvious but I could not figure it out, neither through this forum or documentation: I understand that if one wants to get access to sound data then the sound has to be locked. Why is that? I presume this has to do how the long stream is processed. If I understand correclty this goes through internal buffers.

What would happen if I would not lock the buffer/sound?

Also, I do not understand what is meant by "circular buffer"?

Hope someome can help.
With best regards
ZoranK

  • You must to post comments
0
0

He’s not wrong, I was just saying that if the buffer isnt playing, it is just a buffer and it depends where you read from/write to if it wraps around or not.

The fact that one example behaves as if it was circular is because data is continuously being streamed into it, in a circular fashion.

  • You must to post comments
0
0

Oooh, I see. How it behaves depends really on the context in which it is used. Many thanks I understand now!

  • You must to post comments
0
0

Buffer is usually much smaller than full sound size, i.e. only a small chunk of audio is stored at a time. And it gets constantly overwritten, that’s why it is called circular.

Looking the buffer prevents writing to it (and thus processing and playing the sound). However, you can safely access the data in it, the data in buffer won’t get changed until it gets released.

  • You must to post comments
0
0

Hmmm… Thanks.

(1) But what is strange is that method that locks the buffer can just lock a portion of it (if I have not missunderstood how Sound::lock works). If this is the correct statement, then it would imply that when buffer is filed FMOD has to avoid part/fraction that is locked in some way. Is this really true?

(2) The buffer itself must be a rather complicated beast, since part of it must be under "filling" process, and part of it under "playing" process and these two processes have to carefully syncronize their activities. Preparation of data has to go ahead of playing it (this was mentioned somewhere in the documentation, I think).

It is not clear to me how locking the buffer interferes with the issue (1) I discussed above…

Z.

p.s. I guess I would like to understand a little bit more how internals of buffer processing work in a streaming situation. Obviously, all the discussion above is irrelevant in the situation when sound is constructed in memory (FMOD_CREATESOUND, was it?).

  • You must to post comments
0
0

In retrospect, I think that what I really wanted to ask was why there is a need for two chunks of data in sound::lock. I have started a separate thread with more precise question.

[url:2xtykrjz]http://www.fmod.org/forum/viewtopic.php?p=38465#38465[/url:2xtykrjz]

Many thanks for trying to help me out korDen!

Z.

  • You must to post comments
0
0

It is a common pattern to have multiple buffers and double buffering is the most typical one. Let’s say you created two buffers and filled them with the correct wav data. The first buffer is then sent to the audio driver and second one is not. Then you typically wait for a callback or some blocking operation to complete. Once it is complete and first buffer is finished playing you sent second one without waiting because it is already ready. This approach reduces latency and so-called ‘click’ing. Once you sent your second buffer, you may fill the first one (in a background thread, for example). Beware that you should fill it before another one finished playing!

In case of double buffering, the active buffer index is changed like this:
0, 1, 0, 1, 0, 1 etc.

Sometimes you need more that two buffers (because of instable data transmition rate or high code complexity). I use 4 buffers for one of my applications. In this case the active buffer index is as follows:
0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 etc.

I believe that the circular nature of active buffer indexing gives the name to the "circular buffering" term. There is also a good article on circular buffering in Wikipedia: http://en.wikipedia.org/wiki/Circular_buffer

Hope this helps, Koroskin Denis

  • You must to post comments
0
0

Many thanks Denis! I checked the wiki link. It was eye opener. Many thanks again. Hope I can bother you with more question in connection with this. Is this the way FMOD streams data? Through circular buffer?

What puzzles me is that in the documentaion for sound::lock two peaces of data are returned from the sound::lock call (there are two pointers returned, with two length variables respectivelly). From what you said one could assume that FMOD works by using "0,1,0,1…" (double) buffering. Is that correct? I guess only FMOD developers can answer this… But then strangely, in the documentation it says

ptr1
Address of a pointer that will point to the first part of the locked data.

ptr2
Address of a pointer that will point to the second part of the locked data. This will be null if the data locked hasn’t wrapped at the end of the buffer.

The second pointer description is puzzling: "null if the data hasn’t wrapped at the end of the buffer". What do they mean by this? This is what confuses me, this suggests that FMOD actually uses circular buffer.

Here is example in c# when buffer is used to grab data being recorded by some device:

[code:2xu7cfz4]
if (recordpos != lastrecordpos)
{
IntPtr ptr1 = IntPtr.Zero, ptr2 = IntPtr.Zero;
int blocklength;
uint len1 = 0, len2 = 0;

                blocklength = (int)recordpos - (int)lastrecordpos; 
                if (blocklength < 0) 
                { 
                    blocklength += (int)soundlength; 
                } 

                /* 
                    Lock the sound to get access to the raw data. 
                */ 
                sound.@lock(lastrecordpos * 4, (uint)blocklength * 4, ref ptr1, ref ptr2, ref len1, ref len2); /* *4 = stereo 16bit.  1 sample = 4 bytes. */ 

                /* 
                    Write it to disk. 
                */ 
                if (ptr1 != IntPtr.Zero && len1 > 0) 
                { 
                    byte[] buf = new byte[len1]; 

                    Marshal.Copy(ptr1, buf, 0, (int)len1); 

                    datalength += (int)len1; 

                    fs.Write(buf, 0, (int)len1); 

                } 
                if (ptr2 != IntPtr.Zero && len2 > 0) 
                { 
                    byte[] buf = new byte[len2]; 

                    Marshal.Copy(ptr2, buf, 0, (int)len2); 

                    datalength += (int)len2; 

                    fs.Write(buf, 0, (int)len2); 
                } 

                /* 
                    Unlock the sound to allow FMOD to use it again. 
                */ 
                sound.unlock(ptr1, ptr1, len1, len2); 
            } 

[/code:2xu7cfz4]

The thing I do not understand is that

(1) two pieces of data are used (two pointers) ptr1 and ptr2. Ok from discussion with you I understand that it might have to with double buffering but it would be nice to get some clarification from FMOD developers . :)

(2) Also, from documentation it is not clear how ptr2 behaves (perhaps expert understands immediately, but I am not the expert ๐Ÿ˜ณ ).

Having said all this, all assumptions I discussed above are probably not correct since the first two variables that serves as input to sound::lock are user defined length of data that one wants to locke. This implies that two pointers really do not point to double buffer boundaries but something determined by the user/caller of sound::lock.

FMOD developers please help! This might be an issue that could deserve special explenation in the documentation.

Zoran

  • You must to post comments
0
0

If I understand this, it’s working exactly how DirectSound works. This isn’t double buffering – it’s a mechanism for retrieving data from a single circular buffer.

Check out Game Audio Programming, page 135, which explains how this works.

http://books.google.com/books?id=0TAE5m … #PPA127,M1

Ignore the code and such – it’s only relevant if you’re programing streaming DirectSound buffer.

The reason you need two buffers returned to you with a circular buffer is that the data may be split across the buffer boundary. In other words, if the buffer is 10 bytes long (just as an example), it may be using 6 bytes of that, but it starts at byte 8. You’d receive buffer A as a two byte buffer, and buffer B would be a four-byte buffer.

Note: I’m not sure if FMOD uses a circular buffer internally, but I believe you can conceptualize it this way from an API standpoint. The FMOD devs would have to answer that definitively.

  • You must to post comments
0
0

FMOD doesnt use a circular buffer, it uses a ‘buffer’.

It’s up to you if you want the behaviour to be circular, ie you are streaming data of a non divisible size into it.
If you just want to lock the whole sound, and use length, it will never fill in ptr2 or len2.

If you’re writing the buffer continusouly, and you’re playing it looping (like you would with a stream), you might want to write 1000 bytes, but you are at position 9,500 out of a 10,000 byte sound, so ptr1 will be end 500 bytes, ptr2 will be the start 500 bytes.

Its nothing to do with directsound, though they did seem to come up with the ptr1,ptr2 logic its just a logical way to handle it.

Btw the fact that there is actually a lock function is so that ‘unlock’ can do something with the data – ie on ps2 it has to dma your data to sound ram. You can’t just address sound ram directly.
korDen is right as lock/unlock might also be there to be a mutex function, so that one thread cannot write to the buffer while another has a lock on it.

  • You must to post comments
0
0

Ah, I see. Thanks for the clarification. That’s what I get for making assumptions, eh? ๐Ÿ˜‰

  • You must to post comments
0
0

[quote="brett":11dn7x19]FMOD doesnt use a circular buffer, it uses a ‘buffer’.
[/quote:11dn7x19]

Hi Brett

Hmmm… I do not want to argue with "God" but please bear with me (just for my own understanding):

I have added write statements to check how recordtodisk.cs example behaves. By tracing ptr1 and ptr2 values it seems that FMOD uses circural buffer. Two scenarios showed up. First one looks like this

0—-ptr1——————ptr1+len1————————-end

and data from ptr1 to ptr1+len1 will be locked. In such a case ptr2 is null, len2=0.

Second scenario is

0=ptr2—–len2——————–ptr1————–end

which corresponds to the situation where buffer is wrapped, and locked region starts from ptr1 to end, wraping back to ptr2 untill len2 is reached. In such a case len1=end-ptr1, ptr2=0 (denotes first address of the buffer).

So this particular example when sound buffer is filled by external device shows that every time buffer boundary was crossed ptr2 was non zero. So JamesB’s suggestion was not entielry wrong. It was also my understanding after studying pointer values. I am lost … ๐Ÿ˜ฎ :) How this squares with what you have said above?

I have to meditate on your post a little…

ZoranK

  • You must to post comments
Showing 11 results
Your Answer

Please first to submit.