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__ */