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 
00044 #include <dev/vs1001k.h>
00045 #include <dev/debug.h>
00046 #include <dev/urom.h>
00047 
00048 #include <sys/version.h>
00049 #include <sys/heap.h>
00050 #include <sys/event.h>
00051 #include <sys/timer.h>
00052 #include <sys/thread.h>
00053 #include <sys/bankmem.h>
00054 
00055 #include <stdlib.h>
00056 #include <string.h>
00057 #include <stdio.h>
00058 #include <io.h>
00059 #include <fcntl.h>
00060 #include <errno.h>
00061 
00062 static int PlayMp3File(char *path);
00063 
00087 int main(void)
00088 {
00089     /* Baudrate for debug output. */
00090     u_long baud = 115200;
00091 
00092     /*
00093      * Register our devices.
00094      */
00095     NutRegisterDevice(&devUrom, 0, 0);
00096     NutRegisterDevice(&devDebug0, 0, 0);
00097 
00098     /*
00099      * Assign stdout to the debug device.
00100      */
00101     freopen("uart0", "w", stdout);
00102     _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
00103 
00104     /*
00105      * Print a banner.
00106      */
00107     printf("\n\nPlay MP3 files on Nut/OS %s\n", NutVersionString());
00108 
00109     /*
00110      * Initialize the MP3 buffer. The NutSegBuf routines provide a global
00111      * system buffer, which works with banked and non-banked systems.
00112      */
00113     if (NutSegBufInit(8192) == 0) {
00114         puts("NutSegBufInit: Fatal error");
00115     }
00116 
00117     /* 
00118      * Initialize the MP3 decoder hardware.
00119      */
00120     if (VsPlayerInit() || VsPlayerReset(0)) {
00121         puts("VsPlayer: Fatal error");
00122     }
00123 
00124     /*
00125      * Play the MP3 files in an endless loop. For each file set the volume 
00126      * of the left and right channel, call the local routine PlayMp3File() 
00127      * and sleep one second before playing the next sound file.
00128      */
00129     for (;;) {
00130         VsSetVolume(0, 254);
00131         PlayMp3File("UROM:sound1a.mp3");
00132         NutSleep(1000);
00133 
00134         VsSetVolume(0, 0);
00135         PlayMp3File("UROM:sound2a.mp3");
00136         NutSleep(1000);
00137 
00138         VsSetVolume(254, 0);
00139         PlayMp3File("UROM:sound3a.mp3");
00140         NutSleep(1000);
00141 
00142         VsSetVolume(0, 0);
00143         PlayMp3File("UROM:sound4a.mp3");
00144         NutSleep(1000);
00145     }
00146 }
00147 
00148 
00149 /*
00150  * Play MP3 file from local file system.
00151  *
00152  * \param path Pathname of the MP3 file to play.
00153  *
00154  * \return 0 on success, -1 if opening the file failed.
00155  */
00156 static int PlayMp3File(char *path)
00157 {
00158     int fd;
00159     size_t rbytes;
00160     u_char *mp3buf;
00161     int got;
00162     u_char ief;
00163 
00164     /*
00165      * Open the MP3 file.
00166      */
00167     printf("Play %s: ", path);
00168     if ((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
00169         printf("Error %d\n", errno);
00170         return -1;
00171     }
00172     puts("OK");
00173 
00174     /* 
00175      * Reset decoder buffer.
00176      */
00177     printf("[B.RST]");
00178     ief = VsPlayerInterrupts(0);
00179     NutSegBufReset();
00180     VsPlayerInterrupts(ief);
00181 
00182     for (;;) {
00183         /*
00184          * Query number of byte available in MP3 buffer.
00185          */
00186         ief = VsPlayerInterrupts(0);
00187         mp3buf = NutSegBufWriteRequest(&rbytes);
00188         VsPlayerInterrupts(ief);
00189 
00190         /* 
00191          * Read data directly into the MP3 buffer. 
00192          */
00193         if (rbytes) {
00194             printf("[B.RD%d]", rbytes);
00195             if ((got = _read(fd, mp3buf, rbytes)) > 0) {
00196                 printf("[B.CMT%d]", got);
00197                 ief = VsPlayerInterrupts(0);
00198                 mp3buf = NutSegBufWriteCommit(got);
00199                 VsPlayerInterrupts(ief);
00200             } else {
00201                 printf("[EOF]");
00202                 break;
00203             }
00204         }
00205 
00206         /*
00207          * If the player is not running, kick it.
00208          */
00209         if (VsGetStatus() != VS_STATUS_RUNNING) {
00210             printf("[P.KICK]");
00211             VsPlayerKick();
00212         }
00213 
00214         /*
00215          * Allow background threads to take over.
00216          */
00217         NutThreadYield();
00218     }
00219 
00220     _close(fd);
00221 
00222     /* 
00223      * Flush decoder and wait until finished. 
00224      */
00225     printf("[P.FLUSH]");
00226     VsPlayerFlush();
00227     while (VsGetStatus() != VS_STATUS_EMPTY) {
00228         NutSleep(1);
00229     }
00230 
00231     /*
00232      * Reset the decoder. 
00233      */
00234     printf("[P.RST]");
00235     VsPlayerReset(0);
00236 
00237     printf("\nDone, %u bytes free\n", NutHeapAvailable());
00238     return 0;
00239 }

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