Thmp3

From ProjectWiki
(Difference between revisions)
Jump to: navigation, search
m (Reverted edits by Iqoquhir (Talk); changed back to last version by Wikisysop)
Line 1: Line 1:
=[http://imygijesusy.co.cc Page Is Unavailable Due To Site Maintenance, Please Visit Reserve Copy Page]=
+
<big>mp3lib for NDS</big>
&lt;big&gt;mp3lib for NDS&lt;/big&gt;
+
 
__TOC__
 
__TOC__
 
''Project Status: Alpha Testing''
 
''Project Status: Alpha Testing''
Line 29: Line 28:
  
 
==Where to get it==
 
==Where to get it==
Currently the sources for this are part of [http://blea.ch/wiki/index.php/Category:LIBTHDS LibThds] and is probably the easiest to use due to its dependence on [[Thfifo]]. The latest version of the source can also be downloaded via SVN (see libthds page) or directly from the svn httpd:&lt;br&gt;
+
Currently the sources for this are part of [http://blea.ch/wiki/index.php/Category:LIBTHDS LibThds] and is probably the easiest to use due to its dependence on [[Thfifo]]. The latest version of the source can also be downloaded via SVN (see libthds page) or directly from the svn httpd:<br>
 
* [http://svn.blea.ch/thdslib/trunk/thdslib/source/shared/include/thmp3.h thmp3.h]  (This file is for both arm7 and arm9 sides)
 
* [http://svn.blea.ch/thdslib/trunk/thdslib/source/shared/include/thmp3.h thmp3.h]  (This file is for both arm7 and arm9 sides)
 
* [http://svn.blea.ch/thdslib/trunk/thdslib/source/arm9/source/thmp3arm9.c thmp3arm9.c]
 
* [http://svn.blea.ch/thdslib/trunk/thdslib/source/arm9/source/thmp3arm9.c thmp3arm9.c]
Line 36: Line 35:
 
Note: [[Thfifo]] is required for interprocessor communications.  
 
Note: [[Thfifo]] is required for interprocessor communications.  
  
An example project from svn is here:&lt;br&gt;
+
An example project from svn is here:<br>
 
[http://svn.blea.ch/thdslib/trunk/thdslib/examples/thmp3/ thmp3 example]
 
[http://svn.blea.ch/thdslib/trunk/thdslib/examples/thmp3/ thmp3 example]
  
Very very alpha release: [http://blea.ch/~eris/litter/thmp3/dsmp3test.v.1.alpha.tar.bz2 thmp3 v.1.alpha] 15MB with all the mp3s and such ~_~ &lt;br&gt; This is a self contained project however the above links to the svn sources will contain the newest versions and should be used instead.  
+
Very very alpha release: [http://blea.ch/~eris/litter/thmp3/dsmp3test.v.1.alpha.tar.bz2 thmp3 v.1.alpha] 15MB with all the mp3s and such ~_~ <br> This is a self contained project however the above links to the svn sources will contain the newest versions and should be used instead.  
  
 
Dont expect much yet, it will play mp3s, but is still very immature and has some issues with song advance (A button). tho stopping the song first (b button) helps. These errors should repair themselves after fifo is added. ^^
 
Dont expect much yet, it will play mp3s, but is still very immature and has some issues with song advance (A button). tho stopping the song first (b button) helps. These errors should repair themselves after fifo is added. ^^
  
 
==Todo/Bugs==
 
==Todo/Bugs==
* &lt;s&gt;add volume/fadeout support!!!! (i soooo keeep forgetting this)&lt;/s&gt;   done
+
* <s>add volume/fadeout support!!!! (i soooo keeep forgetting this)</s>   done
* &lt;s&gt;add fifo support (this will fix only known bug relating to song switching as well)&lt;/s&gt;   done
+
* <s>add fifo support (this will fix only known bug relating to song switching as well)</s>   done
* &lt;s&gt;modify decoder assembly language file to write pcm data to two seperate buffers instead of interleaving LRLR&lt;/s&gt;   no need to do this, the C function is insanely efficient as is :p
+
* <s>modify decoder assembly language file to write pcm data to two seperate buffers instead of interleaving LRLR</s>   no need to do this, the C function is insanely efficient as is :p
 
* need functions to set playback and artist format callbacks
 
* need functions to set playback and artist format callbacks
 
* add information headers to all files ^^
 
* add information headers to all files ^^
Line 54: Line 53:
 
==ARM9 Functions==
 
==ARM9 Functions==
 
===Mp3 Playback===
 
===Mp3 Playback===
'''mp3Init'''&lt;br&gt;
+
'''mp3Init'''<br>
 
Initalize mp3 player (on the ARM9 side). Will wait for arm7 to indicate its ready before continuing. Should be called once and only once at start of program.
 
Initalize mp3 player (on the ARM9 side). Will wait for arm7 to indicate its ready before continuing. Should be called once and only once at start of program.
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
void mp3Init(void);
 
void mp3Init(void);
&lt;/source&gt;
+
</source>
'''mp3Play'''&lt;br&gt;
+
'''mp3Play'''<br>
Start playing the mp3 specified by the filesystem path. &lt;br&gt;
+
Start playing the mp3 specified by the filesystem path. <br>
 
(FAT and/or [[Nitrofs]] should be initialized prior to calling this or any other mp3/playlist functions!)
 
(FAT and/or [[Nitrofs]] should be initialized prior to calling this or any other mp3/playlist functions!)
 
* filename - pointer to string containing path to and the mp3 filename
 
* filename - pointer to string containing path to and the mp3 filename
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
bool mp3Play(char *filename);
 
bool mp3Play(char *filename);
&lt;/source&gt;
+
</source>
'''mp3Update'''&lt;br&gt;
+
'''mp3Update'''<br>
 
This function should be placed in the game's idle loop. It is used to refill the input buffer from the stream as needed. The mp3 will not start, change, or much of anything untill this is called.
 
This function should be placed in the game's idle loop. It is used to refill the input buffer from the stream as needed. The mp3 will not start, change, or much of anything untill this is called.
  
 
This along with mp3Init, and mp3Play represent the minimal requirements for playing an mp3. ^^  
 
This along with mp3Init, and mp3Play represent the minimal requirements for playing an mp3. ^^  
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
void mp3Update(void);
 
void mp3Update(void);
&lt;/source&gt;
+
</source>
'''mp3Stop'''&lt;br&gt;
+
'''mp3Stop'''<br>
 
Stops a playing an mp3
 
Stops a playing an mp3
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
void mp3Stop(void);
 
void mp3Stop(void);
&lt;/source&gt;
+
</source>
'''mp3Queue'''&lt;br&gt;
+
'''mp3Queue'''<br>
 
Sets the next song to play when this one eof's.
 
Sets the next song to play when this one eof's.
 
* filename - pointer to string containing path to and the mp3 filename
 
* filename - pointer to string containing path to and the mp3 filename
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
void mp3Queue(const char *filename);
 
void mp3Queue(const char *filename);
&lt;/source&gt;
+
</source>
'''mp3GetSongPos'''&lt;br&gt;
+
'''mp3GetSongPos'''<br>
Get the song's current playback position in minutes, seconds, and milliseconds. &lt;br&gt;
+
Get the song's current playback position in minutes, seconds, and milliseconds. <br>
 
All input variables should be of type int !!!
 
All input variables should be of type int !!!
 
* mins - pointer to mins variable
 
* mins - pointer to mins variable
Line 91: Line 90:
 
* ms - pointer to milliseconds variable
 
* ms - pointer to milliseconds variable
 
Returns the elapsed time in ms*100.
 
Returns the elapsed time in ms*100.
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
int mp3GetSongPos(int *mins, int *secs, int *ms);
 
int mp3GetSongPos(int *mins, int *secs, int *ms);
&lt;/source&gt;
+
</source>
'''mp3SetPlayCb'''&lt;br&gt;
+
'''mp3SetPlayCb'''<br>
 
Sets a callback thats called whenever the song changes (for displaying title)
 
Sets a callback thats called whenever the song changes (for displaying title)
 
should be in the format of: void myMp3PlayCallback(char *filename, char *title). See example below..
 
should be in the format of: void myMp3PlayCallback(char *filename, char *title). See example below..
 
* func - address of a function to call each time song changes. Set as NULL to disable (default).
 
* func - address of a function to call each time song changes. Set as NULL to disable (default).
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
void mp3SetPlayCb(void *func)
 
void mp3SetPlayCb(void *func)
&lt;/source&gt;
+
</source>
'''mp3SetVolume'''&lt;br&gt;
+
'''mp3SetVolume'''<br>
 
Sets playback volume.
 
Sets playback volume.
 
* volume - new volume (1 ~ 127) will change volume for current and all subsequent mp3 playbacks
 
* volume - new volume (1 ~ 127) will change volume for current and all subsequent mp3 playbacks
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
void mp3SetVolume(char volume)
 
void mp3SetVolume(char volume)
&lt;/source&gt;
+
</source>
  
 
===Mp3 Playback Macros===
 
===Mp3 Playback Macros===
'''mp3SetOpts(o)'''&lt;br&gt;
+
'''mp3SetOpts(o)'''<br>
 
Sets various optons for mp3 playback, such as:
 
Sets various optons for mp3 playback, such as:
 
* MP3_ADVANCE - advance to next song on playlist after this one finishes
 
* MP3_ADVANCE - advance to next song on playlist after this one finishes
 
* MP3_REPEAT  - return to beginning of playlist after last song
 
* MP3_REPEAT  - return to beginning of playlist after last song
 
* MP3_LOOP    - loop currently playing song over and over and over and over till ya cant stand it no moar!! ;;
 
* MP3_LOOP    - loop currently playing song over and over and over and over till ya cant stand it no moar!! ;;
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
#define mp3SetOpts(o) (mp3Ipc-&gt;flags|=(o)) //set options
+
#define mp3SetOpts(o) (mp3Ipc->flags|=(o)) //set options
&lt;/source&gt;
+
</source>
'''mp3ClearOpts'''&lt;br&gt;
+
'''mp3ClearOpts'''<br>
 
Same as above but instead will clear the given options
 
Same as above but instead will clear the given options
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
#define mp3ClearOpts(o) (mp3Ipc-&gt;flags=(mp3Ipc-&gt;flags&amp;~(o)))
+
#define mp3ClearOpts(o) (mp3Ipc->flags=(mp3Ipc->flags&~(o)))
&lt;/source&gt;
+
</source>
 
'''mp3PlaylistAdv'''
 
'''mp3PlaylistAdv'''
 
Advance to the next song on the playlist.
 
Advance to the next song on the playlist.
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
#define mp3PlaylistAdv() (mp3PlaylistPlay(mp3Pl.nowplaying+1))
 
#define mp3PlaylistAdv() (mp3PlaylistPlay(mp3Pl.nowplaying+1))
&lt;/source&gt;
+
</source>
  
  
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
//macros to get or set various things
 
//macros to get or set various things
 
//set options
 
//set options
#define mp3SetOpts(o) (mp3Ipc-&gt;flags|=(o))
+
#define mp3SetOpts(o) (mp3Ipc->flags|=(o))
 
//same as above but clears instead
 
//same as above but clears instead
#define mp3ClearOpts(o) (mp3Ipc-&gt;flags=(mp3Ipc-&gt;flags&amp;~(o)))
+
#define mp3ClearOpts(o) (mp3Ipc->flags=(mp3Ipc->flags&~(o)))
 
//move to next song on playlist
 
//move to next song on playlist
 
#define mp3PlaylistAdv() (mp3PlaylistPlay(mp3Pl.nowplaying+1))
 
#define mp3PlaylistAdv() (mp3PlaylistPlay(mp3Pl.nowplaying+1))
 
//song position in samples
 
//song position in samples
#define mp3GetSongPosSamples() (mp3Ipc-&gt;mfram)
+
#define mp3GetSongPosSamples() (mp3Ipc->mfram)
 
//song position in milliseconds
 
//song position in milliseconds
#define mp3GetSongPosms() ((mp3Ipc-&gt;mfram*100)/mp3Ipc-&gt;framenfo.samprate)
+
#define mp3GetSongPosms() ((mp3Ipc->mfram*100)/mp3Ipc->framenfo.samprate)
 
//mp3 bitrate such as 96000 128000 192000,  
 
//mp3 bitrate such as 96000 128000 192000,  
#define mp3GetBitrate() (mp3Ipc-&gt;framenfo.bitrate)
+
#define mp3GetBitrate() (mp3Ipc->framenfo.bitrate)
 
//number of channels (1 = mono, 2 = stereo)
 
//number of channels (1 = mono, 2 = stereo)
#define mp3GetChans() (mp3Ipc-&gt;framenfo.nChans)
+
#define mp3GetChans() (mp3Ipc->framenfo.nChans)
 
//Sample rate. like: 44100,32000,19200 etc  
 
//Sample rate. like: 44100,32000,19200 etc  
#define mp3GetRate() (mp3Ipc-&gt;framenfo.samprate)
+
#define mp3GetRate() (mp3Ipc->framenfo.samprate)
 
//bits per sample either 8, 16, 24 (we only support 16!!!!)
 
//bits per sample either 8, 16, 24 (we only support 16!!!!)
#define mp3GetBits() (mp3Ipc-&gt;framenfo.bitsPerSample)
+
#define mp3GetBits() (mp3Ipc->framenfo.bitsPerSample)
 
//mp3 layer
 
//mp3 layer
#define mp3GetLayer() (mp3Ipc-&gt;framenfo.layer)
+
#define mp3GetLayer() (mp3Ipc->framenfo.layer)
 
//mp3 layer version
 
//mp3 layer version
#define mp3GetVersion() (mp3Ipc-&gt;framenfo.version)
+
#define mp3GetVersion() (mp3Ipc->framenfo.version)
 
//last error  
 
//last error  
#define mp3GetError() (mp3Ipc-&gt;error)
+
#define mp3GetError() (mp3Ipc->error)
 
//How much data (in bytes) is in the pcm buffer
 
//How much data (in bytes) is in the pcm buffer
#define mp3GetPCMUsed() (mp3Ipc-&gt;pcmbleft)
+
#define mp3GetPCMUsed() (mp3Ipc->pcmbleft)
 
//same as above but reports in percent instead ^^
 
//same as above but reports in percent instead ^^
 
#define mp3GetPCMUsedPct() ((int)((mp3GetPCMUsed()*100)/PCMBUF_SAMPLES))
 
#define mp3GetPCMUsedPct() ((int)((mp3GetPCMUsed()*100)/PCMBUF_SAMPLES))
 
//how much data (bytes) is in the stream buffer
 
//how much data (bytes) is in the stream buffer
#define mp3GetDataUsed() (mp3Ipc-&gt;dleft)
+
#define mp3GetDataUsed() (mp3Ipc->dleft)
 
//same as above but reports in percent instead ^^
 
//same as above but reports in percent instead ^^
#define mp3GetDataUsedPct() ((int)((mp3Ipc-&gt;dleft*100)/DECODEBUF_SIZE))
+
#define mp3GetDataUsedPct() ((int)((mp3Ipc->dleft*100)/DECODEBUF_SIZE))
 
//position of playback pointer within pcm buffer
 
//position of playback pointer within pcm buffer
#define mp3GetPBPos() (mp3Ipc-&gt;pcmbpos) //useless except for debugging and even then should be removed mebbe? @_@
+
#define mp3GetPBPos() (mp3Ipc->pcmbpos) //useless except for debugging and even then should be removed mebbe? @_@
 
//Number of frames decoded
 
//Number of frames decoded
#define mp3GetDecoded() (mp3Ipc-&gt;fdec)  
+
#define mp3GetDecoded() (mp3Ipc->fdec)  
 
//re/set the above variable
 
//re/set the above variable
#define mp3SetDecoded(d) (mp3Ipc-&gt;fdec=(d))
+
#define mp3SetDecoded(d) (mp3Ipc->fdec=(d))
 
//this value is incremented each idle loop of the arm7. should increment +60 each second.
 
//this value is incremented each idle loop of the arm7. should increment +60 each second.
 
//starts moving slower as arm7 becomes saturated. used mostly for debugging
 
//starts moving slower as arm7 becomes saturated. used mostly for debugging
#define mp3GetVBlnks() (mp3Ipc-&gt;vfram) //Number of  
+
#define mp3GetVBlnks() (mp3Ipc->vfram) //Number of  
 
//re/set the above variable
 
//re/set the above variable
#define mp3SetVBlnks(d) (mp3Ipc-&gt;vfram=(d)) //zero or whatever them
+
#define mp3SetVBlnks(d) (mp3Ipc->vfram=(d)) //zero or whatever them
#define mp3GetState() (mp3Ipc-&gt;state) //arm7's current operational state
+
#define mp3GetState() (mp3Ipc->state) //arm7's current operational state
#define mp3GetCommand() (mp3Ipc-&gt;command) //for debug rly, reads contents of command buffer (fifo will prolly eliminate this)
+
#define mp3GetCommand() (mp3Ipc->command) //for debug rly, reads contents of command buffer (fifo will prolly eliminate this)
 
//fade out nicely in x amount of seconds (see thSound for exact seconds format!_!)
 
//fade out nicely in x amount of seconds (see thSound for exact seconds format!_!)
 
#define mp3FadeOut(s) (thSndFade(HWSCHANNEL0, (s)),thSndFade(HWSCHANNEL1, (s)))
 
#define mp3FadeOut(s) (thSndFade(HWSCHANNEL0, (s)),thSndFade(HWSCHANNEL1, (s)))
&lt;/source&gt;
+
</source>
  
 
===Playlist===
 
===Playlist===
 
All functions here are for the arm9.
 
All functions here are for the arm9.
  
'''mp3ReadId3V1'''&lt;br&gt;
+
'''mp3ReadId3V1'''<br>
 
Read IDv3 tag from mp3.
 
Read IDv3 tag from mp3.
 
* filename - pointer to string containing path to and the mp3 filename
 
* filename - pointer to string containing path to and the mp3 filename
 
* id3 - pointer to structure of type ID3V1_T (see below)
 
* id3 - pointer to structure of type ID3V1_T (see below)
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
bool mp3ReadId3V1(char *filename, ID3V1_T *id3);
 
bool mp3ReadId3V1(char *filename, ID3V1_T *id3);
&lt;/source&gt;
+
</source>
  
'''mp3GetId3FromFile'''&lt;br&gt;
+
'''mp3GetId3FromFile'''<br>
 
Same as above but uses an already open filehandle instead.
 
Same as above but uses an already open filehandle instead.
 
* f - already opened filehandle (should be an mp3 ofc! :)
 
* f - already opened filehandle (should be an mp3 ofc! :)
 
* id3 - pointer to structure of type ID3V1_T
 
* id3 - pointer to structure of type ID3V1_T
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
bool mp3GetId3FromFile(FILE *f, ID3V1_T *id3);
 
bool mp3GetId3FromFile(FILE *f, ID3V1_T *id3);
&lt;/source&gt;
+
</source>
 
'''ID3V1_T structure'''
 
'''ID3V1_T structure'''
 
The ID3V1_T structure type used by the two preceeding functions is defined as:
 
The ID3V1_T structure type used by the two preceeding functions is defined as:
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
//This at last 128 (-3 for &quot;TAG&quot;) bytes of file is the tag
+
//This at last 128 (-3 for "TAG") bytes of file is the tag
 
typedef struct _ID3V1_T {
 
typedef struct _ID3V1_T {
 
char title[30];
 
char title[30];
Line 210: Line 209:
 
char genre;
 
char genre;
 
} ID3V1_T __attribute__((packed));
 
} ID3V1_T __attribute__((packed));
&lt;/source&gt;
+
</source>
'''mp3PlaylistClear'''&lt;br&gt;
+
'''mp3PlaylistClear'''<br>
 
Clears all entries from the playlist.
 
Clears all entries from the playlist.
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
void mp3PlaylistClear(void);
 
void mp3PlaylistClear(void);
&lt;/source&gt;
+
</source>
'''mp3PlaylistAdd'''&lt;br&gt;
+
'''mp3PlaylistAdd'''<br>
 
Add a single song to the playlist.  
 
Add a single song to the playlist.  
 
* filename - pointer to string containing path to and the mp3 filename
 
* filename - pointer to string containing path to and the mp3 filename
 
* title - ascii string containing title of song
 
* title - ascii string containing title of song
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
void mp3PlaylistAdd(char *filename, char *title);
 
void mp3PlaylistAdd(char *filename, char *title);
&lt;/source&gt;
+
</source>
'''mp3FormatId3'''&lt;br&gt;
+
'''mp3FormatId3'''<br>
 
This function determins is the default way id3 data is presented. Hard to explain this @_@. The user may override this to change how titles are created for the playlist by setting a different callback.  
 
This function determins is the default way id3 data is presented. Hard to explain this @_@. The user may override this to change how titles are created for the playlist by setting a different callback.  
 
* id3 - pointer to already populated id3 struct
 
* id3 - pointer to already populated id3 struct
 
* titlestr - buffer to hold title string (should be 256 bytes at least)
 
* titlestr - buffer to hold title string (should be 256 bytes at least)
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
void mp3FormatId3(ID3V1_T *id3, char *titlestr);
 
void mp3FormatId3(ID3V1_T *id3, char *titlestr);
&lt;/source&gt;
+
</source>
'''mp3PlaylistAddDir'''&lt;br&gt;
+
'''mp3PlaylistAddDir'''<br>
 
Add all mp3s in directory to playlist.
 
Add all mp3s in directory to playlist.
 
* dirpath - path/to/yourmp3s/  
 
* dirpath - path/to/yourmp3s/  
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
bool mp3PlaylistAddDir(char *dirpath);
 
bool mp3PlaylistAddDir(char *dirpath);
&lt;/source&gt;
+
</source>
'''mp3PlaylistAddM3u'''&lt;br&gt;
+
'''mp3PlaylistAddM3u'''<br>
 
Add all songs in .m3u file to playlist. M3u is the text based playlist format popular with most mp3 players.
 
Add all songs in .m3u file to playlist. M3u is the text based playlist format popular with most mp3 players.
 
* filename - path/to/your.m3u   
 
* filename - path/to/your.m3u   
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
int mp3PlaylistAddM3u(char *filename);
 
int mp3PlaylistAddM3u(char *filename);
&lt;/source&gt;
+
</source>
'''mp3PlaylistPlay'''&lt;br&gt;
+
'''mp3PlaylistPlay'''<br>
 
Plays a song from the playlist
 
Plays a song from the playlist
 
* index - integer describing which song to play. 0 = first song, 1 = second song on list, 2 = third song, etc etc
 
* index - integer describing which song to play. 0 = first song, 1 = second song on list, 2 = third song, etc etc
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
bool mp3PlaylistPlay(int index);
 
bool mp3PlaylistPlay(int index);
&lt;/source&gt;
+
</source>
  
 
===Playlist Macros===
 
===Playlist Macros===
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
//Get number of song in playlist
 
//Get number of song in playlist
 
#define mp3GetPlaylistCnt() (mp3Pl.numsongs)
 
#define mp3GetPlaylistCnt() (mp3Pl.numsongs)
 
//Returns char * to entry 'i' on playlist's title
 
//Returns char * to entry 'i' on playlist's title
#define mp3GetPlaylistTitle(i) (mp3Pl.entry[i]-&gt;title)
+
#define mp3GetPlaylistTitle(i) (mp3Pl.entry[i]->title)
 
//Returns char * to entry 'i' on playlist's filename
 
//Returns char * to entry 'i' on playlist's filename
#define mp3GetPlaylistFilename(i) (mp3Pl.entry[i]-&gt;filename)
+
#define mp3GetPlaylistFilename(i) (mp3Pl.entry[i]->filename)
 
//get currently playing song index
 
//get currently playing song index
 
#define mp3GetPlaylistNowPlay() (mp3Pl.nowplaying)
 
#define mp3GetPlaylistNowPlay() (mp3Pl.nowplaying)
&lt;/source&gt;
+
</source>
  
 
==ARM7==
 
==ARM7==
'''mp3Init'''&lt;br&gt;
+
'''mp3Init'''<br>
Initializes the ARM7 side of mp3 decoder. Waits for ARM9 to be initialized before returning. Should be called once in the arm7's main() function before the idle loop.&lt;br&gt;
+
Initializes the ARM7 side of mp3 decoder. Waits for ARM9 to be initialized before returning. Should be called once in the arm7's main() function before the idle loop.<br>
 
Will return false if helix decoder fails to initialize.
 
Will return false if helix decoder fails to initialize.
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
bool mp3Init(void);
 
bool mp3Init(void);
&lt;/source&gt;
+
</source>
  
'''mp3Loop'''&lt;br&gt;
+
'''mp3Loop'''<br>
 
This function should be placed in the ARM7's idle loop. It is here all the real work is done, the function may not always return before the end of each vblank interval so take this into consideration.  
 
This function should be placed in the ARM7's idle loop. It is here all the real work is done, the function may not always return before the end of each vblank interval so take this into consideration.  
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
void mp3Loop(void);
 
void mp3Loop(void);
&lt;/source&gt;
+
</source>
  
 
==Examples==
 
==Examples==
 
===Simplest Playback===
 
===Simplest Playback===
 
Basic Mp3 Playing. Probably the simplest way to use this library.  
 
Basic Mp3 Playing. Probably the simplest way to use this library.  
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
#include &lt;thmp3.h&gt; //Make sure you gots this in the top plz :D
+
#include <thmp3.h> //Make sure you gots this in the top plz :D
  
 
mp3Init();
 
mp3Init();
mp3Play(&quot;path/to/your.mp3&quot;);
+
mp3Play("path/to/your.mp3");
  
 
while(1) {
 
while(1) {
Line 288: Line 287:
 
};
 
};
  
&lt;/source&gt;
+
</source>
  
 
''All subsequent examples will assume you have already called mp3Init(), and have mp3Update(); in your idle loop..''
 
''All subsequent examples will assume you have already called mp3Init(), and have mp3Update(); in your idle loop..''
  
 
===Read ID3v1 tag from mp3===
 
===Read ID3v1 tag from mp3===
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
ID3V1_T id3;
 
ID3V1_T id3;
mp3ReadId3V1(filename,&amp;id3);
+
mp3ReadId3V1(filename,&id3);
printf(&quot;%s - %s [%s (%s)]\n&quot;,id3.artist, id3.title, id3.album, id3.year);
+
printf("%s - %s [%s (%s)]\n",id3.artist, id3.title, id3.album, id3.year);
&lt;/source&gt;
+
</source>
 
Will print:
 
Will print:
 
  Artistname - Songtitle [Album name (YEAR)]
 
  Artistname - Songtitle [Album name (YEAR)]
  
 
===Display song position===
 
===Display song position===
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
int mins,secs,ms;
 
int mins,secs,ms;
mp3GetSongPos(&amp;mins, &amp;secs, &amp;ms);
+
mp3GetSongPos(&mins, &secs, &ms);
iprintf(&quot;TIME (M:S:MS): %02d:%02d:%02d  \n&quot;,mins,secs,ms);
+
iprintf("TIME (M:S:MS): %02d:%02d:%02d  \n",mins,secs,ms);
&lt;/source&gt;
+
</source>
  
 
===Load m3u and play the first song in the list===
 
===Load m3u and play the first song in the list===
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
mp3PlaylistAddM3u(&quot;nitro:/playlist.m3u&quot;); //add m3u playlist
+
mp3PlaylistAddM3u("nitro:/playlist.m3u"); //add m3u playlist
 
mp3PlaylistPlay(0); //play first song  (mp3PlaylistAdv(); will advance to next song on list
 
mp3PlaylistPlay(0); //play first song  (mp3PlaylistAdv(); will advance to next song on list
&lt;/source&gt;
+
</source>
  
 
===List all songs on playlist===
 
===List all songs on playlist===
&lt;source lang=&quot;c&quot;&gt;
+
<source lang="c">
 
int c=0;
 
int c=0;
 
do {
 
do {
iprintf(&quot;%3d%s\n&quot;,c, mp3GetPlaylistTitle(c));   
+
iprintf("%3d%s\n",c, mp3GetPlaylistTitle(c));   
} while(++c&lt;mp3GetPlaylistCnt());
+
} while(++c<mp3GetPlaylistCnt());
&lt;/source&gt;
+
</source>
  
 
[[Category:NDS]]
 
[[Category:NDS]]
 
[[Category:C]]
 
[[Category:C]]
 
[[Category:LIBTHDS]]
 
[[Category:LIBTHDS]]

Revision as of 11:45, 26 November 2010

mp3lib for NDS

Contents

Project Status: Alpha Testing

What is this

Touhou Mp3, or simply Thmp3, is a library for playing mp3s as BGM (background music) in Nintendo DS games with the goals of being simple to use, modular, small, and fast.

Some features include:

  • up to 44100 sample rates, 192K/VBR bitrates, 16 bit stereo playback possible (however 32000 is more reliable at this time)
  • m3u support, playlist manager
  • ID3v1 supported
  • playback position indicator (perfect for rhythm games :D)
  • supports streaming audio from FAT, or Nitrofs
  • most work is done on the ARM7 cpu
  • small size
  • speedy code
  • c++ compatibility

Drawbacks:

  • buffers use a lot of memory
  • pcm dma transfers and decoding use some arm9 memory bandwidth
  • high bit/sample rates use all or most all of the ARM7 CPU

It may not be the best option for all games, but if you want high quality bgm and have cpu to spare might give it a try. ^^ Was originally written for a touhou fangame and is where it gets it's name. Because of interest from other developers was decided to release as a separate lib. Hopes you find it useful.

  • 2008.8.14 - fifo added for a bit now but refining things still
  • 2009.7.3 - Updated version comming soon! including pausing, seemless switching between songs, syncronous operations, song swapping (for pausing currently playing song to play alternate music and returning back), and much more :D (2009.07.13 ~ beta is on svn)

Where to get it

Currently the sources for this are part of LibThds and is probably the easiest to use due to its dependence on Thfifo. The latest version of the source can also be downloaded via SVN (see libthds page) or directly from the svn httpd:

Note: Thfifo is required for interprocessor communications.

An example project from svn is here:
thmp3 example

Very very alpha release: thmp3 v.1.alpha 15MB with all the mp3s and such ~_~
This is a self contained project however the above links to the svn sources will contain the newest versions and should be used instead.

Dont expect much yet, it will play mp3s, but is still very immature and has some issues with song advance (A button). tho stopping the song first (b button) helps. These errors should repair themselves after fifo is added. ^^

Todo/Bugs

  • add volume/fadeout support!!!! (i soooo keeep forgetting this) done
  • add fifo support (this will fix only known bug relating to song switching as well) done
  • modify decoder assembly language file to write pcm data to two seperate buffers instead of interleaving LRLR no need to do this, the C function is insanely efficient as is :p
  • need functions to set playback and artist format callbacks
  • add information headers to all files ^^
  • explain things better ~_~
  • add moar examples!!

ARM9 Functions

Mp3 Playback

mp3Init
Initalize mp3 player (on the ARM9 side). Will wait for arm7 to indicate its ready before continuing. Should be called once and only once at start of program.

void mp3Init(void);

mp3Play
Start playing the mp3 specified by the filesystem path.
(FAT and/or Nitrofs should be initialized prior to calling this or any other mp3/playlist functions!)

  • filename - pointer to string containing path to and the mp3 filename
bool mp3Play(char *filename);

mp3Update
This function should be placed in the game's idle loop. It is used to refill the input buffer from the stream as needed. The mp3 will not start, change, or much of anything untill this is called.

This along with mp3Init, and mp3Play represent the minimal requirements for playing an mp3. ^^

void mp3Update(void);

mp3Stop
Stops a playing an mp3

void mp3Stop(void);

mp3Queue
Sets the next song to play when this one eof's.

  • filename - pointer to string containing path to and the mp3 filename
void mp3Queue(const char *filename);

mp3GetSongPos
Get the song's current playback position in minutes, seconds, and milliseconds.
All input variables should be of type int !!!

  • mins - pointer to mins variable
  • secs - pointer to seconds variable
  • ms - pointer to milliseconds variable

Returns the elapsed time in ms*100.

int mp3GetSongPos(int *mins, int *secs, int *ms);

mp3SetPlayCb
Sets a callback thats called whenever the song changes (for displaying title) should be in the format of: void myMp3PlayCallback(char *filename, char *title). See example below..

  • func - address of a function to call each time song changes. Set as NULL to disable (default).
void mp3SetPlayCb(void *func)

mp3SetVolume
Sets playback volume.

  • volume - new volume (1 ~ 127) will change volume for current and all subsequent mp3 playbacks
void mp3SetVolume(char volume)

Mp3 Playback Macros

mp3SetOpts(o)
Sets various optons for mp3 playback, such as:

  • MP3_ADVANCE - advance to next song on playlist after this one finishes
  • MP3_REPEAT - return to beginning of playlist after last song
  • MP3_LOOP - loop currently playing song over and over and over and over till ya cant stand it no moar!! ;;
#define mp3SetOpts(o) (mp3Ipc->flags|=(o))	//set options

mp3ClearOpts
Same as above but instead will clear the given options

#define mp3ClearOpts(o) (mp3Ipc->flags=(mp3Ipc->flags&~(o)))

mp3PlaylistAdv Advance to the next song on the playlist.

#define mp3PlaylistAdv() (mp3PlaylistPlay(mp3Pl.nowplaying+1))


//macros to get or set various things
//set options
#define mp3SetOpts(o) (mp3Ipc->flags|=(o))	
//same as above but clears instead
#define mp3ClearOpts(o) (mp3Ipc->flags=(mp3Ipc->flags&~(o)))
//move to next song on playlist
#define mp3PlaylistAdv() (mp3PlaylistPlay(mp3Pl.nowplaying+1))
//song position in samples
#define mp3GetSongPosSamples() (mp3Ipc->mfram)
//song position in milliseconds
#define mp3GetSongPosms() ((mp3Ipc->mfram*100)/mp3Ipc->framenfo.samprate)
//mp3 bitrate such as 96000 128000 192000, 
#define mp3GetBitrate()	(mp3Ipc->framenfo.bitrate)
//number of channels (1 = mono, 2 = stereo)
#define mp3GetChans() (mp3Ipc->framenfo.nChans)
//Sample rate. like: 44100,32000,19200 etc 
#define mp3GetRate() (mp3Ipc->framenfo.samprate)
//bits per sample either 8, 16, 24 (we only support 16!!!!)
#define mp3GetBits() (mp3Ipc->framenfo.bitsPerSample)
//mp3 layer
#define mp3GetLayer() (mp3Ipc->framenfo.layer)
//mp3 layer version
#define mp3GetVersion() (mp3Ipc->framenfo.version)
//last error 
#define mp3GetError() (mp3Ipc->error)
//How much data (in bytes) is in the pcm buffer
#define mp3GetPCMUsed() (mp3Ipc->pcmbleft)
//same as above but reports in percent instead ^^
#define mp3GetPCMUsedPct() ((int)((mp3GetPCMUsed()*100)/PCMBUF_SAMPLES))
//how much data (bytes) is in the stream buffer
#define mp3GetDataUsed() (mp3Ipc->dleft)
//same as above but reports in percent instead ^^
#define mp3GetDataUsedPct() ((int)((mp3Ipc->dleft*100)/DECODEBUF_SIZE))
//position of playback pointer within pcm buffer
#define mp3GetPBPos() (mp3Ipc->pcmbpos)	//useless except for debugging and even then should be removed mebbe? @_@
//Number of frames decoded
#define mp3GetDecoded() (mp3Ipc->fdec) 
//re/set the above variable
#define mp3SetDecoded(d) (mp3Ipc->fdec=(d))	
//this value is incremented each idle loop of the arm7. should increment +60 each second.
//starts moving slower as arm7 becomes saturated. used mostly for debugging
#define mp3GetVBlnks() (mp3Ipc->vfram) //Number of 
//re/set the above variable
#define mp3SetVBlnks(d) (mp3Ipc->vfram=(d))	//zero or whatever them
#define mp3GetState() (mp3Ipc->state)		//arm7's current operational state
#define mp3GetCommand() (mp3Ipc->command)	//for debug rly, reads contents of command buffer (fifo will prolly eliminate this)
//fade out nicely in x amount of seconds (see thSound for exact seconds format!_!)
#define mp3FadeOut(s) (thSndFade(HWSCHANNEL0, (s)),thSndFade(HWSCHANNEL1, (s)))

Playlist

All functions here are for the arm9.

mp3ReadId3V1
Read IDv3 tag from mp3.

  • filename - pointer to string containing path to and the mp3 filename
  • id3 - pointer to structure of type ID3V1_T (see below)
bool mp3ReadId3V1(char *filename, ID3V1_T *id3);

mp3GetId3FromFile
Same as above but uses an already open filehandle instead.

  • f - already opened filehandle (should be an mp3 ofc! :)
  • id3 - pointer to structure of type ID3V1_T
bool mp3GetId3FromFile(FILE *f, ID3V1_T *id3);

ID3V1_T structure The ID3V1_T structure type used by the two preceeding functions is defined as:

//This at last 128 (-3 for "TAG") bytes of file is the tag
typedef struct _ID3V1_T {
	char	title[30];
	char	artist[30];
	char	album[30];
	char	year[4];
	char	comment[30];
	char	genre;
} ID3V1_T __attribute__((packed));

mp3PlaylistClear
Clears all entries from the playlist.

void mp3PlaylistClear(void);

mp3PlaylistAdd
Add a single song to the playlist.

  • filename - pointer to string containing path to and the mp3 filename
  • title - ascii string containing title of song
void mp3PlaylistAdd(char *filename, char *title);

mp3FormatId3
This function determins is the default way id3 data is presented. Hard to explain this @_@. The user may override this to change how titles are created for the playlist by setting a different callback.

  • id3 - pointer to already populated id3 struct
  • titlestr - buffer to hold title string (should be 256 bytes at least)
void mp3FormatId3(ID3V1_T *id3, char *titlestr);

mp3PlaylistAddDir
Add all mp3s in directory to playlist.

  • dirpath - path/to/yourmp3s/
bool mp3PlaylistAddDir(char *dirpath);

mp3PlaylistAddM3u
Add all songs in .m3u file to playlist. M3u is the text based playlist format popular with most mp3 players.

  • filename - path/to/your.m3u
int mp3PlaylistAddM3u(char *filename);

mp3PlaylistPlay
Plays a song from the playlist

  • index - integer describing which song to play. 0 = first song, 1 = second song on list, 2 = third song, etc etc
bool mp3PlaylistPlay(int index);

Playlist Macros

//Get number of song in playlist
#define mp3GetPlaylistCnt() (mp3Pl.numsongs)
//Returns char * to entry 'i' on playlist's title
#define mp3GetPlaylistTitle(i) (mp3Pl.entry[i]->title)
//Returns char * to entry 'i' on playlist's filename
#define mp3GetPlaylistFilename(i) (mp3Pl.entry[i]->filename)
//get currently playing song index
#define mp3GetPlaylistNowPlay() (mp3Pl.nowplaying)

ARM7

mp3Init
Initializes the ARM7 side of mp3 decoder. Waits for ARM9 to be initialized before returning. Should be called once in the arm7's main() function before the idle loop.
Will return false if helix decoder fails to initialize.

bool mp3Init(void);

mp3Loop
This function should be placed in the ARM7's idle loop. It is here all the real work is done, the function may not always return before the end of each vblank interval so take this into consideration.

void mp3Loop(void);

Examples

Simplest Playback

Basic Mp3 Playing. Probably the simplest way to use this library.

#include <thmp3.h> //Make sure you gots this in the top plz :D
 
mp3Init();
mp3Play("path/to/your.mp3");
 
while(1) {
  mp3Update();
};

All subsequent examples will assume you have already called mp3Init(), and have mp3Update(); in your idle loop..

Read ID3v1 tag from mp3

ID3V1_T id3;
mp3ReadId3V1(filename,&id3);
printf("%s - %s [%s (%s)]\n",id3.artist, id3.title, id3.album, id3.year);

Will print:

Artistname - Songtitle [Album name (YEAR)]

Display song position

int mins,secs,ms;
mp3GetSongPos(&mins, &secs, &ms);
iprintf("TIME (M:S:MS): %02d:%02d:%02d  \n",mins,secs,ms);

Load m3u and play the first song in the list

mp3PlaylistAddM3u("nitro:/playlist.m3u");	//add m3u playlist
mp3PlaylistPlay(0); //play first song  (mp3PlaylistAdv(); will advance to next song on list

List all songs on playlist

int c=0;
do {
	iprintf("%3d%s\n",c, mp3GetPlaylistTitle(c));   
} while(++c<mp3GetPlaylistCnt());
Personal tools
irssi scripts
eggdrop scripts