Flash MP3 Player

From Nutwiki
Revision as of 17:02, 27 October 2016 by Harald (Talk | contribs) (1 revision imported)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Description

This is a simple MP3 player. It plays an MP3 from Flash. You'll need a data directory in your project directory containing your "example.mp3" file. Also make sure your binary with the included doesn't get larger than your board's Flash.

Source Code

<source lang="c">

  1. include <dev/board.h>
  2. include <dev/vscodec.h>
  3. include <dev/urom.h>
  4. include <fs/uromfs.h>
  1. include <stdlib.h>
  2. include <stdio.h>
  3. include <fcntl.h>
  4. include <io.h>
  5. include <dirent.h>
  1. include "urom_data.c"

static char buff[512];

int main(void) {

   int fh;
   int decoder;
   int n;


   /* register debug device */
   u_long baud = 115200;


   NutRegisterDevice(&DEV_DEBUG, 0, 0);
   freopen(DEV_DEBUG_NAME, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   /* NOTE: This assumes the hardware codec is present */
   if (NutRegisterSpiDevice(&devSpiVsCodec0, &DEV_SPIBUS, 1)) {
       puts("Codec unavailable.\n");
   }
   /* Register UROM device */
   if (NutRegisterDevice(&devUrom, 0, 0)) {
       printf("UROM error\n");
   }	
   decoder = _open("audio0", _O_WRONLY | _O_BINARY);
   fh = _open("UROM:example.mp3", _O_RDONLY | _O_BINARY);
   for (;;) {	
       n = _read(fh, buff, 512);

if (n <= 0) { break; } _write(decoder, buff, n); _write(decoder, NULL, 0);

   }
   _close(decoder);
   _close(fh);
   for (;;);	

}


</source>

Makefile

Here's the Makefile to build the MP3 player. Note, that all leading spaces have to be tabs instead of spaces. Change the PROJ variable to match the name of your main .c file.

<source lang="text"> PROJ = mp3_example DATADIR = data DATAFILE = urom_data.c

include ../Makedefs

SRCS = $(PROJ).c OBJS = $(SRCS:.c=.o) LIBS = $(LIBDIR)/nutinit.o -lnutpro -lnutos -lnutnet -lnutfs -lnutcrt -lnutdev -lnutarch TARG = $(PROJ).hex

all: $(DATAFILE) $(OBJS) $(TARG) $(ITARG) $(DTARG)

$(DATAFILE): $(DATADIR)/example.mp3 $(CRUROM) -r -o$(DATAFILE) $(DATADIR)

include ../Makerules

clean: -rm -f $(OBJS) -rm -f $(TARG) $(ITARG) $(DTARG) -rm -f $(DATAFILE) </source>

Description

<source lang="c"> u_long baud = 115200;

NutRegisterDevice(&DEV_DEBUG, 0, 0); freopen(DEV_DEBUG_NAME, "w", stdout); _ioctl(_fileno(stdout), UART_SETSPEED, &baud); </source>

Set up the debug device so we can output to the terminal. See the Hello World! sample for more details.

<source lang="c"> /* NOTE: This assumes the hardware codec is present */

if (NutRegisterSpiDevice(&devSpiVsCodec0, &DEV_SPIBUS, 1)) {

   puts("Codec unavailable.\n");

} </source>

This line registers the VS Codec. Note that we don't use the normal NutRegisterDevice here. Since the VS Codec is a device on the SPI bus, we have to register it using NutRegisterSpiDevice. The parameter DEV_SPIBUS passes the bus we want to register it to.

Alternatively you can use a software decoder, if your target board can provide sufficient processing power. For ARM-based boards, Nut/OS offers the Helix MP3 decoder. Note, that this is distributed under an incompatible license and you need to this license in the Nut/OS Configurator (last item in the tree).

To register the Helix decoder, use

<source lang="c"> if (NutRegisterDevice(&devHelixCodec, 0, 0)) {

   puts("Audio codec not available");

} </source>

There had been a few problems with this decoder lately. Recent Nut/OS versions (4.8 up to 5.0) do not allow to register bit-banging I2C drivers, if I2C hardware (TWI in Atmel terms) is available on that CPU. Check the code repository at [1] for the latest updates of the files dev/hxcodec.c and arch/arm/dev/tlv320dac.c.

<source lang="c"> /* Register UROM device */

if (NutRegisterDevice(&devUrom, 0, 0)) {

   printf("UROM error\n");

} </source>

Now we register the uROM device. For more information on uROM access see the Reading UROM Files article.

<source lang="c"> decoder = _open("audio0", _O_WRONLY | _O_BINARY); fh = _open("UROM:example.mp3", _O_RDONLY | _O_BINARY); </source>

For the MP3 Codec to play, we need to pass data directly to it. To achieve this, we open both the decoder (audio0) and the mp3 file we want to use (example.mp3) via the open command. This is a lower level command than fopen and does not return a file pointer but a handle of type integer.

<source lang="c"> for (;;) {

   n = _read(fh, buff, 512);
   if (n <= 0) {
       break;
   }
   _write(decoder, buff, n);
   _write(decoder, NULL, 0);

} </source>

This loop does the actual MP3 playing. It first reads 512 bytes from the MP3 file and stores the number of bytes read in n.

Before writing the data the decoder, we have to make sure there is actually data left for writing. We do this by checking n (the number of bytes read) for a size <= 0. If it is, we have no more data left to write and can safely exit the play loop.

If there's data left to write, we write it to the decoder.

The line "_write(decoder, NULL, 0);" is something special. Usually all data transfers are buffered, sometimes resulting in data that is not yet written when the _write command returns control to your program. By writing a NULL pointer to the audio device, we instruct Nut/OS to flush all data to the decoder. Do NOT use this elsewhere as this is a special trick of Nut/OS and will result in bugs and crashes if used anywhere else.

<source lang="c"> _close(decoder); _close(fh); </source>

We're done playing, now close our open files.

It may happen, that the decoder stops playing before the end of the file has been reached. This had been an issue with early VS10XX hardware drivers and, at the time of this writing, is a problem with the Helix decoder. To force playing up to the end of the file, use

<source lang="c"> int i;

memset(buff, 0, sizeof(buff)); for (i = 0; i < 8; i++) {

   _write(dh, buff, sizeof(buff));

} </source>

immediately before closing the decoder.

See also

External Links

  • C file input/output The C programming language provides many standard library functions for file input and output.
  • MP3 MPEG-1 Audio Layer 3, more commonly referred to as MP3, is a digital audio encoding format using a form of lossy data compression.


Template:Languages