forked from len0rd/rockbox
moved and renamed the codecs, gave the codecs a new extension (.codec),
unified to a single codec-only API, made a new codeclib, disabled the building of the *2wav plugins git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6812 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
b7aaa641b8
commit
1dd672fe32
29 changed files with 1709 additions and 937 deletions
|
@ -16,7 +16,6 @@ plugins/viewers.config
|
|||
plugins/snake2.levels
|
||||
SOURCES
|
||||
plugins/SOURCES
|
||||
plugins/CODECS
|
||||
plugins/lib/SOURCES
|
||||
plugins/rockboy/*.[ch]
|
||||
plugins/rockboy/Makefile
|
||||
|
@ -53,3 +52,5 @@ codecs/dumb/src/core/*
|
|||
codecs/dumb/src/helpers/*
|
||||
codecs/dumb/src/it/*
|
||||
codecs/libmusepack/*
|
||||
codecs/lib/*.[ch]
|
||||
codecs/lib/Makefile
|
||||
|
|
|
@ -57,6 +57,7 @@ endif
|
|||
dep: $(DEPFILE)
|
||||
|
||||
build-codecs:
|
||||
@$(MAKE) -C codecs/lib OBJDIR=$(OBJDIR)/codecs/lib
|
||||
@$(MAKE) -C codecs OBJDIR=$(OBJDIR)/codecs
|
||||
|
||||
rocks:
|
||||
|
|
|
@ -48,9 +48,10 @@ recorder/radio.c
|
|||
#ifdef HAVE_RECORDING
|
||||
recorder/recording.c
|
||||
#endif
|
||||
#ifdef IRIVER_H100
|
||||
#if CONFIG_HWCODEC == MASNONE
|
||||
playback.c
|
||||
metadata.c
|
||||
codecs.c
|
||||
#ifndef SIMULATOR
|
||||
pcm_recording.c
|
||||
#endif
|
||||
|
|
364
apps/codecs.c
Normal file
364
apps/codecs.c
Normal file
|
@ -0,0 +1,364 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002 Björn Stenberg
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <atoi.h>
|
||||
#include <timefuncs.h>
|
||||
#include <ctype.h>
|
||||
#include "debug.h"
|
||||
#include "button.h"
|
||||
#include "lcd.h"
|
||||
#include "dir.h"
|
||||
#include "file.h"
|
||||
#include "kernel.h"
|
||||
#include "sprintf.h"
|
||||
#include "logf.h"
|
||||
#include "screens.h"
|
||||
#include "misc.h"
|
||||
#include "mas.h"
|
||||
#include "codecs.h"
|
||||
#include "lang.h"
|
||||
#include "keyboard.h"
|
||||
#include "mpeg.h"
|
||||
#include "buffer.h"
|
||||
#include "mp3_playback.h"
|
||||
#include "backlight.h"
|
||||
#include "ata.h"
|
||||
#include "talk.h"
|
||||
#include "mp3data.h"
|
||||
#include "powermgmt.h"
|
||||
#include "system.h"
|
||||
#include "sound.h"
|
||||
#include "database.h"
|
||||
#if (CONFIG_HWCODEC == MASNONE)
|
||||
#include "pcm_playback.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
#include "peakmeter.h"
|
||||
#include "widgets.h"
|
||||
#include "bmp.h"
|
||||
#endif
|
||||
|
||||
#ifdef SIMULATOR
|
||||
#if CONFIG_HWCODEC == MASNONE
|
||||
static unsigned char codecbuf[CODEC_BUFFER_SIZE];
|
||||
#endif
|
||||
void *sim_codec_load(char *plugin, int *fd);
|
||||
void sim_codec_close(int fd);
|
||||
#else
|
||||
#define sim_codec_close(x)
|
||||
extern unsigned char codecbuf[];
|
||||
#endif
|
||||
|
||||
extern void* plugin_get_audio_buffer(int *buffer_size);
|
||||
|
||||
static int codec_test(int api_version, int model, int memsize);
|
||||
|
||||
const struct codec_api ci = {
|
||||
CODEC_API_VERSION,
|
||||
codec_test,
|
||||
|
||||
0, /* filesize */
|
||||
0, /* curpos */
|
||||
NULL, /* id3 */
|
||||
NULL, /* mp3data */
|
||||
NULL, /* taginfo_ready */
|
||||
false, /* stop_codec */
|
||||
false, /* reload_codec */
|
||||
0, /* seek_time */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
/* lcd */
|
||||
lcd_clear_display,
|
||||
lcd_puts,
|
||||
lcd_puts_scroll,
|
||||
lcd_stop_scroll,
|
||||
lcd_set_contrast,
|
||||
#ifdef HAVE_LCD_CHARCELLS
|
||||
lcd_define_pattern,
|
||||
lcd_get_locked_pattern,
|
||||
lcd_unlock_pattern,
|
||||
lcd_putc,
|
||||
lcd_put_cursor,
|
||||
lcd_remove_cursor,
|
||||
PREFIX(lcd_icon),
|
||||
#else
|
||||
lcd_putsxy,
|
||||
lcd_puts_style,
|
||||
lcd_puts_scroll_style,
|
||||
lcd_bitmap,
|
||||
lcd_drawline,
|
||||
lcd_clearline,
|
||||
lcd_drawpixel,
|
||||
lcd_clearpixel,
|
||||
lcd_setfont,
|
||||
font_get,
|
||||
lcd_clearrect,
|
||||
lcd_fillrect,
|
||||
lcd_drawrect,
|
||||
lcd_invertrect,
|
||||
lcd_getstringsize,
|
||||
lcd_update,
|
||||
lcd_update_rect,
|
||||
scrollbar,
|
||||
checkbox,
|
||||
&lcd_framebuffer[0][0],
|
||||
lcd_blit,
|
||||
#ifndef SIMULATOR
|
||||
lcd_roll,
|
||||
#endif
|
||||
#endif
|
||||
backlight_on,
|
||||
backlight_off,
|
||||
backlight_set_timeout,
|
||||
splash,
|
||||
|
||||
/* file */
|
||||
(open_func)PREFIX(open),
|
||||
close,
|
||||
(read_func)read,
|
||||
PREFIX(lseek),
|
||||
(creat_func)PREFIX(creat),
|
||||
(write_func)write,
|
||||
PREFIX(remove),
|
||||
PREFIX(rename),
|
||||
PREFIX(ftruncate),
|
||||
fdprintf,
|
||||
read_line,
|
||||
settings_parseline,
|
||||
#ifndef SIMULATOR
|
||||
ata_sleep,
|
||||
#endif
|
||||
|
||||
/* dir */
|
||||
PREFIX(opendir),
|
||||
PREFIX(closedir),
|
||||
PREFIX(readdir),
|
||||
PREFIX(mkdir),
|
||||
|
||||
/* kernel/ system */
|
||||
PREFIX(sleep),
|
||||
yield,
|
||||
¤t_tick,
|
||||
default_event_handler,
|
||||
default_event_handler_ex,
|
||||
create_thread,
|
||||
remove_thread,
|
||||
reset_poweroff_timer,
|
||||
#ifndef SIMULATOR
|
||||
system_memory_guard,
|
||||
&cpu_frequency,
|
||||
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
||||
cpu_boost,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* strings and memory */
|
||||
snprintf,
|
||||
strcpy,
|
||||
strncpy,
|
||||
strlen,
|
||||
strrchr,
|
||||
strcmp,
|
||||
strcasecmp,
|
||||
strncasecmp,
|
||||
memset,
|
||||
memcpy,
|
||||
_ctype_,
|
||||
atoi,
|
||||
strchr,
|
||||
strcat,
|
||||
memcmp,
|
||||
strcasestr,
|
||||
|
||||
/* sound */
|
||||
sound_set,
|
||||
#ifndef SIMULATOR
|
||||
mp3_play_data,
|
||||
mp3_play_pause,
|
||||
mp3_play_stop,
|
||||
mp3_is_playing,
|
||||
#if CONFIG_HWCODEC != MASNONE
|
||||
bitswap,
|
||||
#endif
|
||||
#if CONFIG_HWCODEC == MASNONE
|
||||
pcm_play_data,
|
||||
pcm_play_stop,
|
||||
pcm_set_frequency,
|
||||
pcm_is_playing,
|
||||
pcm_play_pause,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* playback control */
|
||||
PREFIX(audio_play),
|
||||
audio_stop,
|
||||
audio_pause,
|
||||
audio_resume,
|
||||
audio_next,
|
||||
audio_prev,
|
||||
audio_ff_rewind,
|
||||
audio_next_track,
|
||||
playlist_amount,
|
||||
audio_status,
|
||||
audio_has_changed_track,
|
||||
audio_current_track,
|
||||
audio_flush_and_reload_tracks,
|
||||
audio_get_file_pos,
|
||||
#if !defined(SIMULATOR) && (CONFIG_HWCODEC != MASNONE)
|
||||
mpeg_get_last_header,
|
||||
#endif
|
||||
#if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
|
||||
sound_set_pitch,
|
||||
#endif
|
||||
|
||||
#if !defined(SIMULATOR) && (CONFIG_HWCODEC != MASNONE)
|
||||
/* MAS communication */
|
||||
mas_readmem,
|
||||
mas_writemem,
|
||||
mas_readreg,
|
||||
mas_writereg,
|
||||
#if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
|
||||
mas_codec_writereg,
|
||||
mas_codec_readreg,
|
||||
#endif
|
||||
#endif /* !simulator and HWCODEC != MASNONE */
|
||||
|
||||
/* tag database */
|
||||
&tagdbheader,
|
||||
&tagdb_fd,
|
||||
&tagdb_initialized,
|
||||
tagdb_init,
|
||||
|
||||
/* misc */
|
||||
srand,
|
||||
rand,
|
||||
(qsort_func)qsort,
|
||||
kbd_input,
|
||||
get_time,
|
||||
set_time,
|
||||
plugin_get_audio_buffer,
|
||||
|
||||
#if defined(DEBUG) || defined(SIMULATOR)
|
||||
debugf,
|
||||
#endif
|
||||
&global_settings,
|
||||
mp3info,
|
||||
count_mp3_frames,
|
||||
create_xing_header,
|
||||
find_next_frame,
|
||||
battery_level,
|
||||
battery_level_safe,
|
||||
#if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
|
||||
peak_meter_scale_value,
|
||||
peak_meter_set_use_dbfs,
|
||||
peak_meter_get_use_dbfs,
|
||||
#endif
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
read_bmp_file,
|
||||
#endif
|
||||
|
||||
/* new stuff at the end, sort into place next time
|
||||
the API gets incompatible */
|
||||
|
||||
#ifdef ROCKBOX_HAS_LOGF
|
||||
logf,
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
int codec_load_ram(char* codecptr, size_t size, void* ptr2, size_t bufwrap)
|
||||
{
|
||||
enum codec_status (*codec_start)(const struct codec_api* api, void* param);
|
||||
int copy_n;
|
||||
int status;
|
||||
|
||||
if ((char *)&codecbuf[0] != codecptr) {
|
||||
/* zero out codec buffer to ensure a properly zeroed bss area */
|
||||
memset(codecbuf, 0, CODEC_BUFFER_SIZE);
|
||||
|
||||
size = MIN(size, CODEC_BUFFER_SIZE);
|
||||
copy_n = MIN(size, bufwrap);
|
||||
memcpy(codecbuf, codecptr, copy_n);
|
||||
size -= copy_n;
|
||||
if (size > 0) {
|
||||
memcpy(&codecbuf[copy_n], ptr2, size);
|
||||
}
|
||||
}
|
||||
codec_start = (void*)&codecbuf;
|
||||
|
||||
invalidate_icache();
|
||||
status = codec_start(&ci, NULL);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int codec_load_file(const char *plugin)
|
||||
{
|
||||
char msgbuf[80];
|
||||
int fd;
|
||||
int rc;
|
||||
|
||||
fd = open(plugin, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
snprintf(msgbuf, sizeof(msgbuf)-1, "Couldn't load codec: %s", plugin);
|
||||
logf("Codec load error:%d", fd);
|
||||
splash(HZ*2, true, msgbuf);
|
||||
return fd;
|
||||
}
|
||||
|
||||
rc = read(fd, &codecbuf[0], CODEC_BUFFER_SIZE);
|
||||
close(fd);
|
||||
if (rc <= 0) {
|
||||
logf("Codec read error");
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
|
||||
return codec_load_ram(codecbuf, (size_t)rc, NULL, 0);
|
||||
}
|
||||
|
||||
static int codec_test(int api_version, int model, int memsize)
|
||||
{
|
||||
if (api_version < CODEC_MIN_API_VERSION ||
|
||||
api_version > CODEC_API_VERSION)
|
||||
return CODEC_WRONG_API_VERSION;
|
||||
|
||||
(void)model;
|
||||
#if 0
|
||||
if (model != MODEL)
|
||||
return CODEC_WRONG_MODEL;
|
||||
#endif
|
||||
|
||||
if (memsize != MEM)
|
||||
return CODEC_WRONG_MODEL;
|
||||
|
||||
return CODEC_OK;
|
||||
}
|
403
apps/codecs.h
Normal file
403
apps/codecs.h
Normal file
|
@ -0,0 +1,403 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002 Björn Stenberg
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef _CODECS_H_
|
||||
#define _CODECS_H_
|
||||
|
||||
/* instruct simulator code to not redefine any symbols when compiling codecs.
|
||||
(the CODEC macro is defined in apps/codecs/Makefile) */
|
||||
#ifdef CODEC
|
||||
#define NO_REDEFINES_PLEASE
|
||||
#endif
|
||||
|
||||
#ifndef MEM
|
||||
#define MEM 2
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include "config.h"
|
||||
#include "dir.h"
|
||||
#include "kernel.h"
|
||||
#include "button.h"
|
||||
#include "font.h"
|
||||
#include "system.h"
|
||||
#include "lcd.h"
|
||||
#include "id3.h"
|
||||
#include "mpeg.h"
|
||||
#include "audio.h"
|
||||
#include "mp3_playback.h"
|
||||
#if (HWCODEC == MASNONE)
|
||||
#include "pcm_playback.h"
|
||||
#endif
|
||||
#include "settings.h"
|
||||
#include "thread.h"
|
||||
#include "playlist.h"
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
#include "widgets.h"
|
||||
#endif
|
||||
#include "sound.h"
|
||||
|
||||
#ifdef HAVE_REMOTE_LCD
|
||||
#include "lcd-remote.h"
|
||||
#endif
|
||||
|
||||
#ifdef CODEC
|
||||
|
||||
#if defined(DEBUG) || defined(SIMULATOR)
|
||||
#undef DEBUGF
|
||||
#define DEBUGF rb->debugf
|
||||
#undef LDEBUGF
|
||||
#define LDEBUGF rb->debugf
|
||||
#else
|
||||
#define DEBUGF(...)
|
||||
#define LDEBUGF(...)
|
||||
#endif
|
||||
|
||||
#ifdef ROCKBOX_HAS_LOGF
|
||||
#undef LOGF
|
||||
#define LOGF rb->logf
|
||||
#else
|
||||
#define LOGF(...)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* This size must match the one set in ../plugins/plugin.lds */
|
||||
#define CODEC_BUFFER_SIZE 0x3C000
|
||||
|
||||
#ifdef SIMULATOR
|
||||
#define PREFIX(_x_) sim_ ## _x_
|
||||
#else
|
||||
#define PREFIX(_x_) _x_
|
||||
#endif
|
||||
|
||||
/* increase this every time the api struct changes */
|
||||
#define CODEC_API_VERSION 40
|
||||
|
||||
/* update this to latest version if a change to the api struct breaks
|
||||
backwards compatibility (and please take the opportunity to sort in any
|
||||
new function which are "waiting" at the end of the function table) */
|
||||
#define CODEC_MIN_API_VERSION 40
|
||||
|
||||
/* codec return codes */
|
||||
enum codec_status {
|
||||
CODEC_OK = 0,
|
||||
CODEC_USB_CONNECTED,
|
||||
|
||||
CODEC_WRONG_API_VERSION = -1,
|
||||
CODEC_WRONG_MODEL = -2,
|
||||
CODEC_ERROR = -3,
|
||||
};
|
||||
|
||||
/* compatibility test macro */
|
||||
#define TEST_CODEC_API(_api_) \
|
||||
do { \
|
||||
int _rc_ = _api_->codec_test(CODEC_API_VERSION, 1, MEM); \
|
||||
if (_rc_<0) \
|
||||
return _rc_; \
|
||||
} while(0)
|
||||
|
||||
/* NOTE: To support backwards compatibility, only add new functions at
|
||||
the end of the structure. Every time you add a new function,
|
||||
remember to increase CODEC_API_VERSION. If you make changes to the
|
||||
existing APIs then also update CODEC_MIN_API_VERSION to current
|
||||
version
|
||||
*/
|
||||
struct codec_api {
|
||||
/* these two fields must always be first, to ensure
|
||||
TEST_CODEC_API will always work */
|
||||
int version;
|
||||
int (*codec_test)(int api_version, int model, int memsize);
|
||||
|
||||
off_t filesize; /* Total file length */
|
||||
off_t curpos; /* Current buffer position */
|
||||
|
||||
/* For gapless mp3 */
|
||||
struct mp3entry *id3; /* TAG metadata pointer */
|
||||
struct mp3info *mp3data; /* MP3 metadata pointer */
|
||||
bool *taginfo_ready; /* Is metadata read */
|
||||
|
||||
/* Codec should periodically check if stop_codec is set to true.
|
||||
In case it's, codec must return with PLUGIN_OK status immediately. */
|
||||
bool stop_codec;
|
||||
/* Codec should periodically check if reload_codec is set to true.
|
||||
In case it's, codec should reload itself without exiting. */
|
||||
bool reload_codec;
|
||||
/* If seek_time != 0, codec should seek to that song position (in ms)
|
||||
if codec supports seeking. */
|
||||
int seek_time;
|
||||
|
||||
/* Returns buffer to malloc array. Only codeclib should need this. */
|
||||
void* (*get_codec_memory)(size_t *size);
|
||||
/* Insert PCM data into audio buffer for playback. Playback will start
|
||||
automatically. */
|
||||
bool (*audiobuffer_insert)(char *data, size_t length);
|
||||
/* Set song position in WPS (value in ms). */
|
||||
void (*set_elapsed)(unsigned int value);
|
||||
|
||||
/* Read next <size> amount bytes from file buffer to <ptr>.
|
||||
Will return number of bytes read or 0 if end of file. */
|
||||
size_t (*read_filebuf)(void *ptr, size_t size);
|
||||
/* Request pointer to file buffer which can be used to read
|
||||
<realsize> amount of data. <reqsize> tells the buffer system
|
||||
how much data it should try to allocate. If <realsize> is 0,
|
||||
end of file is reached. */
|
||||
void* (*request_buffer)(size_t *realsize, size_t reqsize);
|
||||
/* Advance file buffer position by <amount> amount of bytes. */
|
||||
void (*advance_buffer)(size_t amount);
|
||||
/* Advance file buffer to a pointer location inside file buffer. */
|
||||
void (*advance_buffer_loc)(void *ptr);
|
||||
/* Seek file buffer to position <newpos> beginning of file. */
|
||||
bool (*seek_buffer)(off_t newpos);
|
||||
/* Calculate mp3 seek position from given time data in ms. */
|
||||
off_t (*mp3_get_filepos)(int newtime);
|
||||
/* Request file change from file buffer. Returns true is next
|
||||
track is available and changed. If return value is false,
|
||||
codec should exit immediately with PLUGIN_OK status. */
|
||||
bool (*request_next_track)(void);
|
||||
|
||||
/* Configure different codec buffer parameters. */
|
||||
void (*configure)(int setting, void *value);
|
||||
|
||||
|
||||
/* lcd */
|
||||
void (*lcd_clear_display)(void);
|
||||
void (*lcd_puts)(int x, int y, const unsigned char *string);
|
||||
void (*lcd_puts_scroll)(int x, int y, const unsigned char* string);
|
||||
void (*lcd_stop_scroll)(void);
|
||||
void (*lcd_set_contrast)(int x);
|
||||
#ifdef HAVE_LCD_CHARCELLS
|
||||
void (*lcd_define_pattern)(int which,const char *pattern);
|
||||
unsigned char (*lcd_get_locked_pattern)(void);
|
||||
void (*lcd_unlock_pattern)(unsigned char pat);
|
||||
void (*lcd_putc)(int x, int y, unsigned short ch);
|
||||
void (*lcd_put_cursor)(int x, int y, char cursor_char);
|
||||
void (*lcd_remove_cursor)(void);
|
||||
void (*PREFIX(lcd_icon))(int icon, bool enable);
|
||||
#else
|
||||
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_scroll_style)(int x, int y, const unsigned char* string,
|
||||
int style);
|
||||
void (*lcd_bitmap)(const unsigned char *src, int x, int y,
|
||||
int nx, int ny, bool clear);
|
||||
void (*lcd_drawline)(int x1, int y1, int x2, int y2);
|
||||
void (*lcd_clearline)(int x1, int y1, int x2, int y2);
|
||||
void (*lcd_drawpixel)(int x, int y);
|
||||
void (*lcd_clearpixel)(int x, int y);
|
||||
void (*lcd_setfont)(int font);
|
||||
struct font* (*font_get)(int font);
|
||||
void (*lcd_clearrect)(int x, int y, int nx, int ny);
|
||||
void (*lcd_fillrect)(int x, int y, int nx, int ny);
|
||||
void (*lcd_drawrect)(int x, int y, int nx, int ny);
|
||||
void (*lcd_invertrect)(int x, int y, int nx, int ny);
|
||||
int (*lcd_getstringsize)(const unsigned char *str, int *w, int *h);
|
||||
void (*lcd_update)(void);
|
||||
void (*lcd_update_rect)(int x, int y, int width, int height);
|
||||
void (*scrollbar)(int x, int y, int width, int height, int items,
|
||||
int min_shown, int max_shown, int orientation);
|
||||
void (*checkbox)(int x, int y, int width, int height, bool checked);
|
||||
unsigned char* lcd_framebuffer;
|
||||
void (*lcd_blit) (const unsigned char* p_data, int x, int y, int width,
|
||||
int height, int stride);
|
||||
#ifndef SIMULATOR
|
||||
void (*lcd_roll)(int pixels);
|
||||
#endif
|
||||
#endif
|
||||
void (*backlight_on)(void);
|
||||
void (*backlight_off)(void);
|
||||
void (*backlight_set_timeout)(int index);
|
||||
void (*splash)(int ticks, bool center, const char *fmt, ...);
|
||||
|
||||
/* file */
|
||||
int (*PREFIX(open))(const char* pathname, int flags);
|
||||
int (*close)(int fd);
|
||||
ssize_t (*read)(int fd, void* buf, size_t count);
|
||||
off_t (*PREFIX(lseek))(int fd, off_t offset, int whence);
|
||||
int (*PREFIX(creat))(const char *pathname, mode_t mode);
|
||||
ssize_t (*write)(int fd, const void* buf, size_t count);
|
||||
int (*PREFIX(remove))(const char* pathname);
|
||||
int (*PREFIX(rename))(const char* path, const char* newname);
|
||||
int (*PREFIX(ftruncate))(int fd, off_t length);
|
||||
|
||||
int (*fdprintf)(int fd, const char *fmt, ...);
|
||||
int (*read_line)(int fd, char* buffer, int buffer_size);
|
||||
bool (*settings_parseline)(char* line, char** name, char** value);
|
||||
#ifndef SIMULATOR
|
||||
int (*ata_sleep)(void);
|
||||
#endif
|
||||
|
||||
/* dir */
|
||||
DIR* (*PREFIX(opendir))(const char* name);
|
||||
int (*PREFIX(closedir))(DIR* dir);
|
||||
struct dirent* (*PREFIX(readdir))(DIR* dir);
|
||||
int (*PREFIX(mkdir))(const char *name, int mode);
|
||||
|
||||
/* kernel/ system */
|
||||
void (*PREFIX(sleep))(int ticks);
|
||||
void (*yield)(void);
|
||||
long* current_tick;
|
||||
long (*default_event_handler)(long event);
|
||||
long (*default_event_handler_ex)(long event, void (*callback)(void *), void *parameter);
|
||||
int (*create_thread)(void* function, void* stack, int stack_size, const char *name);
|
||||
void (*remove_thread)(int threadnum);
|
||||
void (*reset_poweroff_timer)(void);
|
||||
#ifndef SIMULATOR
|
||||
int (*system_memory_guard)(int newmode);
|
||||
long *cpu_frequency;
|
||||
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
||||
void (*cpu_boost)(bool on_off);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* strings and memory */
|
||||
int (*snprintf)(char *buf, size_t size, const char *fmt, ...);
|
||||
char* (*strcpy)(char *dst, const char *src);
|
||||
char* (*strncpy)(char *dst, const char *src, size_t length);
|
||||
size_t (*strlen)(const char *str);
|
||||
char * (*strrchr)(const char *s, int c);
|
||||
int (*strcmp)(const char *, const char *);
|
||||
int (*strcasecmp)(const char *, const char *);
|
||||
int (*strncasecmp)(const char *s1, const char *s2, size_t n);
|
||||
void* (*memset)(void *dst, int c, size_t length);
|
||||
void* (*memcpy)(void *out, const void *in, size_t n);
|
||||
const char *_ctype_;
|
||||
int (*atoi)(const char *str);
|
||||
char *(*strchr)(const char *s, int c);
|
||||
char *(*strcat)(char *s1, const char *s2);
|
||||
int (*memcmp)(const void *s1, const void *s2, size_t n);
|
||||
char *(*strcasestr) (const char* phaystack, const char* pneedle);
|
||||
|
||||
/* sound */
|
||||
void (*sound_set)(int setting, int value);
|
||||
#ifndef SIMULATOR
|
||||
void (*mp3_play_data)(const unsigned char* start, int size, void (*get_more)(unsigned char** start, int* size));
|
||||
void (*mp3_play_pause)(bool play);
|
||||
void (*mp3_play_stop)(void);
|
||||
bool (*mp3_is_playing)(void);
|
||||
#if CONFIG_HWCODEC != MASNONE
|
||||
void (*bitswap)(unsigned char *data, int length);
|
||||
#endif
|
||||
#if CONFIG_HWCODEC == MASNONE
|
||||
void (*pcm_play_data)(const unsigned char *start, int size,
|
||||
void (*get_more)(unsigned char** start, long*size));
|
||||
void (*pcm_play_stop)(void);
|
||||
void (*pcm_set_frequency)(unsigned int frequency);
|
||||
bool (*pcm_is_playing)(void);
|
||||
void (*pcm_play_pause)(bool play);
|
||||
#endif
|
||||
#endif /* !SIMULATOR */
|
||||
|
||||
/* playback control */
|
||||
void (*PREFIX(audio_play))(int offset);
|
||||
void (*audio_stop)(void);
|
||||
void (*audio_pause)(void);
|
||||
void (*audio_resume)(void);
|
||||
void (*audio_next)(void);
|
||||
void (*audio_prev)(void);
|
||||
void (*audio_ff_rewind)(int newtime);
|
||||
struct mp3entry* (*audio_next_track)(void);
|
||||
int (*playlist_amount)(void);
|
||||
int (*audio_status)(void);
|
||||
bool (*audio_has_changed_track)(void);
|
||||
struct mp3entry* (*audio_current_track)(void);
|
||||
void (*audio_flush_and_reload_tracks)(void);
|
||||
int (*audio_get_file_pos)(void);
|
||||
#if !defined(SIMULATOR) && (CONFIG_HWCODEC != MASNONE)
|
||||
unsigned long (*mpeg_get_last_header)(void);
|
||||
#endif
|
||||
#if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
|
||||
void (*sound_set_pitch)(int pitch);
|
||||
#endif
|
||||
|
||||
/* MAS communication */
|
||||
#if !defined(SIMULATOR) && (CONFIG_HWCODEC != MASNONE)
|
||||
int (*mas_readmem)(int bank, int addr, unsigned long* dest, int len);
|
||||
int (*mas_writemem)(int bank, int addr, const unsigned long* src, int len);
|
||||
int (*mas_readreg)(int reg);
|
||||
int (*mas_writereg)(int reg, unsigned int val);
|
||||
#if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
|
||||
int (*mas_codec_writereg)(int reg, unsigned int val);
|
||||
int (*mas_codec_readreg)(int reg);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* tag database */
|
||||
struct tagdb_header *tagdbheader;
|
||||
int *tagdb_fd;
|
||||
int *tagdb_initialized;
|
||||
int (*tagdb_init) (void);
|
||||
|
||||
/* misc */
|
||||
void (*srand)(unsigned int seed);
|
||||
int (*rand)(void);
|
||||
void (*qsort)(void *base, size_t nmemb, size_t size,
|
||||
int(*compar)(const void *, const void *));
|
||||
int (*kbd_input)(char* buffer, int buflen);
|
||||
struct tm* (*get_time)(void);
|
||||
int (*set_time)(const struct tm *tm);
|
||||
void* (*plugin_get_audio_buffer)(int* buffer_size);
|
||||
|
||||
#if defined(DEBUG) || defined(SIMULATOR)
|
||||
void (*debugf)(const char *fmt, ...);
|
||||
#endif
|
||||
struct user_settings* global_settings;
|
||||
bool (*mp3info)(struct mp3entry *entry, const char *filename, bool v1first);
|
||||
int (*count_mp3_frames)(int fd, int startpos, int filesize,
|
||||
void (*progressfunc)(int));
|
||||
int (*create_xing_header)(int fd, int startpos, int filesize,
|
||||
unsigned char *buf, int num_frames,
|
||||
unsigned long header_template,
|
||||
void (*progressfunc)(int), bool generate_toc);
|
||||
unsigned long (*find_next_frame)(int fd, long *offset,
|
||||
long max_offset, unsigned long last_header);
|
||||
int (*battery_level)(void);
|
||||
bool (*battery_level_safe)(void);
|
||||
#if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
|
||||
unsigned short (*peak_meter_scale_value)(unsigned short val,
|
||||
int meterwidth);
|
||||
void (*peak_meter_set_use_dbfs)(int use);
|
||||
int (*peak_meter_get_use_dbfs)(void);
|
||||
#endif
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
int (*read_bmp_file)(char* filename, int *get_width, int *get_height,
|
||||
char *bitmap, int maxsize);
|
||||
#endif
|
||||
|
||||
/* new stuff at the end, sort into place next time
|
||||
the API gets incompatible */
|
||||
|
||||
#ifdef ROCKBOX_HAS_LOGF
|
||||
void (*logf)(const char *fmt, ...);
|
||||
#endif
|
||||
};
|
||||
|
||||
/* defined by the codec loader (codec.c) */
|
||||
#if CONFIG_HWCODEC == MASNONE
|
||||
int codec_load_ram(char* codecptr, size_t size, void* ptr2, size_t bufwrap);
|
||||
int codec_load_file(const char* codec);
|
||||
#endif
|
||||
|
||||
/* defined by the codec */
|
||||
enum codec_status codec_start(struct codec_api* rockbox, void* parameter)
|
||||
__attribute__ ((section (".entry")));
|
||||
|
||||
#endif
|
|
@ -10,20 +10,97 @@
|
|||
INCLUDES = -I$(FIRMDIR)/include -I$(FIRMDIR)/export -I$(FIRMDIR)/common \
|
||||
-I$(FIRMDIR)/drivers -I$(APPSDIR) -Ilib -I$(BUILDDIR)
|
||||
CFLAGS = $(GCCOPTS) $(INCLUDES) $(TARGET) $(EXTRA_DEFINES) \
|
||||
-DMEM=${MEMORYSIZE}
|
||||
-DMEM=${MEMORYSIZE} -DCODEC
|
||||
|
||||
ifdef APPEXTRA
|
||||
INCLUDES += -I$(APPSDIR)/$(APPEXTRA)
|
||||
endif
|
||||
|
||||
ifdef SOFTWARECODECS
|
||||
CODECLIBS = -lmad -la52 -lFLAC -lTremor -lwavpack -lmusepack
|
||||
endif
|
||||
|
||||
# we "borrow" the plugin LDS file
|
||||
LDS := $(APPSDIR)/plugins/plugin.lds
|
||||
|
||||
LINKCODEC := $(OBJDIR)/codeclink.lds
|
||||
DEPFILE = $(OBJDIR)/dep-codecs
|
||||
|
||||
# This sets up 'SRC' based on the files mentioned in SOURCES
|
||||
include $(TOOLSDIR)/makesrc.inc
|
||||
|
||||
ROCKS := $(SRC:%.c=$(OBJDIR)/%.codec)
|
||||
SOURCES = $(SRC)
|
||||
ELFS := $(SRC:%.c=$(OBJDIR)/%.elf)
|
||||
OBJS := $(SRC:%.c=$(OBJDIR)/%.o)
|
||||
# as created by the cross-compiler for win32:
|
||||
DEFS := $(SRC:%.c=$(OBJDIR)/%.def)
|
||||
DIRS = .
|
||||
|
||||
.PHONY: libmad liba52 libFLAC libTremor libwavpack dumb libmusepack
|
||||
|
||||
OUTPUT = $(SOFTWARECODECS)
|
||||
|
||||
all: $(OUTPUT)
|
||||
all: $(OUTPUT) $(ROCKS) $(DEPFILE)
|
||||
|
||||
ifndef SIMVER
|
||||
$(OBJDIR)/%.elf: $(OBJDIR)/%.o $(LINKCODEC)
|
||||
$(SILENT)(file=`basename $@`; \
|
||||
echo "LD $$file"; \
|
||||
$(CC) $(GCCOPTS) -O -nostdlib -o $@ $< -L$(BUILDDIR) $(CODECLIBS) -lcodec -lgcc -T$(LINKCODEC) -Wl,-Map,$(OBJDIR)/$*.map)
|
||||
|
||||
$(OBJDIR)/%.codec : $(OBJDIR)/%.elf
|
||||
@echo "OBJCOPY "`basename $@`
|
||||
@$(OC) -O binary $< $@
|
||||
else
|
||||
|
||||
ifeq ($(SIMVER), x11)
|
||||
###################################################
|
||||
# This is the X11 simulator version
|
||||
|
||||
$(OBJDIR)/%.codec : $(OBJDIR)/%.o $(BUILDDIR)/libplugin.a
|
||||
@echo "LD "`basename $@`
|
||||
@$(CC) $(CFLAGS) -shared $< -L$(BUILDDIR) $(CODECLIBS) -lplugin -o $@
|
||||
ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
|
||||
# 'x' must be kept or you'll have "Win32 error 5"
|
||||
# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
|
||||
# #define ERROR_ACCESS_DENIED 5L
|
||||
else
|
||||
@chmod -x $@
|
||||
endif
|
||||
|
||||
else # end of x11-simulator
|
||||
###################################################
|
||||
# This is the win32 simulator version
|
||||
DLLTOOLFLAGS = --export-all
|
||||
DLLWRAPFLAGS = -s --entry _DllMain@12 --target=i386-mingw32 -mno-cygwin
|
||||
|
||||
$(OBJDIR)/%.codec : $(OBJDIR)/%.o $(BUILDDIR)/libplugin.a
|
||||
@echo "DLL "`basename $@`
|
||||
@$(DLLTOOL) $(DLLTOOLFLAGS) -z $(OBJDIR)/$*.def $<
|
||||
@$(DLLWRAP) $(DLLWRAPFLAGS) --def $(OBJDIR)/$*.def $< $(BUILDDIR)/libplugin.a \
|
||||
$(patsubst -l%,$(BUILDDIR)/lib%.a,$(CODECLIBS)) -o $@
|
||||
ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
|
||||
# 'x' must be kept or you'll have "Win32 error 5"
|
||||
# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
|
||||
# #define ERROR_ACCESS_DENIED 5L
|
||||
else
|
||||
@chmod -x $@
|
||||
endif
|
||||
endif # end of win32-simulator
|
||||
|
||||
endif # end of simulator section
|
||||
|
||||
include $(TOOLSDIR)/make.inc
|
||||
|
||||
$(BUILDDIR)/libcodec.a:
|
||||
@echo "MAKE in codecs/lib"
|
||||
@mkdir -p $(OBJDIR)/lib
|
||||
@$(MAKE) -C lib OBJDIR=$(OBJDIR)/lib
|
||||
|
||||
$(LINKCODEC): $(LDS)
|
||||
@echo "build $@"
|
||||
@cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) -DCODEC $(INCLUDES) $(TARGET) $(DEFINES) -E -P - >$@
|
||||
|
||||
libmad:
|
||||
@echo "MAKE in libmad"
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "codec.h"
|
||||
|
||||
#include <inttypes.h> /* Needed by a52.h */
|
||||
#include <codecs/liba52/config-a52.h>
|
||||
|
@ -28,7 +28,7 @@
|
|||
|
||||
#define BUFFER_SIZE 4096
|
||||
|
||||
struct plugin_api* rb;
|
||||
struct codec_api* rb;
|
||||
struct codec_api* ci;
|
||||
|
||||
static float gain = 1;
|
||||
|
@ -154,17 +154,17 @@ extern char iramstart[];
|
|||
extern char iramend[];
|
||||
#endif
|
||||
|
||||
/* this is the plugin entry point */
|
||||
enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||
/* this is the codec entry point */
|
||||
enum codec_status codec_start(struct codec_api* api, void* parm)
|
||||
{
|
||||
size_t n;
|
||||
unsigned char* filebuf;
|
||||
|
||||
/* Generic plugin initialisation */
|
||||
TEST_PLUGIN_API(api);
|
||||
/* Generic codec initialisation */
|
||||
TEST_CODEC_API(api);
|
||||
|
||||
rb = api;
|
||||
ci = (struct codec_api*)parm;
|
||||
ci = (struct codec_api*)api;
|
||||
|
||||
#ifndef SIMULATOR
|
||||
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
|
||||
|
@ -175,8 +175,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
|
||||
next_track:
|
||||
|
||||
if (codec_init(api, ci)) {
|
||||
return PLUGIN_ERROR;
|
||||
if (codec_init(api)) {
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
|
||||
/* Intialise the A52 decoder and check for success */
|
||||
|
@ -206,5 +206,5 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
|
||||
//NOT NEEDED??: a52_free (state);
|
||||
|
||||
return PLUGIN_OK;
|
||||
return CODEC_OK;
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "codec.h"
|
||||
|
||||
#include <codecs/libFLAC/include/FLAC/seekable_stream_decoder.h>
|
||||
#include "playback.h"
|
||||
|
@ -26,7 +26,7 @@
|
|||
#define FLAC_MAX_SUPPORTED_BLOCKSIZE 4608
|
||||
#define FLAC_MAX_SUPPORTED_CHANNELS 2
|
||||
|
||||
static struct plugin_api* rb;
|
||||
static struct codec_api* rb;
|
||||
static uint32_t samplesdone;
|
||||
|
||||
/* Called when the FLAC decoder needs some FLAC data to decode */
|
||||
|
@ -159,14 +159,14 @@ extern char iramstart[];
|
|||
extern char iramend[];
|
||||
#endif
|
||||
|
||||
/* this is the plugin entry point */
|
||||
enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||
/* this is the codec entry point */
|
||||
enum codec_status codec_start(struct codec_api* api, void* parm)
|
||||
{
|
||||
struct codec_api* ci = (struct codec_api*)parm;
|
||||
FLAC__SeekableStreamDecoder* flacDecoder;
|
||||
struct codec_api* ci = api;
|
||||
FLAC__SeekableStreamDecoder* flacDecoder;
|
||||
|
||||
/* Generic plugin initialisation */
|
||||
TEST_PLUGIN_API(api);
|
||||
/* Generic codec initialisation */
|
||||
TEST_CODEC_API(api);
|
||||
|
||||
/* if you are using a global api pointer, don't forget to copy it!
|
||||
otherwise you will get lovely "I04: IllInstr" errors... :-) */
|
||||
|
@ -182,8 +182,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
|
||||
next_track:
|
||||
|
||||
if (codec_init(api, ci)) {
|
||||
return PLUGIN_ERROR;
|
||||
if (codec_init(api)) {
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
|
||||
/* Create a decoder instance */
|
||||
|
@ -209,7 +209,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
|
||||
/* QUESTION: What do we do when the init fails? */
|
||||
if (FLAC__seekable_stream_decoder_init(flacDecoder)) {
|
||||
return PLUGIN_ERROR;
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
|
||||
/* The first thing to do is to parse the metadata */
|
||||
|
@ -244,5 +244,5 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
if (ci->request_next_track())
|
||||
goto next_track;
|
||||
|
||||
return PLUGIN_OK;
|
||||
return CODEC_OK;
|
||||
}
|
46
apps/codecs/lib/Makefile
Normal file
46
apps/codecs/lib/Makefile
Normal file
|
@ -0,0 +1,46 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
# $Id$
|
||||
#
|
||||
|
||||
# ../.. for the codec.h in the apps dir
|
||||
# .. for stuff in the codecs dir
|
||||
# . for stuff in the codeclib dir
|
||||
INCLUDES=-I$(APPSDIR) -I.. -I. -I$(FIRMDIR)/include -I$(FIRMDIR)/export \
|
||||
-I$(FIRMDIR)/common -I$(BUILDDIR)
|
||||
|
||||
ifdef APPEXTRA
|
||||
INCLUDES += -I$(APPSDIR)/$(APPEXTRA)
|
||||
endif
|
||||
|
||||
CFLAGS = $(GCCOPTS) \
|
||||
$(INCLUDES) $(TARGET) $(EXTRA_DEFINES) -DMEM=${MEMORYSIZE} -DCODEC
|
||||
|
||||
# This sets up 'SRC' based on the files mentioned in SOURCES
|
||||
include $(TOOLSDIR)/makesrc.inc
|
||||
|
||||
SOURCES = $(SRC)
|
||||
OBJS := $(SRC:%.c=$(OBJDIR)/%.o)
|
||||
DEPFILE = $(OBJDIR)/dep-codeclib
|
||||
DIRS = .
|
||||
|
||||
OUTPUT = $(BUILDDIR)/libcodec.a
|
||||
|
||||
all: $(OUTPUT)
|
||||
|
||||
$(OUTPUT): $(OBJS)
|
||||
@echo "AR+RANLIB $@"
|
||||
@$(AR) ruv $@ $+ >/dev/null 2>&1
|
||||
@$(RANLIB) $@
|
||||
|
||||
include $(TOOLSDIR)/make.inc
|
||||
|
||||
clean:
|
||||
@echo "cleaning lib"
|
||||
@rm -f $(OBJS) $(OUTPUT) $(DEPFILE)
|
||||
|
||||
-include $(DEPFILE)
|
|
@ -17,21 +17,22 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* Various "helper functions" common to all the xxx2wav decoder plugins */
|
||||
/* "helper functions" common to all codecs */
|
||||
|
||||
#include "plugin.h"
|
||||
#include "playback.h"
|
||||
#include "codeclib.h"
|
||||
#include "xxx2wav.h"
|
||||
|
||||
struct plugin_api* local_rb;
|
||||
struct codec_api *local_rb;
|
||||
|
||||
int codec_init(struct plugin_api* rb, struct codec_api* ci) {
|
||||
int codec_init(struct codec_api* rb)
|
||||
{
|
||||
local_rb = rb;
|
||||
|
||||
xxx2wav_set_api(rb);
|
||||
mem_ptr = 0;
|
||||
mallocbuf = (unsigned char *)ci->get_codec_memory((size_t *)&bufsize);
|
||||
mallocbuf = (unsigned char *)rb->get_codec_memory((size_t *)&bufsize);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -17,7 +17,10 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* Various "helper functions" common to all the xxx2wav decoder plugins */
|
||||
#include "config.h"
|
||||
#include "codecs.h"
|
||||
|
||||
/* Various codec "helper functions" */
|
||||
|
||||
#if CONFIG_CPU == MCF5249 && !defined(SIMULATOR)
|
||||
#define ICODE_ATTR __attribute__ ((section(".icode")))
|
||||
|
@ -42,5 +45,5 @@ void *memset(void *s, int c, size_t n);
|
|||
int memcmp(const void *s1, const void *s2, size_t n);
|
||||
void* memmove(const void *s1, const void *s2, size_t n);
|
||||
|
||||
int codec_init(struct plugin_api* rb, struct codec_api* ci);
|
||||
int codec_init(struct codec_api* rb);
|
||||
|
|
@ -22,10 +22,10 @@
|
|||
#if (CONFIG_HWCODEC == MASNONE)
|
||||
/* software codec platforms, not for simulator */
|
||||
|
||||
#include "plugin.h"
|
||||
#include "codecs.h"
|
||||
#include "xxx2wav.h"
|
||||
|
||||
static struct plugin_api* local_rb;
|
||||
static struct codec_api* local_rb;
|
||||
|
||||
int mem_ptr;
|
||||
int bufsize;
|
||||
|
@ -33,11 +33,12 @@ unsigned char* audiobuf; // The actual audio buffer from Rockbox
|
|||
unsigned char* mallocbuf; // 512K from the start of audio buffer
|
||||
unsigned char* filebuf; // The rest of the audio buffer
|
||||
|
||||
void* codec_malloc(size_t size) {
|
||||
void* x;
|
||||
void* codec_malloc(size_t size)
|
||||
{
|
||||
void* x;
|
||||
|
||||
x=&mallocbuf[mem_ptr];
|
||||
mem_ptr+=(size+3)&~3; // Keep memory 32-bit aligned (if it was already?)
|
||||
x=&mallocbuf[mem_ptr];
|
||||
mem_ptr+=(size+3)&~3; // Keep memory 32-bit aligned (if it was already?)
|
||||
/*
|
||||
if(TIME_AFTER(*(local_rb->current_tick), last_tick + HZ)) {
|
||||
char s[32];
|
||||
|
@ -48,24 +49,26 @@ void* codec_malloc(size_t size) {
|
|||
last_tick = *(local_rb->current_tick);
|
||||
local_rb->lcd_update();
|
||||
}*/
|
||||
return(x);
|
||||
return(x);
|
||||
}
|
||||
|
||||
void* codec_calloc(size_t nmemb, size_t size) {
|
||||
void* x;
|
||||
x = codec_malloc(nmemb*size);
|
||||
local_rb->memset(x,0,nmemb*size);
|
||||
return(x);
|
||||
void* codec_calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void* x;
|
||||
x = codec_malloc(nmemb*size);
|
||||
local_rb->memset(x,0,nmemb*size);
|
||||
return(x);
|
||||
}
|
||||
|
||||
void* codec_alloca(size_t size) {
|
||||
void* x;
|
||||
x = codec_malloc(size);
|
||||
return(x);
|
||||
void* codec_alloca(size_t size)
|
||||
{
|
||||
void* x;
|
||||
x = codec_malloc(size);
|
||||
return(x);
|
||||
}
|
||||
|
||||
void codec_free(void* ptr) {
|
||||
(void)ptr;
|
||||
(void)ptr;
|
||||
}
|
||||
|
||||
void* codec_realloc(void* ptr, size_t size) {
|
||||
|
@ -146,6 +149,7 @@ void display_status(file_info_struct* file_info) {
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static unsigned char wav_header[44]={'R','I','F','F', // 0 - ChunkID
|
||||
0,0,0,0, // 4 - ChunkSize (filesize-8)
|
||||
'W','A','V','E', // 8 - Format
|
||||
|
@ -160,14 +164,18 @@ static unsigned char wav_header[44]={'R','I','F','F', // 0 - ChunkID
|
|||
'd','a','t','a', // 36 - Subchunk2ID
|
||||
0,0,0,0 // 40 - Subchunk2Size
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
void xxx2wav_set_api(struct plugin_api* rb)
|
||||
void xxx2wav_set_api(struct codec_api* rb)
|
||||
{
|
||||
local_rb = rb;
|
||||
}
|
||||
|
||||
int local_init(char* infilename, char* outfilename, file_info_struct* file_info, struct plugin_api* rb) {
|
||||
#if 0
|
||||
int local_init(char* infilename, char* outfilename,
|
||||
file_info_struct* file_info,
|
||||
struct codec_api* rb)
|
||||
{
|
||||
char s[32];
|
||||
int i,n,bytesleft;
|
||||
|
||||
|
@ -218,7 +226,8 @@ int local_init(char* infilename, char* outfilename, file_info_struct* file_info,
|
|||
return(0);
|
||||
}
|
||||
|
||||
void close_wav(file_info_struct* file_info) {
|
||||
void close_wav(file_info_struct* file_info)
|
||||
{
|
||||
int x;
|
||||
int filesize=local_rb->filesize(file_info->outfile);
|
||||
|
||||
|
@ -256,4 +265,6 @@ void close_wav(file_info_struct* file_info) {
|
|||
local_rb->write(file_info->outfile,wav_header,sizeof(wav_header));
|
||||
local_rb->close(file_info->outfile);
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
#endif /* CONFIG_HWCODEC == MASNONE */
|
|
@ -62,6 +62,8 @@ int memcmp(const void *s1, const void *s2, size_t n);
|
|||
void* memmove(const void *s1, const void *s2, size_t n);
|
||||
|
||||
void display_status(file_info_struct* file_info);
|
||||
int local_init(char* infilename, char* outfilename, file_info_struct* file_info, struct plugin_api* rb);
|
||||
int local_init(char* infilename, char* outfilename,
|
||||
file_info_struct* file_info,
|
||||
struct codec_api* rb);
|
||||
void close_wav(file_info_struct* file_info);
|
||||
void xxx2wav_set_api(struct plugin_api* rb);
|
||||
void xxx2wav_set_api(struct codec_api* rb);
|
521
apps/codecs/mpa.c
Normal file
521
apps/codecs/mpa.c
Normal file
|
@ -0,0 +1,521 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2005 Dave Chapman
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "codec.h"
|
||||
|
||||
#include <codecs/libmad/mad.h>
|
||||
|
||||
#include "playback.h"
|
||||
#include "mp3data.h"
|
||||
#include "lib/codeclib.h"
|
||||
|
||||
static struct codec_api* rb;
|
||||
|
||||
struct mad_stream Stream IDATA_ATTR;
|
||||
struct mad_frame Frame IDATA_ATTR;
|
||||
struct mad_synth Synth IDATA_ATTR;
|
||||
mad_timer_t Timer;
|
||||
struct dither d0, d1;
|
||||
|
||||
/* The following function is used inside libmad - let's hope it's never
|
||||
called.
|
||||
*/
|
||||
|
||||
void abort(void) {
|
||||
}
|
||||
|
||||
/* The "dither" code to convert the 24-bit samples produced by libmad was
|
||||
taken from the coolplayer project - coolplayer.sourceforge.net */
|
||||
|
||||
struct dither {
|
||||
mad_fixed_t error[3];
|
||||
mad_fixed_t random;
|
||||
};
|
||||
|
||||
# define SAMPLE_DEPTH 16
|
||||
# define scale(x, y) dither((x), (y))
|
||||
|
||||
/*
|
||||
* NAME: prng()
|
||||
* DESCRIPTION: 32-bit pseudo-random number generator
|
||||
*/
|
||||
static __inline
|
||||
unsigned long prng(unsigned long state)
|
||||
{
|
||||
return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: dither()
|
||||
* DESCRIPTION: dither and scale sample
|
||||
*/
|
||||
static __inline
|
||||
signed int dither(mad_fixed_t sample, struct dither *dither)
|
||||
{
|
||||
unsigned int scalebits;
|
||||
mad_fixed_t output, mask, random;
|
||||
|
||||
enum {
|
||||
MIN = -MAD_F_ONE,
|
||||
MAX = MAD_F_ONE - 1
|
||||
};
|
||||
|
||||
/* noise shape */
|
||||
sample += dither->error[0] - dither->error[1] + dither->error[2];
|
||||
|
||||
dither->error[2] = dither->error[1];
|
||||
dither->error[1] = dither->error[0] / 2;
|
||||
|
||||
/* bias */
|
||||
output = sample + (1L << (MAD_F_FRACBITS + 1 - SAMPLE_DEPTH - 1));
|
||||
|
||||
scalebits = MAD_F_FRACBITS + 1 - SAMPLE_DEPTH;
|
||||
mask = (1L << scalebits) - 1;
|
||||
|
||||
/* dither */
|
||||
random = prng(dither->random);
|
||||
output += (random & mask) - (dither->random & mask);
|
||||
|
||||
//dither->random = random;
|
||||
|
||||
/* clip */
|
||||
if (output > MAX) {
|
||||
output = MAX;
|
||||
|
||||
if (sample > MAX)
|
||||
sample = MAX;
|
||||
}
|
||||
else if (output < MIN) {
|
||||
output = MIN;
|
||||
|
||||
if (sample < MIN)
|
||||
sample = MIN;
|
||||
}
|
||||
|
||||
/* quantize */
|
||||
output &= ~mask;
|
||||
|
||||
/* error feedback */
|
||||
dither->error[0] = sample - output;
|
||||
|
||||
/* scale */
|
||||
return output >> scalebits;
|
||||
}
|
||||
|
||||
static __inline
|
||||
signed int detect_silence(mad_fixed_t sample)
|
||||
{
|
||||
unsigned int scalebits;
|
||||
mad_fixed_t output, mask;
|
||||
|
||||
enum {
|
||||
MIN = -MAD_F_ONE,
|
||||
MAX = MAD_F_ONE - 1
|
||||
};
|
||||
|
||||
/* bias */
|
||||
output = sample + (1L << (MAD_F_FRACBITS + 1 - SAMPLE_DEPTH - 1));
|
||||
|
||||
scalebits = MAD_F_FRACBITS + 1 - SAMPLE_DEPTH;
|
||||
mask = (1L << scalebits) - 1;
|
||||
|
||||
/* clip */
|
||||
if (output > MAX) {
|
||||
output = MAX;
|
||||
|
||||
if (sample > MAX)
|
||||
sample = MAX;
|
||||
}
|
||||
else if (output < MIN) {
|
||||
output = MIN;
|
||||
|
||||
if (sample < MIN)
|
||||
sample = MIN;
|
||||
}
|
||||
|
||||
/* quantize */
|
||||
output &= ~mask;
|
||||
|
||||
/* scale */
|
||||
output >>= scalebits + 4;
|
||||
|
||||
if (output == 0x00 || output == 0xff)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#define SHRT_MAX 32767
|
||||
|
||||
#define INPUT_CHUNK_SIZE 8192
|
||||
#define OUTPUT_BUFFER_SIZE 65536 /* Must be an integer multiple of 4. */
|
||||
|
||||
unsigned char OutputBuffer[OUTPUT_BUFFER_SIZE];
|
||||
unsigned char *OutputPtr;
|
||||
unsigned char *GuardPtr=NULL;
|
||||
const unsigned char *OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE;
|
||||
long resampled_data[2][5000]; /* enough to cope with 11khz upsampling */
|
||||
|
||||
mad_fixed_t mad_frame_overlap[2][32][18] IDATA_ATTR;
|
||||
unsigned char mad_main_data[MAD_BUFFER_MDLEN] IDATA_ATTR;
|
||||
/* TODO: what latency does layer 1 have? */
|
||||
int mpeg_latency[3] = { 0, 481, 529 };
|
||||
#ifdef USE_IRAM
|
||||
extern char iramcopy[];
|
||||
extern char iramstart[];
|
||||
extern char iramend[];
|
||||
#endif
|
||||
|
||||
#undef DEBUG_GAPLESS
|
||||
|
||||
struct resampler {
|
||||
long last_sample, phase, delta;
|
||||
};
|
||||
|
||||
#if CONFIG_CPU==MCF5249 && !defined(SIMULATOR)
|
||||
|
||||
#define INIT() asm volatile ("move.l #0xb0, %macsr") /* frac, round, clip */
|
||||
#define FRACMUL(x, y) \
|
||||
({ \
|
||||
long t; \
|
||||
asm volatile ("mac.l %[a], %[b], %%acc0\n\t" \
|
||||
"movclr.l %%acc0, %[t]\n\t" \
|
||||
: [t] "=r" (t) : [a] "r" (x), [b] "r" (y)); \
|
||||
t; \
|
||||
})
|
||||
|
||||
#else
|
||||
|
||||
#define INIT()
|
||||
#define FRACMUL(x, y) (long)(((long long)(x)*(long long)(y)) << 1)
|
||||
#endif
|
||||
|
||||
/* linear resampling, introduces one sample delay, because of our inability to
|
||||
look into the future at the end of a frame */
|
||||
long downsample(long *in, long *out, int num, struct resampler *s)
|
||||
{
|
||||
long i = 1, pos;
|
||||
long last = s->last_sample;
|
||||
|
||||
INIT();
|
||||
pos = s->phase >> 16;
|
||||
/* check if we need last sample of previous frame for interpolation */
|
||||
if (pos > 0)
|
||||
last = in[pos - 1];
|
||||
out[0] = last + FRACMUL((s->phase & 0xffff) << 15, in[pos] - last);
|
||||
s->phase += s->delta;
|
||||
while ((pos = s->phase >> 16) < num) {
|
||||
out[i++] = in[pos - 1] + FRACMUL((s->phase & 0xffff) << 15, in[pos] - in[pos - 1]);
|
||||
s->phase += s->delta;
|
||||
}
|
||||
/* wrap phase accumulator back to start of next frame */
|
||||
s->phase -= num << 16;
|
||||
s->last_sample = in[num - 1];
|
||||
return i;
|
||||
}
|
||||
|
||||
long upsample(long *in, long *out, int num, struct resampler *s)
|
||||
{
|
||||
long i = 0, pos;
|
||||
|
||||
INIT();
|
||||
while ((pos = s->phase >> 16) == 0) {
|
||||
out[i++] = s->last_sample + FRACMUL((s->phase & 0xffff) << 15, in[pos] - s->last_sample);
|
||||
s->phase += s->delta;
|
||||
}
|
||||
while ((pos = s->phase >> 16) < num) {
|
||||
out[i++] = in[pos - 1] + FRACMUL((s->phase & 0xffff) << 15, in[pos] - in[pos - 1]);
|
||||
s->phase += s->delta;
|
||||
}
|
||||
/* wrap phase accumulator back to start of next frame */
|
||||
s->phase -= num << 16;
|
||||
s->last_sample = in[num - 1];
|
||||
return i;
|
||||
}
|
||||
|
||||
long resample(long *in, long *out, int num, struct resampler *s)
|
||||
{
|
||||
if (s->delta >= (1 << 16))
|
||||
return downsample(in, out, num, s);
|
||||
else
|
||||
return upsample(in, out, num, s);
|
||||
}
|
||||
|
||||
/* this is the codec entry point */
|
||||
enum codec_status codec_start(struct codec_api* api, void* parm)
|
||||
{
|
||||
struct codec_api *ci = api;
|
||||
struct mp3info *info;
|
||||
int Status=0;
|
||||
size_t size;
|
||||
int file_end;
|
||||
unsigned short Sample;
|
||||
char *InputBuffer;
|
||||
unsigned int samplecount;
|
||||
unsigned int samplesdone;
|
||||
bool first_frame;
|
||||
#ifdef DEBUG_GAPLESS
|
||||
bool first = true;
|
||||
int fd;
|
||||
#endif
|
||||
int i;
|
||||
int yieldcounter = 0;
|
||||
int stop_skip, start_skip;
|
||||
struct resampler lr = { 0, 0, 0 }, rr = { 0, 0, 0 };
|
||||
long length;
|
||||
/* Generic codec inititialisation */
|
||||
(void)parm;
|
||||
|
||||
TEST_CODEC_API(api);
|
||||
rb = api;
|
||||
|
||||
#ifdef USE_IRAM
|
||||
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
|
||||
#endif
|
||||
|
||||
/* This function sets up the buffers and reads the file into RAM */
|
||||
|
||||
if (codec_init(api)) {
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
|
||||
/* Create a decoder instance */
|
||||
|
||||
ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2));
|
||||
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16));
|
||||
|
||||
memset(&Stream, 0, sizeof(struct mad_stream));
|
||||
memset(&Frame, 0, sizeof(struct mad_frame));
|
||||
memset(&Synth, 0, sizeof(struct mad_synth));
|
||||
memset(&Timer, 0, sizeof(mad_timer_t));
|
||||
|
||||
mad_stream_init(&Stream);
|
||||
mad_frame_init(&Frame);
|
||||
mad_synth_init(&Synth);
|
||||
mad_timer_reset(&Timer);
|
||||
|
||||
/* We do this so libmad doesn't try to call codec_calloc() */
|
||||
memset(mad_frame_overlap, 0, sizeof(mad_frame_overlap));
|
||||
Frame.overlap = &mad_frame_overlap;
|
||||
Stream.main_data = &mad_main_data;
|
||||
/* This label might need to be moved above all the init code, but I don't
|
||||
think reiniting the codec is necessary for MPEG. It might even be unwanted
|
||||
for gapless playback */
|
||||
next_track:
|
||||
|
||||
#ifdef DEBUG_GAPLESS
|
||||
if (first)
|
||||
fd = rb->open("/first.pcm", O_WRONLY | O_CREAT);
|
||||
else
|
||||
fd = rb->open("/second.pcm", O_WRONLY | O_CREAT);
|
||||
first = false;
|
||||
#endif
|
||||
|
||||
info = ci->mp3data;
|
||||
first_frame = false;
|
||||
file_end = 0;
|
||||
OutputPtr = OutputBuffer;
|
||||
|
||||
while (!*ci->taginfo_ready)
|
||||
rb->yield();
|
||||
|
||||
ci->request_buffer(&size, ci->id3->first_frame_offset);
|
||||
ci->advance_buffer(size);
|
||||
|
||||
if (info->enc_delay >= 0 && info->enc_padding >= 0) {
|
||||
stop_skip = info->enc_padding - mpeg_latency[info->layer];
|
||||
if (stop_skip < 0) stop_skip = 0;
|
||||
start_skip = info->enc_delay + mpeg_latency[info->layer];
|
||||
} else {
|
||||
stop_skip = 0;
|
||||
/* We want to skip this amount anyway */
|
||||
start_skip = mpeg_latency[info->layer];
|
||||
}
|
||||
|
||||
/* NOTE: currently this doesn't work, the below calculated samples_count
|
||||
seems to be right, but sometimes libmad just can't supply us with
|
||||
all the data we need... */
|
||||
if (info->frame_count) {
|
||||
/* TODO: 1152 is the frame size in samples for MPEG1 layer 2 and layer 3,
|
||||
it's probably not correct at all for MPEG2 and layer 1 */
|
||||
samplecount = info->frame_count*1152 - (start_skip + stop_skip);
|
||||
samplesdone = ci->id3->elapsed * (ci->id3->frequency / 100) / 10;
|
||||
} else {
|
||||
samplecount = ci->id3->length * (ci->id3->frequency / 100) / 10;
|
||||
samplesdone = ci->id3->elapsed * (ci->id3->frequency / 100) / 10;
|
||||
}
|
||||
/* rb->snprintf(buf2, sizeof(buf2), "sc: %d", samplecount);
|
||||
rb->splash(0, true, buf2);
|
||||
rb->snprintf(buf2, sizeof(buf2), "length: %d", ci->id3->length);
|
||||
rb->splash(HZ*5, true, buf2);
|
||||
rb->snprintf(buf2, sizeof(buf2), "frequency: %d", ci->id3->frequency);
|
||||
rb->splash(HZ*5, true, buf2); */
|
||||
lr.delta = rr.delta = ci->id3->frequency*65536/44100;
|
||||
/* This is the decoding loop. */
|
||||
while (1) {
|
||||
rb->yield();
|
||||
if (ci->stop_codec || ci->reload_codec) {
|
||||
break ;
|
||||
}
|
||||
|
||||
if (ci->seek_time) {
|
||||
unsigned int sample_loc;
|
||||
int newpos;
|
||||
|
||||
sample_loc = ci->seek_time/1000 * ci->id3->frequency;
|
||||
newpos = ci->mp3_get_filepos(ci->seek_time-1);
|
||||
if (ci->seek_buffer(newpos)) {
|
||||
if (sample_loc >= samplecount + samplesdone)
|
||||
break ;
|
||||
samplecount += samplesdone - sample_loc;
|
||||
samplesdone = sample_loc;
|
||||
}
|
||||
ci->seek_time = 0;
|
||||
}
|
||||
|
||||
/* Lock buffers */
|
||||
if (Stream.error == 0) {
|
||||
InputBuffer = ci->request_buffer(&size, INPUT_CHUNK_SIZE);
|
||||
if (size == 0 || InputBuffer == NULL)
|
||||
break ;
|
||||
mad_stream_buffer(&Stream, InputBuffer, size);
|
||||
}
|
||||
|
||||
//if ((int)ci->curpos >= ci->id3->first_frame_offset)
|
||||
//first_frame = true;
|
||||
|
||||
if(mad_frame_decode(&Frame,&Stream))
|
||||
{
|
||||
if (Stream.error == MAD_FLAG_INCOMPLETE || Stream.error == MAD_ERROR_BUFLEN) {
|
||||
// rb->splash(HZ*1, true, "Incomplete");
|
||||
/* This makes the codec to support partially corrupted files too. */
|
||||
if (file_end == 30)
|
||||
break ;
|
||||
|
||||
/* Fill the buffer */
|
||||
Stream.error = 0;
|
||||
file_end++;
|
||||
continue ;
|
||||
}
|
||||
else if(MAD_RECOVERABLE(Stream.error))
|
||||
{
|
||||
if(Stream.error!=MAD_ERROR_LOSTSYNC || Stream.this_frame!=GuardPtr)
|
||||
{
|
||||
// rb->splash(HZ*1, true, "Recoverable...!");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if(Stream.error==MAD_ERROR_BUFLEN) {
|
||||
//rb->splash(HZ*1, true, "Buflen error");
|
||||
break ;
|
||||
} else {
|
||||
//rb->splash(HZ*1, true, "Unrecoverable error");
|
||||
Status=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Stream.next_frame)
|
||||
ci->advance_buffer_loc((void *)Stream.next_frame);
|
||||
file_end = false;
|
||||
/* ?? Do we need the timer module? */
|
||||
// mad_timer_add(&Timer,Frame.header.duration);
|
||||
|
||||
/* DAVE: This can be used to attenuate the audio */
|
||||
// if(DoFilter)
|
||||
// ApplyFilter(&Frame);
|
||||
|
||||
mad_synth_frame(&Synth,&Frame);
|
||||
|
||||
//if (!first_frame) {
|
||||
//samplecount -= Synth.pcm.length;
|
||||
//continue ;
|
||||
//}
|
||||
|
||||
/* Convert MAD's numbers to an array of 16-bit LE signed integers */
|
||||
/* We skip start_skip number of samples here, this should only happen for
|
||||
very first frame in the stream. */
|
||||
/* TODO: possible for start_skip to exceed one frames worth of samples? */
|
||||
length = resample((long *)&Synth.pcm.samples[0][start_skip], resampled_data[0], Synth.pcm.length, &lr);
|
||||
if (MAD_NCHANNELS(&Frame.header) == 2)
|
||||
resample((long *)&Synth.pcm.samples[1][start_skip], resampled_data[1], Synth.pcm.length, &rr);
|
||||
for (i = 0;i<length;i++)
|
||||
{
|
||||
start_skip = 0; /* not very elegant, and might want to keep this value */
|
||||
samplesdone++;
|
||||
//if (ci->mp3data->padding > 0) {
|
||||
// ci->mp3data->padding--;
|
||||
// continue ;
|
||||
//}
|
||||
/*if (!first_frame) {
|
||||
if (detect_silence(Synth.pcm.samples[0][i]))
|
||||
continue ;
|
||||
first_frame = true;
|
||||
}*/
|
||||
|
||||
/* Left channel */
|
||||
Sample=scale(resampled_data[0][i],&d0);
|
||||
*(OutputPtr++)=Sample>>8;
|
||||
*(OutputPtr++)=Sample&0xff;
|
||||
|
||||
/* Right channel. If the decoded stream is monophonic then
|
||||
* the right output channel is the same as the left one.
|
||||
*/
|
||||
if(MAD_NCHANNELS(&Frame.header)==2)
|
||||
Sample=scale(resampled_data[1][i],&d1);
|
||||
*(OutputPtr++)=Sample>>8;
|
||||
*(OutputPtr++)=Sample&0xff;
|
||||
|
||||
samplecount--;
|
||||
if (samplecount == 0) {
|
||||
#ifdef DEBUG_GAPLESS
|
||||
rb->write(fd, OutputBuffer, (int)OutputPtr-(int)OutputBuffer);
|
||||
#endif
|
||||
while (!ci->audiobuffer_insert(OutputBuffer, (int)OutputPtr-(int)OutputBuffer))
|
||||
rb->yield();
|
||||
goto song_end;
|
||||
}
|
||||
|
||||
if (yieldcounter++ == 200) {
|
||||
rb->yield();
|
||||
yieldcounter = 0;
|
||||
}
|
||||
|
||||
/* Flush the buffer if it is full. */
|
||||
if(OutputPtr==OutputBufferEnd)
|
||||
{
|
||||
#ifdef DEBUG_GAPLESS
|
||||
rb->write(fd, OutputBuffer, OUTPUT_BUFFER_SIZE);
|
||||
#endif
|
||||
while (!ci->audiobuffer_insert(OutputBuffer, OUTPUT_BUFFER_SIZE))
|
||||
rb->yield();
|
||||
OutputPtr=OutputBuffer;
|
||||
}
|
||||
}
|
||||
ci->set_elapsed(samplesdone / (ci->id3->frequency/1000));
|
||||
}
|
||||
|
||||
song_end:
|
||||
#ifdef DEBUG_GAPLESS
|
||||
rb->close(fd);
|
||||
#endif
|
||||
Stream.error = 0;
|
||||
|
||||
if (ci->request_next_track())
|
||||
goto next_track;
|
||||
return CODEC_OK;
|
||||
}
|
|
@ -17,12 +17,12 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "codec.h"
|
||||
#include "playback.h"
|
||||
#include "lib/codeclib.h"
|
||||
#include <codecs/libmusepack/musepack.h>
|
||||
|
||||
static struct plugin_api* rb;
|
||||
static struct codec_api* rb;
|
||||
mpc_decoder decoder;
|
||||
|
||||
/*
|
||||
|
@ -92,10 +92,10 @@ extern char iramstart[];
|
|||
extern char iramend[];
|
||||
#endif
|
||||
|
||||
/* this is the plugin entry point */
|
||||
enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||
/* this is the codec entry point */
|
||||
enum codec_status codec_start(struct codec_api* api, void* parm)
|
||||
{
|
||||
struct codec_api* ci = (struct codec_api*)parm;
|
||||
struct codec_api* ci = api;
|
||||
unsigned short Sample;
|
||||
unsigned long samplesdone;
|
||||
unsigned long frequency;
|
||||
|
@ -103,9 +103,9 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
unsigned int i;
|
||||
mpc_reader reader;
|
||||
|
||||
/* Generic plugin inititialisation */
|
||||
/* Generic codec inititialisation */
|
||||
|
||||
TEST_PLUGIN_API(api);
|
||||
TEST_CODEC_API(api);
|
||||
rb = api;
|
||||
|
||||
#ifndef SIMULATOR
|
||||
|
@ -117,8 +117,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
|
||||
next_track:
|
||||
|
||||
if (codec_init(api, ci)) {
|
||||
return PLUGIN_ERROR;
|
||||
if (codec_init(api)) {
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
|
||||
/* Create a decoder instance */
|
||||
|
@ -134,14 +134,14 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
mpc_streaminfo info;
|
||||
mpc_streaminfo_init(&info);
|
||||
if (mpc_streaminfo_read(&info, &reader) != ERROR_CODE_OK) {
|
||||
return PLUGIN_ERROR;
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
frequency=info.sample_freq;
|
||||
|
||||
/* instantiate a decoder with our file reader */
|
||||
mpc_decoder_setup(&decoder, &reader);
|
||||
if (!mpc_decoder_initialize(&decoder, &info)) {
|
||||
return PLUGIN_ERROR;
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
|
||||
/* Initialise the output buffer. */
|
||||
|
@ -158,7 +158,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
status = mpc_decoder_decode(&decoder, sample_buffer, 0, 0);
|
||||
if (status == (unsigned)(-1)) {
|
||||
//decode error
|
||||
return PLUGIN_ERROR;
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
else //status>0
|
||||
{
|
||||
|
@ -209,6 +209,6 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
if (ci->request_next_track())
|
||||
goto next_track;
|
||||
|
||||
return PLUGIN_OK;
|
||||
return CODEC_OK;
|
||||
}
|
||||
|
168
apps/codecs/vorbis.c
Normal file
168
apps/codecs/vorbis.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002 Björn Stenberg
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "kernel.h"
|
||||
#include "codecs.h"
|
||||
|
||||
#include "Tremor/ivorbisfile.h"
|
||||
#include "playback.h"
|
||||
#include "lib/codeclib.h"
|
||||
|
||||
static struct codec_api* rb;
|
||||
|
||||
/* Some standard functions and variables needed by Tremor */
|
||||
|
||||
int errno;
|
||||
|
||||
size_t strlen(const char *s)
|
||||
{
|
||||
return(rb->strlen(s));
|
||||
}
|
||||
|
||||
char *strcpy(char *dest, const char *src)
|
||||
{
|
||||
return(rb->strcpy(dest,src));
|
||||
}
|
||||
|
||||
char *strcat(char *dest, const char *src)
|
||||
{
|
||||
return(rb->strcat(dest,src));
|
||||
}
|
||||
|
||||
size_t read_handler(void *ptr, size_t size, size_t nmemb, void *datasource)
|
||||
{
|
||||
return rb->read_filebuf(ptr, nmemb*size);
|
||||
}
|
||||
|
||||
int seek_handler(void *datasource, ogg_int64_t offset, int whence)
|
||||
{
|
||||
/* We are not seekable at the moment */
|
||||
(void)datasource;
|
||||
(void)offset;
|
||||
(void)whence;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int close_handler(void *datasource)
|
||||
{
|
||||
(void)datasource;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long tell_handler(void *datasource)
|
||||
{
|
||||
return rb->curpos;
|
||||
}
|
||||
|
||||
#ifdef USE_IRAM
|
||||
extern char iramcopy[];
|
||||
extern char iramstart[];
|
||||
extern char iramend[];
|
||||
#endif
|
||||
|
||||
|
||||
/* reserve the PCM buffer in the IRAM area */
|
||||
static char pcmbuf[4096] IDATA_ATTR;
|
||||
|
||||
/* this is the codec entry point */
|
||||
enum codec_status codec_start(struct codec_api* api, void* parm)
|
||||
{
|
||||
ov_callbacks callbacks;
|
||||
OggVorbis_File vf;
|
||||
vorbis_info* vi;
|
||||
|
||||
int error;
|
||||
long n;
|
||||
int current_section;
|
||||
int eof;
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
int i;
|
||||
char x;
|
||||
#endif
|
||||
|
||||
TEST_CODEC_API(api);
|
||||
|
||||
/* if you are using a global api pointer, don't forget to copy it!
|
||||
otherwise you will get lovely "I04: IllInstr" errors... :-) */
|
||||
rb = api;
|
||||
|
||||
#ifdef USE_IRAM
|
||||
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
|
||||
#endif
|
||||
|
||||
rb->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2));
|
||||
rb->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*64));
|
||||
|
||||
/* We need to flush reserver memory every track load. */
|
||||
next_track:
|
||||
if (codec_init(rb)) {
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/* Create a decoder instance */
|
||||
|
||||
callbacks.read_func=read_handler;
|
||||
callbacks.seek_func=seek_handler;
|
||||
callbacks.tell_func=tell_handler;
|
||||
callbacks.close_func=close_handler;
|
||||
|
||||
error=ov_open_callbacks(rb,&vf,NULL,0,callbacks);
|
||||
|
||||
vi=ov_info(&vf,-1);
|
||||
|
||||
if (vi==NULL) {
|
||||
// rb->splash(HZ*2, true, "Vorbis Error");
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
|
||||
eof=0;
|
||||
while (!eof) {
|
||||
/* Read host-endian signed 16 bit PCM samples */
|
||||
n=ov_read(&vf,pcmbuf,sizeof(pcmbuf),¤t_section);
|
||||
|
||||
if (n==0) {
|
||||
eof=1;
|
||||
}
|
||||
else if (n < 0) {
|
||||
DEBUGF("Error decoding frame\n");
|
||||
} else {
|
||||
rb->yield();
|
||||
if (rb->stop_codec || rb->reload_codec)
|
||||
break ;
|
||||
|
||||
rb->yield();
|
||||
while (!rb->audiobuffer_insert(pcmbuf, n))
|
||||
rb->yield();
|
||||
|
||||
rb->set_elapsed(ov_time_tell(&vf));
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
for (i=0;i<n;i+=2) {
|
||||
x=pcmbuf[i]; pcmbuf[i]=pcmbuf[i+1]; pcmbuf[i+1]=x;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (rb->request_next_track())
|
||||
goto next_track;
|
||||
|
||||
return CODEC_OK;
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "codec.h"
|
||||
#include "playback.h"
|
||||
#include "lib/codeclib.h"
|
||||
|
||||
|
@ -32,11 +32,11 @@ extern char iramstart[];
|
|||
extern char iramend[];
|
||||
#endif
|
||||
|
||||
/* this is the plugin entry point */
|
||||
enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||
/* this is the codec entry point */
|
||||
enum codec_status codec_start(struct codec_api* api, void* parm)
|
||||
{
|
||||
struct plugin_api* rb = (struct plugin_api*)api;
|
||||
struct codec_api* ci = (struct codec_api*)parm;
|
||||
struct codec_api* rb = api;
|
||||
struct codec_api* ci = api;
|
||||
unsigned long samplerate,numbytes,totalsamples,samplesdone,nsamples;
|
||||
int channels,bytespersample,bitspersample;
|
||||
unsigned int i;
|
||||
|
@ -45,8 +45,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
unsigned char* header;
|
||||
unsigned short* wavbuf;
|
||||
|
||||
/* Generic plugin initialisation */
|
||||
TEST_PLUGIN_API(api);
|
||||
/* Generic codec initialisation */
|
||||
TEST_CODEC_API(api);
|
||||
|
||||
/* if you are using a global api pointer, don't forget to copy it!
|
||||
otherwise you will get lovely "I04: IllInstr" errors... :-) */
|
||||
|
@ -62,18 +62,18 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
|
||||
next_track:
|
||||
|
||||
if (codec_init(api, ci)) {
|
||||
return PLUGIN_ERROR;
|
||||
if (codec_init(api)) {
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
|
||||
/* FIX: Correctly parse WAV header - we assume canonical 44-byte header */
|
||||
|
||||
header=ci->request_buffer(&n,44);
|
||||
if (n!=44) {
|
||||
return PLUGIN_ERROR;
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
if ((memcmp(header,"RIFF",4)!=0) || (memcmp(&header[8],"WAVEfmt",7)!=0)) {
|
||||
return PLUGIN_ERROR;
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
|
||||
samplerate=header[24]|(header[25]<<8)|(header[26]<<16)|(header[27]<<24);
|
||||
|
@ -84,7 +84,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
totalsamples=numbytes/bytespersample;
|
||||
|
||||
if ((bitspersample!=16) || (channels != 2)) {
|
||||
return PLUGIN_ERROR;
|
||||
return CODEC_ERROR;
|
||||
}
|
||||
|
||||
ci->advance_buffer(44);
|
||||
|
@ -132,5 +132,5 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
if (ci->request_next_track())
|
||||
goto next_track;
|
||||
|
||||
return PLUGIN_OK;
|
||||
return CODEC_OK;
|
||||
}
|
|
@ -17,13 +17,13 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "codec.h"
|
||||
|
||||
#include <codecs/libwavpack/wavpack.h>
|
||||
#include "playback.h"
|
||||
#include "lib/codeclib.h"
|
||||
|
||||
static struct plugin_api *rb;
|
||||
static struct codec_api *rb;
|
||||
static struct codec_api *ci;
|
||||
|
||||
#define BUFFER_SIZE 4096
|
||||
|
@ -41,18 +41,18 @@ extern char iramstart[];
|
|||
extern char iramend[];
|
||||
#endif
|
||||
|
||||
/* this is the plugin entry point */
|
||||
enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||
/* this is the codec entry point */
|
||||
enum codec_status codec_start(struct codec_api* api, void* parm)
|
||||
{
|
||||
WavpackContext *wpc;
|
||||
char error [80];
|
||||
int bps, nchans;
|
||||
|
||||
/* Generic plugin initialisation */
|
||||
TEST_PLUGIN_API(api);
|
||||
/* Generic codec initialisation */
|
||||
TEST_CODEC_API(api);
|
||||
|
||||
rb = api;
|
||||
ci = (struct codec_api*) parm;
|
||||
ci = api;
|
||||
|
||||
#ifndef SIMULATOR
|
||||
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
|
||||
|
@ -64,15 +64,15 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
|
||||
next_track:
|
||||
|
||||
if (codec_init(api, ci))
|
||||
return PLUGIN_ERROR;
|
||||
if (codec_init(api))
|
||||
return CODEC_ERROR;
|
||||
|
||||
/* Create a decoder instance */
|
||||
|
||||
wpc = WavpackOpenFileInput (read_callback, error);
|
||||
|
||||
if (!wpc)
|
||||
return PLUGIN_ERROR;
|
||||
return CODEC_ERROR;
|
||||
|
||||
bps = WavpackGetBytesPerSample (wpc);
|
||||
nchans = WavpackGetReducedChannels (wpc);
|
||||
|
@ -181,5 +181,5 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
|||
if (ci->request_next_track())
|
||||
goto next_track;
|
||||
|
||||
return PLUGIN_OK;
|
||||
return CODEC_OK;
|
||||
}
|
|
@ -33,7 +33,7 @@
|
|||
#include "debug.h"
|
||||
#include "sprintf.h"
|
||||
#include "settings.h"
|
||||
#include "plugin.h"
|
||||
#include "codecs.h"
|
||||
#include "wps.h"
|
||||
#include "wps-display.h"
|
||||
#include "audio.h"
|
||||
|
@ -63,13 +63,13 @@
|
|||
static volatile bool playing;
|
||||
static volatile bool paused;
|
||||
|
||||
#define CODEC_VORBIS "/.rockbox/codecs/codecvorbis.rock";
|
||||
#define CODEC_MPA_L3 "/.rockbox/codecs/codecmpa.rock";
|
||||
#define CODEC_FLAC "/.rockbox/codecs/codecflac.rock";
|
||||
#define CODEC_WAV "/.rockbox/codecs/codecwav.rock";
|
||||
#define CODEC_A52 "/.rockbox/codecs/codeca52.rock";
|
||||
#define CODEC_MPC "/.rockbox/codecs/codecmpc.rock";
|
||||
#define CODEC_WAVPACK "/.rockbox/codecs/codecwavpack.rock";
|
||||
#define CODEC_VORBIS "/.rockbox/codecs/vorbis.codec";
|
||||
#define CODEC_MPA_L3 "/.rockbox/codecs/mpa.codec";
|
||||
#define CODEC_FLAC "/.rockbox/codecs/flac.codec";
|
||||
#define CODEC_WAV "/.rockbox/codecs/wav.codec";
|
||||
#define CODEC_A52 "/.rockbox/codecs/a52.codec";
|
||||
#define CODEC_MPC "/.rockbox/codecs/mpc.codec";
|
||||
#define CODEC_WAVPACK "/.rockbox/codecs/wavpack.codec";
|
||||
|
||||
#define AUDIO_FILL_CYCLE (1024*256)
|
||||
#define AUDIO_DEFAULT_WATERMARK (1024*256)
|
||||
|
@ -153,7 +153,7 @@ static struct track_info tracks[MAX_TRACK];
|
|||
static volatile struct track_info *cur_ti;
|
||||
|
||||
/* Codec API including function callbacks. */
|
||||
static struct codec_api ci;
|
||||
extern struct codec_api ci;
|
||||
|
||||
/* When we change a song and buffer is not in filling state, this
|
||||
variable keeps information about whether to go a next/previous track. */
|
||||
|
@ -1074,7 +1074,7 @@ void codec_thread(void)
|
|||
switch (ev.id) {
|
||||
case CODEC_LOAD_DISK:
|
||||
ci.stop_codec = false;
|
||||
status = codec_load_file((char *)ev.data, &ci);
|
||||
status = codec_load_file((char *)ev.data);
|
||||
break ;
|
||||
|
||||
case CODEC_LOAD:
|
||||
|
@ -1089,7 +1089,7 @@ void codec_thread(void)
|
|||
ci.stop_codec = false;
|
||||
wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf;
|
||||
status = codec_load_ram(cur_ti->codecbuf, codecsize,
|
||||
&ci, &codecbuf[0], wrap);
|
||||
&codecbuf[0], wrap);
|
||||
break ;
|
||||
|
||||
#ifndef SIMULATOR
|
||||
|
@ -1103,7 +1103,7 @@ void codec_thread(void)
|
|||
switch (ev.id) {
|
||||
case CODEC_LOAD_DISK:
|
||||
case CODEC_LOAD:
|
||||
if (status != PLUGIN_OK) {
|
||||
if (status != CODEC_OK) {
|
||||
logf("Codec failure");
|
||||
splash(HZ*2, true, "Codec failure");
|
||||
playing = false;
|
||||
|
|
|
@ -51,60 +51,6 @@ struct track_info {
|
|||
int playlist_offset; /* File location in playlist */
|
||||
};
|
||||
|
||||
|
||||
/* Codec Interface */
|
||||
struct codec_api {
|
||||
off_t filesize; /* Total file length */
|
||||
off_t curpos; /* Current buffer position */
|
||||
|
||||
/* For gapless mp3 */
|
||||
struct mp3entry *id3; /* TAG metadata pointer */
|
||||
struct mp3info *mp3data; /* MP3 metadata pointer */
|
||||
bool *taginfo_ready; /* Is metadata read */
|
||||
|
||||
/* Codec should periodically check if stop_codec is set to true.
|
||||
In case it's, codec must return with PLUGIN_OK status immediately. */
|
||||
bool stop_codec;
|
||||
/* Codec should periodically check if reload_codec is set to true.
|
||||
In case it's, codec should reload itself without exiting. */
|
||||
bool reload_codec;
|
||||
/* If seek_time != 0, codec should seek to that song position (in ms)
|
||||
if codec supports seeking. */
|
||||
int seek_time;
|
||||
|
||||
/* Returns buffer to malloc array. Only codeclib should need this. */
|
||||
void* (*get_codec_memory)(size_t *size);
|
||||
/* Insert PCM data into audio buffer for playback. Playback will start
|
||||
automatically. */
|
||||
bool (*audiobuffer_insert)(char *data, size_t length);
|
||||
/* Set song position in WPS (value in ms). */
|
||||
void (*set_elapsed)(unsigned int value);
|
||||
|
||||
/* Read next <size> amount bytes from file buffer to <ptr>.
|
||||
Will return number of bytes read or 0 if end of file. */
|
||||
size_t (*read_filebuf)(void *ptr, size_t size);
|
||||
/* Request pointer to file buffer which can be used to read
|
||||
<realsize> amount of data. <reqsize> tells the buffer system
|
||||
how much data it should try to allocate. If <realsize> is 0,
|
||||
end of file is reached. */
|
||||
void* (*request_buffer)(size_t *realsize, size_t reqsize);
|
||||
/* Advance file buffer position by <amount> amount of bytes. */
|
||||
void (*advance_buffer)(size_t amount);
|
||||
/* Advance file buffer to a pointer location inside file buffer. */
|
||||
void (*advance_buffer_loc)(void *ptr);
|
||||
/* Seek file buffer to position <newpos> beginning of file. */
|
||||
bool (*seek_buffer)(off_t newpos);
|
||||
/* Calculate mp3 seek position from given time data in ms. */
|
||||
off_t (*mp3_get_filepos)(int newtime);
|
||||
/* Request file change from file buffer. Returns true is next
|
||||
track is available and changed. If return value is false,
|
||||
codec should exit immediately with PLUGIN_OK status. */
|
||||
bool (*request_next_track)(void);
|
||||
|
||||
/* Configure different codec buffer parameters. */
|
||||
void (*configure)(int setting, void *value);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -332,60 +332,6 @@ static const struct plugin_api rockbox_api = {
|
|||
|
||||
};
|
||||
|
||||
#if CONFIG_HWCODEC == MASNONE
|
||||
int codec_load_ram(char* codecptr, size_t size, void *parameter, void* ptr2,
|
||||
size_t bufwrap)
|
||||
{
|
||||
enum plugin_status (*plugin_start)(struct plugin_api* api, void* param);
|
||||
int copy_n;
|
||||
int status;
|
||||
|
||||
if ((char *)&codecbuf[0] != codecptr) {
|
||||
/* zero out codec buffer to ensure a properly zeroed bss area */
|
||||
memset(codecbuf, 0, CODEC_BUFFER_SIZE);
|
||||
|
||||
size = MIN(size, CODEC_BUFFER_SIZE);
|
||||
copy_n = MIN(size, bufwrap);
|
||||
memcpy(codecbuf, codecptr, copy_n);
|
||||
size -= copy_n;
|
||||
if (size > 0) {
|
||||
memcpy(&codecbuf[copy_n], ptr2, size);
|
||||
}
|
||||
}
|
||||
plugin_start = (void*)&codecbuf;
|
||||
|
||||
invalidate_icache();
|
||||
status = plugin_start((struct plugin_api*) &rockbox_api, parameter);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int codec_load_file(const char *plugin, void *parameter)
|
||||
{
|
||||
char msgbuf[80];
|
||||
int fd;
|
||||
int rc;
|
||||
|
||||
fd = open(plugin, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
snprintf(msgbuf, sizeof(msgbuf)-1, "Couldn't load codec: %s", plugin);
|
||||
logf("Codec load error:%d", fd);
|
||||
splash(HZ*2, true, msgbuf);
|
||||
return fd;
|
||||
}
|
||||
|
||||
rc = read(fd, &codecbuf[0], CODEC_BUFFER_SIZE);
|
||||
close(fd);
|
||||
if (rc <= 0) {
|
||||
logf("Codec read error");
|
||||
return PLUGIN_ERROR;
|
||||
}
|
||||
|
||||
return codec_load_ram(codecbuf, (size_t)rc, parameter, NULL, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int plugin_load(const char* plugin, void* parameter)
|
||||
{
|
||||
enum plugin_status (*plugin_start)(struct plugin_api* api, void* param);
|
||||
|
|
|
@ -403,13 +403,6 @@ struct plugin_api {
|
|||
#endif
|
||||
};
|
||||
|
||||
/* defined by the plugin loader (plugin.c) */
|
||||
#if CONFIG_HWCODEC == MASNONE
|
||||
int codec_load_ram(char* pluginptr, size_t size, void *parameter, void* ptr2,
|
||||
size_t bufwrap);
|
||||
int codec_load_file(const char* plugin, void* parameter);
|
||||
#endif
|
||||
|
||||
int plugin_load(const char* plugin, void* parameter);
|
||||
void* plugin_get_buffer(int *buffer_size);
|
||||
void* plugin_get_audio_buffer(int *buffer_size);
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
codecvorbis.elf
|
||||
codecmpa.elf
|
||||
codecflac.elf
|
||||
codecwav.elf
|
||||
codeca52.elf
|
||||
codecmpc.elf
|
||||
codecwavpack.elf
|
|
@ -22,7 +22,6 @@ endif
|
|||
|
||||
LDS := plugin.lds
|
||||
LINKFILE := $(OBJDIR)/pluginlink.lds
|
||||
LINKCODEC := $(OBJDIR)/codeclink.lds
|
||||
DEPFILE = $(OBJDIR)/dep-plugins
|
||||
|
||||
# This sets up 'SRC' based on the files mentioned in SOURCES
|
||||
|
@ -55,13 +54,7 @@ ifndef SIMVER
|
|||
$(OBJDIR)/%.elf: $(OBJDIR)/%.o $(LINKFILE) $(LINKCODEC) $(BUILDDIR)/libplugin.a
|
||||
$(SILENT)(file=`basename $@`; \
|
||||
echo "LD $$file"; \
|
||||
match=`grep $$file CODECS`; \
|
||||
if test -z "$$match"; then \
|
||||
LINKWITH=$(LINKFILE); \
|
||||
else \
|
||||
LINKWITH=$(LINKCODEC); \
|
||||
fi; \
|
||||
$(CC) $(GCCOPTS) -O -nostdlib -o $@ $< -L$(BUILDDIR) $(CODECLIBS) -lplugin -lgcc -T$$LINKWITH -Wl,-Map,$(OBJDIR)/$*.map)
|
||||
$(CC) $(GCCOPTS) -O -nostdlib -o $@ $< -L$(BUILDDIR) $(CODECLIBS) -lplugin -lgcc -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/$*.map)
|
||||
|
||||
$(OBJDIR)/%.rock : $(OBJDIR)/%.elf
|
||||
@echo "OBJCOPY "`basename $@`
|
||||
|
@ -108,7 +101,7 @@ endif # end of simulator section
|
|||
include $(TOOLSDIR)/make.inc
|
||||
|
||||
$(BUILDDIR)/libplugin.a:
|
||||
@echo "MAKE in lib"
|
||||
@echo "MAKE in plugin/lib"
|
||||
@mkdir -p $(OBJDIR)/lib
|
||||
@$(MAKE) -C lib OBJDIR=$(OBJDIR)/lib
|
||||
|
||||
|
@ -116,10 +109,6 @@ $(LINKFILE): $(LDS)
|
|||
@echo "build $@"
|
||||
@cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) $(DEFINES) -E -P - >$@
|
||||
|
||||
$(LINKCODEC): $(LDS)
|
||||
@echo "build $@"
|
||||
@cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) -DCODEC $(INCLUDES) $(TARGET) $(DEFINES) -E -P - >$@
|
||||
|
||||
$(SUBDIRS):
|
||||
@echo "MAKE in $@"
|
||||
@mkdir -p $(OBJDIR)/$@
|
||||
|
|
|
@ -67,22 +67,15 @@ alpine_cdc.c
|
|||
#endif
|
||||
|
||||
#if CONFIG_HWCODEC == MASNONE /* software codec platforms */
|
||||
#if 0
|
||||
mpa2wav.c
|
||||
a52towav.c
|
||||
flac2wav.c
|
||||
vorbis2wav.c
|
||||
#ifdef IRIVER_H100
|
||||
codecvorbis.c
|
||||
codecmpa.c
|
||||
codecflac.c
|
||||
codecwav.c
|
||||
codeca52.c
|
||||
codecmpc.c
|
||||
codecwavpack.c
|
||||
#endif
|
||||
wv2wav.c
|
||||
mpc2wav.c
|
||||
midi2wav.c
|
||||
#endif
|
||||
iriverify.c
|
||||
#else
|
||||
splitedit.c
|
||||
|
|
|
@ -1,520 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2005 Dave Chapman
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
#include <codecs/libmad/mad.h>
|
||||
|
||||
#include "playback.h"
|
||||
#include "mp3data.h"
|
||||
#include "lib/codeclib.h"
|
||||
|
||||
static struct plugin_api* rb;
|
||||
|
||||
struct mad_stream Stream IDATA_ATTR;
|
||||
struct mad_frame Frame IDATA_ATTR;
|
||||
struct mad_synth Synth IDATA_ATTR;
|
||||
mad_timer_t Timer;
|
||||
struct dither d0, d1;
|
||||
|
||||
/* The following function is used inside libmad - let's hope it's never
|
||||
called.
|
||||
*/
|
||||
|
||||
void abort(void) {
|
||||
}
|
||||
|
||||
/* The "dither" code to convert the 24-bit samples produced by libmad was
|
||||
taken from the coolplayer project - coolplayer.sourceforge.net */
|
||||
|
||||
struct dither {
|
||||
mad_fixed_t error[3];
|
||||
mad_fixed_t random;
|
||||
};
|
||||
|
||||
# define SAMPLE_DEPTH 16
|
||||
# define scale(x, y) dither((x), (y))
|
||||
|
||||
/*
|
||||
* NAME: prng()
|
||||
* DESCRIPTION: 32-bit pseudo-random number generator
|
||||
*/
|
||||
static __inline
|
||||
unsigned long prng(unsigned long state)
|
||||
{
|
||||
return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAME: dither()
|
||||
* DESCRIPTION: dither and scale sample
|
||||
*/
|
||||
static __inline
|
||||
signed int dither(mad_fixed_t sample, struct dither *dither)
|
||||
{
|
||||
unsigned int scalebits;
|
||||
mad_fixed_t output, mask, random;
|
||||
|
||||
enum {
|
||||
MIN = -MAD_F_ONE,
|
||||
MAX = MAD_F_ONE - 1
|
||||
};
|
||||
|
||||
/* noise shape */
|
||||
sample += dither->error[0] - dither->error[1] + dither->error[2];
|
||||
|
||||
dither->error[2] = dither->error[1];
|
||||
dither->error[1] = dither->error[0] / 2;
|
||||
|
||||
/* bias */
|
||||
output = sample + (1L << (MAD_F_FRACBITS + 1 - SAMPLE_DEPTH - 1));
|
||||
|
||||
scalebits = MAD_F_FRACBITS + 1 - SAMPLE_DEPTH;
|
||||
mask = (1L << scalebits) - 1;
|
||||
|
||||
/* dither */
|
||||
random = prng(dither->random);
|
||||
output += (random & mask) - (dither->random & mask);
|
||||
|
||||
//dither->random = random;
|
||||
|
||||
/* clip */
|
||||
if (output > MAX) {
|
||||
output = MAX;
|
||||
|
||||
if (sample > MAX)
|
||||
sample = MAX;
|
||||
}
|
||||
else if (output < MIN) {
|
||||
output = MIN;
|
||||
|
||||
if (sample < MIN)
|
||||
sample = MIN;
|
||||
}
|
||||
|
||||
/* quantize */
|
||||
output &= ~mask;
|
||||
|
||||
/* error feedback */
|
||||
dither->error[0] = sample - output;
|
||||
|
||||
/* scale */
|
||||
return output >> scalebits;
|
||||
}
|
||||
|
||||
static __inline
|
||||
signed int detect_silence(mad_fixed_t sample)
|
||||
{
|
||||
unsigned int scalebits;
|
||||
mad_fixed_t output, mask;
|
||||
|
||||
enum {
|
||||
MIN = -MAD_F_ONE,
|
||||
MAX = MAD_F_ONE - 1
|
||||
};
|
||||
|
||||
/* bias */
|
||||
output = sample + (1L << (MAD_F_FRACBITS + 1 - SAMPLE_DEPTH - 1));
|
||||
|
||||
scalebits = MAD_F_FRACBITS + 1 - SAMPLE_DEPTH;
|
||||
mask = (1L << scalebits) - 1;
|
||||
|
||||
/* clip */
|
||||
if (output > MAX) {
|
||||
output = MAX;
|
||||
|
||||
if (sample > MAX)
|
||||
sample = MAX;
|
||||
}
|
||||
else if (output < MIN) {
|
||||
output = MIN;
|
||||
|
||||
if (sample < MIN)
|
||||
sample = MIN;
|
||||
}
|
||||
|
||||
/* quantize */
|
||||
output &= ~mask;
|
||||
|
||||
/* scale */
|
||||
output >>= scalebits + 4;
|
||||
|
||||
if (output == 0x00 || output == 0xff)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#define SHRT_MAX 32767
|
||||
|
||||
#define INPUT_CHUNK_SIZE 8192
|
||||
#define OUTPUT_BUFFER_SIZE 65536 /* Must be an integer multiple of 4. */
|
||||
|
||||
unsigned char OutputBuffer[OUTPUT_BUFFER_SIZE];
|
||||
unsigned char *OutputPtr;
|
||||
unsigned char *GuardPtr=NULL;
|
||||
const unsigned char *OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE;
|
||||
long resampled_data[2][5000]; /* enough to cope with 11khz upsampling */
|
||||
|
||||
mad_fixed_t mad_frame_overlap[2][32][18] IDATA_ATTR;
|
||||
unsigned char mad_main_data[MAD_BUFFER_MDLEN] IDATA_ATTR;
|
||||
/* TODO: what latency does layer 1 have? */
|
||||
int mpeg_latency[3] = { 0, 481, 529 };
|
||||
#ifdef USE_IRAM
|
||||
extern char iramcopy[];
|
||||
extern char iramstart[];
|
||||
extern char iramend[];
|
||||
#endif
|
||||
|
||||
#undef DEBUG_GAPLESS
|
||||
|
||||
struct resampler {
|
||||
long last_sample, phase, delta;
|
||||
};
|
||||
|
||||
#if CONFIG_CPU==MCF5249 && !defined(SIMULATOR)
|
||||
|
||||
#define INIT() asm volatile ("move.l #0xb0, %macsr") /* frac, round, clip */
|
||||
#define FRACMUL(x, y) \
|
||||
({ \
|
||||
long t; \
|
||||
asm volatile ("mac.l %[a], %[b], %%acc0\n\t" \
|
||||
"movclr.l %%acc0, %[t]\n\t" \
|
||||
: [t] "=r" (t) : [a] "r" (x), [b] "r" (y)); \
|
||||
t; \
|
||||
})
|
||||
|
||||
#else
|
||||
|
||||
#define INIT()
|
||||
#define FRACMUL(x, y) (long)(((long long)(x)*(long long)(y)) << 1)
|
||||
#endif
|
||||
|
||||
/* linear resampling, introduces one sample delay, because of our inability to
|
||||
look into the future at the end of a frame */
|
||||
long downsample(long *in, long *out, int num, struct resampler *s)
|
||||
{
|
||||
long i = 1, pos;
|
||||
long last = s->last_sample;
|
||||
|
||||
INIT();
|
||||
pos = s->phase >> 16;
|
||||
/* check if we need last sample of previous frame for interpolation */
|
||||
if (pos > 0)
|
||||
last = in[pos - 1];
|
||||
out[0] = last + FRACMUL((s->phase & 0xffff) << 15, in[pos] - last);
|
||||
s->phase += s->delta;
|
||||
while ((pos = s->phase >> 16) < num) {
|
||||
out[i++] = in[pos - 1] + FRACMUL((s->phase & 0xffff) << 15, in[pos] - in[pos - 1]);
|
||||
s->phase += s->delta;
|
||||
}
|
||||
/* wrap phase accumulator back to start of next frame */
|
||||
s->phase -= num << 16;
|
||||
s->last_sample = in[num - 1];
|
||||
return i;
|
||||
}
|
||||
|
||||
long upsample(long *in, long *out, int num, struct resampler *s)
|
||||
{
|
||||
long i = 0, pos;
|
||||
|
||||
INIT();
|
||||
while ((pos = s->phase >> 16) == 0) {
|
||||
out[i++] = s->last_sample + FRACMUL((s->phase & 0xffff) << 15, in[pos] - s->last_sample);
|
||||
s->phase += s->delta;
|
||||
}
|
||||
while ((pos = s->phase >> 16) < num) {
|
||||
out[i++] = in[pos - 1] + FRACMUL((s->phase & 0xffff) << 15, in[pos] - in[pos - 1]);
|
||||
s->phase += s->delta;
|
||||
}
|
||||
/* wrap phase accumulator back to start of next frame */
|
||||
s->phase -= num << 16;
|
||||
s->last_sample = in[num - 1];
|
||||
return i;
|
||||
}
|
||||
|
||||
long resample(long *in, long *out, int num, struct resampler *s)
|
||||
{
|
||||
if (s->delta >= (1 << 16))
|
||||
return downsample(in, out, num, s);
|
||||
else
|
||||
return upsample(in, out, num, s);
|
||||
}
|
||||
|
||||
/* this is the plugin entry point */
|
||||
enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||
{
|
||||
struct codec_api *ci = (struct codec_api *)parm;
|
||||
struct mp3info *info;
|
||||
int Status=0;
|
||||
size_t size;
|
||||
int file_end;
|
||||
unsigned short Sample;
|
||||
char *InputBuffer;
|
||||
unsigned int samplecount;
|
||||
unsigned int samplesdone;
|
||||
bool first_frame;
|
||||
#ifdef DEBUG_GAPLESS
|
||||
bool first = true;
|
||||
int fd;
|
||||
#endif
|
||||
int i;
|
||||
int yieldcounter = 0;
|
||||
int stop_skip, start_skip;
|
||||
struct resampler lr = { 0, 0, 0 }, rr = { 0, 0, 0 };
|
||||
long length;
|
||||
/* Generic plugin inititialisation */
|
||||
|
||||
TEST_PLUGIN_API(api);
|
||||
rb = api;
|
||||
|
||||
#ifdef USE_IRAM
|
||||
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
|
||||
#endif
|
||||
|
||||
/* This function sets up the buffers and reads the file into RAM */
|
||||
|
||||
if (codec_init(api, ci)) {
|
||||
return PLUGIN_ERROR;
|
||||
}
|
||||
|
||||
/* Create a decoder instance */
|
||||
|
||||
ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2));
|
||||
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16));
|
||||
|
||||
memset(&Stream, 0, sizeof(struct mad_stream));
|
||||
memset(&Frame, 0, sizeof(struct mad_frame));
|
||||
memset(&Synth, 0, sizeof(struct mad_synth));
|
||||
memset(&Timer, 0, sizeof(mad_timer_t));
|
||||
|
||||
mad_stream_init(&Stream);
|
||||
mad_frame_init(&Frame);
|
||||
mad_synth_init(&Synth);
|
||||
mad_timer_reset(&Timer);
|
||||
|
||||
/* We do this so libmad doesn't try to call codec_calloc() */
|
||||
memset(mad_frame_overlap, 0, sizeof(mad_frame_overlap));
|
||||
Frame.overlap = &mad_frame_overlap;
|
||||
Stream.main_data = &mad_main_data;
|
||||
/* This label might need to be moved above all the init code, but I don't
|
||||
think reiniting the codec is necessary for MPEG. It might even be unwanted
|
||||
for gapless playback */
|
||||
next_track:
|
||||
|
||||
#ifdef DEBUG_GAPLESS
|
||||
if (first)
|
||||
fd = rb->open("/first.pcm", O_WRONLY | O_CREAT);
|
||||
else
|
||||
fd = rb->open("/second.pcm", O_WRONLY | O_CREAT);
|
||||
first = false;
|
||||
#endif
|
||||
|
||||
info = ci->mp3data;
|
||||
first_frame = false;
|
||||
file_end = 0;
|
||||
OutputPtr = OutputBuffer;
|
||||
|
||||
while (!*ci->taginfo_ready)
|
||||
rb->yield();
|
||||
|
||||
ci->request_buffer(&size, ci->id3->first_frame_offset);
|
||||
ci->advance_buffer(size);
|
||||
|
||||
if (info->enc_delay >= 0 && info->enc_padding >= 0) {
|
||||
stop_skip = info->enc_padding - mpeg_latency[info->layer];
|
||||
if (stop_skip < 0) stop_skip = 0;
|
||||
start_skip = info->enc_delay + mpeg_latency[info->layer];
|
||||
} else {
|
||||
stop_skip = 0;
|
||||
/* We want to skip this amount anyway */
|
||||
start_skip = mpeg_latency[info->layer];
|
||||
}
|
||||
|
||||
/* NOTE: currently this doesn't work, the below calculated samples_count
|
||||
seems to be right, but sometimes libmad just can't supply us with
|
||||
all the data we need... */
|
||||
if (info->frame_count) {
|
||||
/* TODO: 1152 is the frame size in samples for MPEG1 layer 2 and layer 3,
|
||||
it's probably not correct at all for MPEG2 and layer 1 */
|
||||
samplecount = info->frame_count*1152 - (start_skip + stop_skip);
|
||||
samplesdone = ci->id3->elapsed * (ci->id3->frequency / 100) / 10;
|
||||
} else {
|
||||
samplecount = ci->id3->length * (ci->id3->frequency / 100) / 10;
|
||||
samplesdone = ci->id3->elapsed * (ci->id3->frequency / 100) / 10;
|
||||
}
|
||||
/* rb->snprintf(buf2, sizeof(buf2), "sc: %d", samplecount);
|
||||
rb->splash(0, true, buf2);
|
||||
rb->snprintf(buf2, sizeof(buf2), "length: %d", ci->id3->length);
|
||||
rb->splash(HZ*5, true, buf2);
|
||||
rb->snprintf(buf2, sizeof(buf2), "frequency: %d", ci->id3->frequency);
|
||||
rb->splash(HZ*5, true, buf2); */
|
||||
lr.delta = rr.delta = ci->id3->frequency*65536/44100;
|
||||
/* This is the decoding loop. */
|
||||
while (1) {
|
||||
rb->yield();
|
||||
if (ci->stop_codec || ci->reload_codec) {
|
||||
break ;
|
||||
}
|
||||
|
||||
if (ci->seek_time) {
|
||||
unsigned int sample_loc;
|
||||
int newpos;
|
||||
|
||||
sample_loc = ci->seek_time/1000 * ci->id3->frequency;
|
||||
newpos = ci->mp3_get_filepos(ci->seek_time-1);
|
||||
if (ci->seek_buffer(newpos)) {
|
||||
if (sample_loc >= samplecount + samplesdone)
|
||||
break ;
|
||||
samplecount += samplesdone - sample_loc;
|
||||
samplesdone = sample_loc;
|
||||
}
|
||||
ci->seek_time = 0;
|
||||
}
|
||||
|
||||
/* Lock buffers */
|
||||
if (Stream.error == 0) {
|
||||
InputBuffer = ci->request_buffer(&size, INPUT_CHUNK_SIZE);
|
||||
if (size == 0 || InputBuffer == NULL)
|
||||
break ;
|
||||
mad_stream_buffer(&Stream, InputBuffer, size);
|
||||
}
|
||||
|
||||
//if ((int)ci->curpos >= ci->id3->first_frame_offset)
|
||||
//first_frame = true;
|
||||
|
||||
if(mad_frame_decode(&Frame,&Stream))
|
||||
{
|
||||
if (Stream.error == MAD_FLAG_INCOMPLETE || Stream.error == MAD_ERROR_BUFLEN) {
|
||||
// rb->splash(HZ*1, true, "Incomplete");
|
||||
/* This makes the codec to support partially corrupted files too. */
|
||||
if (file_end == 30)
|
||||
break ;
|
||||
|
||||
/* Fill the buffer */
|
||||
Stream.error = 0;
|
||||
file_end++;
|
||||
continue ;
|
||||
}
|
||||
else if(MAD_RECOVERABLE(Stream.error))
|
||||
{
|
||||
if(Stream.error!=MAD_ERROR_LOSTSYNC || Stream.this_frame!=GuardPtr)
|
||||
{
|
||||
// rb->splash(HZ*1, true, "Recoverable...!");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if(Stream.error==MAD_ERROR_BUFLEN) {
|
||||
//rb->splash(HZ*1, true, "Buflen error");
|
||||
break ;
|
||||
} else {
|
||||
//rb->splash(HZ*1, true, "Unrecoverable error");
|
||||
Status=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Stream.next_frame)
|
||||
ci->advance_buffer_loc((void *)Stream.next_frame);
|
||||
file_end = false;
|
||||
/* ?? Do we need the timer module? */
|
||||
// mad_timer_add(&Timer,Frame.header.duration);
|
||||
|
||||
/* DAVE: This can be used to attenuate the audio */
|
||||
// if(DoFilter)
|
||||
// ApplyFilter(&Frame);
|
||||
|
||||
mad_synth_frame(&Synth,&Frame);
|
||||
|
||||
//if (!first_frame) {
|
||||
//samplecount -= Synth.pcm.length;
|
||||
//continue ;
|
||||
//}
|
||||
|
||||
/* Convert MAD's numbers to an array of 16-bit LE signed integers */
|
||||
/* We skip start_skip number of samples here, this should only happen for
|
||||
very first frame in the stream. */
|
||||
/* TODO: possible for start_skip to exceed one frames worth of samples? */
|
||||
length = resample((long *)&Synth.pcm.samples[0][start_skip], resampled_data[0], Synth.pcm.length, &lr);
|
||||
if (MAD_NCHANNELS(&Frame.header) == 2)
|
||||
resample((long *)&Synth.pcm.samples[1][start_skip], resampled_data[1], Synth.pcm.length, &rr);
|
||||
for (i = 0;i<length;i++)
|
||||
{
|
||||
start_skip = 0; /* not very elegant, and might want to keep this value */
|
||||
samplesdone++;
|
||||
//if (ci->mp3data->padding > 0) {
|
||||
// ci->mp3data->padding--;
|
||||
// continue ;
|
||||
//}
|
||||
/*if (!first_frame) {
|
||||
if (detect_silence(Synth.pcm.samples[0][i]))
|
||||
continue ;
|
||||
first_frame = true;
|
||||
}*/
|
||||
|
||||
/* Left channel */
|
||||
Sample=scale(resampled_data[0][i],&d0);
|
||||
*(OutputPtr++)=Sample>>8;
|
||||
*(OutputPtr++)=Sample&0xff;
|
||||
|
||||
/* Right channel. If the decoded stream is monophonic then
|
||||
* the right output channel is the same as the left one.
|
||||
*/
|
||||
if(MAD_NCHANNELS(&Frame.header)==2)
|
||||
Sample=scale(resampled_data[1][i],&d1);
|
||||
*(OutputPtr++)=Sample>>8;
|
||||
*(OutputPtr++)=Sample&0xff;
|
||||
|
||||
samplecount--;
|
||||
if (samplecount == 0) {
|
||||
#ifdef DEBUG_GAPLESS
|
||||
rb->write(fd, OutputBuffer, (int)OutputPtr-(int)OutputBuffer);
|
||||
#endif
|
||||
while (!ci->audiobuffer_insert(OutputBuffer, (int)OutputPtr-(int)OutputBuffer))
|
||||
rb->yield();
|
||||
goto song_end;
|
||||
}
|
||||
|
||||
if (yieldcounter++ == 200) {
|
||||
rb->yield();
|
||||
yieldcounter = 0;
|
||||
}
|
||||
|
||||
/* Flush the buffer if it is full. */
|
||||
if(OutputPtr==OutputBufferEnd)
|
||||
{
|
||||
#ifdef DEBUG_GAPLESS
|
||||
rb->write(fd, OutputBuffer, OUTPUT_BUFFER_SIZE);
|
||||
#endif
|
||||
while (!ci->audiobuffer_insert(OutputBuffer, OUTPUT_BUFFER_SIZE))
|
||||
rb->yield();
|
||||
OutputPtr=OutputBuffer;
|
||||
}
|
||||
}
|
||||
ci->set_elapsed(samplesdone / (ci->id3->frequency/1000));
|
||||
}
|
||||
|
||||
song_end:
|
||||
#ifdef DEBUG_GAPLESS
|
||||
rb->close(fd);
|
||||
#endif
|
||||
Stream.error = 0;
|
||||
|
||||
if (ci->request_next_track())
|
||||
goto next_track;
|
||||
return PLUGIN_OK;
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002 Björn Stenberg
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "kernel.h"
|
||||
#include "plugin.h"
|
||||
|
||||
#include <codecs/Tremor/ivorbisfile.h>
|
||||
|
||||
#include "playback.h"
|
||||
#include "lib/codeclib.h"
|
||||
|
||||
static struct plugin_api* rb;
|
||||
|
||||
/* Some standard functions and variables needed by Tremor */
|
||||
|
||||
|
||||
int errno;
|
||||
|
||||
size_t strlen(const char *s) {
|
||||
return(rb->strlen(s));
|
||||
}
|
||||
|
||||
char *strcpy(char *dest, const char *src) {
|
||||
return(rb->strcpy(dest,src));
|
||||
}
|
||||
|
||||
char *strcat(char *dest, const char *src) {
|
||||
return(rb->strcat(dest,src));
|
||||
}
|
||||
|
||||
size_t read_handler(void *ptr, size_t size, size_t nmemb, void *datasource) {
|
||||
struct codec_api *p = (struct codec_api *) datasource;
|
||||
|
||||
return p->read_filebuf(ptr, nmemb*size);
|
||||
}
|
||||
|
||||
int seek_handler(void *datasource, ogg_int64_t offset, int whence) {
|
||||
/* We are not seekable at the moment */
|
||||
(void)datasource;
|
||||
(void)offset;
|
||||
(void)whence;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int close_handler(void *datasource) {
|
||||
(void)datasource;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long tell_handler(void *datasource) {
|
||||
struct codec_api *p = (struct codec_api *) datasource;
|
||||
return p->curpos;
|
||||
}
|
||||
|
||||
#ifdef USE_IRAM
|
||||
extern char iramcopy[];
|
||||
extern char iramstart[];
|
||||
extern char iramend[];
|
||||
#endif
|
||||
|
||||
|
||||
/* reserve the PCM buffer in the IRAM area */
|
||||
static char pcmbuf[4096] IDATA_ATTR;
|
||||
|
||||
/* this is the plugin entry point */
|
||||
enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||
{
|
||||
struct codec_api *ci = (struct codec_api *)parm;
|
||||
ov_callbacks callbacks;
|
||||
OggVorbis_File vf;
|
||||
vorbis_info* vi;
|
||||
|
||||
int error;
|
||||
long n;
|
||||
int current_section;
|
||||
int eof;
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
int i;
|
||||
char x;
|
||||
#endif
|
||||
|
||||
TEST_PLUGIN_API(api);
|
||||
|
||||
/* if you are using a global api pointer, don't forget to copy it!
|
||||
otherwise you will get lovely "I04: IllInstr" errors... :-) */
|
||||
rb = api;
|
||||
|
||||
#ifdef USE_IRAM
|
||||
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
|
||||
#endif
|
||||
|
||||
ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2));
|
||||
ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*64));
|
||||
|
||||
/* We need to flush reserver memory every track load. */
|
||||
next_track:
|
||||
if (codec_init(api, ci)) {
|
||||
return PLUGIN_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/* Create a decoder instance */
|
||||
|
||||
callbacks.read_func=read_handler;
|
||||
callbacks.seek_func=seek_handler;
|
||||
callbacks.tell_func=tell_handler;
|
||||
callbacks.close_func=close_handler;
|
||||
|
||||
error=ov_open_callbacks(ci,&vf,NULL,0,callbacks);
|
||||
|
||||
vi=ov_info(&vf,-1);
|
||||
|
||||
if (vi==NULL) {
|
||||
// rb->splash(HZ*2, true, "Vorbis Error");
|
||||
return PLUGIN_ERROR;
|
||||
}
|
||||
|
||||
eof=0;
|
||||
while (!eof) {
|
||||
/* Read host-endian signed 16 bit PCM samples */
|
||||
n=ov_read(&vf,pcmbuf,sizeof(pcmbuf),¤t_section);
|
||||
|
||||
if (n==0) {
|
||||
eof=1;
|
||||
} else if (n < 0) {
|
||||
DEBUGF("Error decoding frame\n");
|
||||
} else {
|
||||
rb->yield();
|
||||
if (ci->stop_codec || ci->reload_codec)
|
||||
break ;
|
||||
|
||||
rb->yield();
|
||||
while (!ci->audiobuffer_insert(pcmbuf, n))
|
||||
rb->yield();
|
||||
|
||||
ci->set_elapsed(ov_time_tell(&vf));
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
for (i=0;i<n;i+=2) {
|
||||
x=pcmbuf[i]; pcmbuf[i]=pcmbuf[i+1]; pcmbuf[i+1]=x;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (ci->request_next_track())
|
||||
goto next_track;
|
||||
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
|
|
@ -34,9 +34,8 @@ gray_verline.c
|
|||
#ifdef HAVE_LCD_CHARCELLS
|
||||
playergfx.c
|
||||
#endif
|
||||
#if 0
|
||||
#if CONFIG_HWCODEC == MASNONE /* software codec platforms */
|
||||
xxx2wav.c
|
||||
#ifdef IRIVER_H100
|
||||
codeclib.c
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -48,7 +48,7 @@ sub buildzip {
|
|||
mkdir ".rockbox/langs", 0777;
|
||||
mkdir ".rockbox/rocks", 0777;
|
||||
mkdir ".rockbox/codecs", 0777;
|
||||
`find apps -name "codec*.rock" ! -empty | xargs --replace=foo cp foo .rockbox/codecs/`;
|
||||
`find apps -name "*.codec" ! -empty | xargs --replace=foo cp foo .rockbox/codecs/`;
|
||||
`find apps -name "*.rock" -o -name "*.ovl" ! -empty ! -name "codec*.rock" | xargs --replace=foo cp foo .rockbox/rocks/`;
|
||||
|
||||
open VIEWERS, "$ROOT/apps/plugins/viewers.config" or
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue