# Experimental patch.
# - added 1 MB ring buffer for audio (maybe too large)
# - audiobuffer_insert(ptr, size) added for plugins
# - modified mpa2wav and vorbis2wav to write directly into
#   pcm ring buffer
# 
# Patched by Miika Pekkarinen <slasher@ihme.org>

Index: apps/plugin.c
===================================================================
RCS file: /cvsroot/rockbox/apps/plugin.c,v
retrieving revision 1.93
diff -u -3 -p -r1.93 plugin.c
--- apps/plugin.c	28 Apr 2005 12:33:37 -0000	1.93
+++ apps/plugin.c	26 May 2005 17:42:03 -0000
@@ -38,6 +38,7 @@
 #include "mpeg.h"
 #include "buffer.h"
 #include "mp3_playback.h"
+#include "pcm_playback.h"
 #include "backlight.h"
 #include "ata.h"
 #include "talk.h"
@@ -325,6 +326,7 @@ static const struct plugin_api rockbox_a
     &tagdb_initialized,
     tagdb_init,
     strcasestr,
+    audiobuffer_insert,
 };
 
 int plugin_load(const char* plugin, void* parameter)
Index: apps/plugin.h
===================================================================
RCS file: /cvsroot/rockbox/apps/plugin.h,v
retrieving revision 1.104
diff -u -3 -p -r1.104 plugin.h
--- apps/plugin.h	28 Apr 2005 12:33:37 -0000	1.104
+++ apps/plugin.h	26 May 2005 17:42:03 -0000
@@ -78,7 +78,7 @@
 #endif
 
 /* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 39
+#define PLUGIN_API_VERSION 40
 
 /* update this to latest version if a change to the api struct breaks
    backwards compatibility (and please take the opportunity to sort in any 
@@ -380,6 +380,7 @@ struct plugin_api {
     int *tagdb_initialized;
     int (*tagdb_init) (void);
     char *(*strcasestr) (const char* phaystack, const char* pneedle);
+    void (*audiobuffer_insert)(char *data, size_t length);
 };
 
 /* defined by the plugin loader (plugin.c) */
