Crossfade (and pcm buffer size) length is now configurable.

Implemented anti-skip buffer setting for iriver also. Settings block
bumped up, PLEASE SAVE YOUR SETTINGS BEFORE UPGRADING.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7210 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Miika Pekkarinen 2005-07-21 11:44:00 +00:00
parent 4bee507502
commit f090dc3829
9 changed files with 145 additions and 74 deletions

View file

@ -230,6 +230,7 @@ bool dbg_audio_thread(void)
int button;
int line;
bool done = false;
int bufsize = pcmbuf_get_bufsize();
ticks = boost_ticks = 0;
@ -253,12 +254,12 @@ bool dbg_audio_thread(void)
lcd_clear_display();
snprintf(buf, sizeof(buf), "pcm: %d/%d",
PCMBUF_SIZE-(int)audiobuffer_free, PCMBUF_SIZE);
bufsize-(int)audiobuffer_free, bufsize);
lcd_puts(0, line++, buf);
/* Playable space left */
scrollbar(0, line*8, LCD_WIDTH, 6, PCMBUF_SIZE, 0,
PCMBUF_SIZE-audiobuffer_free, HORIZONTAL);
scrollbar(0, line*8, LCD_WIDTH, 6, bufsize, 0,
bufsize-audiobuffer_free, HORIZONTAL);
line++;
snprintf(buf, sizeof(buf), "codec: %d/%d", codecbufused, codecbuflen);

View file

@ -106,6 +106,7 @@ void init(void)
font_init();
show_logo();
lang_init();
audio_init();
settings_reset();
settings_calc_config_sector();
settings_load(SETTINGS_ALL);
@ -127,8 +128,6 @@ void init(void)
global_settings.mdb_shape,
global_settings.mdb_enable,
global_settings.superbass);
audio_init();
pcmbuf_init();
button_clear_queue(); /* Empty the keyboard buffer */
}
@ -260,6 +259,11 @@ void init(void)
}
}
/* On software codec platforms we have to init audio before
calling audio_set_buffer_margin(). */
#if (CONFIG_HWCODEC == MASNONE)
audio_init();
#endif
settings_calc_config_sector();
settings_load(SETTINGS_ALL);
settings_apply();
@ -284,10 +288,10 @@ void init(void)
global_settings.mdb_shape,
global_settings.mdb_enable,
global_settings.superbass);
audio_init();
#if (CONFIG_HWCODEC == MASNONE)
pcmbuf_init();
sound_settings_apply();
#else
audio_init();
#endif
#if defined(IRIVER_H100_SERIES) && !defined(SIMULATOR)
pcm_init_recording();

View file

