From 3c2c2f59f4578c41d591f0e8e88a07103cee499b Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Fri, 10 Jun 2005 18:08:08 +0000 Subject: Add first version of WAV playback to iRiver - only 16-bit Stereo 44.1KHz files supported. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6654 a1c6a512-1295-4272-9138-f99709370657 --- apps/playback.c | 53 +++++++++++++++++++- apps/plugins/codecwav.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 apps/plugins/codecwav.c diff --git a/apps/playback.c b/apps/playback.c index 71cb479059..4cefed20c2 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -598,7 +598,7 @@ bool audio_load_track(int offset, bool start_play, int peek_offset) int rc, i; int copy_n; /* Used by the FLAC metadata parser */ - unsigned long totalsamples; + unsigned long totalsamples,bytespersample,channels,bitspersample,numbytes; unsigned char* buf; if (track_count >= MAX_TRACK) @@ -677,6 +677,57 @@ bool audio_load_track(int offset, bool start_play, int peek_offset) tracks[track_widx].taginfo_ready = true; break ; + case AFMT_PCM_WAV: + /* Use the trackname part of the id3 structure as a temporary buffer */ + buf=tracks[track_widx].id3.path; + + lseek(fd, 0, SEEK_SET); + + rc = read(fd, buf, 44); + if (rc < 44) { + close(fd); + return false; + } + + if ((memcmp(buf,"RIFF",4)!=0) || + (memcmp(&buf[8],"WAVEfmt",7)!=0)) { + logf("%s is not a WAV file\n",trackname); + close(fd); + return(false); + } + + /* FIX: Correctly parse WAV header - we assume canonical + 44-byte header */ + + bitspersample=buf[34]; + channels=buf[22]; + + if ((bitspersample!=16) || (channels != 2)) { + logf("Unsupported WAV file - %d bitspersample, %d channels\n", + bitspersample,channels); + close(fd); + return(false); + } + + bytespersample=((bitspersample/8)*channels); + numbytes=(buf[40]|(buf[41]<<8)|(buf[42]<<16)|(buf[43]<<24)); + totalsamples=numbytes/bytespersample; + + tracks[track_widx].id3.vbr=false; /* All WAV files are CBR */ + tracks[track_widx].id3.filesize=filesize(fd); + tracks[track_widx].id3.frequency=buf[24]|(buf[25]<<8)|(buf[26]<<16)|(buf[27]<<24); + + /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */ + tracks[track_widx].id3.length=(totalsamples/tracks[track_widx].id3.frequency)*1000; + tracks[track_widx].id3.bitrate=(tracks[track_widx].id3.frequency*bytespersample)/1024; + + lseek(fd, 0, SEEK_SET); + strncpy(tracks[track_widx].id3.path,trackname,sizeof(tracks[track_widx].id3.path)); + tracks[track_widx].taginfo_ready = true; + + break; + + case AFMT_FLAC: /* A simple parser to read vital metadata from a FLAC file - length, frequency, bitrate etc. */ /* This code should either be moved to a seperate file, or discarded in favour of the libFLAC code */ diff --git a/apps/plugins/codecwav.c b/apps/plugins/codecwav.c new file mode 100644 index 0000000000..a02f2cdbff --- /dev/null +++ b/apps/plugins/codecwav.c @@ -0,0 +1,131 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Dave Chapman + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "plugin.h" +#include "playback.h" +#include "lib/codeclib.h" + +#ifndef SIMULATOR +extern char iramcopy[]; +extern char iramstart[]; +extern char iramend[]; +#endif + +/* This is probably a waste of IRAM, but why not? */ +static unsigned char wavbuf[16384] IDATA_ATTR; + +/* this is the plugin entry point */ +enum plugin_status plugin_start(struct plugin_api* api, void* parm) +{ + struct plugin_api* rb = (struct plugin_api*)api; + struct codec_api* ci = (struct codec_api*)parm; + unsigned long samplerate,numbytes,totalsamples,samplesdone,nsamples; + int channels,bytespersample,bitspersample; + unsigned int i,j,n; + int endofstream; + + /* Generic plugin initialisation */ + TEST_PLUGIN_API(api); + + /* if you are using a global api pointer, don't forget to copy it! + otherwise you will get lovely "I04: IllInstr" errors... :-) */ + rb = api; + +#ifndef SIMULATOR + rb->memcpy(iramstart, iramcopy, iramend-iramstart); +#endif + + ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*10)); + ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); + + next_track: + + if (codec_init(api, ci)) { + return PLUGIN_ERROR; + } + + /* FIX: Correctly parse WAV header - we assume canonical 44-byte header */ + + n=(unsigned)(ci->read_filebuf(wavbuf,44)); + if (n!=44) { + return PLUGIN_ERROR; + } + if ((memcmp(wavbuf,"RIFF",4)!=0) || (memcmp(&wavbuf[8],"WAVEfmt",7)!=0)) { + return PLUGIN_ERROR; + } + + samplerate=wavbuf[24]|(wavbuf[25]<<8)|(wavbuf[26]<<16)|(wavbuf[27]<<24); + bitspersample=wavbuf[34]; + channels=wavbuf[22]; + bytespersample=((bitspersample/8)*channels); + numbytes=(wavbuf[40]|(wavbuf[41]<<8)|(wavbuf[42]<<16)|(wavbuf[43]<<24)); + totalsamples=numbytes/bytespersample; + + if ((bitspersample!=16) || (channels != 2)) { + return PLUGIN_ERROR; + } + + /* The main decoder loop */ + + samplesdone=0; + ci->set_elapsed(0); + endofstream=0; + while (!endofstream) { + rb->yield(); + if (ci->stop_codec || ci->reload_codec) { + break; + } + + n=(unsigned)(ci->read_filebuf(wavbuf,sizeof(wavbuf))); + + rb->yield(); + + if (n==0) break; /* End of stream */ + + nsamples=(n/bytespersample); + + /* WAV files can contain extra data at the end - so we can't just + process until the end of the file */ + + if (samplesdone+nsamples > totalsamples) { + nsamples=(totalsamples-samplesdone); + n=nsamples*bytespersample; + endofstream=1; + } + + /* Byte-swap data */ + for (i=0;iset_elapsed(samplesdone/(ci->id3->frequency/1000)); + + rb->yield(); + while (!ci->audiobuffer_insert(wavbuf, n)) + rb->yield(); + } + + if (ci->request_next_track()) + goto next_track; + + return PLUGIN_OK; +} -- cgit v1.2.3