Jump to content
  • Advertisement
Sign in to follow this  
load_bitmap_file

Streaming Music

This topic is 4804 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Two questions about streaming music: 1. What's a good buffer size for the amount of data to be read each stream? Right now I'm using 64 kilobyte buffers, but that number was chosen arbitrarily. I'm streaming Ogg Vorbis files decompressed to PCM if that matters. 2. When playing the streaming music, are you supposed to leave the file open until you stop the music or close and reopen the file every time you need to grab the next section of music?

Share this post


Link to post
Share on other sites
Advertisement
im not sure about your first question. But for the second, opening and closing a file constantly can really be a bottleneck in your application. I would reccomend just opening the file once and closing it when you are done streaming.

Share this post


Link to post
Share on other sites
#1 depends on the bitrate of your file output (e.g. 44KHz, 48KHz, or whatever), although there's not going to be much harm in overbuffering a little. Looking at my WinAmp settings (at default for buffering), based on the DirectSound output plugin, it prebuffers 500ms (that is, loads 0.5+ seconds of sound before starting to play) and tries to mantain a buffer of 2000ms (2 seconds) - both these figures are adjustable. If you're streaming from a website you may want to buffer some more to account for possible lag spikes. The waveOut plugin also mantains a 2000ms buffer by default, although it does not prebuffer, except for a 200ms "Buffer-ahead on track change".

For #2, I'd definately suggest keeping the file open. This prevents un-necessary overhead in open/close calls, plus it prevents the file from being modified while being read. This is important, otherwise, the file could be written to while being streamed from, quite possibly (if a variable bitrate) with the unit of data being read becoming misaligned with the units of data of the file, likely causing noise.

[Edited by - MaulingMonkey on May 15, 2005 7:30:50 PM]

Share this post


Link to post
Share on other sites
No problem :-). Note I just edited my post - really, it should depend on what bitrate you're outputing to, as that's the bitrate the file is going to be decompressed into, regardless of the file's bitrate (which may very well be variable - a case I was pondering how to handle when all this dawned on me and made me feel like an idiot :-))

Share this post


Link to post
Share on other sites
1) I personally use two 32k buffers, which I fill one at a time (play one, fill the other, reverse and repeat).
2) You want to leave the file open while you are streaming from it.

Another suggestion:

Play your music in another thread. If your main thread's update loop takes longer than normal (say, by loading things from disk), you'll fall off the end of your buffer. I found (pretty much experimentially) that with the two 32k buffers, sleeping the music thread for 85 milliseconds between updates was a reliable ammount.

Share this post


Link to post
Share on other sites
I personally would use at least one second of audio buffer (that is, decoded PCM), which would be ~172KB 44khz 16-bit stereo PCM. And yeah, you'll definitely want to decode in a separate thread. And lastly, there's no reason to close the file after every read (and plenty of reasons not to). For my streaming system I use a triple-thread model:
- decode thread running at highest priority: decodes audio data periodicially (generally 100 ms) for each stream, but caps itself at 1.5x real time (to prevent monopolizing the CPU)
- prebuffering thread running at normal priority: decodes the minimum prebuffer amount (such as 250 ms) of each sound before actually starting it playing, in a FIFO manner. At normal priority it can fight for the CPU along with all the other threads (a tradeoff of latency vs. CPU monopolization)
- prefetch thread at highest priority: prefetches raw file data for streams that are on slow media (and thus is I/O bound, and spends next to no CPU time, despite having highest priority), so that the decode thread will always have the compressed data in memory when it needs to decode it

Share this post


Link to post
Share on other sites
Blargh! Back from the dead. New question:

What's a good approach to tell when to stop the current buffer, play the other buffer, and then load data into the current buffer? Right now I'm testing to see if the play cursor last Update() was != 0 meaning it was playing and whether this Update() if the play cursor is at 0, meaning it stopped. However, with this method I get these horrible hiccups in the music every other time the music stops to update, presumably because the time inbetween each Update() was too long.