Index: apps/plugins/mpa2wav.c
===================================================================
RCS file: /cvsroot/rockbox/apps/plugins/mpa2wav.c,v
retrieving revision 1.10
diff -u -3 -p -r1.10 mpa2wav.c
--- apps/plugins/mpa2wav.c	19 Apr 2005 10:52:20 -0000	1.10
+++ apps/plugins/mpa2wav.c	26 May 2005 17:42:03 -0000
@@ -156,6 +156,7 @@ enum plugin_status plugin_start(struct p
   rb->memcpy(iramstart, iramcopy, iramend-iramstart);
 #endif
 
+  rb->cpu_boost(true);
   /* This function sets up the buffers and reads the file into RAM */
 
   if (local_init(file,"/libmadtest.wav",&file_info,api)) {
@@ -232,21 +233,22 @@ enum plugin_status plugin_start(struct p
     {
       /* Left channel */
       Sample=scale(Synth.pcm.samples[0][i],&d0);
+      *(OutputPtr++)=Sample>>8;   /* BIG ENDIAN for iRiver */
       *(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=scale(Synth.pcm.samples[1][i],&d1);
-      *(OutputPtr++)=Sample&0xff;
       *(OutputPtr++)=Sample>>8;
+      *(OutputPtr++)=Sample&0xff;
 
       /* Flush the buffer if it is full. */
       if(OutputPtr==OutputBufferEnd)
       {
-        rb->write(file_info.outfile,OutputBuffer,OUTPUT_BUFFER_SIZE);
+	rb->audiobuffer_insert(OutputBuffer, OUTPUT_BUFFER_SIZE);
+        // rb->write(file_info.outfile,OutputBuffer,OUTPUT_BUFFER_SIZE);
         OutputPtr=OutputBuffer;
       }
     }
@@ -263,6 +265,7 @@ enum plugin_status plugin_start(struct p
 
   close_wav(&file_info);
   rb->splash(HZ*2, true, "FINISHED!");
+  rb->cpu_boost(false);
 
   return PLUGIN_OK;
 }
Index: apps/plugins/vorbis2wav.c
===================================================================
RCS file: /cvsroot/rockbox/apps/plugins/vorbis2wav.c,v
retrieving revision 1.4
diff -u -3 -p -r1.4 vorbis2wav.c
--- apps/plugins/vorbis2wav.c	23 May 2005 09:39:56 -0000	1.4
+++ apps/plugins/vorbis2wav.c	26 May 2005 17:42:03 -0000
@@ -152,16 +152,18 @@ enum plugin_status plugin_start(struct p
       DEBUGF("Error decoding frame\n");
     } else {
       file_info.frames_decoded++;
+      file_info.current_sample+=(n/4);
+      display_status(&file_info);
+      rb->audiobuffer_insert(pcmbuf, n);
+	    
 #if BYTE_ORDER == BIG_ENDIAN
       for (i=0;i<n;i+=2) { 
         x=pcmbuf[i]; pcmbuf[i]=pcmbuf[i+1]; pcmbuf[i+1]=x;
       }
 #endif
-      rb->write(file_info.outfile,pcmbuf,n);
-      file_info.current_sample+=(n/4);
+      // rb->write(file_info.outfile,pcmbuf,n);
     }
 
-    display_status(&file_info);
 
     if (rb->button_get(false)!=BUTTON_NONE) {
       close_wav(&file_info);
Index: firmware/pcm_playback.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/pcm_playback.c,v
retrieving revision 1.4
diff -u -3 -p -r1.4 pcm_playback.c
--- firmware/pcm_playback.c	14 Apr 2005 11:51:31 -0000	1.4
+++ firmware/pcm_playback.c	26 May 2005 17:42:04 -0000
@@ -21,7 +21,6 @@
 #include "debug.h"
 #include "panic.h"
 #include <kernel.h>
-#include "pcm_playback.h"
 #ifndef SIMULATOR
 #include "cpu.h"
 #include "i2c.h"
@@ -32,11 +31,16 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
+#include "pcm_playback.h"
 #include "lcd.h"
 #include "button.h"
 #include "file.h"
 #include "buffer.h"
 
+#include "kernel.h"
+#include "thread.h"
+#include "system.h"
+
 #include "sprintf.h"
 #include "button.h"
 #include <string.h>
@@ -45,6 +49,11 @@ static bool pcm_playing;
 static bool pcm_paused;
 static int pcm_freq = 0x6; /* 44.1 is default */
 
+#define AUDIOBUF_SIZE   (1*1024*1024)
+static char *audiobuffer;
+static size_t audiobuffer_pos;
+static volatile size_t audiobuffer_free;
+
 /* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
 static void dma_start(const void *addr, long size)
 {
@@ -186,6 +195,8 @@ void DMA0(void)
     IPR |= (1<<14); /* Clear pending interrupt request */
 }
 
+void pcm_thread(void);
+
 void pcm_init(void)
 {
     pcm_playing = false;
@@ -206,6 +217,10 @@ void pcm_init(void)
     IMR &= ~(1<<14);      /* bit 14 is DMA0 */
 
     pcm_set_frequency(44100);
+    
+    pcm_play_init();
+    pcm_set_frequency(44100);
+    pcm_set_volume(0x80);
 }
 
 
@@ -219,8 +234,8 @@ struct pcmbufdesc
     void (*callback)(void); /* Call this when the buffer has been played */
 } pcmbuffers[NUM_PCM_BUFFERS];
 
-int pcmbuf_read_index;
-int pcmbuf_write_index;
+volatile int pcmbuf_read_index;
+volatile int pcmbuf_write_index;
 int pcmbuf_unplayed_bytes;
 int pcmbuf_watermark;
 void (*pcmbuf_watermark_callback)(int bytes_left);
@@ -253,8 +268,49 @@ bool pcm_play_add_chunk(void *addr, int 
         return false;
 }
 
+void audiobuffer_insert(char *buf, size_t length)
+{
+	size_t copy_n = 0;
+	
+	/* Too long sample. */
+	if (length > AUDIOBUF_SIZE) {
+		return ;
+	}
+	
+	while (length > 0) {
+		/* yield() etc. would crash this at the moment.
+		 * Some bug somewhere.
+		 */
+		while (audiobuffer_free == 0) {
+			yield();
+		}
+		
+		copy_n = MIN(length, AUDIOBUF_SIZE - audiobuffer_pos);
+		memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n);
+		while (!pcm_play_add_chunk(&audiobuffer[audiobuffer_pos], copy_n, NULL)) {
+			yield();
+		}
+		
+		audiobuffer_pos += copy_n;
+		buf += copy_n;
+		length -= copy_n;
+		
+		if (audiobuffer_pos >= AUDIOBUF_SIZE) {
+			audiobuffer_pos = 0;
+		}
+		
+		if (!pcm_is_playing()) {
+			pcm_play_start();
+		}
+	}
+}
+
 void pcm_play_init(void)
 {
+    audiobuffer = &audiobuf[(audiobufend - audiobuf) - 
+			    AUDIOBUF_SIZE];
+    audiobuffer_free = AUDIOBUF_SIZE;
+    audiobuffer_pos = 0;
     pcmbuf_read_index = 0;
     pcmbuf_write_index = 0;
     pcmbuf_unplayed_bytes = 0;
@@ -276,6 +332,8 @@ static void pcm_play_callback(unsigned c
         if(desc->callback)
             desc->callback();
 
+	audiobuffer_free += pcmbuffers[pcmbuf_read_index].size;
+	    
         /* Advance to the next buffer */
         pcmbuf_read_index = (pcmbuf_read_index + 1) & NUM_PCM_BUFFERS_MASK;
         desc = &pcmbuffers[pcmbuf_read_index];
@@ -326,3 +384,4 @@ void pcm_play_start(void)
         desc->addr += size;
     }
 }
+
Index: firmware/export/pcm_playback.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/pcm_playback.h,v
retrieving revision 1.4
diff -u -3 -p -r1.4 pcm_playback.h
--- firmware/export/pcm_playback.h	14 Apr 2005 11:51:31 -0000	1.4
+++ firmware/export/pcm_playback.h	26 May 2005 17:42:04 -0000
@@ -38,4 +38,6 @@ bool pcm_play_add_chunk(void *addr, int 
 int pcm_play_num_used_buffers(void);
 void pcm_play_set_watermark(int numbytes, void (*callback)(int bytes_left));
 
+void audiobuffer_insert(char *buf, size_t length);
+
 #endif
