1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Brandon Low 2006-02-07 20:38:55 +00:00
parent 566ce5f951
commit 413da2a3d9
13 changed files with 667 additions and 531 deletions

View file

@ -128,8 +128,8 @@ struct codec_api {
void* (*get_codec_memory)(long *size); void* (*get_codec_memory)(long *size);
/* Insert PCM data into audio buffer for playback. Playback will start /* Insert PCM data into audio buffer for playback. Playback will start
automatically. */ automatically. */
bool (*pcmbuf_insert)(char *data, long length); bool (*pcmbuf_insert)(const char *data, size_t length);
bool (*pcmbuf_insert_split)(void *ch1, void *ch2, long length); bool (*pcmbuf_insert_split)(const void *ch1, const void *ch2, size_t length);
/* Set song position in WPS (value in ms). */ /* Set song position in WPS (value in ms). */
void (*set_elapsed)(unsigned int value); void (*set_elapsed)(unsigned int value);

View file

@ -209,7 +209,7 @@ extern int filebuflen;
extern int filebufused; extern int filebufused;
extern int track_count; extern int track_count;
static int ticks, boost_ticks; static unsigned int ticks, boost_ticks;
void dbg_audio_task(void) void dbg_audio_task(void)
{ {
@ -225,7 +225,8 @@ bool dbg_audio_thread(void)
int button; int button;
int line; int line;
bool done = false; bool done = false;
int bufsize = pcmbuf_get_bufsize(); size_t bufsize = pcmbuf_get_bufsize();
int pcmbufdescs = pcmbuf_descs();
ticks = boost_ticks = 0; ticks = boost_ticks = 0;
@ -239,6 +240,12 @@ bool dbg_audio_thread(void)
button = button_get_w_tmo(HZ/5); button = button_get_w_tmo(HZ/5);
switch(button) switch(button)
{ {
case SETTINGS_NEXT:
audio_next();
break;
case SETTINGS_PREV:
audio_prev();
break;
case SETTINGS_CANCEL: case SETTINGS_CANCEL:
done = true; done = true;
break; break;
@ -248,8 +255,8 @@ bool dbg_audio_thread(void)
lcd_clear_display(); lcd_clear_display();
snprintf(buf, sizeof(buf), "pcm: %d/%d", snprintf(buf, sizeof(buf), "pcm: %7ld/%7ld",
bufsize-(int)audiobuffer_free, bufsize); bufsize-audiobuffer_free, bufsize);
lcd_puts(0, line++, buf); lcd_puts(0, line++, buf);
/* Playable space left */ /* Playable space left */
@ -257,7 +264,7 @@ bool dbg_audio_thread(void)
bufsize-audiobuffer_free, HORIZONTAL); bufsize-audiobuffer_free, HORIZONTAL);
line++; line++;
snprintf(buf, sizeof(buf), "codec: %d/%d", filebufused, filebuflen); snprintf(buf, sizeof(buf), "codec: %8d/%8d", filebufused, filebuflen);
lcd_puts(0, line++, buf); lcd_puts(0, line++, buf);
/* Playable space left */ /* Playable space left */
@ -265,17 +272,21 @@ bool dbg_audio_thread(void)
filebufused, HORIZONTAL); filebufused, HORIZONTAL);
line++; line++;
snprintf(buf, sizeof(buf), "track count: %d", track_count); snprintf(buf, sizeof(buf), "track count: %2d", track_count);
lcd_puts(0, line++, buf); lcd_puts(0, line++, buf);
snprintf(buf, sizeof(buf), "cpu freq: %dMHz", snprintf(buf, sizeof(buf), "cpu freq: %3dMHz",
(int)((FREQ + 500000) / 1000000)); (int)((FREQ + 500000) / 1000000));
lcd_puts(0, line++, buf); lcd_puts(0, line++, buf);
snprintf(buf, sizeof(buf), "boost ratio: %d%%", snprintf(buf, sizeof(buf), "boost ratio: %3d%%",
boost_ticks * 100 / ticks); boost_ticks * 100 / ticks);
lcd_puts(0, line++, buf); lcd_puts(0, line++, buf);
snprintf(buf, sizeof(buf), "pcmbufdesc: %2d/%2d",
pcmbuf_used_descs(), pcmbufdescs);
lcd_puts(0, line++, buf);
lcd_update(); lcd_update();
} }

View file

