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:
parent
566ce5f951
commit
413da2a3d9
13 changed files with 667 additions and 531 deletions
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
709
apps/pcmbuf.c
709
apps/pcmbuf.c
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||||
|
|
107
apps/playback.c
107
apps/playback.c
|
@ -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,14 +1693,16 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ci.stop_codec || !playing)
|
||||||
|
return false;
|
||||||
|
|
||||||
#ifdef AB_REPEAT_ENABLE
|
#ifdef AB_REPEAT_ENABLE
|
||||||
ab_end_of_track_report();
|
ab_end_of_track_report();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pcmbuf_set_position_callback(pcmbuf_position_callback);
|
if (!new_track)
|
||||||
|
pcmbuf_set_position_callback(pcmbuf_position_callback);
|
||||||
if (ci.stop_codec || !playing)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
logf("Request new track");
|
logf("Request new 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;
|
||||||
|
|
|
@ -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,36 +400,6 @@ 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
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue