playmp3/playmp3.c

To run this example code, you need to attach the Medianut Board to the Ethernut or use a similar hardware design based on the VS1001K MP3 decoder.

This sample application plays MP3 files from the UROM filesystem. It demonstrates how to use the global segmented buffer and the MP3 decoder driver and can provide a basis for talking equipment, alarm sound output etc.

The UROM filesystem is located in the CPU's flash ROM. No external file storage device is required. Use the crurom utility to create a C source file named urom.c from the MP3 files located in subdirectory sounds. Here's how to call crurom:

crurom -r -ourom.c sounds

The created file will then be compiled and linked to the application code.

UART0 is used for debug output.

00001 /*
00002  * Copyright (C) 2003-2006 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00052 #include <dev/board.h>
00053 #include <dev/vs1001k.h>
00054 #include <dev/debug.h>
00055 #include <dev/urom.h>
00056 
00057 #include <sys/version.h>
00058 #include <sys/heap.h>
00059 #include <sys/event.h>
00060 #include <sys/timer.h>
00061 #include <sys/thread.h>
00062 #include <sys/bankmem.h>
00063 
00064 #include <stdlib.h>
00065 #include <string.h>
00066 #include <stdio.h>
00067 #include <io.h>
00068 #include <fcntl.h>
00069 #include <errno.h>
00070 
00071 static int PlayMp3File(char *path);
00072 
00096 int main(void)
00097 {
00098     /* Baudrate for debug output. */
00099     u_long baud = 115200;
00100 
00101     /*
00102      * Register our devices.
00103      */
00104     NutRegisterDevice(&devUrom, 0, 0);
00105     NutRegisterDevice(&DEV_DEBUG, 0, 0);
00106 
00107     /*
00108      * Assign stdout to the debug device.
00109      */
00110     freopen(DEV_DEBUG_NAME, "w", stdout);
00111     _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
00112 
00113     /*
00114      * Print a banner.
00115      */
00116     printf("\n\nPlay MP3 files on Nut/OS %s\n", NutVersionString());
00117 
00118 #if defined(__AVR__)
00119 
00120     /*
00121      * Initialize the MP3 buffer. The NutSegBuf routines provide a global
00122      * system buffer, which works with banked and non-banked systems.
00123      */
00124     if (NutSegBufInit(8192) == 0) {
00125         puts("NutSegBufInit: Fatal error");
00126     }
00127 
00128     /* 
00129      * Initialize the MP3 decoder hardware.
00130      */
00131     if (VsPlayerInit() || VsPlayerReset(0)) {
00132         puts("VsPlayer: Fatal error");
00133     }
00134 
00135     /*
00136      * Play the MP3 files in an endless loop. For each file set the volume 
00137      * of the left and right channel, call the local routine PlayMp3File() 
00138      * and sleep one second before playing the next sound file.
00139      */
00140     for (;;) {
00141         VsSetVolume(0, 254);
00142         PlayMp3File("UROM:sound1a.mp3");
00143         NutSleep(1000);
00144 
00145         VsSetVolume(0, 0);
00146         PlayMp3File("UROM:sound2a.mp3");
00147         NutSleep(1000);
00148 
00149         VsSetVolume(254, 0);
00150         PlayMp3File("UROM:sound3a.mp3");
00151         NutSleep(1000);
00152 
00153         VsSetVolume(0, 0);
00154         PlayMp3File("UROM:sound4a.mp3");
00155         NutSleep(1000);
00156     }
00157 #else /* !__AVR__ */
00158     for (;;);
00159 #endif /* !__AVR__ */
00160 }
00161 
00162 #if defined(__AVR__)
00163 
00164 /*
00165  * Play MP3 file from local file system.
00166  *
00167  * \param path Pathname of the MP3 file to play.
00168  *
00169  * \return 0 on success, -1 if opening the file failed.
00170  */
00171 static int PlayMp3File(char *path)
00172 {
00173     int fd;
00174     size_t rbytes;
00175     u_char *mp3buf;
00176     int got;
00177     u_char ief;
00178 
00179     /*
00180      * Open the MP3 file.
00181      */
00182     printf("Play %s: ", path);
00183     if ((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
00184         printf("Error %d\n", errno);
00185         return -1;
00186     }
00187     puts("OK");
00188 
00189     /* 
00190      * Reset decoder buffer.
00191      */
00192     printf("[B.RST]");
00193     ief = VsPlayerInterrupts(0);
00194     NutSegBufReset();
00195     VsPlayerInterrupts(ief);
00196 
00197     for (;;) {
00198         /*
00199          * Query number of byte available in MP3 buffer.
00200          */
00201         ief = VsPlayerInterrupts(0);
00202         mp3buf = NutSegBufWriteRequest(&rbytes);
00203         VsPlayerInterrupts(ief);
00204 
00205         /* 
00206          * Read data directly into the MP3 buffer. 
00207          */
00208         if (rbytes) {
00209             printf("[B.RD%d]", rbytes);
00210             if ((got = _read(fd, mp3buf, rbytes)) > 0) {
00211                 printf("[B.CMT%d]", got);
00212                 ief = VsPlayerInterrupts(0);
00213                 mp3buf = NutSegBufWriteCommit(got);
00214                 VsPlayerInterrupts(ief);
00215             } else {
00216                 printf("[EOF]");
00217                 break;
00218             }
00219         }
00220 
00221         /*
00222          * If the player is not running, kick it.
00223          */
00224         if (VsGetStatus() != VS_STATUS_RUNNING) {
00225             printf("[P.KICK]");
00226             VsPlayerKick();
00227         }
00228 
00229         /*
00230          * Allow background threads to take over.
00231          */
00232         NutThreadYield();
00233     }
00234 
00235     _close(fd);
00236 
00237     /* 
00238      * Flush decoder and wait until finished. 
00239      */
00240     printf("[P.FLUSH]");
00241     VsPlayerFlush();
00242     while (VsGetStatus() != VS_STATUS_EMPTY) {
00243         NutSleep(1);
00244     }
00245 
00246     /*
00247      * Reset the decoder. 
00248      */
00249     printf("[P.RST]");
00250     VsPlayerReset(0);
00251 
00252     printf("\nDone, %u bytes free\n", NutHeapAvailable());
00253     return 0;
00254 }
00255 
00256 #endif /* !__AVR__ */

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/