streaming mp3 :)
streaming mp3 :)
Hi folks,
i want to stream mp3 music files in my application.
The way i do it now is that the whole mp3 is loaded into memory and played. However since my game has expanded alot i only have like 3 to 6 mb of spare memory to play music. Since alot of player have larger files in there music dir, the game crashes when such a large file is loaded.
What is want it to stream the mp3 so that for example there is only 1 mb needed for playing every mp3 there is no matter how large it is.
is this possible? what does this do with speed? what libraries do i need? are there any examples?
hope to get some replies about this,
greets,
ghoti
i want to stream mp3 music files in my application.
The way i do it now is that the whole mp3 is loaded into memory and played. However since my game has expanded alot i only have like 3 to 6 mb of spare memory to play music. Since alot of player have larger files in there music dir, the game crashes when such a large file is loaded.
What is want it to stream the mp3 so that for example there is only 1 mb needed for playing every mp3 there is no matter how large it is.
is this possible? what does this do with speed? what libraries do i need? are there any examples?
hope to get some replies about this,
greets,
ghoti
My PSP games:
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Ah yes thanks, I have search and found out that it is called buffering :) and also some sources and examples so i'll try it out.
thanks and great work on the psplink app btw
thanks and great work on the psplink app btw
My PSP games:
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Hi me again,
i have looked at the source of the pspmediacenter but if i am correct it loads the entire mp3 file into memory :(
is there a quick way of modifying it? (my mp3 codec skills are non existing :S )
another question:
at this thread: http://forums.ps2dev.org/viewtopic.php? ... d+playback PeterM has posted an example. in it i see this line: does it set the callback so that you don't have to call it every loop iteration? or do i not understand correctly? and if so does it every callback check the fillOutputBuffer to see what has to be done?
also is it this way better then to do a custom callback every frameloop of the game?
hope to get some answer and thanks in advance
i have looked at the source of the pspmediacenter but if i am correct it loads the entire mp3 file into memory :(
is there a quick way of modifying it? (my mp3 codec skills are non existing :S )
another question:
at this thread: http://forums.ps2dev.org/viewtopic.php? ... d+playback PeterM has posted an example. in it i see this line:
Code: Select all
pspAudioSetChannelCallback(0, fillOutputBuffer, 0);
also is it this way better then to do a custom callback every frameloop of the game?
hope to get some answer and thanks in advance
My PSP games:
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Ghoti wrote:Hi me again,
another question:
at this thread: http://forums.ps2dev.org/viewtopic.php? ... d+playback PeterM has posted an example. in it i see this line:does it set the callback so that you don't have to call it every loop iteration? or do i not understand correctly? and if so does it every callback check the fillOutputBuffer to see what has to be done?Code: Select all
pspAudioSetChannelCallback(0, fillOutputBuffer, 0);
Code: Select all
void pspAudioSetChannelCallback(int channel, pspAudioCallback_t callback, void *pdata)
You need to create the callback function yourself, if you take a look at that source, you should find a function named fillOutputBuffer(...). Take a look at it to see how it should look and work.
Using the threaded callback method, you gain the advantage that the music playback is independent of your main loop, therefore you can easily pause your game and still have the music continue playing. Other than that, and saving you from having to manage the thread creation and management there is no advantage.also is it this way better then to do a custom callback every frameloop of the game?
hope to get some answer and thanks in advance
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki
Alexander Berl
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki
Alexander Berl
Hi i have the sample of PeterM almost working an i understand almost everything of the code. I have one problem though :s
This function (static_cast) converts the Sample to a buffer right?
however i get this error when i try to compile it:
any ideas why this is and what do i not get?
btw my code is in c not c++
greets ghoti
Code: Select all
Sample* destination = static_cast<Sample*> (buffer);
however i get this error when i try to compile it:
Code: Select all
mp3player.c: In function 'fillOutputBuffer':
mp3player.c:789: error: 'static_cast' undeclared (first use in this function)
mp3player.c:789: error: (Each undeclared identifier is reported only once
mp3player.c:789: error: for each function it appears in.)
mp3player.c:789: error: syntax error before 'Sample'
btw my code is in c not c++
greets ghoti
My PSP games:
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
this is C++ specific. In c, just do :Ghoti wrote:btw my code is in c not c++Code: Select all
Sample* destination = static_cast<Sample*> (buffer);
Code: Select all
Sample* destination = (Sample*)buffer;
Hi folks, i have the mp3 playing working but how do i stop the callback? and how do i pause it? and can i just change the file when a new song has to be loaded or do i have to do it some other way?
greets ghoti
PS to pause i have tried to make a boolean to just exit the callback function but then it gives a hanging sound as if the same part is playing in repeat. To stop it i have tried to shut down the audio and that works but there has to be a better way because that way i can't turn it back on. I have also tried to make a new callback to the 0 channel by passing 0 as a function and that stops the music but then if i try to load the fillbuffer into the callback then i get all craqcking and squeking noise...
greets ghoti
PS to pause i have tried to make a boolean to just exit the callback function but then it gives a hanging sound as if the same part is playing in repeat. To stop it i have tried to shut down the audio and that works but there has to be a better way because that way i can't turn it back on. I have also tried to make a new callback to the 0 channel by passing 0 as a function and that stops the music but then if i try to load the fillbuffer into the callback then i get all craqcking and squeking noise...
Last edited by Ghoti on Mon Jan 15, 2007 6:51 am, edited 1 time in total.
My PSP games:
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
You probably don't want to stop the callback as such, but look into passing messages from your main thread to the callback thread.
Note that multi threaded programming is perhaps not for the uninitiated.
BTW, since the buffer will play continuously, you should fill it with zeroes if the player is paused or stopped.
Edit:
To clarify the message passing idea, investigate semaphores or mutexes. You probably want to set up a global queue.
The main thread could lock the queue, add a command message (play, pause, stop, skip, etc etc) and unlock the queue.
The callback thread could lock the queue, take the next command, unlock the queue and handle the command.
Note that it could hurt playback if opening files and stuff takes a long time and the decoded mp3 buffer can't be filled up in time before the buffer starts to play.
Clever buffering should fix this.
Note that multi threaded programming is perhaps not for the uninitiated.
BTW, since the buffer will play continuously, you should fill it with zeroes if the player is paused or stopped.
Edit:
To clarify the message passing idea, investigate semaphores or mutexes. You probably want to set up a global queue.
The main thread could lock the queue, add a command message (play, pause, stop, skip, etc etc) and unlock the queue.
The callback thread could lock the queue, take the next command, unlock the queue and handle the command.
Note that it could hurt playback if opening files and stuff takes a long time and the decoded mp3 buffer can't be filled up in time before the buffer starts to play.
Clever buffering should fix this.
hi i'll look into the two things you have said, I'll learn alot from those things. But are those neccesary to just make the code pause, replay a song(isn't that just seek to the beginning of the file?) and load up a next song?
anyway, this will keep me occupite for a few days :) thanks and i'll let you know if i get it to work.
greets ghoti
anyway, this will keep me occupite for a few days :) thanks and i'll let you know if i get it to work.
greets ghoti
My PSP games:
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Hi I am trying to let the mp3 pause and It does not work like i want it:
What Am i doing wrong here? because it does actually pause but when i unpause it, it crashes.
Code: Select all
static void decode()
{
// While we need to fill the buffer...
while (
(mad_frame_decode(&frame, &stream) == -1) &&
((stream.error == MAD_ERROR_BUFLEN) || (stream.error == MAD_ERROR_BUFPTR))
)
{
// Give new buffer to the stream.
if (pausesong == 1) {
mad_stream_buffer(&stream, 0, 0);
//return;
}
else {
// Fill up the remainder of the file buffer.
fillFileBuffer();
mad_stream_buffer(&stream, fileBuffer, sizeof(fileBuffer));
}
}
// Synth the frame.
mad_synth_frame(&synth, &frame);
}
My PSP games:
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
I'm sorry but i just don't get it :(
i have this:
this pauses the game but still plays one veryvery small part so it sounds like it hangs.
I just don't really understand the code :( can you explain the code for me line by line or is that to much to ask?
PS. using the convertleft and right in the pause piece of code does not make any difference, leaving them out results also into a hang...
i have this:
Code: Select all
static void fillOutputBuffer(void* buffer, unsigned int samplesToWrite, void* userData)
{
// Where are we writing to?
Sample* destination = (Sample*)buffer;
if (pausesong == 1) {
//convertLeftSamples(destination, destination, NULL);
//convertRightSamples(destination, destination, NULL);
//mad_synth_frame(NULL, NULL);
return;
}
//Sample* destination = static_cast<Sample*> (buffer);
// While we've got samples to write...
while (samplesToWrite > 0)
{
// Enough samples available?
const unsigned int samplesAvailable = synth.pcm.length - samplesRead;
if (samplesAvailable > samplesToWrite)
{
// Write samplesToWrite samples.
convertLeftSamples(destination, destination + samplesToWrite, &synth.pcm.samples[0][samplesRead]);
convertRightSamples(destination, destination + samplesToWrite, &synth.pcm.samples[1][samplesRead]);
// We're still using the same PCM data.
samplesRead += samplesToWrite;
// Done.
samplesToWrite = 0;
}
else
{
// Write samplesAvailable samples.
convertLeftSamples(destination, destination + samplesAvailable, &synth.pcm.samples[0][samplesRead]);
convertRightSamples(destination, destination + samplesAvailable, &synth.pcm.samples[1][samplesRead]);
// We need more PCM data.
samplesRead = 0;
decode();
// We've still got more to write.
destination += samplesAvailable;
samplesToWrite -= samplesAvailable;
}
}
}
I just don't really understand the code :( can you explain the code for me line by line or is that to much to ask?
PS. using the convertleft and right in the pause piece of code does not make any difference, leaving them out results also into a hang...
My PSP games:
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Try clearing the destination buffer inside the 'if' block. Use memset() or C++'s std::fill_n if you prefer.Ghoti wrote:I'm sorry but i just don't get it :(
i have this:
Code: Select all
static void fillOutputBuffer(void* buffer, unsigned int samplesToWrite, void* userData) { // Where are we writing to? Sample* destination = (Sample*)buffer; if (pausesong == 1) { //convertLeftSamples(destination, destination, NULL); //convertRightSamples(destination, destination, NULL); //mad_synth_frame(NULL, NULL); return; }
I'm afraid so -- it would take a while.Ghoti wrote:I just don't really understand the code :( can you explain the code for me line by line or is that to much to ask?
It sounds like you are missing some regular C and C++ knowledge. Perhaps you should start with a simpler project, on Windows not PSP.
Pete
Hi,
i'll try to clear the buffer thanks for the tip.
I have done alot of C and C++ programming, I have made some software program for my company, also multi-user software. I have never come across these callback functions... :(
like i have never come across a function which you pass without parameters but the function itself has parameters which also already hold data. I did not understand that.
i understand almost everything from the code only the part why there is data in a function to which i give no parameters or data. That is what confusing me and what i don't get. :s
anyway thanks again for the tip try to find it out now.
greets ghoti
i'll try to clear the buffer thanks for the tip.
I have done alot of C and C++ programming, I have made some software program for my company, also multi-user software. I have never come across these callback functions... :(
like i have never come across a function which you pass without parameters but the function itself has parameters which also already hold data. I did not understand that.
i understand almost everything from the code only the part why there is data in a function to which i give no parameters or data. That is what confusing me and what i don't get. :s
anyway thanks again for the tip try to find it out now.
greets ghoti
My PSP games:
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Ahh! It sounds like you know what you're talking about then. Sorry about that - I assumed you were new and out of your depth. Guess I made an ass out of myself there. Sorry again.
If I understand you correctly, you're having problems with function pointers, is that right? They're indeed one of the dark corners of C (and they get even uglier with C++ member function pointers), but well worth knowing.
This page ( http://www.newty.de/fpt/index.html ) is very good at teaching about function pointers.
If I understand you correctly, you're having problems with function pointers, is that right? They're indeed one of the dark corners of C (and they get even uglier with C++ member function pointers), but well worth knowing.
This page ( http://www.newty.de/fpt/index.html ) is very good at teaching about function pointers.
Ah thank you very much for that link!
My PSP games:
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Hi it's me again,
well the pause function works and i have put in a playnextsong button. the problem however is that I guess that the variable which hold the path to the song is being used by two thread :S
I have this char array, Song, this is used in fillFileBuffer() however this function is called as an callbackfunction (a different thread i guess)
the problem is that when i press the LBUTTON i call the function nextMusicNumber() which reads from a 2d char array which holds all songs(paths) but then i change the Song char. However since the song char can also be used by the thread, Now i have looked around and it looks like a dining philosophers problem. However how can i solve this on the PSP in C? I have not found any usable working articles about this in C. Is it possible in C? any pointers ??
thanks in advance also if it does not look like the problem i sketch or you have some other opinions please, please let me know it really gives me a headacke :S
well the pause function works and i have put in a playnextsong button. the problem however is that I guess that the variable which hold the path to the song is being used by two thread :S
I have this char array, Song, this is used in fillFileBuffer() however this function is called as an callbackfunction (a different thread i guess)
the problem is that when i press the LBUTTON i call the function nextMusicNumber() which reads from a 2d char array which holds all songs(paths) but then i change the Song char. However since the song char can also be used by the thread, Now i have looked around and it looks like a dining philosophers problem. However how can i solve this on the PSP in C? I have not found any usable working articles about this in C. Is it possible in C? any pointers ??
thanks in advance also if it does not look like the problem i sketch or you have some other opinions please, please let me know it really gives me a headacke :S
My PSP games:
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Hello,
Good to hear you've had some success in getting things working.
Sounds like you need to ensure that the two threads aren't reading/modifying the variables at the same time?
I don't think the PSP SDK has mutexes, but it does have semaphores. Hopefully a search on here for semaphore will turn something up.
Check here for some info on semaphores:
http://en.wikipedia.org/wiki/Semaphore_(programming)
Good luck!
Good to hear you've had some success in getting things working.
Sounds like you need to ensure that the two threads aren't reading/modifying the variables at the same time?
I don't think the PSP SDK has mutexes, but it does have semaphores. Hopefully a search on here for semaphore will turn something up.
Check here for some info on semaphores:
http://en.wikipedia.org/wiki/Semaphore_(programming)
Good luck!
Hi thanks! nice to know someone with alot of knowledge answers this thread :) anyway i have another problem:S
I have 9 mp3 in a 2d char array. I loop through it to play them. after the last one has played the increment value is set to 0 so that it plays the first song again. This works fine for the first song of the array. I can loop 1 time through the song array but the second time it can only open the first song and after that it cannot open the mp3 file :S the mp3file however has not been changed so i guess the problem is that it is not closed properly and is still open. However i tried to solve this but it does not work. any ideas ?
how i change the song:
and the fillbuffer function:
any idea what is going wrong? is it really the opening and forgetting the closing of the file ?
greets ghoti
I have 9 mp3 in a 2d char array. I loop through it to play them. after the last one has played the increment value is set to 0 so that it plays the first song again. This works fine for the first song of the array. I can loop 1 time through the song array but the second time it can only open the first song and after that it cannot open the mp3 file :S the mp3file however has not been changed so i guess the problem is that it is not closed properly and is still open. However i tried to solve this but it does not work. any ideas ?
how i change the song:
Code: Select all
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ChangeSong: This function changes the song that
the mp3 buffering will play.
Param1: A path to a musicsong
*/
void ChangeSong(const char *Songtmp) {
// wait for thread to be open
sceKernelWaitSema(mutex, 1, 0);
// Song is not used by another thread so we can change it
sprintf(Song, "%s", Songtmp);
// reset the file so it starts at the beginning
//file = 0;
// Mark status that the song is changed
SongIsChanged = 1;
// free the lock of this thread.
sceKernelSignalSema(mutex, 1);
return;
}
Code: Select all
void fillFileBuffer()
{
// wait for semaphore to be open
sceKernelWaitSema(mutex, 1, 0);
// Open the file if it's not open.
if (SongIsChanged == 1) {
//sceIoClose(file);
SongIsChanged = 0;
file = 0;
}
if (file <= 0)
{
char cd[1024];
memset(cd, 0, sizeof(cd));
getcwd(cd, sizeof(cd) - 1);
char fileName[1024];
memset(fileName, 0, sizeof(fileName));
snprintf(fileName, sizeof(fileName) - 1, "%s", Song);
//pspDebugScreenPrintf("Opening %s... ", fileName);
file = sceIoOpen(fileName, PSP_O_RDONLY, 777);
if (file <= 0)
{
pspDebugScreenPrintf("Failed (%s).\n", Song);
sceKernelSignalSema(mutex, 1);
MusicPlayerNextSong();
return;
}
else
{
//pspDebugScreenPrintf("OK (%d).\n", file);
}
// Get the size.
fileSize = sceIoLseek(file, 0, SEEK_END);
sceIoLseek(file, 0, SEEK_SET);
}
// Find out how much to keep and how much to fill.
const unsigned int bytesToKeep = stream.bufend - stream.next_frame;
unsigned int bytesToFill = sizeof(fileBuffer) - bytesToKeep;
//pspDebugScreenPrintf("bytesToFill = %u, bytesToKeep = %u.\n", bytesToFill, bytesToKeep);
// Want to keep any bytes?
if (bytesToKeep)
{
// Copy the tail to the head.
memmove(fileBuffer, fileBuffer + sizeof(fileBuffer) - bytesToKeep, bytesToKeep);
}
// Read into the rest of the file buffer.
unsigned char* bufferPos = fileBuffer + bytesToKeep;
while (bytesToFill > 0)
{
// Read some.
//pspDebugScreenPrintf("Reading %u bytes...\n", bytesToFill);
const unsigned int bytesRead = sceIoRead(file, bufferPos, bytesToFill);
// EOF?
if (bytesRead == 0)
{
//pspDebugScreenPrintf("End of file.\n");
//sceIoLseek(file, 0, SEEK_SET);
//filePos = 0;
MusicPlayerNextSong();
break;
}
// Adjust where we're writing to.
bytesToFill -= bytesRead;
bufferPos += bytesRead;
filePos += bytesRead;
//pspDebugScreenPrintf("Read %u bytes from the file, %u left to fill.\n", bytesRead, bytesToFill);
//pspDebugScreenPrintf("%u%%.\n", filePos * 100 / fileSize);
}
sceKernelSignalSema(mutex, 1);
}
greets ghoti
My PSP games:
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Yes, that should be the problem. You should probably try to close the file as soon as the EOF is reached.
Also, you probably should only call the open file function when a new song is selected, rather then every time the callback is entered without a file open, because the playback might just be stopped alltogether. Then change the fillbuffer to fill the buffer with zeros when file <= 0.
Code: Select all
if (SongIsChanged == 1) {
SongIsChanged = 0;
if (file>0) sceIoClose(file); // If the file wasn't closed before (got to next song before reaching EOF), close it now
file = 0;
}
Code: Select all
if (bytesRead == 0)
{
//pspDebugScreenPrintf("End of file.\n");
sceIoClose(file);
file = 0;
//sceIoLseek(file, 0, SEEK_SET);
//filePos = 0;
MusicPlayerNextSong();
break;
}
<Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki
Alexander Berl
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki
Alexander Berl
ah yes that fixed the problem :D mp3 buffering is working :) thank you all
My PSP games:
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
back again after quite a while :)
The buffering is working correctly and without any problems :D
The one big problem is that it is quite slow :(
Now I heard something about using the ME ? is there any progress made on this? example codes or something like that available ?
greets ghoti
The buffering is working correctly and without any problems :D
The one big problem is that it is quite slow :(
Now I heard something about using the ME ? is there any progress made on this? example codes or something like that available ?
greets ghoti
My PSP games:
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
Boxy II: http://www.ghoti.nl/boxyii.php
Elementals: http://www.ghoti.nl/Elementals.php
en , you can use audiocodec.prx to decode mp3 frameGhoti wrote:back again after quite a while :)
The buffering is working correctly and without any problems :D
The one big problem is that it is quite slow :(
Now I heard something about using the ME ? is there any progress made on this? example codes or something like that available ?
greets ghoti
here is my demo code
http://forums.ps2dev.org/viewtopic.php? ... highlight=