@ -32,15 +32,17 @@
#include "system.h"
#include <string.h>
#include "buffer.h"
#include "settings.h"
#include "audio.h"
#define CHUNK_SIZE 32768
#define CHUNK_SIZE PCMBUF_GUARD
/* Must be a power of 2 */
#define NUM_PCM_BUFFERS (PCMBUF_SIZE / CHUNK_SIZE)
#define NUM_PCM_BUFFERS 64
#define NUM_PCM_BUFFERS_MASK (NUM_PCM_BUFFERS - 1)
#define PCMBUF_WATERMARK (CHUNK_SIZE * 10)
#define PCMBUF_CF_WATERMARK (PCMBUF_SIZE - CHUNK_SIZE*8)
#define PCMBUF_WATERMARK (CHUNK_SIZE * 6)
/* Audio buffer related settings. */
static long pcmbuf_size = 0; /* Size of the PCM buffer. */
static char *audiobuffer;
static long audiobuffer_pos; /* Current audio buffer write index. */
long audiobuffer_free; /* Amount of bytes left in the buffer. */
@ -85,7 +87,7 @@ volatile int pcmbuf_write_index;
int pcmbuf_unplayed_bytes;
int pcmbuf_watermark;
void (*pcmbuf_watermark_event)(int bytes_left);
//static int last_chunksize;
static int last_chunksize;
static void pcmbuf_boost(bool state)
{
@ -111,6 +113,9 @@ static void pcmbuf_callback(unsigned char** start, long* size)
{
struct pcmbufdesc *desc = &pcmbuffers[pcmbuf_read_index];
pcmbuf_unplayed_bytes -= last_chunksize;
audiobuffer_free += last_chunksize;
if(desc->size == 0)
{
/* The buffer is finished, call the callback function */
@ -124,8 +129,6 @@ static void pcmbuf_callback(unsigned char** start, long* size)
if(pcmbuf_num_used_buffers())
{
pcmbuf_unplayed_bytes -= desc->size;
audiobuffer_free += desc->size;
*start = desc->addr;
*size = desc->size;
@ -142,6 +145,7 @@ static void pcmbuf_callback(unsigned char** start, long* size)
pcmbuf_event_handler();
}
last_chunksize = *size;
if(pcmbuf_unplayed_bytes <= pcmbuf_watermark)
{
if(pcmbuf_watermark_event)
@ -199,7 +203,7 @@ unsigned int pcmbuf_get_latency(void)
int latency;
/* This has to be done better. */
latency = (PCMBUF_SIZE - audiobuffer_free - CHUNK_SIZE)/4 / (44100/1000);
latency = (pcmbuf_size - audiobuffer_free - CHUNK_SIZE)/4 / (44100/1000);
if (latency < 0)
latency = 0;
@ -211,7 +215,7 @@ bool pcmbuf_is_lowdata(void)
if (!pcm_is_playing() || pcm_is_paused() || crossfade_init || crossfade_active)
return false;
if (pcmbuf_unplayed_bytes < PCMBUF_WATERMARK)
if (pcmbuf_unplayed_bytes < CHUNK_SIZE * 4)
return true;
return false;
@ -219,7 +223,7 @@ bool pcmbuf_is_lowdata(void)
bool pcmbuf_crossfade_init(void)
{
if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 8 || !crossfade_enabled
if (pcmbuf_size - audiobuffer_free < CHUNK_SIZE * 8 || !crossfade_enabled
|| crossfade_active || crossfade_init) {
pcmbuf_flush_audio();
return false;
@ -236,13 +240,13 @@ bool pcmbuf_crossfade_init(void)
void pcmbuf_play_stop(void)
{
pcm_play_stop();
//last_chunksize = 0;
last_chunksize = 0;
pcmbuf_unplayed_bytes = 0;
pcmbuf_read_index = 0;
pcmbuf_write_index = 0;
audiobuffer_pos = 0;
audiobuffer_fillpos = 0;
audiobuffer_free = PCMBUF_SIZE;
audiobuffer_free = pcmbuf_size;
crossfade_init = false;
crossfade_active = false;
@ -251,16 +255,22 @@ void pcmbuf_play_stop(void)
}
void pcmbuf_init(void)
void pcmbuf_init(long bufsize)
{
pcmbuf_size = bufsize;
audiobuffer = &audiobuf[(audiobufend - audiobuf) -
PCMBUF_SIZE - PCMBUF_GUARD];
guardbuf = &audiobuffer[PCMBUF_SIZE];
pcmbuf_size - PCMBUF_GUARD];
guardbuf = &audiobuffer[pcmbuf_size];
pcmbuf_event_handler = NULL;
pcm_init();
pcmbuf_play_stop();
}
long pcmbuf_get_bufsize(void)
{
return pcmbuf_size;
}
/** Initialize a track switch so that audio playback will not stop but
* the switch to next track would happen as soon as possible.
*/
@ -296,8 +306,8 @@ void pcmbuf_flush_fillpos(void)
}
pcmbuf_event_handler = NULL;
audiobuffer_pos += copy_n;
if (audiobuffer_pos >= PCMBUF_SIZE)
audiobuffer_pos -= PCMBUF_SIZE;
if (audiobuffer_pos >= pcmbuf_size)
audiobuffer_pos -= pcmbuf_size;
audiobuffer_free -= copy_n;
audiobuffer_fillpos -= copy_n;
}
@ -334,7 +344,7 @@ static void crossfade_start(void)
crossfade_pos -= crossfade_amount*2;
if (crossfade_pos < 0)
crossfade_pos += PCMBUF_SIZE;
crossfade_pos += pcmbuf_size;
}
static __inline
@ -383,7 +393,7 @@ static bool prepare_insert(long length)
if (!pcm_is_playing()) {
pcmbuf_boost(true);
crossfade_active = false;
if (audiobuffer_free < PCMBUF_SIZE - CHUNK_SIZE*4) {
if (audiobuffer_free < pcmbuf_size - CHUNK_SIZE*4) {
logf("pcm starting");
pcm_play_data(pcmbuf_callback);
}
@ -409,7 +419,7 @@ void* pcmbuf_request_buffer(long length, long *realsize)
*realsize = MIN(length, PCMBUF_GUARD);
ptr = &guardbuf[0];
} else {
*realsize = MIN(length, PCMBUF_SIZE - audiobuffer_pos
*realsize = MIN(length, pcmbuf_size - audiobuffer_pos
- audiobuffer_fillpos);
if (*realsize < length) {
*realsize += MIN((long)(length - *realsize), PCMBUF_GUARD);
@ -436,18 +446,18 @@ void pcmbuf_flush_buffer(long length)
buf = &guardbuf[0];
length = MIN(length, PCMBUF_GUARD);
while (length > 0 && crossfade_active) {
copy_n = MIN(length, PCMBUF_SIZE - crossfade_pos);
copy_n = MIN(length, pcmbuf_size - crossfade_pos);
copy_n = 2 * crossfade((short *)&audiobuffer[crossfade_pos],
(const short *)buf, copy_n/2);
buf += copy_n;
length -= copy_n;
crossfade_pos += copy_n;
if (crossfade_pos >= PCMBUF_SIZE)
crossfade_pos -= PCMBUF_SIZE;
if (crossfade_pos >= pcmbuf_size)
crossfade_pos -= pcmbuf_size;
}
while (length > 0) {
copy_n = MIN(length, PCMBUF_SIZE - audiobuffer_pos);
copy_n = MIN(length, pcmbuf_size - audiobuffer_pos);
memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n);
audiobuffer_fillpos = copy_n;
buf += copy_n;
@ -460,11 +470,11 @@ void pcmbuf_flush_buffer(long length)
audiobuffer_fillpos += length;
try_flush:
if (audiobuffer_fillpos < CHUNK_SIZE && PCMBUF_SIZE
if (audiobuffer_fillpos < CHUNK_SIZE && pcmbuf_size
- audiobuffer_pos - audiobuffer_fillpos > 0)
return ;
copy_n = audiobuffer_fillpos - (PCMBUF_SIZE - audiobuffer_pos);
copy_n = audiobuffer_fillpos - (pcmbuf_size - audiobuffer_pos);
if (copy_n > 0) {
audiobuffer_fillpos -= copy_n;
pcmbuf_flush_fillpos();
@ -486,19 +496,19 @@ bool pcmbuf_insert_buffer(char *buf, long length)
if (crossfade_active) {
while (length > 0 && crossfade_active) {
copy_n = MIN(length, PCMBUF_SIZE - crossfade_pos);
copy_n = MIN(length, pcmbuf_size - crossfade_pos);
copy_n = 2 * crossfade((short *)&audiobuffer[crossfade_pos],
(const short *)buf, copy_n/2);
buf += copy_n;
length -= copy_n;
crossfade_pos += copy_n;
if (crossfade_pos >= PCMBUF_SIZE)
crossfade_pos -= PCMBUF_SIZE;
if (crossfade_pos >= pcmbuf_size)
crossfade_pos -= pcmbuf_size;
}
while (length > 0) {
copy_n = MIN(length, PCMBUF_SIZE - audiobuffer_pos);
copy_n = MIN(length, pcmbuf_size - audiobuffer_pos);
memcpy(&audiobuffer[audiobuffer_pos], buf, copy_n);
audiobuffer_fillpos = copy_n;
buf += copy_n;
@ -509,7 +519,7 @@ bool pcmbuf_insert_buffer(char *buf, long length)
}
while (length > 0) {
copy_n = MIN(length, PCMBUF_SIZE - audiobuffer_pos -
copy_n = MIN(length, pcmbuf_size - audiobuffer_pos -
audiobuffer_fillpos);
copy_n = MIN(CHUNK_SIZE - audiobuffer_fillpos, copy_n);
@ -533,12 +543,12 @@ bool pcmbuf_insert_buffer(char *buf, long length)
void pcmbuf_crossfade_enable(bool on_off)
{
crossfade_enabled = on_off;
if (crossfade_enabled) {
pcmbuf_set_watermark(PCMBUF_CF_WATERMARK, pcmbuf_watermark_callback);
pcmbuf_set_watermark(pcmbuf_size - (CHUNK_SIZE*6), pcmbuf_watermark_callback);
} else {
pcmbuf_set_watermark(PCMBUF_WATERMARK, pcmbuf_watermark_callback);
}
}
}
bool pcmbuf_is_crossfade_enabled(void)

View file

@ -22,10 +22,8 @@
/* Guard buffer for crossfader when dsp is enabled. */
#define PCMBUF_GUARD 32768
/* PCM audio buffer. */
#define PCMBUF_SIZE (1*1024*1024)
void pcmbuf_init(void);
void pcmbuf_init(long bufsize);
long pcmbuf_get_bufsize(void);
void pcmbuf_play_stop(void);
bool pcmbuf_is_crossfade_active(void);

View file

@ -172,6 +172,7 @@ void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track);
static int conf_bufferlimit;
static int conf_watermark;
static int conf_filechunk;
static int buffer_margin;
static bool v1first = false;
@ -468,11 +469,21 @@ bool codec_seek_buffer_callback(off_t newpos)
return true;
}
static void set_filebuf_watermark(int seconds)
{
long bytes;
bytes = MAX((int)cur_ti->id3.bitrate * seconds * (1000/8), conf_watermark);
bytes = MIN(bytes, codecbuflen / 2);
conf_watermark = bytes;
}
void codec_configure_callback(int setting, void *value)
{
switch (setting) {
case CODEC_SET_FILEBUF_WATERMARK:
conf_watermark = (unsigned int)value;
set_filebuf_watermark(buffer_margin);
break;
case CODEC_SET_FILEBUF_CHUNKSIZE:
@ -852,6 +863,7 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
return false;
}
}
set_filebuf_watermark(buffer_margin);
tracks[track_widx].id3.elapsed = 0;
/* Starting playback from an offset is only support in MPA at the moment */
@ -1754,13 +1766,36 @@ int mp3_get_file_pos(void)
return pos;
}
#ifndef SIMULATOR
void audio_set_buffer_margin(int seconds)
void audio_set_buffer_margin(int setting)
{
(void)seconds;
logf("bufmargin: %d", seconds);
int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
buffer_margin = lookup[setting];
logf("buffer margin: %ds", buffer_margin);
set_filebuf_watermark(buffer_margin);
}
void audio_set_crossfade_amount(int seconds)
{
long size;
/* Playback has to be stopped before changing the buffer size. */
audio_stop_playback();
/* Buffer has to be at least 2s long. */
seconds += 2;
logf("buf len: %d", seconds);
size = seconds * (NATIVE_FREQUENCY*4);
if (pcmbuf_get_bufsize() == size)
return ;
/* Re-initialize audio system. */
pcmbuf_init(size);
pcmbuf_crossfade_enable(seconds > 2);
codecbuflen = audiobufend - audiobuf - pcmbuf_get_bufsize()
- PCMBUF_GUARD - MALLOC_BUFSIZE - GUARD_BUFSIZE;
logf("abuf:%dB", pcmbuf_get_bufsize());
logf("fbuf:%dB", codecbuflen);
}
#endif
void mpeg_id3_options(bool _v1first)
{
@ -1786,9 +1821,6 @@ void test_unbuffer_event(struct mp3entry *id3, bool last_track)
void audio_init(void)
{
logf("audio api init");
codecbuflen = audiobufend - audiobuf - PCMBUF_SIZE - PCMBUF_GUARD
- MALLOC_BUFSIZE - GUARD_BUFSIZE;
//codecbuflen = 2*512*1024;
codecbufused = 0;
filling = false;
codecbuf = &audiobuf[MALLOC_BUFSIZE];
@ -1803,10 +1835,6 @@ void audio_init(void)
/* Just to prevent cur_ti never be anything random. */
cur_ti = &tracks[0];
logf("abuf:%0x", PCMBUF_SIZE);
logf("fbuf:%0x", codecbuflen);
logf("mbuf:%0x", MALLOC_BUFSIZE);
audio_set_track_buffer_event(test_buffer_event);
audio_set_track_unbuffer_event(test_unbuffer_event);
@ -1833,9 +1861,6 @@ void audio_init(void)
codec_thread_name);
create_thread(audio_thread, audio_stack, sizeof(audio_stack),
audio_thread_name);
#ifndef SIMULATOR
audio_is_initialized = true;
#endif
}

View file

@ -77,7 +77,7 @@ const char rec_base_directory[] = REC_BASE_DIR;
#include "pcm_playback.h"
#endif
#define CONFIG_BLOCK_VERSION 22
#define CONFIG_BLOCK_VERSION 23
#define CONFIG_BLOCK_SIZE 512
#define RTC_BLOCK_SIZE 44
@ -198,7 +198,7 @@ static const struct bit_entry rtc_bits[] =
"stereo,mono,custom,mono left,mono right,karaoke" },
{8, S_O(stereo_width), 100, "stereo width", NULL},
/* playback */
{2, S_O(resume), false, "resume", off_on },
{1, S_O(resume), false, "resume", off_on },
{1, S_O(playlist_shuffle), false, "shuffle", off_on },
{16 | SIGNED, S_O(resume_index), -1, NULL, NULL },
{16 | SIGNED, S_O(resume_first_index), 0, NULL, NULL },
@ -301,7 +301,12 @@ static const struct bit_entry hd_bits[] =
{4, S_O(ff_rewind_min_step), FF_REWIND_1000,
"scan min step", "1,2,3,4,5,6,8,10,15,20,25,30,45,60" },
{4, S_O(ff_rewind_accel), 3, "scan accel", NULL },
#if CONFIG_HWCODEC == MASNONE
{3, S_O(buffer_margin), 0, "antiskip",
"5s,15s,30s,1min,2min,3min,5min,10min" },
#else
{3, S_O(buffer_margin), 0, "antiskip", NULL },
#endif
/* disk */
#ifndef HAVE_MMC
#ifdef HAVE_ATA_POWER_OFF
@ -392,7 +397,7 @@ static const struct bit_entry hd_bits[] =
#endif
#if CONFIG_HWCODEC == MASNONE
{1, S_O(crossfade), false, "crossfade", off_on},
{3, S_O(crossfade), 0, "crossfade", "off,2s,4s,6s,8s,10s,12s,14s"},
#endif
#if CONFIG_BACKLIGHT == BL_IRIVER
@ -846,7 +851,7 @@ void settings_apply(void)
}
#if CONFIG_HWCODEC == MASNONE
pcmbuf_crossfade_enable(global_settings.crossfade);
audio_set_crossfade_amount(global_settings.crossfade*2);
#endif
#ifdef HAVE_SPDIF_POWER

View file

@ -917,12 +917,33 @@ static bool max_files_in_playlist(void)
NULL, 1000, 1000, 20000 );
}
#if CONFIG_HWCODEC == MASNONE
static bool buffer_margin(void)
{
int ret;
static const struct opt_items names[] = {
{ "5s", TALK_ID(5, UNIT_SEC) },
{ "15s", TALK_ID(15, UNIT_SEC) },
{ "30s", TALK_ID(30, UNIT_SEC) },
{ "1min", TALK_ID(1, UNIT_MIN) },
{ "2min", TALK_ID(2, UNIT_MIN) },
{ "3min", TALK_ID(3, UNIT_MIN) },
{ "5min", TALK_ID(5, UNIT_MIN) },
{ "10min", TALK_ID(10, UNIT_MIN) }
};
ret = set_option(str(LANG_MP3BUFFER_MARGIN), &global_settings.buffer_margin,
INT, names, 8, audio_set_buffer_margin);
return ret;
}
#else
static bool buffer_margin(void)
{
return set_int(str(LANG_MP3BUFFER_MARGIN), "s", UNIT_SEC,
&global_settings.buffer_margin,
audio_set_buffer_margin, 1, 0, 7 );
}
#endif
static bool ff_rewind_min_step(void)
{
@ -1106,11 +1127,23 @@ static bool id3_order(void)
#if CONFIG_HWCODEC == MASNONE
static bool crossfade(void)
{
bool rc = set_bool( str(LANG_CROSSFADE), &global_settings.crossfade );
pcmbuf_crossfade_enable(global_settings.crossfade);
return rc;
static const struct opt_items names[] = {
{ STR(LANG_OFF) },
{ "2s", TALK_ID(2, UNIT_SEC) },
{ "4s", TALK_ID(4, UNIT_SEC) },
{ "6s", TALK_ID(6, UNIT_SEC) },
{ "8s", TALK_ID(8, UNIT_SEC) },
{ "10s", TALK_ID(10, UNIT_SEC) },
{ "12s", TALK_ID(12, UNIT_SEC) },
{ "14s", TALK_ID(14, UNIT_SEC) },
};
bool ret;
ret=set_option( str(LANG_CROSSFADE), &global_settings.crossfade,
INT, names, 8, audio_set_crossfade_amount);
return ret;
}
#endif
static bool next_folder(void)

View file

@ -621,7 +621,7 @@ void mp3_init(int volume, int bass, int treble, int balance, int loudness,
playstart_tick = 0;
cumulative_ticks = 0;
callback_for_more = 0;
audio_is_initialized = false;
audio_is_initialized = true;
#endif
}
void mp3_shutdown(void)

View file

@ -220,11 +220,6 @@ void mpeg_set_pitch(int pitch)
(void)pitch;
}
void audio_set_buffer_margin(int seconds)
{
(void)seconds;
}
static int sleeptime;
void set_sleep_timer(int seconds)
{