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 }