![]() |
| [[ Home | Forums | 3D Engines Database | Wiki | Articles/Tutorials | Game Dev Jobs | IRC Chat Network | Contact Us ]] |
|
|
#1 |
|
DevMaster Editor
Join Date: Jan 2005
Posts: 54
|
Title: Loading OggVorbis Files From Memory
Author: Spree Tree Description: Based on Lesson 8 of the OpenAL series, this tutorial demonstrates how to load an OggVorbis from files into memory. Sample source code is included. |
|
|
|
|
|
#2 |
|
New Member
Join Date: Jun 2005
Posts: 2
|
Nifty tutorial. I know that the Ogg guys are just trying to be helpful with their API based on FILE *. However, my system (like I'm sure many others) uses a file manager. I haven't quite figured out how I'm going to handle the streaming yet, but I'm glad you covered the aspects of dealing with the Ogg files once you get them loaded in memory.
|
|
|
|
|
|
#3 | |
|
New Member
Join Date: Aug 2004
Posts: 15
|
Me again, sure you don't want that fiver Spree Tree?
I've been trying to load a whole ogg into a buffer to play rather than streaming it. This is useful for pre-loaded sound effects. I don't get any errors, but it doesn't make any sound either: Quote:
Last edited by A.Russell : 10-29-2005 at 03:04 AM. |
|
|
|
|
|
|
#4 |
|
New Member
Join Date: Aug 2004
Posts: 15
|
Another try at this.
I'm trying to load one buffer with athe entire contents of an .ogg file so that it can be played as a pre-loaded sound effect -rather than streamed like in the tutorial. I have altered the earlier tutorial for playing .wav files. Code:
the next bit is the same as in the tutorial. Here the .ogg is loaded: Code:
Now, this is where it gets confusing: Code:
I take it the ogg file is loaded and decompressed into a location pointed to by &oggData??? Now I check the file: Code:
Looks okay. And here is where I think the problem is: Code:
Is oggData the "pcm" that is supposed to be loaded into the buffer. If not, then what is? I am completely lost here. What exactly is the parameter I am supposed to feed alBufferData? The function ends by returning a pointer to my screwed up buffer: Code:
|
|
|
|
|
|
#5 |
|
Valued Member
Join Date: Jan 2004
Location: England
Posts: 265
|
I will admit to hating the way in which ogg vorbis and OpenAL work together. I have written countless ogg stream classes for OpenAL applications, and I have yet to get one that feels right. Anyway, thats besides the point
I'll have a look through your code and comment on things as I see them. I don't have access to my code base at the moment, so you can try any changes I suggest and see how that goes. One thing I must say is that I don't think it is simpler to pre-load the ogg buffer format. The tutorial assumes that all buffers will be of x length, whereas, you will not know the size of the buffer until after the file has been decoded. There is a simpler way to read the contents of a file into memory. I don't know why I did it that way in the tutorial, maybe for clarity purpose but anyway :S Try something like the following (there could be syntax errors here) Code:
Regarding ov_open_callbacks(...) This just opens the file ready to be decoded and nothing more. The first param if the memory location of the file to play, which we have loaded above. The second param doesn't have the decoded sample, as that would make streaming pointless. It collects all the information about the ogg file you have just loaded (I assume it just reads the header). For example Code:
The actual decoding comes now. Now that the ogg data has been loaded, we need to read it bit by bit (or in your case, the whole lot). And we do that using ov_read (which calls our read callback we specified earlier). ov_read needs to know the format data (which is in the OggVorbis_File we opened above), the memory we will recive the decoded data to (which will be the pcm data you need), the amount of data we can read (which, at max, should be the size of your pcm data). The last params shoud be 0, 2, 1, §ion); and never change (with section being a signed int). Now in your case, you want to read the entire file. So, you would have to pass in a large pcm pointer (which is just a pointer to char) and a large amount to read (as the read will only read what it can). When you have read this, the pcm data is then passed to alBufferData(...) and the buffer can be played as you would with a wav file. Hope that helps some Spree |
|
|
|
|
|
#6 | |
|
New Member
Join Date: Aug 2004
Posts: 15
|
The Ogg Vorbis SDK is very frustrating.
With that off my chest, I've implimented the advice from your last post, but I am still stuck. What I have now is a program that will seem to load one of six ogg files correctly (the second to last file, so it has nothing to do with order), but will only play about half of its sound. I've modified lesson six and made an alternate function to load ogg files instead of wavs. In the Tutorial the function that does this is LoadALBuffer, so I've made LoadALBufferOgg, and it is called just the same from GetALLoadedData. I wonder if it has something to do with what you said in your last post: Quote:
I'm not sure why this is important, though. I can't see anywhere that you need to specify the size of a buffer. It simply takes as much data as it is given, doesn't it? If it happens to be BUFFER_SIZE or the more dynamic sizeOfFile, I can't see where the size of the buffer need to be entered. Here's what I've done anyway. Perhaps you can what is wrong, or a mistake in my logic: Code:
This next part was in your post, but I don't know what it is supposed to do. Isn't the data for the pcm array feed in by ov_open? This will just get overwritten, won't it? Code:
And now, for the very confusing and frustrating ov_read function. I have implimented this in the same way as in the streaming tutorial, but it is very odd. Each loop reads in a number of bytes that is a power of two, until the last loop. On the last loop it will either red right to the last byte, or it will leave one byte to go. If it leaves one last byte, then on the next loop it will return -131, unkown ogg error. Not very helpful. What is especially odd is that the only file that loads successfully is the second to last of six ogg files. There isn't anything I can see that is special about this file, except that it actually loads without an error and half of it will play. Code:
This is exactly the same as tutorial 6 except for this function, which should return a handle to a buffer with data from an ogg file instead of a wave. The six ogg files all play perfectly well in other media players. Some of them are stereo and others mono. Code:
My main reason for not streaming them is the pause that you get when loading a file from HDD. It is noticable in real time games. Sound effects are usually very small and may need to be repeatedly played many times. Also, the streaming function in the tutorials doesn't work properly with small files. I haven't found out why yet, perhaps itis something that happens if the file isn't big enough to fill the two buffer? |
|
|
|
|
|
|
#7 | ||||
|
Valued Member
Join Date: Jan 2004
Location: England
Posts: 265
|
Ok, I've had a look through your code, but I'm on someone elses machine at the mo, so what I say will be from what I can remeber... But stick with me!
First I think we need to clear up the difference between what the ogg format contains, and what the pcm data is that you want. The ogg format contains (very) compressed audio data, which is obviously why the file is so small. When you start working with the ogg file, you will not know how compressed the audio data is. So there for, you cannot know how much memory the uncompressed PCM data will take up. As a side note, if you converted a 3MB ogg file to a normal pcm wav file, the average size of the wav file is ~50Mb... Which is obviously memory you cannot spare! This is where ov_open and ov_read comes in. ov_open, as I mentioned, just reads in the ogg format header. This has nothing to do with the PCM data needed by openAL. This will allows the ogg vorbis internals to calculate the compression methods, file properties etc. ov_read is where your problem lies. ov_read calls your ReadFromMemory function. This function gets passed the size of data to copy from the ogg source file. So you copy a chunk of still compressed data from the ogg source file into the memory ptr passed to ReadFromMemory(...). It is then, and only then, that the ogg data is decompressed into the pcm data buffer that you passed to ov_read. Obviously, we will only know the size of the data copied to the pcm data buffer after we have decompressed it, hence ov_read returning how much data has been read. This will allow you to know how much data has been read into the pcm buffer, so next time you can point the ov_read function to read to the point pcmBufferStart+amountReadSoFar. Then, when the amountReadSoFar is as big as the pcm buffer size, you know that you have decompressed as much as you can in this loop. This will then allow you to either: a) play the buffer - which I think is what you want to do b) pass another buffer - which is what you do when you stream So what will have happened by now is that you have read compressed data from the ogg file in ReadFromMemory, and that memory has been decompressed into the pcm buffer that will be passed to Play. Now I'll explain why you are encountering the problem you are. Only Playing Half A Sound This is because, as you use ov_read, you have provided a buffer that is only big enough to contain half of the sample decompressed. The buffer you have provided needs to be much bigger if you do not want to use streaming. Or you need to use ov_read on another buffer, then queue the buffers as per the tutorial. No Sound Is Playing Various things could be causing this, but for the sake of this, I would say it is due to the buffer being streamed to is not big enough to contain data that has sound in it! Maybe the first part of the track is silent? I purposly have not included any source as I am worried you don't clearly understand how the ogg vorbis SDK works at the moment (don't worry about that, as you say, it isn't perfect but you will get there!). So i have just stuck to the theory of ogg vorbis for the moment. As for your other specific questions Quote:
Can't help with that at the moment as I don't have the ogg source to hand. -131 sounds a bit odd though. Are you making sure you are not over-ridding any data in your ReadFromMemory function? Quote:
FYI stereo samples cannot be played positionally. Just make sure this is not causeing you any problems with the mono samples (the source position not being set etc.) Quote:
If streaming is done correctly, there is no pause. As the buffers you stream into are generally quite small, are queued and then re-filled, the time taken to fill the buffers and assign them to a source is very small, and definatly not noticable. Quote:
You shouldn't be using streaming for short, simple sound effects. Thats what basic wav files are for. The whole point of using ogg files is for sounds that would be too big for normal wav files. This is usually music or speech. This is why the tutorial will not work for short effect. It is not designed for that, and shouldn't be expected to work. I am worried you are going off on a tangent a little, and not getting a clear idea of what ogg files and (more specifically) streaming is for. Simple, short effects - Use wavs Music or speech - Use streaming It might be a good idea to rethink that you are using ogg files for before you tear your hair out in anger (with OpenAL, its not that hard to go bold IMO!). Anyway, I hope this helps some. Let me know how it goes Spree |
||||
|
|
|
|
|
#8 | ||||
|
New Member
Join Date: Aug 2004
Posts: 15
|
Thanks a lot Spree Tree,
After your explanation I could get it working within a few minutes. Now I understand what you meant by not knowing how much space would be needed for pcm data in advance. What I've done isn't very elegant, but it works well enough. I only had to change a few lines: Code:
Now we have pre-loaded ogg files for sound effects! Quote:
Currently I just have everything being played relatively (AL_SOURCE_RELATIVE), though thanks for the heads up. Quote:
I used a 3d engine (closed source) that employed DirectShow for streaming and DirectSound for pre-loaded effects. There certainly was a pause on that engine. It could be pretty bad on an old machine, too. That's why I thought about it. Quote:
Although there is no advantage in the application, it makes a difference when distributing over the net. All those little sound effects add up. By using oggs several megs can be shaved off the final product. Think of all those poor people in countries like New Zealand on dial up! Quote:
I have some very expensive hair tonics, and they seem to be working. Thank you again for all your help! |
||||
|
|
|
|
|
#9 |
|
New Member
Join Date: Mar 2007
Posts: 1
|
I realize that this thread is probably mostly dead, but for late-comers this might be an interesting piece of information:
It is actually possible to do an exact prediction of the uncompressed Vorbis data size. The idea is that you count the number of PCM samples in the file, the number of channels in the file and the number of bitstreams in the file. This gives you the total number of PCM "frames" that will be decoded. The size of each frame is given by the resolution parameter that you're passing to ov_read. Just multiply the result from above by the resolution parameter (typically 2) and you're done. The number of PCM frames is readily given by ov_pcm_total(). |
|
|
|
|
|
#10 |
|
New Member
Join Date: Jan 2008
Posts: 9
|
I am having a similar problem to A.Russel.... I have implemented your example almost exactly, using my own datastruct (a class called Sound that contains a pointer to an instance of another class called SFResource that holds the points to the Ogg data in memory) in the custom callback functions. I've had all kinds of problems implementing this Ogg decoder, and in an effort to simplify the problem I reduced the buffer fill to just one 32k buffer, using a sound file that's small enough to fit inside.
My Open function is word-for-word what yours is. My other code: Code:
Code:
I had an earlier problem where everything seemed to work fine, but the data buffer in Sound::StreamOgg kept filling with zeros. I thought it might be a problem with my open_func callback, but I can't for the life of me see where it is. That code: Code:
Do you see any place where I might be going wrong? |
|
|
|
![]() |
| Thread Tools | Search this Thread |
| Display Modes | |
|