The thread approach sounds good but I don't know anything about threads [sad]. Is it very complex? I'm using DirectX, storing my sound data in IDirectSoundBuffer8 structures by the way. The docs mentioned a DSBPOSITIONNOTIFY but I couldn't get that to work.

EDIT: Yay, I got DSBPOSITIONNOTIFY working. The same "gaps in the music" problem still occurs however. I need to find out how to contain this updating inside its own thread now [sad]

[Edited by - load_bitmap_file on May 17, 2005 9:13:12 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by load_bitmap_file
What's a good approach to tell when to stop the current buffer, play the other buffer, and then load data into the current buffer? Right now I'm testing to see if the play cursor last Update() was != 0 meaning it was playing and whether this Update() if the play cursor is at 0, meaning it stopped. However, with this method I get these horrible hiccups in the music every other time the music stops to update, presumably because the time inbetween each Update() was too long.

Uhh. I'm not certain I understand what you're doing, but I'll reply assuming I do. You shouldn't wait until your buffer runs out of data to play to start pumping in more data. The simple example used in Inside DirectX tells about using a circular buffer (which is what you use for streaming), where you fill the first half when the play position gets to the middle (so it just finished playing the first half), then filling the second half when the play position gets to the beginning of the buffer. While you can improve on that a fair amount, that's the general idea of all streaming: putting in data where the sound card just finished playing, not where it's about to play (which it sounds like you're doing).

Share this post


Link to post
Share on other sites
Quote:
Original post by Catafriggm
Quote:
Original post by load_bitmap_file
*snip*

Uhh. I'm not certain I understand what you're doing, but I'll reply assuming I do. You shouldn't wait until your buffer runs out of data to play to start pumping in more data. The simple example used in Inside DirectX tells about using a circular buffer (which is what you use for streaming), where you fill the first half when the play position gets to the middle (so it just finished playing the first half), then filling the second half when the play position gets to the beginning of the buffer. While you can improve on that a fair amount, that's the general idea of all streaming: putting in data where the sound card just finished playing, not where it's about to play (which it sounds like you're doing).


I'm already doing this. I have two buffers that get swapped back and forth as the "current" buffer. When the current buffer hits the end, the other buffer starts playing (it has already been loaded) and then the current buffer preloads its data for when the other buffer hits its end and so forth.


Back to the infuriating task at hand, I stuck my buffer update code inside a while loop so that nothing was executed instead and the same problems still occured.

Does anyone know what in the world would cause brief split second sound blips/distortions when streaming music? This is what I'm doing:


while(1)
{
m_music[m_currentBuffer]->GetCurrentPosition(&playCursor, NULL);
if(m_playing && prevPlayCursor > playCursor)
{
m_music[1 - m_currentBuffer]->Play(0, 0, NULL);

//load the next section of data into the current music buffer
LoadCurrentBuffer();

//swap the current buffer with the now playing one
m_currentBuffer = 1 - m_currentBuffer;
}

prevPlayCursor = playCursor;
}


LoadCurrentBuffer() source beneath, all it does is load the next portion of the music file.

void nxt::Music::LoadCurrentBuffer()
{
DWORD size = g_bufferSize;
DWORD position = 0;
int section = 0;
int bytesRead = 1;
char* buffer = NULL;
//lock sound buffer for reading
HRESULT hResult = m_music[m_currentBuffer]->Lock(0, size, (LPVOID*)&buffer, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER);
if(FAILED(hResult))
{
//throw exception
}

//read ogg file data into sound buffer until buffer is filled or EOF is reached
while(position < size)
{
bytesRead = ov_read(&m_oggVorbisFile, buffer + position, size - position, 0, 2, 1, &section);
if(bytesRead <= 0 || position > size)
{
//stop file or something
m_playing = false;
break;
}
position += bytesRead;
}

//unlock sound buffer
m_music[m_currentBuffer]->Unlock(buffer, size, NULL, NULL);
m_music[m_currentBuffer]->SetCurrentPosition(0);
}


What the FUDGE is wrong here? [flaming] [flaming] Someone please help!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!