Playing MP3s

Discussion in 'Wii - Emulation and Homebrew' started by diego_pmc, Oct 18, 2009.

Oct 18, 2009

Playing MP3s by diego_pmc at 4:17 PM (1,386 Views / 0 Likes) 8 replies

  1. diego_pmc
    OP

    Newcomer diego_pmc Advanced Member

    Joined:
    Sep 8, 2009
    Messages:
    52
    Country:
    United States
    I want to port a console game I made for Windows over to Wii Homebrew, and I also want to add some new features while I'm at it. I partly got the game to play an MP3 music file when it opens, but there is a problem. When I start the game, the music plays okay for a little while, and then it starts making one of those weird sounds when the game is blocked on a single note and keeps repeating it over and over. This happens seemingly at random points in game; it could start 2 seconds after I open the game, or it could start after 20 or so seconds.

    I posted the code below; also, here's the Homebrew directory for my application, if you want to check the error yourself. (When the error occurs, take the SD card out of the console, and press a button on the Wii Remote so that the Error() function would be called and the application would exit safely, so you don't have to unplug your Wii.)


    CODE#include mp3player.h // lmad in MakeFile
    #include asndlib.h // lasnd in MakeFile

    int main()
    {
    ÂÂÂÂPlayMP3("data/music/RPB-WoPiMedley.mp3");
    }

    void PlayMP3(const std::string filename) {
    ÂÂÂÂ/* Sources:
    ÂÂÂÂÂÂ1.
    ÂÂÂÂÂÂ2.
    ÂÂÂÂ */
    ÂÂÂÂASND_Init();
    ÂÂÂÂMP3Player_Init();
    ÂÂÂÂFILE* f = OpenFile(filename, "rb");
    ÂÂÂÂlong size = FileSize(f);
    ÂÂÂÂ
    ÂÂÂÂ// allocate memory to contain the whole file:
    ÂÂÂÂchar* buffer;
    ÂÂÂÂbuffer = (char*) malloc (sizeof(char)*size);
    ÂÂÂÂif (buffer == NULL) Error("cannot allocate memory for file '" + filename + "'");
    ÂÂÂÂ
    ÂÂÂÂ// copy the file into the buffer:
    ÂÂÂÂlong result = fread (buffer, 1, size, f);
    ÂÂÂÂif (result != size) Error ("cannot store file '" + filename + "' in memory");
    ÂÂÂÂfclose(f); // file is stored so we can close it now
    ÂÂÂÂ
    ÂÂÂÂ// play the buffer
    ÂÂÂÂMP3Player_PlayBuffer(buffer, size, NULL);
    }

    FILE* OpenFile(const std::string filename, std::string fam)
    {
    ÂÂÂÂFILE* file = NULL;
    ÂÂÂÂif(!fatInitDefault()) Error("cannot initialize FAT system");
    ÂÂÂÂfile = fopen(filename.c_str(), fam.c_str()); // fam = file access mode
    ÂÂÂÂif (file == NULL) Error("cannot open file '" + filename + "'");
    ÂÂÂÂreturn file;
    }

    long FileSize(FILE* f) {
    ÂÂÂÂ/* Sources:
    ÂÂÂÂÂÂ 1.
    ÂÂÂÂÂÂ 2.
    ÂÂÂÂ */
    ÂÂÂÂlong size;
    ÂÂÂÂfseek (f, 0, SEEK_END);
    ÂÂÂÂsize = ftell(f);
    ÂÂÂÂrewind(f);
    ÂÂÂÂreturn size;
    }

    void Error(const std::string message) {
    ÂÂÂÂprintf("\x1b[2J"); // clear the screen
    ÂÂÂÂprintf("\nError: "); printf("%s", message.c_str());
    ÂÂÂÂWaitWiiButton(); // wait for any button to be pressed on the wiimote
    ÂÂÂÂexit(1);
    }

    It would be great if someone could help me. I've tried asking on different forums before, but I got no answer. Also, I took a look at Homebrew music players, but their codes are too complex for me to understand.
     
  2. diego_pmc
    OP

    Newcomer diego_pmc Advanced Member

    Joined:
    Sep 8, 2009
    Messages:
    52
    Country:
    United States
    Pretty please?
     
  3. kLiNiKaL

    Member kLiNiKaL Dr. Greenthumb

    Joined:
    May 24, 2009
    Messages:
    581
    Location:
    Los Ganjales
    Country:
    Jamaica
  4. pembo

    Member pembo GBAtemp Regular

    Joined:
    Jun 1, 2009
    Messages:
    105
    Country:
    United Kingdom
    Can't spot anything obviously wrong with your code at a quick glance...
    I suspect you've got some sort of pointer corruption somewhere overwriting the memory that the MP3 has been loaded into causing your issues...

    Anyhow here's a copy of my working C++ code (Music class) from TetWiis that I've been developing.


    This isn't by any means the prettiest code I've done [​IMG] but it does work, other than there appears to be a slight timing issue at the end of MP3s where it loops too early.
    I've just got around this by adding some silent seconds at the end of the file [​IMG]

    Music.h
    CODE/**
    *
    * Tetwiis
    * (C)2009 http://www.pembo.co.uk
    *
    **/

    //------------------------------------------------------------------------------
    // Headers
    //------------------------------------------------------------------------------
    #include
    #include
    #include
    #include
    #include
    #include
    #include


    #ifndef MUSIC_HPP
    #define MUSIC_HPP
    class Music
    {
    ÂÂÂÂpublic:
    ÂÂÂÂÂÂÂÂMusic();
    ÂÂÂÂÂÂÂÂ~Music();
    ÂÂÂÂÂÂÂÂ
    ÂÂÂÂÂÂÂÂFILE *titleBGM;
    ÂÂÂÂÂÂÂÂlong titlelSize;
    ÂÂÂÂÂÂÂÂchar * titleBuffer;
    ÂÂÂÂÂÂÂÂsize_t titleResult;
    ÂÂÂÂÂÂÂÂbool titleMP3isready;
    ÂÂÂÂÂÂÂÂ
    ÂÂÂÂÂÂÂÂFILE *ingame1BGM;
    ÂÂÂÂÂÂÂÂlong ingame1lSize;
    ÂÂÂÂÂÂÂÂchar * ingame1Buffer;
    ÂÂÂÂÂÂÂÂsize_t ingame1Result;
    ÂÂÂÂÂÂÂÂbool ingame1MP3isready;ÂÂÂÂÂÂÂÂ
    ÂÂÂÂÂÂÂÂ
    ÂÂÂÂÂÂÂÂFILE *gameOverBGM;
    ÂÂÂÂÂÂÂÂlong gameOverlSize;
    ÂÂÂÂÂÂÂÂchar * gameOverBuffer;
    ÂÂÂÂÂÂÂÂsize_t gameOverResult;
    ÂÂÂÂÂÂÂÂbool gameOverMP3isready;ÂÂÂÂ

    ÂÂÂÂÂÂÂÂ

    ÂÂÂÂÂÂÂÂvoid loadMusicIntoBuffer();
    ÂÂÂÂÂÂÂÂ
    ÂÂÂÂÂÂÂÂvoid initTitleMusic();
    ÂÂÂÂÂÂÂÂvoid playTitleMusic();
    ÂÂÂÂÂÂÂÂ
    ÂÂÂÂÂÂÂÂvoid initIngame1Music();
    ÂÂÂÂÂÂÂÂvoid playIngame1Music();

    ÂÂÂÂÂÂÂÂvoid initGameOverMusic();
    ÂÂÂÂÂÂÂÂvoid playGameOverMusic();ÂÂÂÂÂÂÂÂ
    ÂÂÂÂÂÂÂÂ
    ÂÂÂÂÂÂÂÂvoid stop();
    ÂÂÂÂÂÂÂÂ
    ÂÂÂÂÂÂÂÂvoid mute();
    ÂÂÂÂÂÂÂÂvoid unmute();
    ÂÂÂÂÂÂÂÂ
    ÂÂÂÂprivate:
    ÂÂÂÂ
    ÂÂÂÂÂÂÂÂvoid initialiseFat();
    ÂÂÂÂÂÂÂÂbool can_open_root_fs();

    };
    #endif

    Music.cpp
    /**
    CODE *
    * Tetwiis
    * (C)2009 http://www.pembo.co.uk
    *
    **/


    //------------------------------------------------------------------------------
    // Headers
    //------------------------------------------------------------------------------
    # include "Music.h"
    # include

    //------------------------------------------------------------------------------
    // Externals
    //------------------------------------------------------------------------------


    //------------------------------------------------------------------------------
    // Globals
    //------------------------------------------------------------------------------

    //_______________________________________________________________________________
    /**
    * Constructor
    */
    Music::Music()
    {
    ÂÂÂÂinitialiseFat();
    ÂÂÂÂASND_Init();
    ÂÂÂÂMP3Player_Init();
    ÂÂÂÂ
    ÂÂÂÂtitleMP3isready = false;
    ÂÂÂÂingame1MP3isready = false;
    ÂÂÂÂloadMusicIntoBuffer();
    ÂÂÂÂ
    }


    //_______________________________________________________________________________
    /**
    * destructor
    */
    Music::~Music()
    {
    }

    void Music::loadMusicIntoBuffer()
    {
    ÂÂÂÂMP3Player_Stop();
    ÂÂÂÂ//if(titleBuffer)free(titleBuffer);
    ÂÂÂÂtitleBGM = fopen("sd:/apps/tetwiis/music/title.mp3", "rb");
    ÂÂÂÂif(titleBGM)
    ÂÂÂÂ{
    ÂÂÂÂÂÂÂÂ//Obtain file size
    ÂÂÂÂÂÂÂÂfseek (titleBGM , 0 , SEEK_END);
    ÂÂÂÂÂÂÂÂtitlelSize = ftell(titleBGM);
    ÂÂÂÂÂÂÂÂrewind (titleBGM);
    ÂÂÂÂÂÂÂÂ//Allocate memory to contain the whole file
    ÂÂÂÂÂÂÂÂtitleBuffer = (char*) malloc (sizeof(char)*titlelSize);
    ÂÂÂÂÂÂÂÂ//Copy the file into the buffer
    ÂÂÂÂÂÂÂÂtitleResult = fread (titleBuffer,1,titlelSize,titleBGM);
    ÂÂÂÂÂÂÂÂfclose(titleBGM);
    ÂÂÂÂ}
    ÂÂÂÂtitleMP3isready = true;
    ÂÂÂÂ
    ÂÂÂÂingame1BGM = fopen("sd:/apps/tetwiis/music/ingame1.mp3", "rb");
    ÂÂÂÂif(ingame1BGM)
    ÂÂÂÂ{
    ÂÂÂÂÂÂÂÂ//Obtain file size
    ÂÂÂÂÂÂÂÂfseek (ingame1BGM , 0 , SEEK_END);
    ÂÂÂÂÂÂÂÂingame1lSize = ftell(ingame1BGM);
    ÂÂÂÂÂÂÂÂrewind (ingame1BGM);
    ÂÂÂÂÂÂÂÂ//Allocate memory to contain the whole file
    ÂÂÂÂÂÂÂÂingame1Buffer = (char*) malloc (sizeof(char)*ingame1lSize);
    ÂÂÂÂÂÂÂÂ//Copy the file into the buffer
    ÂÂÂÂÂÂÂÂingame1Result = fread (ingame1Buffer,1,ingame1lSize,ingame1BGM);
    ÂÂÂÂÂÂÂÂfclose(ingame1BGM);
    ÂÂÂÂ}
    ÂÂÂÂingame1MP3isready = true;
    ÂÂÂÂ
    ÂÂÂÂgameOverBGM = fopen("sd:/apps/tetwiis/music/gameover.mp3", "rb");
    ÂÂÂÂif(gameOverBGM)
    ÂÂÂÂ{
    ÂÂÂÂÂÂÂÂ//Obtain file size
    ÂÂÂÂÂÂÂÂfseek (gameOverBGM , 0 , SEEK_END);
    ÂÂÂÂÂÂÂÂgameOverlSize = ftell(gameOverBGM);
    ÂÂÂÂÂÂÂÂrewind (gameOverBGM);
    ÂÂÂÂÂÂÂÂ//Allocate memory to contain the whole file
    ÂÂÂÂÂÂÂÂgameOverBuffer = (char*) malloc (sizeof(char)*gameOverlSize);
    ÂÂÂÂÂÂÂÂ//Copy the file into the buffer
    ÂÂÂÂÂÂÂÂgameOverResult = fread (gameOverBuffer,1,gameOverlSize,gameOverBGM);
    ÂÂÂÂÂÂÂÂfclose(gameOverBGM);
    ÂÂÂÂ}
    ÂÂÂÂgameOverMP3isready = true;ÂÂÂÂ

    }

    void Music::initTitleMusic()
    {
    ÂÂÂÂMP3Player_PlayBuffer(titleBuffer,titlelSize,NULL);
    }

    void Music::initIngame1Music()
    {
    ÂÂÂÂMP3Player_PlayBuffer(ingame1Buffer,ingame1lSize,NULL);
    }

    void Music::initGameOverMusic()
    {
    ÂÂÂÂMP3Player_PlayBuffer(gameOverBuffer,gameOverlSize,NULL);
    }

    void Music::PlayTitleMusic()
    {
    ÂÂÂÂif( (!MP3Player_IsPlaying() && titleMP3isready))
    ÂÂÂÂ{
    ÂÂÂÂÂÂÂÂMP3Player_PlayBuffer(titleBuffer, titlelSize, NULL);
    ÂÂÂÂ}

    }

    void Music::PlayIngame1Music()
    {
    ÂÂÂÂif( (!MP3Player_IsPlaying() && ingame1MP3isready))
    ÂÂÂÂ{
    ÂÂÂÂÂÂÂÂMP3Player_PlayBuffer(ingame1Buffer, ingame1lSize, NULL);
    ÂÂÂÂ}
    }

    void Music::PlayGameOverMusic()
    {
    ÂÂÂÂif(MP3Player_IsPlaying() && (gameOverMP3isready))
    ÂÂÂÂ{
    ÂÂÂÂÂÂÂÂMP3Player_PlayBuffer(gameOverBuffer, gameOverlSize, NULL);
    ÂÂÂÂ}

    }

    void Music::stop()
    {
    ÂÂÂÂMP3Player_Stop();
    }

    //_______________________________________________________________________________
    /*
    * Can open the SD Card
    */
    bool Music::can_open_root_fs()
    {
    ÂÂÂÂDIR_ITER *root = diropen("SD:/");
    ÂÂÂÂif (root)
    ÂÂÂÂ{
    ÂÂÂÂÂÂÂÂdirclose(root);
    ÂÂÂÂÂÂÂÂreturn true;
    ÂÂÂÂ}
    ÂÂÂÂreturn false;
    }

    //_______________________________________________________________________________
    /*
    * Initialises FAT
    */
    void Music::initialiseFat()
    {
    ÂÂÂÂ//printf(" Initialising FAT ......... ");
    ÂÂÂÂif (!fatInitDefault())
    ÂÂÂÂ{
    ÂÂÂÂÂÂÂÂ//drawError(15,11,11,50,err1_initFatErr);
    ÂÂÂÂÂÂÂÂ//errorApplication("Unable to initialise FAT subsystem, exiting.\n");
    ÂÂÂÂ}
    ÂÂÂÂ
    ÂÂÂÂif (!can_open_root_fs())
    ÂÂÂÂ{
    ÂÂÂÂÂÂÂÂ//errorApplication("Unable to open SD card, exiting.\n");
    ÂÂÂÂÂÂÂÂ//drawError(15,11,11,50,err2_rootFS);
    ÂÂÂÂ}
    ÂÂÂÂ//printf("Done\n");

    }

    void Music::mute()
    {
    ÂÂÂÂMP3Player_Volume(0);
    }

    void Music::unmute()
    {
    ÂÂÂÂMP3Player_Volume(254);
    }


    And here is a video of it in action playing the music...
     
  5. WiiCrazy

    Member WiiCrazy Be water my friend!

    Joined:
    May 8, 2008
    Messages:
    2,391
    Location:
    Istanbul
    Country:
    Turkey
    Your error is, you call MP3Player_PlayBuffer but this call is a non blocking call (async), means it starts playing the music in it's own thread and once playing started returns to your calling function...

    Let's see you main function

    Code:
    int main()
    {
    ÂÂÂÂPlayMP3("data/music/RPB-WoPiMedley.mp3");
    }
    The last statement by PlayMP3 is the MP3Player_PlayBuffer which starts playing music, returns and your program exits... The weird sound is because you didn't properly stopped the audio...

    ps: You should wait some external event (wiimote button press or something), sleep, or do some processing... Finally you should call MP3Player_IsPlaying, if this function returns true then you may go ahead and stop the music manually...

    like this

    Code:
    ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 
    if (MP3Player_IsPlaying())ÂÂ{
    ÂÂÂÂMP3Player_Stop();
    }
     
  6. diego_pmc
    OP

    Newcomer diego_pmc Advanced Member

    Joined:
    Sep 8, 2009
    Messages:
    52
    Country:
    United States
    But I want the music file to play throughout the whole time the game is running. When should I call MP3Player_Stop()? In main(), after PlayMP3(), or in PlayMP3(), after MP3Player_PlayBuffer()?
     
  7. WiiCrazy

    Member WiiCrazy Be water my friend!

    Joined:
    May 8, 2008
    Messages:
    2,391
    Location:
    Istanbul
    Country:
    Turkey
    Well my comments were for the pasted code in your original post, if you are already doing processing then there is no reason to call stop directly... you need to do it only when user decides to exit and the music is still playing.

    As pembo pointed out possibly you are messing the memory up with invalid pointers and such... First you should find out at what point this happens and examine the code... One good permanent way of it is outputting debug information as your code proceeds... debug output in certain places can really help speed the development...
    For an example : http://code.google.com/p/crazyintro/source...urce/launcher.c (this one using syslogd client, on the pc side you run a server listening
    messages from wii)

    Find the details here : http://forum.wiibrew.org/read.php?11,7232,7860
     
  8. diego_pmc
    OP

    Newcomer diego_pmc Advanced Member

    Joined:
    Sep 8, 2009
    Messages:
    52
    Country:
    United States
    Seems the problem was with how I was storing the size of the music file. Here's the fixed function:
    CODEvoid PlayMP3(const std::string filename) {
    ÂÂÂÂ/* Sources:
    ÂÂÂÂÂÂ1.
    ÂÂÂÂÂÂ2.
    ÂÂÂÂ */
    ÂÂÂÂASND_Init();
    ÂÂÂÂMP3Player_Init();
    ÂÂÂÂFILE* f = OpenFile(filename, "rb");
    ÂÂÂÂsize_t size = FileSize(f); // ONE CHANGE HERE
    ÂÂÂÂ
    ÂÂÂÂ// allocate memory to contain the whole file:
    ÂÂÂÂchar* buffer;
    ÂÂÂÂbuffer = (char*) malloc (sizeof(char)*size);
    ÂÂÂÂif (buffer == NULL) Error("cannot allocate memory for file '" + filename + "'");
    ÂÂÂÂ
    ÂÂÂÂ// copy the file into the buffer:
    ÂÂÂÂsize_t result = fread (buffer, 1, size, f); // ANOTHER CHANGE HERE
    ÂÂÂÂif (result != size) Error ("cannot store file '" + filename + "' in memory");
    ÂÂÂÂfclose(f); // file is stored so we can close it now
    ÂÂÂÂ
    ÂÂÂÂ// play the buffer
    ÂÂÂÂMP3Player_PlayBuffer(buffer, size, NULL);
    }

    Both 'size' and 'result' were of type long; I changed both to type site_t and it works now.
    Now I have to think of a proper design for the music class. [​IMG]
     
  9. diego_pmc
    OP

    Newcomer diego_pmc Advanced Member

    Joined:
    Sep 8, 2009
    Messages:
    52
    Country:
    United States


    You would use PlayList when you have multiple songs you want to play in the background during you game/application, and Sound
    when you have only one song you want to play.

    NOTE: Don't forget to include these libs in your makefile: -lasnd -lmad -lfat
     

Share This Page