summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2002-05-09 23:54:47 +0000
committerDave Chapman <dave@dchapman.com>2002-05-09 23:54:47 +0000
commit4dbbca63d31ad40e8ec778b2ddfc63f33dc9f500 (patch)
treed0301232c53631cf90357ce3cf1e783a7499c43c
parent564bb3edb0d52ce13367c8f53bc54b4fe448b8cf (diff)
downloadrockbox-4dbbca63d31ad40e8ec778b2ddfc63f33dc9f500.tar.gz
rockbox-4dbbca63d31ad40e8ec778b2ddfc63f33dc9f500.zip
first attempt at mp3 playback in x11 simulator using libmad
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@535 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--uisimulator/play.c10
-rw-r--r--uisimulator/x11/Makefile8
-rw-r--r--uisimulator/x11/mpegplay.c232
-rw-r--r--uisimulator/x11/mpegplay.h23
4 files changed, 272 insertions, 1 deletions
diff --git a/uisimulator/play.c b/uisimulator/play.c
index 7031fd208e..f9877134eb 100644
--- a/uisimulator/play.c
+++ b/uisimulator/play.c
@@ -29,6 +29,10 @@
#include "id3.h"
+#ifdef MPEG_PLAY
+#include "x11/mpegplay.h"
+#endif
+
#define LINE_Y 8 /* initial line */
#define LINE_HEIGTH 8 /* line height in pixels */
@@ -68,6 +72,12 @@ void playtune(char *dir, char *file)
lcd_update();
#endif
+#ifdef MPEG_PLAY
+ sprintf(buffer, "%s/%s", dir, file);
+ mpeg_play(buffer);
+ return;
+#endif
+
while(1) {
int key = button_get();
diff --git a/uisimulator/x11/Makefile b/uisimulator/x11/Makefile
index 9753394456..7cc8b088c3 100644
--- a/uisimulator/x11/Makefile
+++ b/uisimulator/x11/Makefile
@@ -57,6 +57,12 @@ APPS = tetris.c screensaver.c tree.c app.c play.c menu.c icons.c
SRCS = screenhack.c uibasic.c resources.c visual.c lcd-x11.c \
button-x11.c io.c sleep.c $(APPS) $(FIRMSRCS)
+ifdef MPEG_PLAY
+ SRCS += mpegplay.c
+ DEFINES += -DMPEG_PLAY
+ LIBS = -lmad
+endif
+
OBJS := $(SRCS:c=o)
all: $(TARGET)
@@ -108,7 +114,7 @@ sprintf.o: $(COMMON)/sprintf.c
$(CC) $(CFLAGS) -c $<
$(TARGET): $(OBJS)
- $(CC) -g -o $(TARGET) $(LIBDIRS) $(LDFLAGS) $(OBJS)
+ $(CC) -g -o $(TARGET) $(LIBDIRS) $(LDFLAGS) $(OBJS) $(LIBS)
DEPS:=.deps
diff --git a/uisimulator/x11/mpegplay.c b/uisimulator/x11/mpegplay.c
new file mode 100644
index 0000000000..2d31c073dd
--- /dev/null
+++ b/uisimulator/x11/mpegplay.c
@@ -0,0 +1,232 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2002 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.
+ *
+ ****************************************************************************/
+
+#ifdef MPEG_PLAY
+
+#include <string.h>
+#include <stdlib.h>
+#include <file.h>
+#include <types.h>
+#include <lcd.h>
+#include <button.h>
+#include "id3.h"
+
+#include <stdio.h>
+#include <mad.h>
+#include <linux/soundcard.h>
+
+/* We want to use the "real" open in some cases */
+#undef open
+
+struct mad_stream Stream;
+struct mad_frame Frame;
+struct mad_synth Synth;
+mad_timer_t Timer;
+int sound;
+
+void init_oss(int sound, int sound_freq, int channels) {
+ int format=AFMT_U16_LE;
+ int setting=0x000C000D; // 12 fragments size 8kb ? WHAT IS THIS?
+
+ if (ioctl(sound,SNDCTL_DSP_SETFRAGMENT,&setting)==-1) {
+ perror("SNDCTL_DSP_SETFRAGMENT");
+ }
+
+ if (ioctl(sound,SNDCTL_DSP_STEREO,&channels)==-1) {
+ perror("SNDCTL_DSP_STEREO");
+ }
+ if (channels==0) { fprintf(stderr,"Warning, only mono supported\n"); }
+
+ if (ioctl(sound,SNDCTL_DSP_SETFMT,&format)==-1) {
+ perror("SNDCTL_DSP_SETFMT");
+ }
+
+ fprintf(stderr,"SETTING /dev/dsp to %dHz\n",sound_freq);
+ if (ioctl(sound,SNDCTL_DSP_SPEED,&sound_freq)==-1) {
+ perror("SNDCTL_DSP_SPEED");
+ }
+}
+
+unsigned short MadFixedToUshort(mad_fixed_t Fixed)
+{
+ Fixed=Fixed>>(MAD_F_FRACBITS-15);
+ return((unsigned short)Fixed);
+}
+
+#define INPUT_BUFFER_SIZE (5*8192)
+#define OUTPUT_BUFFER_SIZE 8192 /* Must be an integer multiple of 4. */
+int mpeg_play(char* fname)
+{
+ unsigned char InputBuffer[INPUT_BUFFER_SIZE],
+ OutputBuffer[OUTPUT_BUFFER_SIZE],
+ *OutputPtr=OutputBuffer;
+ const unsigned char *OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE;
+ int Status=0,
+ i;
+ unsigned long FrameCount=0;
+ int sound,fd;
+ mp3entry mp3;
+
+ mp3info(&mp3, fname);
+
+ #undef open
+ sound=open("/dev/dsp", O_WRONLY);
+
+ if (sound < 0) {
+ fprintf(stderr,"Can not open /dev/dsp - Aborting - sound=%d\n",sound);
+ exit(-1);
+ }
+
+ init_oss(sound,mp3.frequency,2);
+
+ fd=x11_open(fname,O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr,"could not open %s\n",fname);
+ return 0;
+ }
+
+ /* First the structures used by libmad must be initialized. */
+ mad_stream_init(&Stream);
+ mad_frame_init(&Frame);
+ mad_synth_init(&Synth);
+ mad_timer_reset(&Timer);
+
+ do
+ {
+ if (button_get()) break; /* Return if a key is pressed */
+
+ if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN)
+ {
+ size_t ReadSize,Remaining;
+ unsigned char *ReadStart;
+
+ if(Stream.next_frame!=NULL)
+ {
+ Remaining=Stream.bufend-Stream.next_frame;
+ memmove(InputBuffer,Stream.next_frame,Remaining);
+ ReadStart=InputBuffer+Remaining;
+ ReadSize=INPUT_BUFFER_SIZE-Remaining;
+ }
+ else
+ ReadSize=INPUT_BUFFER_SIZE,
+ ReadStart=InputBuffer,
+ Remaining=0;
+
+ ReadSize=read(fd,ReadStart,ReadSize);
+ if(ReadSize<=0)
+ {
+ fprintf(stderr,"end of input stream\n");
+ break;
+ }
+
+ mad_stream_buffer(&Stream,InputBuffer,ReadSize+Remaining);
+ Stream.error=0;
+ }
+
+ if(mad_frame_decode(&Frame,&Stream)) {
+ if(MAD_RECOVERABLE(Stream.error))
+ {
+ fprintf(stderr,"recoverable frame level error\n");
+ fflush(stderr);
+ continue;
+ }
+ else
+ if(Stream.error==MAD_ERROR_BUFLEN) {
+ continue;
+ } else {
+ fprintf(stderr,"unrecoverable frame level error\n");
+ Status=1;
+ break;
+ }
+ }
+
+ FrameCount++;
+ mad_timer_add(&Timer,Frame.header.duration);
+
+ mad_synth_frame(&Synth,&Frame);
+
+ for(i=0;i<Synth.pcm.length;i++)
+ {
+ unsigned short Sample;
+
+ /* Left channel */
+ Sample=MadFixedToUshort(Synth.pcm.samples[0][i]);
+ *(OutputPtr++)=Sample&0xff;
+ *(OutputPtr++)=Sample>>8;
+
+ /* Right channel. If the decoded stream is monophonic then
+ * the right output channel is the same as the left one.
+ */
+ if(MAD_NCHANNELS(&Frame.header)==2)
+ Sample=MadFixedToUshort(Synth.pcm.samples[1][i]);
+ *(OutputPtr++)=Sample&0xff;
+ *(OutputPtr++)=Sample>>8;
+
+ /* Flush the buffer if it is full. */
+ if(OutputPtr==OutputBufferEnd)
+ {
+ if(write(sound,OutputBuffer,OUTPUT_BUFFER_SIZE)!=OUTPUT_BUFFER_SIZE)
+ {
+ fprintf(stderr,"PCM write error.\n");
+ Status=2;
+ break;
+ }
+ OutputPtr=OutputBuffer;
+ }
+ }
+ }while(1);
+
+ fprintf(stderr,"END OF MAD LOOP\n");
+ /* Mad is no longer used, the structures that were initialized must
+ * now be cleared.
+ */
+ mad_synth_finish(&Synth);
+ mad_frame_finish(&Frame);
+ mad_stream_finish(&Stream);
+
+ /* If the output buffer is not empty and no error occured during
+ * the last write, then flush it.
+ */
+ if(OutputPtr!=OutputBuffer && Status!=2)
+ {
+ size_t BufferSize=OutputPtr-OutputBuffer;
+
+ if(write(sound,OutputBuffer,1,BufferSize)!=BufferSize)
+ {
+ fprintf(stderr,"PCM write error\n");
+ Status=2;
+ }
+ }
+
+ /* Accounting report if no error occured. */
+ if(!Status)
+ {
+ char Buffer[80];
+
+ mad_timer_string(Timer,Buffer,"%lu:%02lu.%03u",
+ MAD_UNITS_MINUTES,MAD_UNITS_MILLISECONDS,0);
+ fprintf(stderr,"%lu frames decoded (%s).\n",FrameCount,Buffer);
+ }
+
+ close(sound);
+ /* That's the end of the world (in the H. G. Wells way). */
+ return(Status);
+}
+
+
+#endif
diff --git a/uisimulator/x11/mpegplay.h b/uisimulator/x11/mpegplay.h
new file mode 100644
index 0000000000..cde9fe183f
--- /dev/null
+++ b/uisimulator/x11/mpegplay.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2002 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.
+ *
+ ****************************************************************************/
+
+#ifdef MPEG_PLAY
+
+int mpeg_play(char* fname);
+
+#endif