summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrandon Low <lostlogic@rockbox.org>2006-02-07 20:38:55 +0000
committerBrandon Low <lostlogic@rockbox.org>2006-02-07 20:38:55 +0000
commit413da2a3d93d989d4474edad437ff67888487cb9 (patch)
treeecf938aa0aedc92db749be69e62648050f2fd712
parent566ce5f95163f8bbb7357dc7353bb132365f7b6e (diff)
downloadrockbox-413da2a3d93d989d4474edad437ff67888487cb9.tar.gz
rockbox-413da2a3d93d989d4474edad437ff67888487cb9.zip
Rework PCM buffer
* Linked list instead of static array buffer pointers * Variable sized chunks * Improved mix handling * Reduction in duplicated code * Reduced IRAM usage w/o sacrificing performance * Converted to almost entirely unsigned math * Add pause function to reduce pcm_* exposure to playback. This WILL break playback on the iPod until linuxstb makes a followup commit. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8612 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs.h4
-rw-r--r--apps/debug_menu.c27
-rw-r--r--apps/dsp.c4
-rw-r--r--apps/dsp.h2
-rw-r--r--apps/pcmbuf.c711
-rw-r--r--apps/pcmbuf.h45
-rw-r--r--apps/playback.c107
-rw-r--r--apps/plugin.c68
-rw-r--r--apps/plugin.h90
-rw-r--r--apps/plugins/metronome.c12
-rw-r--r--apps/plugins/rockboy/rbsound.c4
-rw-r--r--firmware/export/pcm_playback.h5
-rw-r--r--firmware/pcm_playback.c105
13 files changed, 660 insertions, 524 deletions
diff --git a/apps/codecs.h b/apps/codecs.h
index 00f0f64733..cf0324b496 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -128,8 +128,8 @@ struct codec_api {
128 void* (*get_codec_memory)(long *size); 128 void* (*get_codec_memory)(long *size);
129 /* Insert PCM data into audio buffer for playback. Playback will start 129 /* Insert PCM data into audio buffer for playback. Playback will start
130 automatically. */ 130 automatically. */
131 bool (*pcmbuf_insert)(char *data, long length); 131 bool (*pcmbuf_insert)(const char *data, size_t length);
132 bool (*pcmbuf_insert_split)(void *ch1, void *ch2, long length); 132 bool (*pcmbuf_insert_split)(const void *ch1, const void *ch2, size_t length);
133 /* Set song position in WPS (value in ms). */ 133 /* Set song position in WPS (value in ms). */
134 void (*set_elapsed)(unsigned int value); 134 void (*set_elapsed)(unsigned int value);
135 135
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index e7067cc055..4c36eaa113 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -209,7 +209,7 @@ extern int filebuflen;
209extern int filebufused; 209extern int filebufused;
210extern int track_count; 210extern int track_count;
211 211
212static int ticks, boost_ticks; 212static unsigned int ticks, boost_ticks;
213 213
214void dbg_audio_task(void) 214void dbg_audio_task(void)
215{ 215{
@@ -225,7 +225,8 @@ bool dbg_audio_thread(void)
225 int button; 225 int button;
226 int line; 226 int line;
227 bool done = false; 227 bool done = false;
228 int bufsize = pcmbuf_get_bufsize(); 228 size_t bufsize = pcmbuf_get_bufsize();
229 int pcmbufdescs = pcmbuf_descs();
229 230
230 ticks = boost_ticks = 0; 231 ticks = boost_ticks = 0;
231 232
@@ -239,6 +240,12 @@ bool dbg_audio_thread(void)
239 button = button_get_w_tmo(HZ/5); 240 button = button_get_w_tmo(HZ/5);
240 switch(button) 241 switch(button)
241 { 242 {
243 case SETTINGS_NEXT:
244 audio_next();
245 break;
246 case SETTINGS_PREV:
247 audio_prev();
248 break;
242 case SETTINGS_CANCEL: 249 case SETTINGS_CANCEL:
243 done = true; 250 done = true;
244 break; 251 break;
@@ -248,8 +255,8 @@ bool dbg_audio_thread(void)
248 255
249 lcd_clear_display(); 256 lcd_clear_display();
250 257
251 snprintf(buf, sizeof(buf), "pcm: %d/%d", 258 snprintf(buf, sizeof(buf), "pcm: %7ld/%7ld",
252 bufsize-(int)audiobuffer_free, bufsize); 259 bufsize-audiobuffer_free, bufsize);
253 lcd_puts(0, line++, buf); 260 lcd_puts(0, line++, buf);
254 261
255 /* Playable space left */ 262 /* Playable space left */
@@ -257,7 +264,7 @@ bool dbg_audio_thread(void)
257 bufsize-audiobuffer_free, HORIZONTAL); 264 bufsize-audiobuffer_free, HORIZONTAL);
258 line++; 265 line++;
259 266
260 snprintf(buf, sizeof(buf), "codec: %d/%d", filebufused, filebuflen); 267 snprintf(buf, sizeof(buf), "codec: %8d/%8d", filebufused, filebuflen);
261 lcd_puts(0, line++, buf); 268 lcd_puts(0, line++, buf);
262 269
263 /* Playable space left */ 270 /* Playable space left */
@@ -265,17 +272,21 @@ bool dbg_audio_thread(void)
265 filebufused, HORIZONTAL); 272 filebufused, HORIZONTAL);
266 line++; 273 line++;
267 274
268 snprintf(buf, sizeof(buf), "track count: %d", track_count); 275 snprintf(buf, sizeof(buf), "track count: %2d", track_count);
269 lcd_puts(0, line++, buf); 276 lcd_puts(0, line++, buf);
270 277
271 snprintf(buf, sizeof(buf), "cpu freq: %dMHz", 278 snprintf(buf, sizeof(buf), "cpu freq: %3dMHz",
272 (int)((FREQ + 500000) / 1000000)); 279 (int)((FREQ + 500000) / 1000000));
273 lcd_puts(0, line++, buf); 280 lcd_puts(0, line++, buf);
274 281
275 snprintf(buf, sizeof(buf), "boost ratio: %d%%", 282 snprintf(buf, sizeof(buf), "boost ratio: %3d%%",
276 boost_ticks * 100 / ticks); 283 boost_ticks * 100 / ticks);
277 lcd_puts(0, line++, buf); 284 lcd_puts(0, line++, buf);
278 285
286 snprintf(buf, sizeof(buf), "pcmbufdesc: %2d/%2d",
287 pcmbuf_used_descs(), pcmbufdescs);
288 lcd_puts(0, line++, buf);
289
279 lcd_update(); 290 lcd_update();
280 } 291 }
281 292
diff --git a/apps/dsp.c b/apps/dsp.c
index e4d28bd083..1106f02679 100644
--- a/apps/dsp.c
+++ b/apps/dsp.c
@@ -213,7 +213,7 @@ void sound_set_pitch(int permille)
213 * consume. Note that for mono, dst[0] equals dst[1], as there is no point 213 * consume. Note that for mono, dst[0] equals dst[1], as there is no point
214 * in processing the same data twice. 214 * in processing the same data twice.
215 */ 215 */
216static int convert_to_internal(char* src[], int count, long* dst[]) 216static int convert_to_internal(const char* src[], int count, long* dst[])
217{ 217{
218 count = MIN(SAMPLE_BUF_SIZE / 2, count); 218 count = MIN(SAMPLE_BUF_SIZE / 2, count);
219 219
@@ -773,7 +773,7 @@ static void write_samples(short* dst, long* src[], int count)
773 * pointers, one for each audio channel. Returns number of bytes written to 773 * pointers, one for each audio channel. Returns number of bytes written to
774 * dest. 774 * dest.
775 */ 775 */
776long dsp_process(char* dst, char* src[], long size) 776long dsp_process(char* dst, const char* src[], long size)
777{ 777{
778 long* tmp[2]; 778 long* tmp[2];
779 long written = 0; 779 long written = 0;
diff --git a/apps/dsp.h b/apps/dsp.h
index 364c8d80f5..7e3acacc32 100644
--- a/apps/dsp.h
+++ b/apps/dsp.h
@@ -47,7 +47,7 @@ enum {
47 DSP_CROSSFEED 47 DSP_CROSSFEED
48}; 48};
49 49
50long dsp_process(char *dest, char *src[], long size); 50long dsp_process(char *dest, const char *src[], long size);
51long dsp_input_size(long size); 51long dsp_input_size(long size);
52long dsp_output_size(long size); 52long dsp_output_size(long size);
53int dsp_stereo_mode(void); 53int dsp_stereo_mode(void);
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index 57058a3e95..cfb297e4f5 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -36,32 +36,32 @@
36#include "audio.h" 36#include "audio.h"
37#include "dsp.h" 37#include "dsp.h"
38 38
39#define CHUNK_SIZE 32768
40/* Must be a power of 2 */
41#define NUM_PCM_BUFFERS 128
42#define NUM_PCM_BUFFERS_MASK (NUM_PCM_BUFFERS - 1)
43/* Watermark level at 1s. */
44#define PCMBUF_WATERMARK (NATIVE_FREQUENCY * 4 * 1) 39#define PCMBUF_WATERMARK (NATIVE_FREQUENCY * 4 * 1)
45 40
46/* Audio buffer related settings. */ 41/* Size of the PCM buffer. */
47static long pcmbuf_size = 0; /* Size of the PCM buffer. */ 42static size_t pcmbuf_size IDATA_ATTR = 0;
48static char *audiobuffer;
49static long audiobuffer_pos; /* Current audio buffer write index. */
50long audiobuffer_free IDATA_ATTR; /* Amount of bytes left in the buffer. */
51static long audiobuffer_fillpos; /* Amount audiobuffer_pos will be increased.*/
52static char *guardbuf;
53 43
54static void (*pcmbuf_event_handler)(void); 44static char *audiobuffer IDATA_ATTR;
45/* Current audio buffer write index. */
46static size_t audiobuffer_pos IDATA_ATTR;
47/* Amount of bytes left in the buffer. */
48size_t audiobuffer_free IDATA_ATTR;
49/* Amount audiobuffer_pos will be increased.*/
50static size_t audiobuffer_fillpos IDATA_ATTR;
51static char *guardbuf IDATA_ATTR;
52
53static void (*pcmbuf_event_handler)(void) IDATA_ATTR;
54static void (*position_callback)(size_t size) IDATA_ATTR;
55 55
56/* Crossfade related. */ 56/* Crossfade related. */
57static int crossfade_mode; 57static int crossfade_mode IDATA_ATTR;
58static bool crossfade_enabled; 58static bool crossfade_enabled IDATA_ATTR;
59static bool crossfade_active; 59static bool crossfade_active IDATA_ATTR;
60static bool crossfade_init; 60static bool crossfade_init IDATA_ATTR;
61static int crossfade_pos; 61static size_t crossfade_pos IDATA_ATTR;
62static int crossfade_rem; 62static size_t crossfade_rem IDATA_ATTR;
63 63
64static struct mutex pcmbuf_mutex; 64static struct mutex pcmbuf_mutex IDATA_ATTR;
65 65
66/* Crossfade modes. If CFM_CROSSFADE is selected, normal 66/* Crossfade modes. If CFM_CROSSFADE is selected, normal
67 * crossfader will activate. Selecting CFM_FLUSH is a special 67 * crossfader will activate. Selecting CFM_FLUSH is a special
@@ -73,32 +73,44 @@ enum {
73 CFM_FLUSH 73 CFM_FLUSH
74}; 74};
75 75
76static int crossfade_fade_in_amount; 76static size_t crossfade_fade_in_amount IDATA_ATTR;
77static int crossfade_fade_in_rem; 77static size_t crossfade_fade_in_rem IDATA_ATTR;
78
78 79
79/* Structure we can use to queue pcm chunks in memory to be played 80/* Structure we can use to queue pcm chunks in memory to be played
80 * by the driver code. */ 81 * by the driver code. */
81struct pcmbufdesc 82struct pcmbufdesc
82{ 83{
83 void *addr; 84 void *addr;
84 int size; 85 size_t size;
86 struct pcmbufdesc* link;
85 /* Call this when the buffer has been played */ 87 /* Call this when the buffer has been played */
86 void (*callback)(void); 88 void (*callback)(void);
87} pcmbuffers[NUM_PCM_BUFFERS] IDATA_ATTR; /* Do we really need IRAM for this? */ 89};
88 90
89static int pcmbuf_read_index; 91static size_t pcmbuf_descsize;
90static int pcmbuf_write_index; 92static struct pcmbufdesc *pcmbuf_read IDATA_ATTR;
91static int pcmbuf_unplayed_bytes IDATA_ATTR; 93static struct pcmbufdesc *pcmbuf_read_end IDATA_ATTR;
92static int pcmbuf_mix_used_bytes; 94static struct pcmbufdesc *pcmbuf_write IDATA_ATTR;
93static int pcmbuf_watermark; 95static struct pcmbufdesc *pcmbuf_write_end IDATA_ATTR;
94static void pcmbuf_under_watermark(int bytes_left); 96static size_t last_chunksize IDATA_ATTR;
95static int pcmbuf_num_used_buffers(void); 97static size_t pcmbuf_unplayed_bytes IDATA_ATTR;
96static void (*position_callback)(int size); 98static size_t pcmbuf_mix_used_bytes IDATA_ATTR;
97static int last_chunksize; 99static size_t pcmbuf_watermark IDATA_ATTR;
98static long mixpos = 0; 100static size_t mixpos IDATA_ATTR = 0;
99static bool low_latency_mode = false; 101static bool low_latency_mode = false;
100 102
101#ifdef HAVE_ADJUSTABLE_CPU_FREQ 103/* Helpful macros for use in conditionals this assumes some of the above
104 * static variable names */
105#define NEED_FLUSH(position) \
106 (audiobuffer_fillpos > PCMBUF_TARGET_CHUNK || position >= pcmbuf_size)
107#define LOW_DATA(quarter_secs) \
108 (pcmbuf_unplayed_bytes < NATIVE_FREQUENCY * quarter_secs)
109
110static void pcmbuf_flush_audio(void);
111static void pcmbuf_under_watermark(void);
112
113#if defined(HAVE_ADJUSTABLE_CPU_FREQ) && !defined(SIMULATOR)
102static bool boost_mode; 114static bool boost_mode;
103 115
104void pcmbuf_boost(bool state) 116void pcmbuf_boost(bool state)
@@ -106,7 +118,7 @@ void pcmbuf_boost(bool state)
106 static bool boost_state = false; 118 static bool boost_state = false;
107 119
108 if (crossfade_init || crossfade_active || boost_mode) 120 if (crossfade_init || crossfade_active || boost_mode)
109 return ; 121 return;
110 122
111 if (state != boost_state) { 123 if (state != boost_state) {
112 cpu_boost(state); 124 cpu_boost(state);
@@ -122,106 +134,129 @@ void pcmbuf_set_boost_mode(bool state)
122} 134}
123#endif 135#endif
124 136
125static int pcmbuf_num_used_buffers(void) 137#define CALL_IF_EXISTS(function, args...) if (function) function(args)
138/* This function has 2 major logical parts (separated by brackets both for
139 * readability and variable scoping). The first part performs the
140 * operastions related to finishing off the last buffer we fed to the DMA.
141 * The second part performs the operations involved in sending a new buffer
142 * to the DMA. Finally the function checks the status of the buffer and
143 * boosts if necessary */
144static void pcmbuf_callback(unsigned char** start, size_t* size) ICODE_ATTR;
145static void pcmbuf_callback(unsigned char** start, size_t* size)
126{ 146{
127 return (pcmbuf_write_index - pcmbuf_read_index) & NUM_PCM_BUFFERS_MASK;
128}
129
130static void pcmbuf_callback(unsigned char** start, long* size) ICODE_ATTR;
131static void pcmbuf_callback(unsigned char** start, long* size)
132{
133 struct pcmbufdesc *desc = &pcmbuffers[pcmbuf_read_index];
134
135 if (position_callback) {
136 position_callback(last_chunksize);
137 }
138
139 pcmbuf_unplayed_bytes -= last_chunksize;
140 audiobuffer_free += last_chunksize;
141
142 if(desc->size == 0)
143 { 147 {
144 /* The buffer is finished, call the callback function */ 148 struct pcmbufdesc *pcmbuf_current = pcmbuf_read;
145 if(desc->callback) 149 /* Take the finished buffer out of circulation */
146 desc->callback(); 150 pcmbuf_read = pcmbuf_current->link;
147 151
148 /* Advance to the next buffer */ 152 {
149 pcmbuf_read_index = (pcmbuf_read_index + 1) & NUM_PCM_BUFFERS_MASK; 153 size_t finished_size = last_chunksize;
150 desc = &pcmbuffers[pcmbuf_read_index]; 154 audiobuffer_free += finished_size;
151 }
152
153 if(pcmbuf_num_used_buffers())
154 {
155
156 *start = desc->addr;
157 *size = desc->size;
158 155
159 /* Update the buffer descriptor */ 156 /* The buffer is finished, call the callback functions */
160 desc->addr += desc->size; 157 CALL_IF_EXISTS(position_callback, finished_size);
161 desc->size = 0; 158 }
162 } 159 CALL_IF_EXISTS(pcmbuf_current->callback);
163 else
164 {
165 /* No more buffers */
166 *size = 0;
167 if (pcmbuf_event_handler)
168 pcmbuf_event_handler();
169 }
170 160
171 last_chunksize = *size; 161 /* Put the finished buffer back into circulation */
162 pcmbuf_write_end->link = pcmbuf_current;
163 pcmbuf_write_end = pcmbuf_current;
164 }
172 165
173 if(pcmbuf_unplayed_bytes <= pcmbuf_watermark)
174 { 166 {
175 pcmbuf_under_watermark(pcmbuf_unplayed_bytes); 167 /* Send the new buffer to the pcm */
168 struct pcmbufdesc *pcmbuf_new = pcmbuf_read;
169 size_t *realsize = size;
170 unsigned char** realstart = start;
171 if(pcmbuf_new)
172 {
173 size_t current_size = pcmbuf_new->size;
174 pcmbuf_unplayed_bytes -= current_size;
175 *realsize = current_size;
176 last_chunksize = current_size;
177 *realstart = pcmbuf_new->addr;
178 }
179 else
180 {
181 /* No more buffers */
182 last_chunksize = 0;
183 *realsize = 0;
184 *realstart = NULL;
185 CALL_IF_EXISTS(pcmbuf_event_handler);
186 }
176 } 187 }
188
189 if(pcmbuf_unplayed_bytes <= pcmbuf_watermark) pcmbuf_under_watermark();
177} 190}
178 191
179void pcmbuf_set_position_callback(void (*callback)(int size)) { 192void pcmbuf_set_position_callback(void (*callback)(size_t size))
193{
180 position_callback = callback; 194 position_callback = callback;
181} 195}
182 196
183static void pcmbuf_set_watermark_bytes(int numbytes) 197static void pcmbuf_set_watermark_bytes(size_t numbytes)
184{ 198{
185 pcmbuf_watermark = numbytes; 199 pcmbuf_watermark = numbytes;
186} 200}
187 201
188bool pcmbuf_add_chunk(void *addr, int size, void (*callback)(void)) 202/* This is really just part of pcmbuf_flush_fillpos, but is easier to keep
189{ 203 * in a separate function for the moment */
190 /* We don't use the last buffer, since we can't see the difference 204static inline void pcmbuf_add_chunk(void)
191 between the full and empty condition */ 205{
192 if(pcmbuf_num_used_buffers() < (NUM_PCM_BUFFERS - 2)) 206 register size_t size = audiobuffer_fillpos;
193 { 207 /* Grab the next description to write, and change the write pointer */
194 pcmbuffers[pcmbuf_write_index].addr = addr; 208 register struct pcmbufdesc *pcmbuf_current = pcmbuf_write;
195 pcmbuffers[pcmbuf_write_index].size = size; 209 pcmbuf_write = pcmbuf_current->link;
196 pcmbuffers[pcmbuf_write_index].callback = callback; 210 /* Fill in the values in the new buffer chunk */
197 pcmbuf_write_index = (pcmbuf_write_index+1) & NUM_PCM_BUFFERS_MASK; 211 pcmbuf_current->addr = &audiobuffer[audiobuffer_pos];
198 pcmbuf_unplayed_bytes += size; 212 pcmbuf_current->size = size;
199 pcmbuf_mix_used_bytes = MAX(0, pcmbuf_mix_used_bytes - size); 213 pcmbuf_current->callback = pcmbuf_event_handler;
200 return true; 214 pcmbuf_current->link = NULL;
215 /* This is single use only */
216 pcmbuf_event_handler = NULL;
217 if (pcmbuf_read) {
218 /* If there is already a read buffer setup, add to it */
219 pcmbuf_read_end->link = pcmbuf_current;
220 } else {
221 /* Otherwise create the buffer */
222 pcmbuf_read = pcmbuf_current;
201 } 223 }
224 /* This is now the last buffer to read */
225 pcmbuf_read_end = pcmbuf_current;
226
227 /* Update bytes counters */
228 pcmbuf_unplayed_bytes += size;
229 if (pcmbuf_mix_used_bytes > size)
230 pcmbuf_mix_used_bytes -= size;
202 else 231 else
203 return false; 232 pcmbuf_mix_used_bytes = 0;
233
234 audiobuffer_pos += size;
235 if (audiobuffer_pos >= pcmbuf_size)
236 audiobuffer_pos = 0;
237
238 audiobuffer_fillpos = 0;
204} 239}
205 240
206static void pcmbuf_under_watermark(int bytes_left) 241static void pcmbuf_under_watermark(void)
207{ 242{
208 /* Fill audio buffer by boosting cpu */ 243 /* Fill audio buffer by boosting cpu */
209 pcmbuf_boost(true); 244 pcmbuf_boost(true);
210 if (bytes_left <= CHUNK_SIZE * 2 && crossfade_mode != CFM_FLUSH) 245 /* Disable crossfade if < .5s of audio */
246 if (LOW_DATA(2) && crossfade_mode != CFM_FLUSH)
211 crossfade_active = false; 247 crossfade_active = false;
212} 248}
213 249
214void pcmbuf_add_event(void (*event_handler)(void)) 250void pcmbuf_set_event_handler(void (*event_handler)(void))
215{ 251{
216 pcmbuf_event_handler = event_handler; 252 pcmbuf_event_handler = event_handler;
217} 253}
218 254
219unsigned int pcmbuf_get_latency(void) 255unsigned int pcmbuf_get_latency(void)
220{ 256{
221 int latency = (pcmbuf_unplayed_bytes + pcm_get_bytes_waiting()) 257 /* Be careful how this calculation is rearranted, it's easy to overflow */
222 * 1000 / 4 / 44100; 258 size_t bytes = pcmbuf_unplayed_bytes + pcm_get_bytes_waiting();
223 259 return bytes / 4 / (NATIVE_FREQUENCY/1000);
224 return latency<0?0:latency;
225} 260}
226 261
227void pcmbuf_set_low_latency(bool state) 262void pcmbuf_set_low_latency(bool state)
@@ -231,19 +266,17 @@ void pcmbuf_set_low_latency(bool state)
231 266
232bool pcmbuf_is_lowdata(void) 267bool pcmbuf_is_lowdata(void)
233{ 268{
234 if (!pcm_is_playing() || pcm_is_paused() || crossfade_init || crossfade_active) 269 if (!pcm_is_playing() || pcm_is_paused() ||
270 crossfade_init || crossfade_active)
235 return false; 271 return false;
236 272
237 /* 0.5s. */ 273 /* 0.5 seconds of buffer is low data */
238 if (pcmbuf_unplayed_bytes < NATIVE_FREQUENCY * 4 / 2) 274 return LOW_DATA(2);
239 return true;
240
241 return false;
242} 275}
243 276
244bool pcmbuf_crossfade_init(bool manual_skip) 277bool pcmbuf_crossfade_init(bool manual_skip)
245{ 278{
246 if (pcmbuf_size - audiobuffer_free < CHUNK_SIZE * 8 279 if (pcmbuf_unplayed_bytes < PCMBUF_TARGET_CHUNK * 8
247 || !pcmbuf_is_crossfade_enabled() 280 || !pcmbuf_is_crossfade_enabled()
248 || crossfade_active || crossfade_init || low_latency_mode) { 281 || crossfade_active || crossfade_init || low_latency_mode) {
249 pcmbuf_flush_audio(); 282 pcmbuf_flush_audio();
@@ -267,18 +300,19 @@ bool pcmbuf_crossfade_init(bool manual_skip)
267void pcmbuf_play_stop(void) 300void pcmbuf_play_stop(void)
268{ 301{
269 mutex_lock(&pcmbuf_mutex); 302 mutex_lock(&pcmbuf_mutex);
270
271 /** Prevent a very tiny pop from happening by muting audio 303 /** Prevent a very tiny pop from happening by muting audio
272 * until dma has been initialized. */ 304 * until dma has been initialized. */
273 pcm_mute(true); 305 pcm_mute(true);
274 pcm_play_stop(); 306 pcm_play_stop();
275 pcm_mute(false); 307 pcm_mute(false);
276 308
277 last_chunksize = 0;
278 pcmbuf_unplayed_bytes = 0; 309 pcmbuf_unplayed_bytes = 0;
279 pcmbuf_mix_used_bytes = 0; 310 pcmbuf_mix_used_bytes = 0;
280 pcmbuf_read_index = 0; 311 if (pcmbuf_read) {
281 pcmbuf_write_index = 0; 312 pcmbuf_write_end->link = pcmbuf_read;
313 pcmbuf_write_end = pcmbuf_read_end;
314 pcmbuf_read = pcmbuf_read_end = NULL;
315 }
282 audiobuffer_pos = 0; 316 audiobuffer_pos = 0;
283 audiobuffer_fillpos = 0; 317 audiobuffer_fillpos = 0;
284 audiobuffer_free = pcmbuf_size; 318 audiobuffer_free = pcmbuf_size;
@@ -291,19 +325,53 @@ void pcmbuf_play_stop(void)
291 mutex_unlock(&pcmbuf_mutex); 325 mutex_unlock(&pcmbuf_mutex);
292} 326}
293 327
294void pcmbuf_init(long bufsize) 328int pcmbuf_used_descs(void) {
329 struct pcmbufdesc *pcmbuf_temp = pcmbuf_read;
330 unsigned int i = 0;
331 while (pcmbuf_temp) {
332 pcmbuf_temp = pcmbuf_temp->link;
333 i++;
334 }
335 return i;
336}
337
338int pcmbuf_descs(void) {
339 return pcmbuf_size / PCMBUF_MINAVG_CHUNK;
340}
341
342size_t get_pcmbuf_descsize(void) {
343 return pcmbuf_descsize;
344}
345
346static void pcmbuf_init_pcmbuffers(void) {
347 struct pcmbufdesc *next = pcmbuf_write;
348 next++;
349 pcmbuf_write_end = pcmbuf_write;
350 while ((void *)next < (void *)audiobufend) {
351 pcmbuf_write_end->link=next;
352 pcmbuf_write_end=next;
353 next++;
354 }
355}
356
357/* Initialize the pcmbuffer the structure looks like this:
358 * ...CODECBUFFER|---------PCMBUF---------|GUARDBUF|DESCS| */
359void pcmbuf_init(size_t bufsize)
295{ 360{
296 mutex_init(&pcmbuf_mutex); 361 mutex_init(&pcmbuf_mutex);
297 pcmbuf_size = bufsize; 362 pcmbuf_size = bufsize;
298 audiobuffer = (char *)&audiobuf[(audiobufend - audiobuf) - 363 pcmbuf_descsize = pcmbuf_descs()*sizeof(struct pcmbufdesc);
299 pcmbuf_size - PCMBUF_GUARD]; 364 audiobuffer = (char *)&audiobuf[(audiobufend - audiobuf) -
365 (pcmbuf_size + PCMBUF_FADE_CHUNK + pcmbuf_descsize)];
300 guardbuf = &audiobuffer[pcmbuf_size]; 366 guardbuf = &audiobuffer[pcmbuf_size];
367 pcmbuf_write = (struct pcmbufdesc *)(&guardbuf[PCMBUF_FADE_CHUNK]);
368 pcmbuf_init_pcmbuffers();
301 position_callback = NULL; 369 position_callback = NULL;
302 pcmbuf_event_handler = NULL; 370 pcmbuf_event_handler = NULL;
303 pcmbuf_play_stop(); 371 pcmbuf_play_stop();
304} 372}
305 373
306long pcmbuf_get_bufsize(void) 374size_t pcmbuf_get_bufsize(void)
307{ 375{
308 return pcmbuf_size; 376 return pcmbuf_size;
309} 377}
@@ -311,7 +379,7 @@ long pcmbuf_get_bufsize(void)
311/** Initialize a track switch so that audio playback will not stop but 379/** Initialize a track switch so that audio playback will not stop but
312 * the switch to next track would happen as soon as possible. 380 * the switch to next track would happen as soon as possible.
313 */ 381 */
314void pcmbuf_flush_audio(void) 382static void pcmbuf_flush_audio(void)
315{ 383{
316 if (crossfade_init || crossfade_active || !pcm_is_playing()) { 384 if (crossfade_init || crossfade_active || !pcm_is_playing()) {
317 pcmbuf_play_stop(); 385 pcmbuf_play_stop();
@@ -323,66 +391,71 @@ void pcmbuf_flush_audio(void)
323 crossfade_init = true; 391 crossfade_init = true;
324} 392}
325 393
394void pcmbuf_pause(bool pause) {
395 pcm_mute(pause);
396 pcm_play_pause(!pause);
397 pcmbuf_boost(!pause);
398}
399
326/* Force playback. */ 400/* Force playback. */
327void pcmbuf_play_start(void) 401void pcmbuf_play_start(void)
328{ 402{
403 mutex_lock(&pcmbuf_mutex);
404
329 if (!pcm_is_playing() && pcmbuf_unplayed_bytes) 405 if (!pcm_is_playing() && pcmbuf_unplayed_bytes)
330 { 406 {
331 /** Prevent a very tiny pop from happening by muting audio 407 /** Prevent a very tiny pop from happening by muting audio
332 * until dma has been initialized. */ 408 * until dma has been initialized. */
333 pcm_mute(true); 409 pcm_mute(true);
334 410
335 pcm_play_data(pcmbuf_callback); 411 last_chunksize = pcmbuf_read->size;
412 pcmbuf_unplayed_bytes -= last_chunksize;
413 pcm_play_data(pcmbuf_callback,
414 (unsigned char *)pcmbuf_read->addr, last_chunksize);
336 415
337 /* Now unmute the audio. */ 416 /* Now unmute the audio. */
338 pcm_mute(false); 417 pcm_mute(false);
339 } 418 }
419
420 mutex_unlock(&pcmbuf_mutex);
340} 421}
341 422
342/** 423/**
343 * Commit samples waiting to the pcm buffer. 424 * Commit samples waiting to the pcm buffer.
344 */ 425 */
345void pcmbuf_flush_fillpos(void) 426static void pcmbuf_flush_fillpos(void)
346{ 427{
347 int copy_n;
348
349 mutex_lock(&pcmbuf_mutex); 428 mutex_lock(&pcmbuf_mutex);
350 429
351 copy_n = MIN(audiobuffer_fillpos, CHUNK_SIZE); 430 if (audiobuffer_fillpos) {
352 431 /* Never use the last buffer descriptor */
353 if (copy_n) { 432 while (pcmbuf_write == pcmbuf_write_end) {
354 while (!pcmbuf_add_chunk(&audiobuffer[audiobuffer_pos], 433 logf("pcmbuf_flush_fillpos no descriptors");
355 copy_n, pcmbuf_event_handler)) { 434 /* Deboost to let the playback catchup */
356 pcmbuf_boost(false); 435 pcmbuf_boost(false);
436 /* Let someone else have fun in the meantime */
357 sleep(1); 437 sleep(1);
358 /* This is a fatal error situation that should never happen. */ 438 /* This is a fatal error situation that should never happen. */
359 if (!pcm_is_playing()) { 439 if (!pcm_is_playing()) {
360 logf("pcm_flush_fillpos error"); 440 logf("pcmbuf_flush_fillpos error");
361 pcmbuf_play_start(); 441 pcmbuf_play_start();
362 mutex_unlock(&pcmbuf_mutex);
363 return ; 442 return ;
364 } 443 }
365 } 444 }
366 position_callback = NULL; 445 pcmbuf_add_chunk();
367 pcmbuf_event_handler = NULL;
368 audiobuffer_pos += copy_n;
369 if (audiobuffer_pos >= pcmbuf_size)
370 audiobuffer_pos -= pcmbuf_size;
371 audiobuffer_free -= copy_n;
372 audiobuffer_fillpos -= copy_n;
373 } 446 }
374 447
375 mutex_unlock(&pcmbuf_mutex); 448 mutex_unlock(&pcmbuf_mutex);
376} 449}
377 450
378/** 451/**
379 * Completely process the crossfade fade out effect with current pcm buffer. 452 * Completely process the crossfade fade out effect with current pcm buffer.
380 */ 453 */
381static void crossfade_process_buffer( 454static void crossfade_process_buffer(unsigned int fade_in_delay,
382 int fade_in_delay, int fade_out_delay, int fade_out_rem) 455 unsigned int fade_out_delay, size_t fade_out_rem)
383{ 456{
384 int amount; 457 size_t amount;
385 int pos; 458 size_t pos;
386 short *buf; 459 short *buf;
387 460
388 /* Fade out the entire current buffer according to settings. */ 461 /* Fade out the entire current buffer according to settings. */
@@ -391,12 +464,12 @@ static void crossfade_process_buffer(
391 464
392 while (fade_out_rem > 0 && crossfade_mode == CFM_CROSSFADE) 465 while (fade_out_rem > 0 && crossfade_mode == CFM_CROSSFADE)
393 { 466 {
394 int blocksize = MIN(8192, fade_out_rem); 467 size_t blocksize = MIN(8192, fade_out_rem);
395 int factor = (fade_out_rem<<8)/amount; 468 int factor = (fade_out_rem<<8)/amount;
396 469
397 /* Prevent pcmbuffer from wrapping. */ 470 /* Prevent pcmbuffer from wrapping. */
398 if (pos >= pcmbuf_size) 471 if (pos >= pcmbuf_size) pos -= pcmbuf_size;
399 pos -= pcmbuf_size; 472
400 blocksize = MIN((pcmbuf_size - pos)/2, blocksize); 473 blocksize = MIN((pcmbuf_size - pos)/2, blocksize);
401 buf = (short *)&audiobuffer[pos]; 474 buf = (short *)&audiobuffer[pos];
402 475
@@ -408,7 +481,6 @@ static void crossfade_process_buffer(
408 *buf++; 481 *buf++;
409 blocksize--; 482 blocksize--;
410 } 483 }
411 //yield();
412 } 484 }
413 485
414 /* And finally set the mixing position where we should start fading in. */ 486 /* And finally set the mixing position where we should start fading in. */
@@ -425,12 +497,13 @@ static void crossfade_process_buffer(
425 */ 497 */
426static void crossfade_start(void) 498static void crossfade_start(void)
427{ 499{
428 int bytesleft = pcmbuf_unplayed_bytes; 500 size_t fade_out_rem = 0;
429 int fade_out_rem = 0, fade_out_delay = 0; 501 unsigned int fade_out_delay = 0;
430 int fade_in_delay = 0; 502 unsigned fade_in_delay = 0;
431 503
432 crossfade_init = 0; 504 crossfade_init = 0;
433 if (bytesleft < CHUNK_SIZE * 4) { 505 /* Reject crossfade if less than .5s of data */
506 if (LOW_DATA(2)) {
434 logf("crossfade rejected"); 507 logf("crossfade rejected");
435 pcmbuf_play_stop(); 508 pcmbuf_play_stop();
436 return ; 509 return ;
@@ -438,18 +511,16 @@ static void crossfade_start(void)
438 511
439 logf("crossfade_start"); 512 logf("crossfade_start");
440 pcmbuf_boost(true); 513 pcmbuf_boost(true);
441 while (audiobuffer_fillpos != 0) 514 pcmbuf_flush_fillpos();
442 pcmbuf_flush_fillpos();
443 crossfade_active = true; 515 crossfade_active = true;
444 crossfade_pos = audiobuffer_pos; 516 crossfade_pos = audiobuffer_pos;
517 /* Initialize the crossfade buffer size to all of the buffered data that
518 * has not yet been sent to the DMA */
519 crossfade_rem = pcmbuf_unplayed_bytes / 2;
445 520
446 switch (crossfade_mode) { 521 switch (crossfade_mode) {
447 case CFM_MIX: 522 case CFM_MIX:
448 case CFM_CROSSFADE: 523 case CFM_CROSSFADE:
449 /* Initialize the crossfade buffer size. */
450 // FIXME: Crashes unless we use CHUNK_SIZE here
451 crossfade_rem = (bytesleft - (CHUNK_SIZE * 2))/2;
452
453 /* Get fade out delay from settings. */ 524 /* Get fade out delay from settings. */
454 fade_out_delay = NATIVE_FREQUENCY 525 fade_out_delay = NATIVE_FREQUENCY
455 * global_settings.crossfade_fade_out_delay * 2; 526 * global_settings.crossfade_fade_out_delay * 2;
@@ -479,23 +550,20 @@ static void crossfade_start(void)
479 * global_settings.crossfade_fade_in_delay * 2; 550 * global_settings.crossfade_fade_in_delay * 2;
480 551
481 /* Decrease the fade out delay if necessary. */ 552 /* Decrease the fade out delay if necessary. */
482 fade_out_delay += MIN(crossfade_rem - 553 if (crossfade_rem < fade_out_rem + fade_out_delay)
483 fade_out_rem - 554 fade_out_delay -=
484 fade_out_delay, 0); 555 (fade_out_rem + fade_out_delay) - crossfade_rem;
485 if (fade_out_delay < 0)
486 fade_out_delay = 0;
487 break ; 556 break ;
488 557
489 case CFM_FLUSH: 558 case CFM_FLUSH:
490 crossfade_rem = (bytesleft - CHUNK_SIZE) /2;
491 crossfade_fade_in_rem = 0; 559 crossfade_fade_in_rem = 0;
492 crossfade_fade_in_amount = 0; 560 crossfade_fade_in_amount = 0;
493 break ; 561 break ;
494 } 562 }
495 563
496 crossfade_pos -= crossfade_rem*2; 564 if (crossfade_pos < crossfade_rem * 2)
497 if (crossfade_pos < 0)
498 crossfade_pos += pcmbuf_size; 565 crossfade_pos += pcmbuf_size;
566 crossfade_pos -= crossfade_rem*2;
499 567
500 if (crossfade_mode != CFM_FLUSH) { 568 if (crossfade_mode != CFM_FLUSH) {
501 /* Process the fade out part of the crossfade. */ 569 /* Process the fade out part of the crossfade. */
@@ -508,29 +576,35 @@ static void crossfade_start(void)
508 * Fades in samples passed to the function and inserts them 576 * Fades in samples passed to the function and inserts them
509 * to the pcm buffer. 577 * to the pcm buffer.
510 */ 578 */
511static void fade_insert(const short *inbuf, int length) 579static void fade_insert(const short *inbuf, size_t length)
512{ 580{
513 int copy_n; 581 size_t copy_n;
514 int factor; 582 int factor;
515 int i, samples; 583 unsigned int i, samples;
516 short *buf; 584 short *buf;
517 585
518 factor = ((crossfade_fade_in_amount-crossfade_fade_in_rem) 586 factor = ((crossfade_fade_in_amount-crossfade_fade_in_rem)<<8)
519 <<8)/crossfade_fade_in_amount; 587 /crossfade_fade_in_amount;
520 588
521 while (audiobuffer_free < length + audiobuffer_fillpos 589 while (audiobuffer_free < length)
522 + CHUNK_SIZE)
523 { 590 {
524 pcmbuf_boost(false); 591 pcmbuf_boost(false);
525 sleep(1); 592 sleep(1);
526 } 593 }
594 audiobuffer_free -= length;
527 595
528 while (length > 0) { 596 while (length > 0) {
529 copy_n = MIN(length, pcmbuf_size - audiobuffer_pos - 597 unsigned int audiobuffer_index = audiobuffer_pos + audiobuffer_fillpos;
530 audiobuffer_fillpos); 598 /* Flush as needed */
531 copy_n = MIN(CHUNK_SIZE - audiobuffer_fillpos, copy_n); 599 if (NEED_FLUSH(audiobuffer_index))
600 {
601 pcmbuf_flush_fillpos();
602 audiobuffer_index = audiobuffer_pos + audiobuffer_fillpos;
603 }
604
605 copy_n = MIN(length, pcmbuf_size - audiobuffer_index);
532 606
533 buf = (short *)&audiobuffer[audiobuffer_pos+audiobuffer_fillpos]; 607 buf = (short *)&audiobuffer[audiobuffer_index];
534 samples = copy_n / 2; 608 samples = copy_n / 2;
535 for (i = 0; i < samples; i++) 609 for (i = 0; i < samples; i++)
536 buf[i] = (inbuf[i] * factor) >> 8; 610 buf[i] = (inbuf[i] * factor) >> 8;
@@ -538,36 +612,30 @@ static void fade_insert(const short *inbuf, int length)
538 inbuf += samples; 612 inbuf += samples;
539 audiobuffer_fillpos += copy_n; 613 audiobuffer_fillpos += copy_n;
540 length -= copy_n; 614 length -= copy_n;
541
542 /* Pre-buffer to meet CHUNK_SIZE requirement */
543 if (audiobuffer_fillpos < CHUNK_SIZE && length == 0) {
544 break ;
545 }
546
547 pcmbuf_flush_fillpos();
548 } 615 }
549} 616}
550 617
551/** 618/**
552 * Fades in buf2 and mixes it with buf. 619 * Fades in buf2 and mixes it with buf.
553 */ 620 */
554static __inline 621static int crossfade(short *buf, const short *buf2, unsigned int length)
555int crossfade(short *buf, const short *buf2, int length)
556{ 622{
557 int size, i; 623 size_t size;
558 int size_insert = 0; 624 unsigned int i;
625 size_t size_insert = 0;
559 int factor; 626 int factor;
560 627
561 size = MAX(0, MIN(length, crossfade_rem)); 628 size = MIN(length, crossfade_rem);
562 switch (crossfade_mode) { 629 switch (crossfade_mode) {
563 /* Fade in the current stream and mix it. */ 630 /* Fade in the current stream and mix it. */
564 case CFM_MIX: 631 case CFM_MIX:
565 case CFM_CROSSFADE: 632 case CFM_CROSSFADE:
566 factor = ((crossfade_fade_in_amount-crossfade_fade_in_rem) 633 factor = ((crossfade_fade_in_amount-crossfade_fade_in_rem)<<8) /
567 <<8)/crossfade_fade_in_amount; 634 crossfade_fade_in_amount;
568 635
569 for (i = 0; i < size; i++) { 636 for (i = 0; i < size; i++) {
570 buf[i] = MIN(MAX(buf[i] + ((buf2[i] * factor) >> 8), -32768), 32767); 637 buf[i] = MIN(32767, MAX(-32768,
638 buf[i] + ((buf2[i] * factor) >> 8)));
571 } 639 }
572 break ; 640 break ;
573 641
@@ -580,25 +648,65 @@ int crossfade(short *buf, const short *buf2, int length)
580 break ; 648 break ;
581 } 649 }
582 650
583 crossfade_fade_in_rem = MAX(0, crossfade_fade_in_rem - size); 651 if (crossfade_fade_in_rem > size)
652 crossfade_fade_in_rem = crossfade_fade_in_rem - size;
653 else
654 crossfade_fade_in_rem = 0;
655
584 crossfade_rem -= size; 656 crossfade_rem -= size;
585 if (crossfade_rem <= 0) 657 if (crossfade_rem == 0)
586 { 658 {
587 if (crossfade_fade_in_rem > 0 && crossfade_fade_in_amount > 0) 659 if (crossfade_fade_in_rem > 0 && crossfade_fade_in_amount > 0)
588 { 660 {
589 size_insert = MAX(0, MIN(crossfade_fade_in_rem, length - size)); 661 size_insert = MIN(crossfade_fade_in_rem, length - size);
590 fade_insert(&buf2[size], size_insert*2); 662 fade_insert(&buf2[size], size_insert*2);
591 crossfade_fade_in_rem -= size_insert; 663 crossfade_fade_in_rem -= size_insert;
592 } 664 }
593 665
594 if (crossfade_fade_in_rem <= 0) 666 if (crossfade_fade_in_rem == 0)
595 crossfade_active = false; 667 crossfade_active = false;
596 } 668 }
597 669
598 return size + size_insert; 670 return size + size_insert;
599} 671}
600 672
601static bool prepare_insert(long length) 673static void pcmbuf_flush_buffer(const char *buf, size_t length)
674{
675 size_t copy_n;
676 audiobuffer_free -= length;
677 while (length > 0) {
678 size_t audiobuffer_index = audiobuffer_pos + audiobuffer_fillpos;
679 if (NEED_FLUSH(audiobuffer_index))
680 {
681 pcmbuf_flush_fillpos();
682 audiobuffer_index = audiobuffer_pos + audiobuffer_fillpos;
683 }
684 copy_n = MIN(length, pcmbuf_size - audiobuffer_index);
685 memcpy(&audiobuffer[audiobuffer_index], buf, copy_n);
686 buf += copy_n;
687 audiobuffer_fillpos += copy_n;
688 length -= copy_n;
689 }
690}
691
692static void flush_crossfade(const char *buf, size_t length) {
693 size_t copy_n;
694
695 while (length > 0 && crossfade_active) {
696 copy_n = MIN(length, pcmbuf_size - crossfade_pos);
697 copy_n = 2 * crossfade((short *)&audiobuffer[crossfade_pos],
698 (const short *)buf, copy_n/2);
699 buf += copy_n;
700 length -= copy_n;
701 crossfade_pos += copy_n;
702 if (crossfade_pos >= pcmbuf_size)
703 crossfade_pos = 0;
704 }
705
706 pcmbuf_flush_buffer(buf, length);
707}
708
709static bool prepare_insert(size_t length)
602{ 710{
603 if (crossfade_init) 711 if (crossfade_init)
604 crossfade_start(); 712 crossfade_start();
@@ -611,48 +719,66 @@ static bool prepare_insert(long length)
611 return false; 719 return false;
612 } 720 }
613 721
614 if (audiobuffer_free < length + audiobuffer_fillpos 722 if (audiobuffer_free < length && !crossfade_active)
615 + CHUNK_SIZE && !crossfade_active) { 723 {
616 pcmbuf_boost(false); 724 pcmbuf_boost(false);
617 return false; 725 return false;
618 } 726 }
619 727
620 if (!pcm_is_playing()) { 728 if (!pcm_is_playing())
729 {
621 pcmbuf_boost(true); 730 pcmbuf_boost(true);
622 crossfade_active = false; 731 crossfade_active = false;
623 /* Pre-buffer 1s. */ 732 /* Pre-buffer 1s. */
624 if (audiobuffer_free < pcmbuf_size - NATIVE_FREQUENCY*4) { 733 if (!LOW_DATA(4))
734 {
625 logf("pcm starting"); 735 logf("pcm starting");
626 pcmbuf_play_start(); 736 pcmbuf_play_start();
627 } 737 }
628 } 738 }
629
630 return true; 739 return true;
631} 740}
632 741
633void* pcmbuf_request_buffer(long length, long *realsize) 742void* pcmbuf_request_buffer(size_t length, size_t *realsize)
634{ 743{
635 void *ptr = NULL;
636
637 if (!prepare_insert(length))
638 {
639 *realsize = 0;
640 return NULL;
641 }
642
643 if (crossfade_active) { 744 if (crossfade_active) {
644 *realsize = MIN(length, PCMBUF_GUARD); 745 *realsize = MIN(length, PCMBUF_FADE_CHUNK);
645 ptr = &guardbuf[0]; 746 return &guardbuf[0];
646 } else { 747 }
647 *realsize = MIN(length, pcmbuf_size - audiobuffer_pos 748 else
648 - audiobuffer_fillpos); 749 {
649 if (*realsize < length) { 750 if(prepare_insert(length))
650 *realsize += MIN((long)(length - *realsize), PCMBUF_GUARD); 751 {
752 size_t audiobuffer_index = audiobuffer_pos + audiobuffer_fillpos;
753 if (pcmbuf_size - audiobuffer_index < PCMBUF_MIN_CHUNK) {
754 pcmbuf_flush_fillpos();
755 audiobuffer_pos = 0;
756 *realsize = MIN(length, pcmbuf_size);
757 return &audiobuffer[0];
758 }
759 else
760 {
761 *realsize = MIN(length, pcmbuf_size - audiobuffer_index);
762 return &audiobuffer[audiobuffer_index];
763 }
764 }
765 else
766 {
767 *realsize = 0;
768 return NULL;
651 } 769 }
652 ptr = &audiobuffer[audiobuffer_pos + audiobuffer_fillpos];
653 } 770 }
654 771}
655 return ptr; 772
773void* pcmbuf_request_voice_buffer(size_t length, size_t *realsize, bool mix)
774{
775 if (mix)
776 {
777 *realsize = MIN(length, PCMBUF_FADE_CHUNK);
778 return &guardbuf[0];
779 }
780 else
781 return pcmbuf_request_buffer(length, realsize);
656} 782}
657 783
658bool pcmbuf_is_crossfade_active(void) 784bool pcmbuf_is_crossfade_active(void)
@@ -660,104 +786,41 @@ bool pcmbuf_is_crossfade_active(void)
660 return crossfade_active || crossfade_init; 786 return crossfade_active || crossfade_init;
661} 787}
662 788
663void pcmbuf_flush_buffer(long length) 789void pcmbuf_write_complete(size_t length)
664{ 790{
665 int copy_n;
666 char *buf;
667
668 if (crossfade_active) { 791 if (crossfade_active) {
669 buf = &guardbuf[0]; 792 length = MIN(length, PCMBUF_FADE_CHUNK);
670 length = MIN(length, PCMBUF_GUARD); 793 flush_crossfade(&guardbuf[0],length);
671 while (length > 0 && crossfade_active) {
672 copy_n = MIN(length, pcmbuf_size - crossfade_pos);
673 copy_n = 2 * crossfade((short *)&audiobuffer[crossfade_pos],
674 (const short *)buf, copy_n/2);
675 buf += copy_n;
676 length -= copy_n;
677 crossfade_pos += copy_n;
678 if (crossfade_pos >= pcmbuf_size)
679 crossfade_pos -= pcmbuf_size;
680 }
681
682 while (length > 0) {
683 pcmbuf_flush_fillpos();
684 copy_n = MIN(length, pcmbuf_size - audiobuffer_pos);
685 memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n);
686 audiobuffer_fillpos = copy_n;
687 buf += copy_n;
688 length -= copy_n;
689 }
690 } 794 }
795 else
796 {
797 audiobuffer_free -= length;
798 audiobuffer_fillpos += length;
691 799
692 audiobuffer_fillpos += length; 800 if (NEED_FLUSH(audiobuffer_pos + audiobuffer_fillpos))
693 801 pcmbuf_flush_fillpos();
694 try_flush:
695 if (audiobuffer_fillpos < CHUNK_SIZE && pcmbuf_size
696 - audiobuffer_pos - audiobuffer_fillpos > 0)
697 return ;
698
699 copy_n = audiobuffer_fillpos - (pcmbuf_size - audiobuffer_pos);
700 if (copy_n > 0) {
701 audiobuffer_fillpos -= copy_n;
702 pcmbuf_flush_fillpos();
703 copy_n = MIN(copy_n, PCMBUF_GUARD);
704 memcpy(&audiobuffer[0], &guardbuf[0], copy_n);
705 audiobuffer_fillpos = copy_n;
706 goto try_flush;
707 } 802 }
708 pcmbuf_flush_fillpos();
709} 803}
710 804
711bool pcmbuf_insert_buffer(char *buf, long length) 805void pcmbuf_write_voice(size_t length)
806{
807 while (pcm_is_playing())
808 sleep(1);
809 pcm_play_data(NULL, &guardbuf[0], length);
810}
811
812bool pcmbuf_insert_buffer(const char *buf, size_t length)
712{ 813{
713 long copy_n = 0;
714
715 if (!prepare_insert(length)) 814 if (!prepare_insert(length))
716 return false; 815 return false;
717 816
718
719 if (crossfade_active) { 817 if (crossfade_active) {
720 while (length > 0 && crossfade_active) { 818 flush_crossfade(buf,length);
721 copy_n = MIN(length, pcmbuf_size - crossfade_pos);
722
723 copy_n = 2 * crossfade((short *)&audiobuffer[crossfade_pos],
724 (const short *)buf, copy_n/2);
725 buf += copy_n;
726 length -= copy_n;
727 crossfade_pos += copy_n;
728 if (crossfade_pos >= pcmbuf_size)
729 crossfade_pos -= pcmbuf_size;
730 }
731
732 while (length > 0) {
733 pcmbuf_flush_fillpos();
734 copy_n = MIN(length, pcmbuf_size - audiobuffer_pos);
735 memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n);
736 audiobuffer_fillpos = copy_n;
737 buf += copy_n;
738 length -= copy_n;
739 }
740 } 819 }
741 820 else
742 while (length > 0) { 821 {
743 copy_n = MIN(length, pcmbuf_size - audiobuffer_pos - 822 pcmbuf_flush_buffer(buf, length);
744 audiobuffer_fillpos);
745 copy_n = MIN(CHUNK_SIZE - audiobuffer_fillpos, copy_n);
746
747 memcpy(&audiobuffer[audiobuffer_pos+audiobuffer_fillpos],
748 buf, copy_n);
749 buf += copy_n;
750 audiobuffer_fillpos += copy_n;
751 length -= copy_n;
752
753 /* Pre-buffer to meet CHUNK_SIZE requirement */
754 if (audiobuffer_fillpos < CHUNK_SIZE && length == 0) {
755 return true;
756 }
757
758 pcmbuf_flush_fillpos();
759 } 823 }
760
761 return true; 824 return true;
762} 825}
763 826
@@ -765,19 +828,21 @@ bool pcmbuf_insert_buffer(char *buf, long length)
765 in Hertz for a duration in milliseconds. */ 828 in Hertz for a duration in milliseconds. */
766void pcmbuf_beep(int frequency, int duration, int amplitude) 829void pcmbuf_beep(int frequency, int duration, int amplitude)
767{ 830{
768 int state = 0, count = 0; 831 unsigned int state = 0, count = 0;
769 int interval = NATIVE_FREQUENCY / frequency; 832 unsigned int interval = NATIVE_FREQUENCY / frequency;
770 int pos; 833 size_t pos;
771 short *buf = (short *)audiobuffer; 834 short *buf = (short *)audiobuffer;
772 int bufsize = pcmbuf_size / 2; 835 size_t bufsize = pcmbuf_size / 2;
773 836
774 /* FIXME: Should start playback. */ 837 /* FIXME: Should start playback. */
775 //if (pcmbuf_unplayed_bytes * 1000 < 4 * NATIVE_FREQUENCY * duration) 838 //if (pcmbuf_unplayed_bytes * 1000 < 4 * NATIVE_FREQUENCY * duration)
776 // return ; 839 // return ;
777 840
778 pos = (audiobuffer_pos - pcmbuf_unplayed_bytes) / 2; 841 if (audiobuffer_pos < pcmbuf_unplayed_bytes)
779 if (pos < 0) 842 pos = pcmbuf_size + audiobuffer_pos - pcmbuf_unplayed_bytes;
780 pos += bufsize; 843 else
844 pos = audiobuffer_pos - pcmbuf_unplayed_bytes;
845 pos /= 2;
781 846
782 duration = NATIVE_FREQUENCY / 1000 * duration; 847 duration = NATIVE_FREQUENCY / 1000 * duration;
783 while (duration-- > 0) 848 while (duration-- > 0)
@@ -821,21 +886,19 @@ int pcmbuf_mix_usage(void)
821 886
822void pcmbuf_reset_mixpos(void) 887void pcmbuf_reset_mixpos(void)
823{ 888{
824 int bufsize = pcmbuf_size / 2;
825
826 pcmbuf_mix_used_bytes = 0; 889 pcmbuf_mix_used_bytes = 0;
827 mixpos = (audiobuffer_pos - pcmbuf_unplayed_bytes) / 2; 890 if (audiobuffer_pos < pcmbuf_unplayed_bytes)
828 if (mixpos < 0) 891 mixpos = pcmbuf_size + audiobuffer_pos - pcmbuf_unplayed_bytes;
829 mixpos += bufsize; 892 else
830 if (mixpos >= bufsize) 893 mixpos = audiobuffer_pos - pcmbuf_unplayed_bytes;
831 mixpos -= bufsize; 894 mixpos /= 2;
832} 895}
833 896
834void pcmbuf_mix(char *buf, long length) 897void pcmbuf_mix(char *buf, size_t length)
835{ 898{
836 short *ibuf = (short *)buf; 899 short *ibuf = (short *)buf;
837 short *obuf = (short *)audiobuffer; 900 short *obuf = (short *)audiobuffer;
838 int bufsize = pcmbuf_size / 2; 901 size_t bufsize = pcmbuf_size / 2;
839 902
840 if (pcmbuf_mix_used_bytes == 0) 903 if (pcmbuf_mix_used_bytes == 0)
841 pcmbuf_reset_mixpos(); 904 pcmbuf_reset_mixpos();
@@ -858,8 +921,10 @@ void pcmbuf_crossfade_enable(bool on_off)
858 crossfade_enabled = on_off; 921 crossfade_enabled = on_off;
859 922
860 if (crossfade_enabled) { 923 if (crossfade_enabled) {
861 pcmbuf_set_watermark_bytes(pcmbuf_size - (NATIVE_FREQUENCY*4/2)); 924 /* If crossfading, try to keep the buffer full other than 2 second */
925 pcmbuf_set_watermark_bytes(pcmbuf_size - PCMBUF_WATERMARK * 2);
862 } else { 926 } else {
927 /* Otherwise, just keep it above 1 second */
863 pcmbuf_set_watermark_bytes(PCMBUF_WATERMARK); 928 pcmbuf_set_watermark_bytes(PCMBUF_WATERMARK);
864 } 929 }
865} 930}
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h
index 2476857f88..555c1bcb33 100644
--- a/apps/pcmbuf.h
+++ b/apps/pcmbuf.h
@@ -19,36 +19,48 @@
19#ifndef PCMBUF_H 19#ifndef PCMBUF_H
20#define PCMBUF_H 20#define PCMBUF_H
21 21
22/* Guard buffer for crossfader when dsp is enabled. */ 22#define PCMBUF_TARGET_CHUNK 32768 /* This is the target fill size of chunks
23#define PCMBUF_GUARD 32768 23 on the pcm buffer */
24#define PCMBUF_MINAVG_CHUNK 24576 /* This is the minimum average size of
25 chunks on the pcm buffer (or we run out
26 of buffer descriptors, which is
27 non-fatal) */
28#define PCMBUF_MIN_CHUNK 4096 /* We try to never feed a chunk smaller than
29 this to the DMA */
30#define PCMBUF_FADE_CHUNK 8192 /* This is the maximum size of one packet
31 for mixing (crossfade or voice) */
24 32
25void pcmbuf_init(long bufsize); 33/* Returns true if the buffer needs to change size */
26long pcmbuf_get_bufsize(void); 34bool pcmbuf_is_same_size(size_t bufsize);
35void pcmbuf_init(size_t bufsize);
36/* Size in bytes used by the pcmbuffer */
37size_t pcmbuf_get_bufsize(void);
38size_t get_pcmbuf_descsize(void);
27 39
40void pcmbuf_pause(bool pause);
28void pcmbuf_play_stop(void); 41void pcmbuf_play_stop(void);
29bool pcmbuf_is_crossfade_active(void); 42bool pcmbuf_is_crossfade_active(void);
30 43
31/* These functions are for playing chained buffers of PCM data */ 44/* These functions are for playing chained buffers of PCM data */
32bool pcmbuf_add_chunk(void *addr, int size, void (*callback)(void)); 45#if defined(HAVE_ADJUSTABLE_CPU_FREQ) && !defined(SIMULATOR)
33
34#ifdef HAVE_ADJUSTABLE_CPU_FREQ
35void pcmbuf_boost(bool state); 46void pcmbuf_boost(bool state);
36void pcmbuf_set_boost_mode(bool state); 47void pcmbuf_set_boost_mode(bool state);
37#else 48#else
38#define pcmbuf_boost(state) do { } while(0) 49#define pcmbuf_boost(state) do { } while(0)
39#define pcmbuf_set_boost_mode(state) do { } while(0) 50#define pcmbuf_set_boost_mode(state) do { } while(0)
40#endif 51#endif
41bool pcmbuf_is_lowdata(void); 52bool pcmbuf_is_lowdata(void);
42void pcmbuf_flush_audio(void);
43void pcmbuf_play_start(void); 53void pcmbuf_play_start(void);
44bool pcmbuf_crossfade_init(bool manual_skip); 54bool pcmbuf_crossfade_init(bool manual_skip);
45void pcmbuf_add_event(void (*event_handler)(void)); 55void pcmbuf_set_event_handler(void (*callback)(void));
46void pcmbuf_set_position_callback(void (*callback)(int size)); 56void pcmbuf_set_position_callback(void (*callback)(size_t size));
47unsigned int pcmbuf_get_latency(void); 57unsigned int pcmbuf_get_latency(void);
48void pcmbuf_set_low_latency(bool state); 58void pcmbuf_set_low_latency(bool state);
49bool pcmbuf_insert_buffer(char *buf, long length); 59bool pcmbuf_insert_buffer(const char *buf, size_t length);
50void pcmbuf_flush_buffer(long length); 60void pcmbuf_write_complete(size_t length);
51void* pcmbuf_request_buffer(long length, long *realsize); 61void pcmbuf_write_voice(size_t length);
62void* pcmbuf_request_buffer(size_t length, size_t *realsize);
63void* pcmbuf_request_voice_buffer(size_t length, size_t *realsize, bool mix);
52bool pcmbuf_is_crossfade_enabled(void); 64bool pcmbuf_is_crossfade_enabled(void);
53void pcmbuf_crossfade_enable(bool on_off); 65void pcmbuf_crossfade_enable(bool on_off);
54 66
@@ -56,6 +68,9 @@ int pcmbuf_usage(void);
56int pcmbuf_mix_usage(void); 68int pcmbuf_mix_usage(void);
57void pcmbuf_beep(int frequency, int duration, int amplitude); 69void pcmbuf_beep(int frequency, int duration, int amplitude);
58void pcmbuf_reset_mixpos(void); 70void pcmbuf_reset_mixpos(void);
59void pcmbuf_mix(char *buf, long length); 71void pcmbuf_mix(char *buf, size_t length);
72
73int pcmbuf_used_descs(void);
74int pcmbuf_descs(void);
60 75
61#endif 76#endif
diff --git a/apps/playback.c b/apps/playback.c
index 5ed6c5e00c..7688534e07 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -216,6 +216,13 @@ static bool v1first = false;
216static void mp3_set_elapsed(struct mp3entry* id3); 216static void mp3_set_elapsed(struct mp3entry* id3);
217int mp3_get_file_pos(void); 217int mp3_get_file_pos(void);
218 218
219#ifdef TIME_CODEC
220bool is_filling(void)
221{
222 return filling;
223}
224#endif
225
219static void do_swap(int idx_old, int idx_new) 226static void do_swap(int idx_old, int idx_new)
220{ 227{
221#ifndef SIMULATOR 228#ifndef SIMULATOR
@@ -287,13 +294,13 @@ static void voice_boost_cpu(bool state)
287#define voice_boost_cpu(state) do { } while(0) 294#define voice_boost_cpu(state) do { } while(0)
288#endif 295#endif
289 296
290bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2, 297bool codec_pcmbuf_insert_split_callback(const void *ch1, const void *ch2,
291 long length) 298 size_t length)
292{ 299{
293 char* src[2]; 300 const char* src[2];
294 char *dest; 301 char *dest;
295 long input_size; 302 long input_size;
296 long output_size; 303 size_t output_size;
297 304
298 src[0] = ch1; 305 src[0] = ch1;
299 src[1] = ch2; 306 src[1] = ch2;
@@ -311,47 +318,50 @@ bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2,
311 } 318 }
312 319
313 while (length > 0) { 320 while (length > 0) {
321 long est_output_size = dsp_output_size(length);
314 /* This will prevent old audio from playing when skipping tracks. */ 322 /* This will prevent old audio from playing when skipping tracks. */
315 if ((ci.reload_codec || ci.stop_codec) && 323 if (current_codec == CODEC_IDX_VOICE) {
316 current_codec != CODEC_IDX_VOICE) 324 while ((dest = pcmbuf_request_voice_buffer(est_output_size,
317 return true; 325 &output_size, audio_codec_loaded)) == NULL)
318 326 sleep(1);
319 while ((dest = pcmbuf_request_buffer(dsp_output_size(length), 327 }
320 &output_size)) == NULL) { 328 else
321 sleep(1); 329 {
322 if ((ci.reload_codec || ci.stop_codec) && 330 if (ci.reload_codec || ci.stop_codec)
323 current_codec != CODEC_IDX_VOICE)
324 return true; 331 return true;
332
333 while ((dest = pcmbuf_request_buffer(est_output_size,
334 &output_size)) == NULL) {
335 sleep(1);
336 if (ci.reload_codec || ci.stop_codec)
337 return true;
338 }
325 } 339 }
326 340
327 /* Get the real input_size for output_size bytes, guarding 341 /* Get the real input_size for output_size bytes, guarding
328 * against resampling buffer overflows. */ 342 * against resampling buffer overflows. */
329 input_size = dsp_input_size(output_size); 343 input_size = dsp_input_size(output_size);
330 if (input_size > length) {
331 DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld > %ld\n",
332 output_size, length, input_size, length);
333 input_size = length;
334 }
335 344
336 if (input_size <= 0) { 345 if (input_size <= 0) {
337 pcmbuf_flush_buffer(0);
338 DEBUGF("Warning: dsp_input_size(%ld=dsp_output_size(%ld))=%ld <= 0\n", 346 DEBUGF("Warning: dsp_input_size(%ld=dsp_output_size(%ld))=%ld <= 0\n",
339 output_size, length, input_size); 347 output_size, length, input_size);
340 /* should we really continue, or should we break? 348 /* this cannot happen */
341 * We should probably continue because calling 349 break;
342 * pcmbuf_flush_buffer(0) will wrap the buffer if it was fully
343 * filled and so next call to pcmbuf_request_buffer should give
344 * the requested output_size. */
345 continue;
346 } 350 }
347 351
352 if ((size_t)input_size > length) {
353 DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld > %ld\n",
354 output_size, length, input_size, length);
355 input_size = length;
356 }
357
348 output_size = dsp_process(dest, src, input_size); 358 output_size = dsp_process(dest, src, input_size);
349 359
350 /* Hotswap between audio and voice codecs as necessary. */ 360 /* Hotswap between audio and voice codecs as necessary. */
351 switch (current_codec) 361 switch (current_codec)
352 { 362 {
353 case CODEC_IDX_AUDIO: 363 case CODEC_IDX_AUDIO:
354 pcmbuf_flush_buffer(output_size); 364 pcmbuf_write_complete(output_size);
355 if (voice_is_playing && pcmbuf_usage() > 30 365 if (voice_is_playing && pcmbuf_usage() > 30
356 && pcmbuf_mix_usage() < 20) 366 && pcmbuf_mix_usage() < 20)
357 { 367 {
@@ -368,7 +378,7 @@ bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2,
368 || pcmbuf_mix_usage() > 70) 378 || pcmbuf_mix_usage() > 70)
369 swap_codec(); 379 swap_codec();
370 } else { 380 } else {
371 pcmbuf_flush_buffer(output_size); 381 pcmbuf_write_complete(output_size);
372 } 382 }
373 break ; 383 break ;
374 } 384 }
@@ -379,7 +389,7 @@ bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2,
379 return true; 389 return true;
380} 390}
381 391
382bool codec_pcmbuf_insert_callback(char *buf, long length) 392bool codec_pcmbuf_insert_callback(const char *buf, size_t length)
383{ 393{
384 /* TODO: The audiobuffer API should probably be updated, and be based on 394 /* TODO: The audiobuffer API should probably be updated, and be based on
385 * pcmbuf_insert_split(). 395 * pcmbuf_insert_split().
@@ -405,9 +415,10 @@ void* get_codec_memory_callback(long *size)
405 return &audiobuf[0]; 415 return &audiobuf[0];
406} 416}
407 417
408static void pcmbuf_position_callback(int size) ICODE_ATTR; 418static void pcmbuf_position_callback(size_t size) ICODE_ATTR;
409static void pcmbuf_position_callback(int size) { 419static void pcmbuf_position_callback(size_t size) {
410 unsigned int time = size * 1000 / 4 / 44100 + prev_ti->id3.elapsed; 420 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
421 prev_ti->id3.elapsed;
411 if (time >= prev_ti->id3.length) { 422 if (time >= prev_ti->id3.length) {
412 pcmbuf_set_position_callback(NULL); 423 pcmbuf_set_position_callback(NULL);
413 prev_ti->id3.elapsed = prev_ti->id3.length; 424 prev_ti->id3.elapsed = prev_ti->id3.length;
@@ -785,6 +796,13 @@ static void codec_track_changed(void)
785 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0); 796 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
786} 797}
787 798
799static void pcmbuf_track_changed_callback(void)
800{
801 track_changed = true;
802 pcmbuf_set_position_callback(NULL);
803 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
804}
805
788/* Give codecs or file buffering the right amount of processing time 806/* Give codecs or file buffering the right amount of processing time
789 to prevent pcm audio buffer from going empty. */ 807 to prevent pcm audio buffer from going empty. */
790static void yield_codecs(void) 808static void yield_codecs(void)
@@ -1529,7 +1547,7 @@ static void audio_update_trackinfo(void)
1529 /* Gapless playback. */ 1547 /* Gapless playback. */
1530 else 1548 else
1531 { 1549 {
1532 pcmbuf_add_event(codec_track_changed); 1550 pcmbuf_set_event_handler(pcmbuf_track_changed_callback);
1533 } 1551 }
1534} 1552}
1535 1553
@@ -1675,15 +1693,17 @@ bool codec_request_next_track_callback(void)
1675 the core has been requested the codec to be terminated. */ 1693 the core has been requested the codec to be terminated. */
1676 return !ci_voice.stop_codec && queue_empty(&voice_codec_queue); 1694 return !ci_voice.stop_codec && queue_empty(&voice_codec_queue);
1677 } 1695 }
1678#ifdef AB_REPEAT_ENABLE
1679 ab_end_of_track_report();
1680#endif
1681
1682 pcmbuf_set_position_callback(pcmbuf_position_callback);
1683 1696
1684 if (ci.stop_codec || !playing) 1697 if (ci.stop_codec || !playing)
1685 return false; 1698 return false;
1686 1699
1700#ifdef AB_REPEAT_ENABLE
1701 ab_end_of_track_report();
1702#endif
1703
1704 if (!new_track)
1705 pcmbuf_set_position_callback(pcmbuf_position_callback);
1706
1687 logf("Request new track"); 1707 logf("Request new track");
1688 1708
1689 /* Advance to next track. */ 1709 /* Advance to next track. */
@@ -1856,15 +1876,13 @@ void audio_thread(void)
1856 1876
1857 case Q_AUDIO_PAUSE: 1877 case Q_AUDIO_PAUSE:
1858 logf("audio_pause"); 1878 logf("audio_pause");
1859 pcm_mute(true); 1879 pcmbuf_pause(true);
1860 pcm_play_pause(false);
1861 paused = true; 1880 paused = true;
1862 break ; 1881 break ;
1863 1882
1864 case Q_AUDIO_RESUME: 1883 case Q_AUDIO_RESUME:
1865 logf("audio_resume"); 1884 logf("audio_resume");
1866 pcm_play_pause(true); 1885 pcmbuf_pause(false);
1867 pcm_mute(false);
1868 paused = false; 1886 paused = false;
1869 break ; 1887 break ;
1870 1888
@@ -2022,8 +2040,9 @@ void codec_thread(void)
2022static void reset_buffer(void) 2040static void reset_buffer(void)
2023{ 2041{
2024 filebuf = (char *)&audiobuf[MALLOC_BUFSIZE]; 2042 filebuf = (char *)&audiobuf[MALLOC_BUFSIZE];
2025 filebuflen = audiobufend - audiobuf - pcmbuf_get_bufsize() 2043 filebuflen = audiobufend - audiobuf - MALLOC_BUFSIZE - GUARD_BUFSIZE -
2026 - PCMBUF_GUARD - MALLOC_BUFSIZE - GUARD_BUFSIZE; 2044 (pcmbuf_get_bufsize() + get_pcmbuf_descsize() + PCMBUF_FADE_CHUNK);
2045
2027 2046
2028 if (talk_get_bufsize() && voice_codec_loaded) 2047 if (talk_get_bufsize() && voice_codec_loaded)
2029 { 2048 {
@@ -2422,7 +2441,7 @@ void audio_set_buffer_margin(int setting)
2422/* Set crossfade & PCM buffer length. */ 2441/* Set crossfade & PCM buffer length. */
2423void audio_set_crossfade(int enable) 2442void audio_set_crossfade(int enable)
2424{ 2443{
2425 long size; 2444 size_t size;
2426 bool was_playing = playing; 2445 bool was_playing = playing;
2427 int offset = 0; 2446 int offset = 0;
2428 int seconds = 1; 2447 int seconds = 1;
diff --git a/apps/plugin.c b/apps/plugin.c
index 286c36cfb7..f5b33c65ce 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -124,6 +124,10 @@ static const struct plugin_api rockbox_api = {
124 lcd_bitmap_part, 124 lcd_bitmap_part,
125 lcd_bitmap, 125 lcd_bitmap,
126#endif 126#endif
127#if LCD_DEPTH == 16
128 lcd_bitmap_transparent_part,
129 lcd_bitmap_transparent,
130#endif
127 lcd_putsxy, 131 lcd_putsxy,
128 lcd_puts_style, 132 lcd_puts_style,
129 lcd_puts_scroll_style, 133 lcd_puts_scroll_style,
@@ -198,6 +202,7 @@ static const struct plugin_api rockbox_api = {
198 settings_parseline, 202 settings_parseline,
199#ifndef SIMULATOR 203#ifndef SIMULATOR
200 ata_sleep, 204 ata_sleep,
205 ata_disk_is_active,
201#endif 206#endif
202 207
203 /* dir */ 208 /* dir */
@@ -225,6 +230,17 @@ static const struct plugin_api rockbox_api = {
225 timer_unregister, 230 timer_unregister,
226 timer_set_period, 231 timer_set_period,
227#endif 232#endif
233 queue_init,
234 queue_delete,
235 queue_post,
236 queue_wait_w_tmo,
237 usb_acknowledge,
238#ifdef RB_PROFILE
239 profile_thread,
240 profstop,
241 profile_func_enter,
242 profile_func_exit,
243#endif
228 244
229 /* strings and memory */ 245 /* strings and memory */
230 snprintf, 246 snprintf,
@@ -238,6 +254,7 @@ static const struct plugin_api rockbox_api = {
238 strncasecmp, 254 strncasecmp,
239 memset, 255 memset,
240 memcpy, 256 memcpy,
257 memmove,
241 _ctype_, 258 _ctype_,
242 atoi, 259 atoi,
243 strchr, 260 strchr,
@@ -332,6 +349,23 @@ static const struct plugin_api rockbox_api = {
332 menu_insert, 349 menu_insert,
333 menu_set_cursor, 350 menu_set_cursor,
334 351
352 /* power */
353 battery_level,
354 battery_level_safe,
355 battery_time,
356#ifndef SIMULATOR
357 battery_voltage,
358#endif
359#ifdef HAVE_CHARGING
360 charger_inserted,
361# ifdef HAVE_CHARGE_STATE
362 charging_state,
363# endif
364#endif
365#ifdef HAVE_USB_POWER
366 usb_powered,
367#endif
368
335 /* misc */ 369 /* misc */
336 srand, 370 srand,
337 rand, 371 rand,
@@ -353,8 +387,6 @@ static const struct plugin_api rockbox_api = {
353 count_mp3_frames, 387 count_mp3_frames,
354 create_xing_header, 388 create_xing_header,
355 find_next_frame, 389 find_next_frame,
356 battery_level,
357 battery_level_safe,
358#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) 390#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
359 peak_meter_scale_value, 391 peak_meter_scale_value,
360 peak_meter_set_use_dbfs, 392 peak_meter_set_use_dbfs,
@@ -368,37 +400,7 @@ static const struct plugin_api rockbox_api = {
368 400
369 /* new stuff at the end, sort into place next time 401 /* new stuff at the end, sort into place next time
370 the API gets incompatible */ 402 the API gets incompatible */
371#ifdef RB_PROFILE 403
372 profile_thread,
373 profstop,
374 profile_func_enter,
375 profile_func_exit,
376#endif
377 battery_time,
378#ifndef SIMULATOR
379 ata_disk_is_active,
380 battery_voltage,
381#endif
382 queue_init,
383 queue_delete,
384 queue_post,
385 queue_wait_w_tmo,
386 usb_acknowledge,
387#if LCD_DEPTH == 16
388 lcd_bitmap_transparent_part,
389 lcd_bitmap_transparent,
390#endif
391 memmove,
392#ifdef HAVE_CHARGING
393 charger_inserted,
394# ifdef HAVE_CHARGE_STATE
395 charging_state,
396# endif
397#endif
398#ifdef HAVE_USB_POWER
399 usb_powered,
400#endif
401
402}; 404};
403 405
404int plugin_load(const char* plugin, void* parameter) 406int plugin_load(const char* plugin, void* parameter)
diff --git a/apps/plugin.h b/apps/plugin.h
index 3d9161a456..286ca4087f 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -97,12 +97,12 @@
97#define PLUGIN_MAGIC 0x526F634B /* RocK */ 97#define PLUGIN_MAGIC 0x526F634B /* RocK */
98 98
99/* increase this every time the api struct changes */ 99/* increase this every time the api struct changes */
100#define PLUGIN_API_VERSION 6 100#define PLUGIN_API_VERSION 7
101 101
102/* update this to latest version if a change to the api struct breaks 102/* update this to latest version if a change to the api struct breaks
103 backwards compatibility (and please take the opportunity to sort in any 103 backwards compatibility (and please take the opportunity to sort in any
104 new function which are "waiting" at the end of the function table) */ 104 new function which are "waiting" at the end of the function table) */
105#define PLUGIN_MIN_API_VERSION 2 105#define PLUGIN_MIN_API_VERSION 7
106 106
107/* plugin return codes */ 107/* plugin return codes */
108enum plugin_status { 108enum plugin_status {
@@ -162,6 +162,13 @@ struct plugin_api {
162 void (*lcd_bitmap)(const fb_data *src, int x, int y, int width, 162 void (*lcd_bitmap)(const fb_data *src, int x, int y, int width,
163 int height); 163 int height);
164#endif 164#endif
165#if LCD_DEPTH == 16
166 void (*lcd_bitmap_transparent_part)(const fb_data *src,
167 int src_x, int src_y, int stride,
168 int x, int y, int width, int height);
169 void (*lcd_bitmap_transparent)(const fb_data *src, int x, int y,
170 int width, int height);
171#endif
165 void (*lcd_putsxy)(int x, int y, const unsigned char *string); 172 void (*lcd_putsxy)(int x, int y, const unsigned char *string);
166 void (*lcd_puts_style)(int x, int y, const unsigned char *str, int style); 173 void (*lcd_puts_style)(int x, int y, const unsigned char *str, int style);
167 void (*lcd_puts_scroll_style)(int x, int y, const unsigned char* string, 174 void (*lcd_puts_scroll_style)(int x, int y, const unsigned char* string,
@@ -246,6 +253,7 @@ struct plugin_api {
246 bool (*settings_parseline)(char* line, char** name, char** value); 253 bool (*settings_parseline)(char* line, char** name, char** value);
247#ifndef SIMULATOR 254#ifndef SIMULATOR
248 void (*ata_sleep)(void); 255 void (*ata_sleep)(void);
256 bool (*ata_disk_is_active)(void);
249#endif 257#endif
250 258
251 /* dir */ 259 /* dir */
@@ -275,6 +283,18 @@ struct plugin_api {
275 void (*timer_unregister)(void); 283 void (*timer_unregister)(void);
276 bool (*timer_set_period)(long count); 284 bool (*timer_set_period)(long count);
277#endif 285#endif
286 void (*queue_init)(struct event_queue *q);
287 void (*queue_delete)(struct event_queue *q);
288 void (*queue_post)(struct event_queue *q, long id, void *data);
289 void (*queue_wait_w_tmo)(struct event_queue *q, struct event *ev,
290 int ticks);
291 void (*usb_acknowledge)(long id);
292#ifdef RB_PROFILE
293 void (*profile_thread)(void);
294 void (*profstop)(void);
295 void (*profile_func_enter)(void *this_fn, void *call_site);
296 void (*profile_func_exit)(void *this_fn, void *call_site);
297#endif
278 298
279 /* strings and memory */ 299 /* strings and memory */
280 int (*snprintf)(char *buf, size_t size, const char *fmt, ...); 300 int (*snprintf)(char *buf, size_t size, const char *fmt, ...);
@@ -288,6 +308,7 @@ struct plugin_api {
288 int (*strncasecmp)(const char *s1, const char *s2, size_t n); 308 int (*strncasecmp)(const char *s1, const char *s2, size_t n);
289 void* (*memset)(void *dst, int c, size_t length); 309 void* (*memset)(void *dst, int c, size_t length);
290 void* (*memcpy)(void *out, const void *in, size_t n); 310 void* (*memcpy)(void *out, const void *in, size_t n);
311 void* (*memmove)(void *out, const void *in, size_t n);
291 const unsigned char *_ctype_; 312 const unsigned char *_ctype_;
292 int (*atoi)(const char *str); 313 int (*atoi)(const char *str);
293 char *(*strchr)(const char *s, int c); 314 char *(*strchr)(const char *s, int c);
@@ -315,7 +336,8 @@ struct plugin_api {
315 void (*bitswap)(unsigned char *data, int length); 336 void (*bitswap)(unsigned char *data, int length);
316#endif 337#endif
317#if CONFIG_CODEC == SWCODEC 338#if CONFIG_CODEC == SWCODEC
318 void (*pcm_play_data)(void (*get_more)(unsigned char** start, long*size)); 339 void (*pcm_play_data)(void (*get_more)(unsigned char** start, size_t*size),
340 unsigned char* start, size_t size);
319 void (*pcm_play_stop)(void); 341 void (*pcm_play_stop)(void);
320 void (*pcm_set_frequency)(unsigned int frequency); 342 void (*pcm_set_frequency)(unsigned int frequency);
321 bool (*pcm_is_playing)(void); 343 bool (*pcm_is_playing)(void);
@@ -384,6 +406,23 @@ struct plugin_api {
384 void (*menu_insert)(int menu, int position, char *desc, bool (*function) (void)); 406 void (*menu_insert)(int menu, int position, char *desc, bool (*function) (void));
385 void (*menu_set_cursor)(int menu, int position); 407 void (*menu_set_cursor)(int menu, int position);
386 408
409 /* power */
410 int (*battery_level)(void);
411 bool (*battery_level_safe)(void);
412 int (*battery_time)(void);
413#ifndef SIMULATOR
414 unsigned int (*battery_voltage)(void);
415#endif
416#ifdef HAVE_CHARGING
417 bool (*charger_inserted)(void);
418# ifdef HAVE_CHARGE_STATE
419 bool (*charging_state)(void);
420# endif
421#endif
422#ifdef HAVE_USB_POWER
423 bool (*usb_powered)(void);
424#endif
425
387 /* misc */ 426 /* misc */
388 void (*srand)(unsigned int seed); 427 void (*srand)(unsigned int seed);
389 int (*rand)(void); 428 int (*rand)(void);
@@ -406,13 +445,12 @@ struct plugin_api {
406 int (*count_mp3_frames)(int fd, int startpos, int filesize, 445 int (*count_mp3_frames)(int fd, int startpos, int filesize,
407 void (*progressfunc)(int)); 446 void (*progressfunc)(int));
408 int (*create_xing_header)(int fd, long startpos, long filesize, 447 int (*create_xing_header)(int fd, long startpos, long filesize,
409 unsigned char *buf, unsigned long num_frames, 448 unsigned char *buf, unsigned long num_frames,
410 unsigned long rec_time, unsigned long header_template, 449 unsigned long rec_time, unsigned long header_template,
411 void (*progressfunc)(int), bool generate_toc); 450 void (*progressfunc)(int), bool generate_toc);
412 unsigned long (*find_next_frame)(int fd, long *offset, 451 unsigned long (*find_next_frame)(int fd, long *offset,
413 long max_offset, unsigned long last_header); 452 long max_offset, unsigned long last_header);
414 int (*battery_level)(void); 453
415 bool (*battery_level_safe)(void);
416#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) 454#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
417 unsigned short (*peak_meter_scale_value)(unsigned short val, 455 unsigned short (*peak_meter_scale_value)(unsigned short val,
418 int meterwidth); 456 int meterwidth);
@@ -429,40 +467,6 @@ struct plugin_api {
429 /* new stuff at the end, sort into place next time 467 /* new stuff at the end, sort into place next time
430 the API gets incompatible */ 468 the API gets incompatible */
431 469
432#ifdef RB_PROFILE
433 void (*profile_thread)(void);
434 void (*profstop)(void);
435 void (*profile_func_enter)(void *this_fn, void *call_site);
436 void (*profile_func_exit)(void *this_fn, void *call_site);
437#endif
438 int (*battery_time)(void);
439#ifndef SIMULATOR
440 bool (*ata_disk_is_active)(void);
441 unsigned int (*battery_voltage)(void);
442#endif
443 void (*queue_init)(struct event_queue *q);
444 void (*queue_delete)(struct event_queue *q);
445 void (*queue_post)(struct event_queue *q, long id, void *data);
446 void (*queue_wait_w_tmo)(struct event_queue *q, struct event *ev, int ticks);
447 void (*usb_acknowledge)(long id);
448#if LCD_DEPTH == 16
449 void (*lcd_bitmap_transparent_part)(const fb_data *src, int src_x, int src_y,
450 int stride, int x, int y, int width, int height);
451 void (*lcd_bitmap_transparent)(const fb_data *src, int x, int y,
452 int width, int height);
453#endif
454 void* (*memmove)(void *out, const void *in, size_t n);
455
456#ifdef HAVE_CHARGING
457 bool (*charger_inserted)(void);
458# ifdef HAVE_CHARGE_STATE
459 bool (*charging_state)(void);
460# endif
461#endif
462#ifdef HAVE_USB_POWER
463 bool (*usb_powered)(void);
464#endif
465
466}; 470};
467 471
468/* plugin header */ 472/* plugin header */
diff --git a/apps/plugins/metronome.c b/apps/plugins/metronome.c
index 2f897d72a2..ac4a990f61 100644
--- a/apps/plugins/metronome.c
+++ b/apps/plugins/metronome.c
@@ -736,18 +736,8 @@ void prepare_tock(void)
736 } 736 }
737} 737}
738 738
739void callback_pcm(unsigned char** start, long* size)
740{
741 if(sound_active) {
742 *start = (unsigned char *)sndbuf;
743 *size = sizeof(sndbuf);
744 sound_active = false;
745 }
746}
747
748void play_tock(void) { 739void play_tock(void) {
749 sound_active = true; 740 rb->pcm_play_data(NULL,(unsigned char *)sndbuf,sizeof(sndbuf));
750 rb->pcm_play_data(callback_pcm);
751 tock++; 741 tock++;
752} 742}
753 743
diff --git a/apps/plugins/rockboy/rbsound.c b/apps/plugins/rockboy/rbsound.c
index 3eebea8bef..6371212ca8 100644
--- a/apps/plugins/rockboy/rbsound.c
+++ b/apps/plugins/rockboy/rbsound.c
@@ -35,7 +35,7 @@ static unsigned short *gmbuf;
35 35
36static bool newly_started; 36static bool newly_started;
37 37
38void get_more(unsigned char** start, long* size) 38void get_more(unsigned char** start, size_t* size)
39{ 39{
40#ifdef ONEBUF 40#ifdef ONEBUF
41 doneplay=1; 41 doneplay=1;
@@ -108,7 +108,7 @@ int pcm_submit(void)
108 108
109 if(newly_started) 109 if(newly_started)
110 { 110 {
111 rb->pcm_play_data(&get_more); 111 rb->pcm_play_data(&get_more,NULL,0);
112 newly_started = false; 112 newly_started = false;
113 } 113 }
114 114
diff --git a/firmware/export/pcm_playback.h b/firmware/export/pcm_playback.h
index 5b61beb34d..a4cd93969b 100644
--- a/firmware/export/pcm_playback.h
+++ b/firmware/export/pcm_playback.h
@@ -23,10 +23,11 @@ void pcm_init(void);
23void pcm_set_frequency(unsigned int frequency); 23void pcm_set_frequency(unsigned int frequency);
24 24
25/* This is for playing "raw" PCM data */ 25/* This is for playing "raw" PCM data */
26void pcm_play_data(void (*get_more)(unsigned char** start, long* size)); 26void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size),
27 unsigned char* start, size_t size);
27 28
28void pcm_calculate_peaks(int *left, int *right); 29void pcm_calculate_peaks(int *left, int *right);
29long pcm_get_bytes_waiting(void); 30size_t pcm_get_bytes_waiting(void);
30 31
31void pcm_play_stop(void); 32void pcm_play_stop(void);
32void pcm_mute(bool mute); 33void pcm_mute(bool mute);
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c
index 0d9af14f2c..d3e9f3eca5 100644
--- a/firmware/pcm_playback.c
+++ b/firmware/pcm_playback.c
@@ -61,11 +61,11 @@ static bool pcm_playing;
61static bool pcm_paused; 61static bool pcm_paused;
62static int pcm_freq = 0x6; /* 44.1 is default */ 62static int pcm_freq = 0x6; /* 44.1 is default */
63 63
64static unsigned char *next_start IDATA_ATTR; 64size_t next_size IBSS_ATTR;
65static long next_size IDATA_ATTR; 65unsigned char *next_start IBSS_ATTR;
66 66
67/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ 67/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
68static void dma_start(const void *addr, long size) 68static void dma_start(const void *addr, size_t size)
69{ 69{
70 pcm_playing = true; 70 pcm_playing = true;
71 71
@@ -104,8 +104,6 @@ static void dma_stop(void)
104 EBU1CONFIG = IIS_RESET | EBU_DEFPARM; 104 EBU1CONFIG = IIS_RESET | EBU_DEFPARM;
105#endif 105#endif
106 106
107 next_start = NULL;
108 next_size = 0;
109 pcm_paused = false; 107 pcm_paused = false;
110} 108}
111 109
@@ -131,23 +129,27 @@ void pcm_set_frequency(unsigned int frequency)
131} 129}
132 130
133/* the registered callback function to ask for more mp3 data */ 131/* the registered callback function to ask for more mp3 data */
134static void (*callback_for_more)(unsigned char**, long*) IDATA_ATTR = NULL; 132static void (*callback_for_more)(unsigned char**, size_t*) IDATA_ATTR = NULL;
135 133
136void pcm_play_data(void (*get_more)(unsigned char** start, long* size)) 134void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size),
135 unsigned char* start, size_t size)
137{ 136{
138 unsigned char *start;
139 long size;
140
141 callback_for_more = get_more; 137 callback_for_more = get_more;
142 138
143 get_more((unsigned char **)&start, (long *)&size); 139 if (!(start && size))
144 get_more(&next_start, &next_size); 140 {
145 dma_start(start, size); 141 if (get_more)
142 get_more(&start, &size);
143 else
144 return;
145 }
146 if (start && size)
147 dma_start(start, size);
146} 148}
147 149
148long pcm_get_bytes_waiting(void) 150size_t pcm_get_bytes_waiting(void)
149{ 151{
150 return next_size + (BCR0 & 0xffffff); 152 return (BCR0 & 0xffffff);
151} 153}
152 154
153void pcm_mute(bool mute) 155void pcm_mute(bool mute)
@@ -169,19 +171,32 @@ void pcm_play_pause(bool play)
169 if (!pcm_playing) 171 if (!pcm_playing)
170 return ; 172 return ;
171 173
172 if(pcm_paused && play && next_size) 174 if(pcm_paused && play)
173 { 175 {
174 logf("unpause"); 176 if (BCR0 & 0xffffff)
175 /* Reset chunk size so dma has enough data to fill the fifo. */ 177 {
176 /* This shouldn't be needed anymore. */ 178 logf("unpause");
177 //SAR0 = (unsigned long)next_start; 179 /* Enable the FIFO and force one write to it */
178 //BCR0 = next_size; 180 IIS2CONFIG = IIS_DEFPARM(pcm_freq);
179 /* Enable the FIFO and force one write to it */
180 IIS2CONFIG = IIS_DEFPARM(pcm_freq);
181#ifdef HAVE_SPDIF_OUT 181#ifdef HAVE_SPDIF_OUT
182 EBU1CONFIG = EBU_DEFPARM; 182 EBU1CONFIG = EBU_DEFPARM;
183#endif 183#endif
184 DCR0 |= DMA_EEXT | DMA_START; 184 DCR0 |= DMA_EEXT | DMA_START;
185 }
186 else
187 {
188 logf("unpause, no data waiting");
189 void (*get_more)(unsigned char**, size_t*) = callback_for_more;
190 if (get_more)
191 get_more(&next_start, &next_size);
192 if (next_start && next_size)
193 dma_start(next_start, next_size);
194 else
195 {
196 dma_stop();
197 logf("unpause attempted, no data");
198 }
199 }
185 } 200 }
186 else if(!pcm_paused && !play) 201 else if(!pcm_paused && !play)
187 { 202 {
@@ -224,13 +239,22 @@ void DMA0(void)
224 } 239 }
225 else 240 else
226 { 241 {
242 {
243 void (*get_more)(unsigned char**, size_t*) = callback_for_more;
244 if (get_more)
245 get_more(&next_start, &next_size);
246 else
247 {
248 next_size = 0;
249 next_start = NULL;
250 }
251 }
227 if(next_size) 252 if(next_size)
228 { 253 {
229 SAR0 = (unsigned long)next_start; /* Source address */ 254 SAR0 = (unsigned long)next_start; /* Source address */
230 BCR0 = next_size; /* Bytes to transfer */ 255 BCR0 = next_size; /* Bytes to transfer */
231 DCR0 |= DMA_EEXT; 256 DCR0 |= DMA_EEXT;
232 if (callback_for_more) 257
233 callback_for_more(&next_start, &next_size);
234 } 258 }
235 else 259 else
236 { 260 {
@@ -301,9 +325,9 @@ static bool pcm_paused;
301static int pcm_freq = 0x6; /* 44.1 is default */ 325static int pcm_freq = 0x6; /* 44.1 is default */
302 326
303/* the registered callback function to ask for more mp3 data */ 327/* the registered callback function to ask for more mp3 data */
304static void (*callback_for_more)(unsigned char**, long*) = NULL; 328static void (*callback_for_more)(unsigned char**, size_t*) = NULL;
305static unsigned short *p IBSS_ATTR; 329static unsigned short *p IBSS_ATTR;
306static long size IBSS_ATTR; 330static size_t size IBSS_ATTR;
307 331
308/* Stops the DMA transfer and interrupt */ 332/* Stops the DMA transfer and interrupt */
309static void dma_stop(void) 333static void dma_stop(void)
@@ -353,7 +377,7 @@ void fiq(void)
353 IISCONFIG &= ~0x2; 377 IISCONFIG &= ~0x2;
354 378
355 if ((size==0) && (callback_for_more)) { 379 if ((size==0) && (callback_for_more)) {
356 callback_for_more((unsigned char **)&p, (long *)&size); 380 callback_for_more((unsigned char **)&p, &size);
357 } 381 }
358 382
359 while (size > 0) { 383 while (size > 0) {
@@ -368,20 +392,22 @@ void fiq(void)
368 size-=4; 392 size-=4;
369 393
370 if ((size==0) && (callback_for_more)) { 394 if ((size==0) && (callback_for_more)) {
371 callback_for_more((unsigned char **)&p, (long *)&size); 395 callback_for_more((unsigned char **)&p, &size);
372 } 396 }
373 } 397 }
374} 398}
375 399
376void pcm_play_data(void (*get_more)(unsigned char** start, long* size)) 400void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size),
401 unsigned char* _p, size_t _size)
377{ 402{
378 int free_count; 403 size_t free_count;
379 404
380 callback_for_more = get_more; 405 callback_for_more = get_more;
381 406
382 if (size > 0) { return; } 407 if (size > 0) { return; }
383 408
384 get_more((unsigned char **)&p, (long *)&size); 409 p = (unsigned short *)_p;
410 size = _size;
385 411
386 /* setup I2S interrupt for FIQ */ 412 /* setup I2S interrupt for FIQ */
387 outl(inl(0x6000402c) | I2S_MASK, 0x6000402c); 413 outl(inl(0x6000402c) | I2S_MASK, 0x6000402c);
@@ -406,7 +432,7 @@ void pcm_play_data(void (*get_more)(unsigned char** start, long* size))
406 size-=4; 432 size-=4;
407 433
408 if ((size==0) && (get_more)) { 434 if ((size==0) && (get_more)) {
409 get_more((unsigned char **)&p, (long *)&size); 435 get_more((unsigned char **)&p, &size);
410 } 436 }
411 } 437 }
412} 438}
@@ -448,7 +474,7 @@ bool pcm_is_playing(void)
448 return pcm_playing; 474 return pcm_playing;
449} 475}
450 476
451long pcm_get_bytes_waiting(void) 477size_t pcm_get_bytes_waiting(void)
452{ 478{
453 return size; 479 return size;
454} 480}
@@ -608,9 +634,12 @@ void pcm_set_frequency(unsigned int frequency)
608 (void)frequency; 634 (void)frequency;
609} 635}
610 636
611void pcm_play_data(void (*get_more)(unsigned char** start, long* size)) 637void pcm_play_data(void (*get_more)(unsigned char** start, long* size),
638 unsigned char* start, long size)
612{ 639{
613 (void)get_more; 640 (void)get_more;
641 (void)start;
642 (void)size;
614} 643}
615 644
616void pcm_play_stop(void) 645void pcm_play_stop(void)