@ -213,7 +213,7 @@ void sound_set_pitch(int permille)
* consume. Note that for mono, dst[0] equals dst[1], as there is no point * consume. Note that for mono, dst[0] equals dst[1], as there is no point
* in processing the same data twice. * in processing the same data twice.
*/ */
static int convert_to_internal(char* src[], int count, long* dst[]) static int convert_to_internal(const char* src[], int count, long* dst[])
{ {
count = MIN(SAMPLE_BUF_SIZE / 2, count); count = MIN(SAMPLE_BUF_SIZE / 2, count);
@ -773,7 +773,7 @@ static void write_samples(short* dst, long* src[], int count)
* pointers, one for each audio channel. Returns number of bytes written to * pointers, one for each audio channel. Returns number of bytes written to
* dest. * dest.
*/ */
long dsp_process(char* dst, char* src[], long size) long dsp_process(char* dst, const char* src[], long size)
{ {
long* tmp[2]; long* tmp[2];
long written = 0; long written = 0;

View file

@ -47,7 +47,7 @@ enum {
DSP_CROSSFEED DSP_CROSSFEED
}; };
long dsp_process(char *dest, char *src[], long size); long dsp_process(char *dest, const char *src[], long size);
long dsp_input_size(long size); long dsp_input_size(long size);
long dsp_output_size(long size); long dsp_output_size(long size);
int dsp_stereo_mode(void); int dsp_stereo_mode(void);

File diff suppressed because it is too large Load diff

View file

@ -19,36 +19,48 @@
#ifndef PCMBUF_H #ifndef PCMBUF_H
#define PCMBUF_H #define PCMBUF_H
/* Guard buffer for crossfader when dsp is enabled. */ #define PCMBUF_TARGET_CHUNK 32768 /* This is the target fill size of chunks
#define PCMBUF_GUARD 32768 on the pcm buffer */
#define PCMBUF_MINAVG_CHUNK 24576 /* This is the minimum average size of
chunks on the pcm buffer (or we run out
of buffer descriptors, which is
non-fatal) */
#define PCMBUF_MIN_CHUNK 4096 /* We try to never feed a chunk smaller than
this to the DMA */
#define PCMBUF_FADE_CHUNK 8192 /* This is the maximum size of one packet
for mixing (crossfade or voice) */
void pcmbuf_init(long bufsize); /* Returns true if the buffer needs to change size */
long pcmbuf_get_bufsize(void); bool pcmbuf_is_same_size(size_t bufsize);
void pcmbuf_init(size_t bufsize);
/* Size in bytes used by the pcmbuffer */
size_t pcmbuf_get_bufsize(void);
size_t get_pcmbuf_descsize(void);
void pcmbuf_pause(bool pause);
void pcmbuf_play_stop(void); void pcmbuf_play_stop(void);
bool pcmbuf_is_crossfade_active(void); bool pcmbuf_is_crossfade_active(void);
/* These functions are for playing chained buffers of PCM data */ /* These functions are for playing chained buffers of PCM data */
bool pcmbuf_add_chunk(void *addr, int size, void (*callback)(void)); #if defined(HAVE_ADJUSTABLE_CPU_FREQ) && !defined(SIMULATOR)
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
void pcmbuf_boost(bool state); void pcmbuf_boost(bool state);
void pcmbuf_set_boost_mode(bool state); void pcmbuf_set_boost_mode(bool state);
#else #else
#define pcmbuf_boost(state) do { } while(0) #define pcmbuf_boost(state) do { } while(0)
#define pcmbuf_set_boost_mode(state) do { } while(0) #define pcmbuf_set_boost_mode(state) do { } while(0)
#endif #endif
bool pcmbuf_is_lowdata(void); bool pcmbuf_is_lowdata(void);
void pcmbuf_flush_audio(void);
void pcmbuf_play_start(void); void pcmbuf_play_start(void);
bool pcmbuf_crossfade_init(bool manual_skip); bool pcmbuf_crossfade_init(bool manual_skip);
void pcmbuf_add_event(void (*event_handler)(void)); void pcmbuf_set_event_handler(void (*callback)(void));
void pcmbuf_set_position_callback(void (*callback)(int size)); void pcmbuf_set_position_callback(void (*callback)(size_t size));
unsigned int pcmbuf_get_latency(void); unsigned int pcmbuf_get_latency(void);
void pcmbuf_set_low_latency(bool state); void pcmbuf_set_low_latency(bool state);
bool pcmbuf_insert_buffer(char *buf, long length); bool pcmbuf_insert_buffer(const char *buf, size_t length);
void pcmbuf_flush_buffer(long length); void pcmbuf_write_complete(size_t length);
void* pcmbuf_request_buffer(long length, long *realsize); void pcmbuf_write_voice(size_t length);
void* pcmbuf_request_buffer(size_t length, size_t *realsize);
void* pcmbuf_request_voice_buffer(size_t length, size_t *realsize, bool mix);
bool pcmbuf_is_crossfade_enabled(void); bool pcmbuf_is_crossfade_enabled(void);
void pcmbuf_crossfade_enable(bool on_off); void pcmbuf_crossfade_enable(bool on_off);
@ -56,6 +68,9 @@ int pcmbuf_usage(void);
int pcmbuf_mix_usage(void); int pcmbuf_mix_usage(void);
void pcmbuf_beep(int frequency, int duration, int amplitude); void pcmbuf_beep(int frequency, int duration, int amplitude);
void pcmbuf_reset_mixpos(void); void pcmbuf_reset_mixpos(void);
void pcmbuf_mix(char *buf, long length); void pcmbuf_mix(char *buf, size_t length);
int pcmbuf_used_descs(void);
int pcmbuf_descs(void);
#endif #endif

View file

@ -216,6 +216,13 @@ static bool v1first = false;
static void mp3_set_elapsed(struct mp3entry* id3); static void mp3_set_elapsed(struct mp3entry* id3);
int mp3_get_file_pos(void); int mp3_get_file_pos(void);
#ifdef TIME_CODEC
bool is_filling(void)
{
return filling;
}
#endif
static void do_swap(int idx_old, int idx_new) static void do_swap(int idx_old, int idx_new)
{ {
#ifndef SIMULATOR #ifndef SIMULATOR
@ -287,13 +294,13 @@ static void voice_boost_cpu(bool state)
#define voice_boost_cpu(state) do { } while(0) #define voice_boost_cpu(state) do { } while(0)
#endif #endif
bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2, bool codec_pcmbuf_insert_split_callback(const void *ch1, const void *ch2,
long length) size_t length)
{ {
char* src[2]; const char* src[2];
char *dest; char *dest;
long input_size; long input_size;
long output_size; size_t output_size;
src[0] = ch1; src[0] = ch1;
src[1] = ch2; src[1] = ch2;
@ -311,47 +318,50 @@ bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2,
} }
while (length > 0) { while (length > 0) {
long est_output_size = dsp_output_size(length);
/* This will prevent old audio from playing when skipping tracks. */ /* This will prevent old audio from playing when skipping tracks. */
if ((ci.reload_codec || ci.stop_codec) && if (current_codec == CODEC_IDX_VOICE) {
current_codec != CODEC_IDX_VOICE) while ((dest = pcmbuf_request_voice_buffer(est_output_size,
return true; &output_size, audio_codec_loaded)) == NULL)
sleep(1);
while ((dest = pcmbuf_request_buffer(dsp_output_size(length), }
&output_size)) == NULL) { else
sleep(1); {
if ((ci.reload_codec || ci.stop_codec) && if (ci.reload_codec || ci.stop_codec)
current_codec != CODEC_IDX_VOICE)
return true; return true;
while ((dest = pcmbuf_request_buffer(est_output_size,
&output_size)) == NULL) {
sleep(1);
if (ci.reload_codec || ci.stop_codec)
return true;
}
} }
/* Get the real input_size for output_size bytes, guarding /* Get the real input_size for output_size bytes, guarding
* against resampling buffer overflows. */ * against resampling buffer overflows. */
input_size = dsp_input_size(output_size); input_size = dsp_input_size(output_size);
if (input_size > length) {
if (input_size <= 0) {
DEBUGF("Warning: dsp_input_size(%ld=dsp_output_size(%ld))=%ld <= 0\n",
output_size, length, input_size);
/* this cannot happen */
break;
}
if ((size_t)input_size > length) {
DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld > %ld\n", DEBUGF("Error: dsp_input_size(%ld=dsp_output_size(%ld))=%ld > %ld\n",
output_size, length, input_size, length); output_size, length, input_size, length);
input_size = length; input_size = length;
} }
if (input_size <= 0) {
pcmbuf_flush_buffer(0);
DEBUGF("Warning: dsp_input_size(%ld=dsp_output_size(%ld))=%ld <= 0\n",
output_size, length, input_size);
/* should we really continue, or should we break?
* We should probably continue because calling
* pcmbuf_flush_buffer(0) will wrap the buffer if it was fully
* filled and so next call to pcmbuf_request_buffer should give
* the requested output_size. */
continue;
}
output_size = dsp_process(dest, src, input_size); output_size = dsp_process(dest, src, input_size);
/* Hotswap between audio and voice codecs as necessary. */ /* Hotswap between audio and voice codecs as necessary. */
switch (current_codec) switch (current_codec)
{ {
case CODEC_IDX_AUDIO: case CODEC_IDX_AUDIO:
pcmbuf_flush_buffer(output_size); pcmbuf_write_complete(output_size);
if (voice_is_playing && pcmbuf_usage() > 30 if (voice_is_playing && pcmbuf_usage() > 30
&& pcmbuf_mix_usage() < 20) && pcmbuf_mix_usage() < 20)
{ {
@ -368,7 +378,7 @@ bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2,
|| pcmbuf_mix_usage() > 70) || pcmbuf_mix_usage() > 70)
swap_codec(); swap_codec();
} else { } else {
pcmbuf_flush_buffer(output_size); pcmbuf_write_complete(output_size);
} }
break ; break ;
} }
@ -379,7 +389,7 @@ bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2,
return true; return true;
} }
bool codec_pcmbuf_insert_callback(char *buf, long length) bool codec_pcmbuf_insert_callback(const char *buf, size_t length)
{ {
/* TODO: The audiobuffer API should probably be updated, and be based on /* TODO: The audiobuffer API should probably be updated, and be based on
* pcmbuf_insert_split(). * pcmbuf_insert_split().
@ -405,9 +415,10 @@ void* get_codec_memory_callback(long *size)
return &audiobuf[0]; return &audiobuf[0];
} }
static void pcmbuf_position_callback(int size) ICODE_ATTR; static void pcmbuf_position_callback(size_t size) ICODE_ATTR;
static void pcmbuf_position_callback(int size) { static void pcmbuf_position_callback(size_t size) {
unsigned int time = size * 1000 / 4 / 44100 + prev_ti->id3.elapsed; unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
prev_ti->id3.elapsed;
if (time >= prev_ti->id3.length) { if (time >= prev_ti->id3.length) {
pcmbuf_set_position_callback(NULL); pcmbuf_set_position_callback(NULL);
prev_ti->id3.elapsed = prev_ti->id3.length; prev_ti->id3.elapsed = prev_ti->id3.length;
@ -785,6 +796,13 @@ static void codec_track_changed(void)
queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0); queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
} }
static void pcmbuf_track_changed_callback(void)
{
track_changed = true;
pcmbuf_set_position_callback(NULL);
queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
}
/* Give codecs or file buffering the right amount of processing time /* Give codecs or file buffering the right amount of processing time
to prevent pcm audio buffer from going empty. */ to prevent pcm audio buffer from going empty. */
static void yield_codecs(void) static void yield_codecs(void)
@ -1529,7 +1547,7 @@ static void audio_update_trackinfo(void)
/* Gapless playback. */ /* Gapless playback. */
else else
{ {
pcmbuf_add_event(codec_track_changed); pcmbuf_set_event_handler(pcmbuf_track_changed_callback);
} }
} }
@ -1675,15 +1693,17 @@ bool codec_request_next_track_callback(void)
the core has been requested the codec to be terminated. */ the core has been requested the codec to be terminated. */
return !ci_voice.stop_codec && queue_empty(&voice_codec_queue); return !ci_voice.stop_codec && queue_empty(&voice_codec_queue);
} }
#ifdef AB_REPEAT_ENABLE
ab_end_of_track_report();
#endif
pcmbuf_set_position_callback(pcmbuf_position_callback);
if (ci.stop_codec || !playing) if (ci.stop_codec || !playing)
return false; return false;
#ifdef AB_REPEAT_ENABLE
ab_end_of_track_report();
#endif
if (!new_track)
pcmbuf_set_position_callback(pcmbuf_position_callback);
logf("Request new track"); logf("Request new track");
/* Advance to next track. */ /* Advance to next track. */
@ -1856,15 +1876,13 @@ void audio_thread(void)
case Q_AUDIO_PAUSE: case Q_AUDIO_PAUSE:
logf("audio_pause"); logf("audio_pause");
pcm_mute(true); pcmbuf_pause(true);
pcm_play_pause(false);
paused = true; paused = true;
break ; break ;
case Q_AUDIO_RESUME: case Q_AUDIO_RESUME:
logf("audio_resume"); logf("audio_resume");
pcm_play_pause(true); pcmbuf_pause(false);
pcm_mute(false);
paused = false; paused = false;
break ; break ;
@ -2022,8 +2040,9 @@ void codec_thread(void)
static void reset_buffer(void) static void reset_buffer(void)
{ {
filebuf = (char *)&audiobuf[MALLOC_BUFSIZE]; filebuf = (char *)&audiobuf[MALLOC_BUFSIZE];
filebuflen = audiobufend - audiobuf - pcmbuf_get_bufsize() filebuflen = audiobufend - audiobuf - MALLOC_BUFSIZE - GUARD_BUFSIZE -
- PCMBUF_GUARD - MALLOC_BUFSIZE - GUARD_BUFSIZE; (pcmbuf_get_bufsize() + get_pcmbuf_descsize() + PCMBUF_FADE_CHUNK);
if (talk_get_bufsize() && voice_codec_loaded) if (talk_get_bufsize() && voice_codec_loaded)
{ {
@ -2422,7 +2441,7 @@ void audio_set_buffer_margin(int setting)
/* Set crossfade & PCM buffer length. */ /* Set crossfade & PCM buffer length. */
void audio_set_crossfade(int enable) void audio_set_crossfade(int enable)
{ {
long size; size_t size;
bool was_playing = playing; bool was_playing = playing;
int offset = 0; int offset = 0;
int seconds = 1; int seconds = 1;

View file

@ -123,6 +123,10 @@ static const struct plugin_api rockbox_api = {
lcd_get_background, lcd_get_background,
lcd_bitmap_part, lcd_bitmap_part,
lcd_bitmap, lcd_bitmap,
#endif
#if LCD_DEPTH == 16
lcd_bitmap_transparent_part,
lcd_bitmap_transparent,
#endif #endif
lcd_putsxy, lcd_putsxy,
lcd_puts_style, lcd_puts_style,
@ -198,6 +202,7 @@ static const struct plugin_api rockbox_api = {
settings_parseline, settings_parseline,
#ifndef SIMULATOR #ifndef SIMULATOR
ata_sleep, ata_sleep,
ata_disk_is_active,
#endif #endif
/* dir */ /* dir */
@ -225,6 +230,17 @@ static const struct plugin_api rockbox_api = {
timer_unregister, timer_unregister,
timer_set_period, timer_set_period,
#endif #endif
queue_init,
queue_delete,
queue_post,
queue_wait_w_tmo,
usb_acknowledge,
#ifdef RB_PROFILE
profile_thread,
profstop,
profile_func_enter,
profile_func_exit,
#endif
/* strings and memory */ /* strings and memory */
snprintf, snprintf,
@ -238,6 +254,7 @@ static const struct plugin_api rockbox_api = {
strncasecmp, strncasecmp,
memset, memset,
memcpy, memcpy,
memmove,
_ctype_, _ctype_,
atoi, atoi,
strchr, strchr,
@ -332,6 +349,23 @@ static const struct plugin_api rockbox_api = {
menu_insert, menu_insert,
menu_set_cursor, menu_set_cursor,
/* power */
battery_level,
battery_level_safe,
battery_time,
#ifndef SIMULATOR
battery_voltage,
#endif
#ifdef HAVE_CHARGING
charger_inserted,
# ifdef HAVE_CHARGE_STATE
charging_state,
# endif
#endif
#ifdef HAVE_USB_POWER
usb_powered,
#endif
/* misc */ /* misc */
srand, srand,
rand, rand,
@ -353,8 +387,6 @@ static const struct plugin_api rockbox_api = {
count_mp3_frames, count_mp3_frames,
create_xing_header, create_xing_header,
find_next_frame, find_next_frame,
battery_level,
battery_level_safe,
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
peak_meter_scale_value, peak_meter_scale_value,
peak_meter_set_use_dbfs, peak_meter_set_use_dbfs,
@ -368,37 +400,7 @@ static const struct plugin_api rockbox_api = {
/* new stuff at the end, sort into place next time /* new stuff at the end, sort into place next time
the API gets incompatible */ the API gets incompatible */
#ifdef RB_PROFILE
profile_thread,
profstop,
profile_func_enter,
profile_func_exit,
#endif
battery_time,
#ifndef SIMULATOR
ata_disk_is_active,
battery_voltage,
#endif
queue_init,
queue_delete,
queue_post,
queue_wait_w_tmo,
usb_acknowledge,
#if LCD_DEPTH == 16
lcd_bitmap_transparent_part,
lcd_bitmap_transparent,
#endif
memmove,
#ifdef HAVE_CHARGING
charger_inserted,
# ifdef HAVE_CHARGE_STATE
charging_state,
# endif
#endif
#ifdef HAVE_USB_POWER
usb_powered,
#endif
}; };
int plugin_load(const char* plugin, void* parameter) int plugin_load(const char* plugin, void* parameter)

View file

@ -97,12 +97,12 @@
#define PLUGIN_MAGIC 0x526F634B /* RocK */ #define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */ /* increase this every time the api struct changes */
#define PLUGIN_API_VERSION 6 #define PLUGIN_API_VERSION 7
/* update this to latest version if a change to the api struct breaks /* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */ new function which are "waiting" at the end of the function table) */
#define PLUGIN_MIN_API_VERSION 2 #define PLUGIN_MIN_API_VERSION 7
/* plugin return codes */ /* plugin return codes */
enum plugin_status { enum plugin_status {
@ -161,6 +161,13 @@ struct plugin_api {
int stride, int x, int y, int width, int height); int stride, int x, int y, int width, int height);
void (*lcd_bitmap)(const fb_data *src, int x, int y, int width, void (*lcd_bitmap)(const fb_data *src, int x, int y, int width,
int height); int height);
#endif
#if LCD_DEPTH == 16
void (*lcd_bitmap_transparent_part)(const fb_data *src,
int src_x, int src_y, int stride,
int x, int y, int width, int height);
void (*lcd_bitmap_transparent)(const fb_data *src, int x, int y,
int width, int height);
#endif #endif
void (*lcd_putsxy)(int x, int y, const unsigned char *string); void (*lcd_putsxy)(int x, int y, const unsigned char *string);
void (*lcd_puts_style)(int x, int y, const unsigned char *str, int style); void (*lcd_puts_style)(int x, int y, const unsigned char *str, int style);
@ -246,6 +253,7 @@ struct plugin_api {
bool (*settings_parseline)(char* line, char** name, char** value); bool (*settings_parseline)(char* line, char** name, char** value);
#ifndef SIMULATOR #ifndef SIMULATOR
void (*ata_sleep)(void); void (*ata_sleep)(void);
bool (*ata_disk_is_active)(void);
#endif #endif
/* dir */ /* dir */
@ -275,6 +283,18 @@ struct plugin_api {
void (*timer_unregister)(void); void (*timer_unregister)(void);
bool (*timer_set_period)(long count); bool (*timer_set_period)(long count);
#endif #endif
void (*queue_init)(struct event_queue *q);
void (*queue_delete)(struct event_queue *q);
void (*queue_post)(struct event_queue *q, long id, void *data);
void (*queue_wait_w_tmo)(struct event_queue *q, struct event *ev,
int ticks);
void (*usb_acknowledge)(long id);
#ifdef RB_PROFILE
void (*profile_thread)(void);
void (*profstop)(void);
void (*profile_func_enter)(void *this_fn, void *call_site);
void (*profile_func_exit)(void *this_fn, void *call_site);
#endif
/* strings and memory */ /* strings and memory */
int (*snprintf)(char *buf, size_t size, const char *fmt, ...); int (*snprintf)(char *buf, size_t size, const char *fmt, ...);
@ -288,6 +308,7 @@ struct plugin_api {
int (*strncasecmp)(const char *s1, const char *s2, size_t n); int (*strncasecmp)(const char *s1, const char *s2, size_t n);
void* (*memset)(void *dst, int c, size_t length); void* (*memset)(void *dst, int c, size_t length);
void* (*memcpy)(void *out, const void *in, size_t n); void* (*memcpy)(void *out, const void *in, size_t n);
void* (*memmove)(void *out, const void *in, size_t n);
const unsigned char *_ctype_; const unsigned char *_ctype_;
int (*atoi)(const char *str); int (*atoi)(const char *str);
char *(*strchr)(const char *s, int c); char *(*strchr)(const char *s, int c);
@ -315,7 +336,8 @@ struct plugin_api {
void (*bitswap)(unsigned char *data, int length); void (*bitswap)(unsigned char *data, int length);
#endif #endif
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
void (*pcm_play_data)(void (*get_more)(unsigned char** start, long*size)); void (*pcm_play_data)(void (*get_more)(unsigned char** start, size_t*size),
unsigned char* start, size_t size);
void (*pcm_play_stop)(void); void (*pcm_play_stop)(void);
void (*pcm_set_frequency)(unsigned int frequency); void (*pcm_set_frequency)(unsigned int frequency);
bool (*pcm_is_playing)(void); bool (*pcm_is_playing)(void);
@ -384,6 +406,23 @@ struct plugin_api {
void (*menu_insert)(int menu, int position, char *desc, bool (*function) (void)); void (*menu_insert)(int menu, int position, char *desc, bool (*function) (void));
void (*menu_set_cursor)(int menu, int position); void (*menu_set_cursor)(int menu, int position);
/* power */
int (*battery_level)(void);
bool (*battery_level_safe)(void);
int (*battery_time)(void);
#ifndef SIMULATOR
unsigned int (*battery_voltage)(void);
#endif
#ifdef HAVE_CHARGING
bool (*charger_inserted)(void);
# ifdef HAVE_CHARGE_STATE
bool (*charging_state)(void);
# endif
#endif
#ifdef HAVE_USB_POWER
bool (*usb_powered)(void);
#endif
/* misc */ /* misc */
void (*srand)(unsigned int seed); void (*srand)(unsigned int seed);
int (*rand)(void); int (*rand)(void);
@ -406,13 +445,12 @@ struct plugin_api {
int (*count_mp3_frames)(int fd, int startpos, int filesize, int (*count_mp3_frames)(int fd, int startpos, int filesize,
void (*progressfunc)(int)); void (*progressfunc)(int));
int (*create_xing_header)(int fd, long startpos, long filesize, int (*create_xing_header)(int fd, long startpos, long filesize,
unsigned char *buf, unsigned long num_frames, unsigned char *buf, unsigned long num_frames,
unsigned long rec_time, unsigned long header_template, unsigned long rec_time, unsigned long header_template,
void (*progressfunc)(int), bool generate_toc); void (*progressfunc)(int), bool generate_toc);
unsigned long (*find_next_frame)(int fd, long *offset, unsigned long (*find_next_frame)(int fd, long *offset,
long max_offset, unsigned long last_header); long max_offset, unsigned long last_header);
int (*battery_level)(void);
bool (*battery_level_safe)(void);
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
unsigned short (*peak_meter_scale_value)(unsigned short val, unsigned short (*peak_meter_scale_value)(unsigned short val,
int meterwidth); int meterwidth);
@ -429,40 +467,6 @@ struct plugin_api {
/* new stuff at the end, sort into place next time /* new stuff at the end, sort into place next time
the API gets incompatible */ the API gets incompatible */
#ifdef RB_PROFILE
void (*profile_thread)(void);
void (*profstop)(void);
void (*profile_func_enter)(void *this_fn, void *call_site);
void (*profile_func_exit)(void *this_fn, void *call_site);
#endif
int (*battery_time)(void);
#ifndef SIMULATOR
bool (*ata_disk_is_active)(void);
unsigned int (*battery_voltage)(void);
#endif
void (*queue_init)(struct event_queue *q);
void (*queue_delete)(struct event_queue *q);
void (*queue_post)(struct event_queue *q, long id, void *data);
void (*queue_wait_w_tmo)(struct event_queue *q, struct event *ev, int ticks);
void (*usb_acknowledge)(long id);
#if LCD_DEPTH == 16
void (*lcd_bitmap_transparent_part)(const fb_data *src, int src_x, int src_y,
int stride, int x, int y, int width, int height);
void (*lcd_bitmap_transparent)(const fb_data *src, int x, int y,
int width, int height);
#endif
void* (*memmove)(void *out, const void *in, size_t n);
#ifdef HAVE_CHARGING
bool (*charger_inserted)(void);
# ifdef HAVE_CHARGE_STATE
bool (*charging_state)(void);
# endif
#endif
#ifdef HAVE_USB_POWER
bool (*usb_powered)(void);
#endif
}; };
/* plugin header */ /* plugin header */

View file

@ -736,18 +736,8 @@ void prepare_tock(void)
} }
} }
void callback_pcm(unsigned char** start, long* size)
{
if(sound_active) {
*start = (unsigned char *)sndbuf;
*size = sizeof(sndbuf);
sound_active = false;
}
}
void play_tock(void) { void play_tock(void) {
sound_active = true; rb->pcm_play_data(NULL,(unsigned char *)sndbuf,sizeof(sndbuf));
rb->pcm_play_data(callback_pcm);
tock++; tock++;
} }

View file

@ -35,7 +35,7 @@ static unsigned short *gmbuf;
static bool newly_started; static bool newly_started;
void get_more(unsigned char** start, long* size) void get_more(unsigned char** start, size_t* size)
{ {
#ifdef ONEBUF #ifdef ONEBUF
doneplay=1; doneplay=1;
@ -108,7 +108,7 @@ int pcm_submit(void)
if(newly_started) if(newly_started)
{ {
rb->pcm_play_data(&get_more); rb->pcm_play_data(&get_more,NULL,0);
newly_started = false; newly_started = false;
} }

View file

@ -23,10 +23,11 @@ void pcm_init(void);
void pcm_set_frequency(unsigned int frequency); void pcm_set_frequency(unsigned int frequency);
/* This is for playing "raw" PCM data */ /* This is for playing "raw" PCM data */
void pcm_play_data(void (*get_more)(unsigned char** start, long* size)); void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size),
unsigned char* start, size_t size);
void pcm_calculate_peaks(int *left, int *right); void pcm_calculate_peaks(int *left, int *right);
long pcm_get_bytes_waiting(void); size_t pcm_get_bytes_waiting(void);
void pcm_play_stop(void); void pcm_play_stop(void);
void pcm_mute(bool mute); void pcm_mute(bool mute);

View file

@ -61,11 +61,11 @@ static bool pcm_playing;
static bool pcm_paused; static bool pcm_paused;
static int pcm_freq = 0x6; /* 44.1 is default */ static int pcm_freq = 0x6; /* 44.1 is default */
static unsigned char *next_start IDATA_ATTR; size_t next_size IBSS_ATTR;
static long next_size IDATA_ATTR; unsigned char *next_start IBSS_ATTR;
/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ /* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
static void dma_start(const void *addr, long size) static void dma_start(const void *addr, size_t size)
{ {
pcm_playing = true; pcm_playing = true;
@ -104,8 +104,6 @@ static void dma_stop(void)
EBU1CONFIG = IIS_RESET | EBU_DEFPARM; EBU1CONFIG = IIS_RESET | EBU_DEFPARM;
#endif #endif
next_start = NULL;
next_size = 0;
pcm_paused = false; pcm_paused = false;
} }
@ -131,23 +129,27 @@ void pcm_set_frequency(unsigned int frequency)
} }
/* the registered callback function to ask for more mp3 data */ /* the registered callback function to ask for more mp3 data */
static void (*callback_for_more)(unsigned char**, long*) IDATA_ATTR = NULL; static void (*callback_for_more)(unsigned char**, size_t*) IDATA_ATTR = NULL;
void pcm_play_data(void (*get_more)(unsigned char** start, long* size)) void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size),
unsigned char* start, size_t size)
{ {
unsigned char *start;
long size;
callback_for_more = get_more; callback_for_more = get_more;
get_more((unsigned char **)&start, (long *)&size); if (!(start && size))
get_more(&next_start, &next_size); {
dma_start(start, size); if (get_more)
get_more(&start, &size);
else
return;
}
if (start && size)
dma_start(start, size);
} }
long pcm_get_bytes_waiting(void) size_t pcm_get_bytes_waiting(void)
{ {
return next_size + (BCR0 & 0xffffff); return (BCR0 & 0xffffff);
} }
void pcm_mute(bool mute) void pcm_mute(bool mute)
@ -169,19 +171,32 @@ void pcm_play_pause(bool play)
if (!pcm_playing) if (!pcm_playing)
return ; return ;
if(pcm_paused && play && next_size) if(pcm_paused && play)
{ {
logf("unpause"); if (BCR0 & 0xffffff)
/* Reset chunk size so dma has enough data to fill the fifo. */ {
/* This shouldn't be needed anymore. */ logf("unpause");
//SAR0 = (unsigned long)next_start; /* Enable the FIFO and force one write to it */
//BCR0 = next_size; IIS2CONFIG = IIS_DEFPARM(pcm_freq);
/* Enable the FIFO and force one write to it */
IIS2CONFIG = IIS_DEFPARM(pcm_freq);
#ifdef HAVE_SPDIF_OUT #ifdef HAVE_SPDIF_OUT
EBU1CONFIG = EBU_DEFPARM; EBU1CONFIG = EBU_DEFPARM;
#endif #endif
DCR0 |= DMA_EEXT | DMA_START; DCR0 |= DMA_EEXT | DMA_START;
}
else
{
logf("unpause, no data waiting");
void (*get_more)(unsigned char**, size_t*) = callback_for_more;
if (get_more)
get_more(&next_start, &next_size);
if (next_start && next_size)
dma_start(next_start, next_size);
else
{
dma_stop();
logf("unpause attempted, no data");
}
}
} }
else if(!pcm_paused && !play) else if(!pcm_paused && !play)
{ {
@ -224,13 +239,22 @@ void DMA0(void)
} }
else else
{ {
{
void (*get_more)(unsigned char**, size_t*) = callback_for_more;
if (get_more)
get_more(&next_start, &next_size);
else
{
next_size = 0;
next_start = NULL;
}
}
if(next_size) if(next_size)
{ {
SAR0 = (unsigned long)next_start; /* Source address */ SAR0 = (unsigned long)next_start; /* Source address */
BCR0 = next_size; /* Bytes to transfer */ BCR0 = next_size; /* Bytes to transfer */
DCR0 |= DMA_EEXT; DCR0 |= DMA_EEXT;
if (callback_for_more)
callback_for_more(&next_start, &next_size);
} }
else else
{ {
@ -301,9 +325,9 @@ static bool pcm_paused;
static int pcm_freq = 0x6; /* 44.1 is default */ static int pcm_freq = 0x6; /* 44.1 is default */
/* the registered callback function to ask for more mp3 data */ /* the registered callback function to ask for more mp3 data */
static void (*callback_for_more)(unsigned char**, long*) = NULL; static void (*callback_for_more)(unsigned char**, size_t*) = NULL;
static unsigned short *p IBSS_ATTR; static unsigned short *p IBSS_ATTR;
static long size IBSS_ATTR; static size_t size IBSS_ATTR;
/* Stops the DMA transfer and interrupt */ /* Stops the DMA transfer and interrupt */
static void dma_stop(void) static void dma_stop(void)
@ -353,7 +377,7 @@ void fiq(void)
IISCONFIG &= ~0x2; IISCONFIG &= ~0x2;
if ((size==0) && (callback_for_more)) { if ((size==0) && (callback_for_more)) {
callback_for_more((unsigned char **)&p, (long *)&size); callback_for_more((unsigned char **)&p, &size);
} }
while (size > 0) { while (size > 0) {
@ -368,20 +392,22 @@ void fiq(void)
size-=4; size-=4;
if ((size==0) && (callback_for_more)) { if ((size==0) && (callback_for_more)) {
callback_for_more((unsigned char **)&p, (long *)&size); callback_for_more((unsigned char **)&p, &size);
} }
} }
} }
void pcm_play_data(void (*get_more)(unsigned char** start, long* size)) void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size),
unsigned char* _p, size_t _size)
{ {
int free_count; size_t free_count;
callback_for_more = get_more; callback_for_more = get_more;
if (size > 0) { return; } if (size > 0) { return; }
get_more((unsigned char **)&p, (long *)&size); p = (unsigned short *)_p;
size = _size;
/* setup I2S interrupt for FIQ */ /* setup I2S interrupt for FIQ */
outl(inl(0x6000402c) | I2S_MASK, 0x6000402c); outl(inl(0x6000402c) | I2S_MASK, 0x6000402c);
@ -406,7 +432,7 @@ void pcm_play_data(void (*get_more)(unsigned char** start, long* size))
size-=4; size-=4;
if ((size==0) && (get_more)) { if ((size==0) && (get_more)) {
get_more((unsigned char **)&p, (long *)&size); get_more((unsigned char **)&p, &size);
} }
} }
} }
@ -448,7 +474,7 @@ bool pcm_is_playing(void)
return pcm_playing; return pcm_playing;
} }
long pcm_get_bytes_waiting(void) size_t pcm_get_bytes_waiting(void)
{ {
return size; return size;
} }
@ -608,9 +634,12 @@ void pcm_set_frequency(unsigned int frequency)
(void)frequency; (void)frequency;
} }
void pcm_play_data(void (*get_more)(unsigned char** start, long* size)) void pcm_play_data(void (*get_more)(unsigned char** start, long* size),
unsigned char* start, long size)
{ {
(void)get_more; (void)get_more;
(void)start;
(void)size;
} }
void pcm_play_stop(void) void pcm_play_stop(void)