mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 02:27:39 -04:00
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
|
plugins/snake2.levels
|
||||||
SOURCES
|
SOURCES
|
||||||
plugins/SOURCES
|
plugins/SOURCES
|
||||||
plugins/CODECS
|
|
||||||
plugins/lib/SOURCES
|
plugins/lib/SOURCES
|
||||||
plugins/rockboy/*.[ch]
|
plugins/rockboy/*.[ch]
|
||||||
plugins/rockboy/Makefile
|
plugins/rockboy/Makefile
|
||||||
|
@ -53,3 +52,5 @@ codecs/dumb/src/core/*
|
||||||
codecs/dumb/src/helpers/*
|
codecs/dumb/src/helpers/*
|
||||||
codecs/dumb/src/it/*
|
codecs/dumb/src/it/*
|
||||||
codecs/libmusepack/*
|
codecs/libmusepack/*
|
||||||
|
codecs/lib/*.[ch]
|
||||||
|
codecs/lib/Makefile
|
||||||
|
|
|
@ -57,6 +57,7 @@ endif
|
||||||
dep: $(DEPFILE)
|
dep: $(DEPFILE)
|
||||||
|
|
||||||
build-codecs:
|
build-codecs:
|
||||||
|
@$(MAKE) -C codecs/lib OBJDIR=$(OBJDIR)/codecs/lib
|
||||||
@$(MAKE) -C codecs OBJDIR=$(OBJDIR)/codecs
|
@$(MAKE) -C codecs OBJDIR=$(OBJDIR)/codecs
|
||||||
|
|
||||||
rocks:
|
rocks:
|
||||||
|
|
|
@ -48,9 +48,10 @@ recorder/radio.c
|
||||||
#ifdef HAVE_RECORDING
|
#ifdef HAVE_RECORDING
|
||||||
recorder/recording.c
|
recorder/recording.c
|
||||||
#endif
|
#endif
|
||||||
#ifdef IRIVER_H100
|
#if CONFIG_HWCODEC == MASNONE
|
||||||
playback.c
|
playback.c
|
||||||
metadata.c
|
metadata.c
|
||||||
|
codecs.c
|
||||||
#ifndef SIMULATOR
|
#ifndef SIMULATOR
|
||||||
pcm_recording.c
|
pcm_recording.c
|
||||||
#endif
|
#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 \
|
INCLUDES = -I$(FIRMDIR)/include -I$(FIRMDIR)/export -I$(FIRMDIR)/common \
|
||||||
-I$(FIRMDIR)/drivers -I$(APPSDIR) -Ilib -I$(BUILDDIR)
|
-I$(FIRMDIR)/drivers -I$(APPSDIR) -Ilib -I$(BUILDDIR)
|
||||||
CFLAGS = $(GCCOPTS) $(INCLUDES) $(TARGET) $(EXTRA_DEFINES) \
|
CFLAGS = $(GCCOPTS) $(INCLUDES) $(TARGET) $(EXTRA_DEFINES) \
|
||||||
-DMEM=${MEMORYSIZE}
|
-DMEM=${MEMORYSIZE} -DCODEC
|
||||||
|
|
||||||
ifdef APPEXTRA
|
ifdef APPEXTRA
|
||||||
INCLUDES += -I$(APPSDIR)/$(APPEXTRA)
|
INCLUDES += -I$(APPSDIR)/$(APPEXTRA)
|
||||||
endif
|
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
|
.PHONY: libmad liba52 libFLAC libTremor libwavpack dumb libmusepack
|
||||||
|
|
||||||
OUTPUT = $(SOFTWARECODECS)
|
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
|
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:
|
libmad:
|
||||||
@echo "MAKE in libmad"
|
@echo "MAKE in libmad"
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "plugin.h"
|
#include "codec.h"
|
||||||
|
|
||||||
#include <inttypes.h> /* Needed by a52.h */
|
#include <inttypes.h> /* Needed by a52.h */
|
||||||
#include <codecs/liba52/config-a52.h>
|
#include <codecs/liba52/config-a52.h>
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
#define BUFFER_SIZE 4096
|
#define BUFFER_SIZE 4096
|
||||||
|
|
||||||
struct plugin_api* rb;
|
struct codec_api* rb;
|
||||||
struct codec_api* ci;
|
struct codec_api* ci;
|
||||||
|
|
||||||
static float gain = 1;
|
static float gain = 1;
|
||||||
|
@ -154,17 +154,17 @@ extern char iramstart[];
|
||||||
extern char iramend[];
|
extern char iramend[];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* this is the plugin entry point */
|
/* this is the codec entry point */
|
||||||
enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
enum codec_status codec_start(struct codec_api* api, void* parm)
|
||||||
{
|
{
|
||||||
size_t n;
|
size_t n;
|
||||||
unsigned char* filebuf;
|
unsigned char* filebuf;
|
||||||
|
|
||||||
/* Generic plugin initialisation */
|
/* Generic codec initialisation */
|
||||||
TEST_PLUGIN_API(api);
|
TEST_CODEC_API(api);
|
||||||
|
|
||||||
rb = api;
|
rb = api;
|
||||||
ci = (struct codec_api*)parm;
|
ci = (struct codec_api*)api;
|
||||||
|
|
||||||
#ifndef SIMULATOR
|
#ifndef SIMULATOR
|
||||||
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
|
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
|
||||||
|
@ -175,8 +175,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||||
|
|
||||||
next_track:
|
next_track:
|
||||||
|
|
||||||
if (codec_init(api, ci)) {
|
if (codec_init(api)) {
|
||||||
return PLUGIN_ERROR;
|
return CODEC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Intialise the A52 decoder and check for success */
|
/* 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);
|
//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 <codecs/libFLAC/include/FLAC/seekable_stream_decoder.h>
|
||||||
#include "playback.h"
|
#include "playback.h"
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
#define FLAC_MAX_SUPPORTED_BLOCKSIZE 4608
|
#define FLAC_MAX_SUPPORTED_BLOCKSIZE 4608
|
||||||
#define FLAC_MAX_SUPPORTED_CHANNELS 2
|
#define FLAC_MAX_SUPPORTED_CHANNELS 2
|
||||||
|
|
||||||
static struct plugin_api* rb;
|
static struct codec_api* rb;
|
||||||
static uint32_t samplesdone;
|
static uint32_t samplesdone;
|
||||||
|
|
||||||
/* Called when the FLAC decoder needs some FLAC data to decode */
|
/* Called when the FLAC decoder needs some FLAC data to decode */
|
||||||
|
@ -159,14 +159,14 @@ extern char iramstart[];
|
||||||
extern char iramend[];
|
extern char iramend[];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* this is the plugin entry point */
|
/* this is the codec entry point */
|
||||||
enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
enum codec_status codec_start(struct codec_api* api, void* parm)
|
||||||
{
|
{
|
||||||
struct codec_api* ci = (struct codec_api*)parm;
|
struct codec_api* ci = api;
|
||||||
FLAC__SeekableStreamDecoder* flacDecoder;
|
FLAC__SeekableStreamDecoder* flacDecoder;
|
||||||
|
|
||||||
/* Generic plugin initialisation */
|
/* Generic codec initialisation */
|
||||||
TEST_PLUGIN_API(api);
|
TEST_CODEC_API(api);
|
||||||
|
|
||||||
/* if you are using a global api pointer, don't forget to copy it!
|
/* if you are using a global api pointer, don't forget to copy it!
|
||||||
otherwise you will get lovely "I04: IllInstr" errors... :-) */
|
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:
|
next_track:
|
||||||
|
|
||||||
if (codec_init(api, ci)) {
|
if (codec_init(api)) {
|
||||||
return PLUGIN_ERROR;
|
return CODEC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a decoder instance */
|
/* 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? */
|
/* QUESTION: What do we do when the init fails? */
|
||||||
if (FLAC__seekable_stream_decoder_init(flacDecoder)) {
|
if (FLAC__seekable_stream_decoder_init(flacDecoder)) {
|
||||||
return PLUGIN_ERROR;
|
return CODEC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The first thing to do is to parse the metadata */
|
/* 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())
|
if (ci->request_next_track())
|
||||||
goto 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 "plugin.h"
|
||||||
#include "playback.h"
|
#include "playback.h"
|
||||||
#include "codeclib.h"
|
#include "codeclib.h"
|
||||||
#include "xxx2wav.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;
|
local_rb = rb;
|
||||||
|
|
||||||
xxx2wav_set_api(rb);
|
xxx2wav_set_api(rb);
|
||||||
mem_ptr = 0;
|
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;
|
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)
|
#if CONFIG_CPU == MCF5249 && !defined(SIMULATOR)
|
||||||
#define ICODE_ATTR __attribute__ ((section(".icode")))
|
#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);
|
int memcmp(const void *s1, const void *s2, size_t n);
|
||||||
void* memmove(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)
|
#if (CONFIG_HWCODEC == MASNONE)
|
||||||
/* software codec platforms, not for simulator */
|
/* software codec platforms, not for simulator */
|
||||||
|
|
||||||
#include "plugin.h"
|
#include "codecs.h"
|
||||||
#include "xxx2wav.h"
|
#include "xxx2wav.h"
|
||||||
|
|
||||||
static struct plugin_api* local_rb;
|
static struct codec_api* local_rb;
|
||||||
|
|
||||||
int mem_ptr;
|
int mem_ptr;
|
||||||
int bufsize;
|
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* mallocbuf; // 512K from the start of audio buffer
|
||||||
unsigned char* filebuf; // The rest of the audio buffer
|
unsigned char* filebuf; // The rest of the audio buffer
|
||||||
|
|
||||||
void* codec_malloc(size_t size) {
|
void* codec_malloc(size_t size)
|
||||||
void* x;
|
{
|
||||||
|
void* x;
|
||||||
|
|
||||||
x=&mallocbuf[mem_ptr];
|
x=&mallocbuf[mem_ptr];
|
||||||
mem_ptr+=(size+3)&~3; // Keep memory 32-bit aligned (if it was already?)
|
mem_ptr+=(size+3)&~3; // Keep memory 32-bit aligned (if it was already?)
|
||||||
/*
|
/*
|
||||||
if(TIME_AFTER(*(local_rb->current_tick), last_tick + HZ)) {
|
if(TIME_AFTER(*(local_rb->current_tick), last_tick + HZ)) {
|
||||||
char s[32];
|
char s[32];
|
||||||
|
@ -48,24 +49,26 @@ void* codec_malloc(size_t size) {
|
||||||
last_tick = *(local_rb->current_tick);
|
last_tick = *(local_rb->current_tick);
|
||||||
local_rb->lcd_update();
|
local_rb->lcd_update();
|
||||||
}*/
|
}*/
|
||||||
return(x);
|
return(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* codec_calloc(size_t nmemb, size_t size) {
|
void* codec_calloc(size_t nmemb, size_t size)
|
||||||
void* x;
|
{
|
||||||
x = codec_malloc(nmemb*size);
|
void* x;
|
||||||
local_rb->memset(x,0,nmemb*size);
|
x = codec_malloc(nmemb*size);
|
||||||
return(x);
|
local_rb->memset(x,0,nmemb*size);
|
||||||
|
return(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* codec_alloca(size_t size) {
|
void* codec_alloca(size_t size)
|
||||||
void* x;
|
{
|
||||||
x = codec_malloc(size);
|
void* x;
|
||||||
return(x);
|
x = codec_malloc(size);
|
||||||
|
return(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void codec_free(void* ptr) {
|
void codec_free(void* ptr) {
|
||||||
(void)ptr;
|
(void)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* codec_realloc(void* ptr, size_t size) {
|
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
|
static unsigned char wav_header[44]={'R','I','F','F', // 0 - ChunkID
|
||||||
0,0,0,0, // 4 - ChunkSize (filesize-8)
|
0,0,0,0, // 4 - ChunkSize (filesize-8)
|
||||||
'W','A','V','E', // 8 - Format
|
'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
|
'd','a','t','a', // 36 - Subchunk2ID
|
||||||
0,0,0,0 // 40 - Subchunk2Size
|
0,0,0,0 // 40 - Subchunk2Size
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void xxx2wav_set_api(struct codec_api* rb)
|
||||||
void xxx2wav_set_api(struct plugin_api* rb)
|
|
||||||
{
|
{
|
||||||
local_rb = 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];
|
char s[32];
|
||||||
int i,n,bytesleft;
|
int i,n,bytesleft;
|
||||||
|
|
||||||
|
@ -218,7 +226,8 @@ int local_init(char* infilename, char* outfilename, file_info_struct* file_info,
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_wav(file_info_struct* file_info) {
|
void close_wav(file_info_struct* file_info)
|
||||||
|
{
|
||||||
int x;
|
int x;
|
||||||
int filesize=local_rb->filesize(file_info->outfile);
|
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->write(file_info->outfile,wav_header,sizeof(wav_header));
|
||||||
local_rb->close(file_info->outfile);
|
local_rb->close(file_info->outfile);
|
||||||
}
|
}
|
||||||
|
#endif /* 0 */
|
||||||
|
|
||||||
#endif /* CONFIG_HWCODEC == MASNONE */
|
#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* memmove(const void *s1, const void *s2, size_t n);
|
||||||
|
|
||||||
void display_status(file_info_struct* file_info);
|
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 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 "playback.h"
|
||||||
#include "lib/codeclib.h"
|
#include "lib/codeclib.h"
|
||||||
#include <codecs/libmusepack/musepack.h>
|
#include <codecs/libmusepack/musepack.h>
|
||||||
|
|
||||||
static struct plugin_api* rb;
|
static struct codec_api* rb;
|
||||||
mpc_decoder decoder;
|
mpc_decoder decoder;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -92,10 +92,10 @@ extern char iramstart[];
|
||||||
extern char iramend[];
|
extern char iramend[];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* this is the plugin entry point */
|
/* this is the codec entry point */
|
||||||
enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
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 short Sample;
|
||||||
unsigned long samplesdone;
|
unsigned long samplesdone;
|
||||||
unsigned long frequency;
|
unsigned long frequency;
|
||||||
|
@ -103,9 +103,9 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
mpc_reader reader;
|
mpc_reader reader;
|
||||||
|
|
||||||
/* Generic plugin inititialisation */
|
/* Generic codec inititialisation */
|
||||||
|
|
||||||
TEST_PLUGIN_API(api);
|
TEST_CODEC_API(api);
|
||||||
rb = api;
|
rb = api;
|
||||||
|
|
||||||
#ifndef SIMULATOR
|
#ifndef SIMULATOR
|
||||||
|
@ -117,8 +117,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||||
|
|
||||||
next_track:
|
next_track:
|
||||||
|
|
||||||
if (codec_init(api, ci)) {
|
if (codec_init(api)) {
|
||||||
return PLUGIN_ERROR;
|
return CODEC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a decoder instance */
|
/* Create a decoder instance */
|
||||||
|
@ -134,14 +134,14 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||||
mpc_streaminfo info;
|
mpc_streaminfo info;
|
||||||
mpc_streaminfo_init(&info);
|
mpc_streaminfo_init(&info);
|
||||||
if (mpc_streaminfo_read(&info, &reader) != ERROR_CODE_OK) {
|
if (mpc_streaminfo_read(&info, &reader) != ERROR_CODE_OK) {
|
||||||
return PLUGIN_ERROR;
|
return CODEC_ERROR;
|
||||||
}
|
}
|
||||||
frequency=info.sample_freq;
|
frequency=info.sample_freq;
|
||||||
|
|
||||||
/* instantiate a decoder with our file reader */
|
/* instantiate a decoder with our file reader */
|
||||||
mpc_decoder_setup(&decoder, &reader);
|
mpc_decoder_setup(&decoder, &reader);
|
||||||
if (!mpc_decoder_initialize(&decoder, &info)) {
|
if (!mpc_decoder_initialize(&decoder, &info)) {
|
||||||
return PLUGIN_ERROR;
|
return CODEC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialise the output buffer. */
|
/* 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);
|
status = mpc_decoder_decode(&decoder, sample_buffer, 0, 0);
|
||||||
if (status == (unsigned)(-1)) {
|
if (status == (unsigned)(-1)) {
|
||||||
//decode error
|
//decode error
|
||||||
return PLUGIN_ERROR;
|
return CODEC_ERROR;
|
||||||
}
|
}
|
||||||
else //status>0
|
else //status>0
|
||||||
{
|
{
|
||||||
|
@ -209,6 +209,6 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||||
if (ci->request_next_track())
|
if (ci->request_next_track())
|
||||||
goto 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 "playback.h"
|
||||||
#include "lib/codeclib.h"
|
#include "lib/codeclib.h"
|
||||||
|
|
||||||
|
@ -32,11 +32,11 @@ extern char iramstart[];
|
||||||
extern char iramend[];
|
extern char iramend[];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* this is the plugin entry point */
|
/* this is the codec entry point */
|
||||||
enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
enum codec_status codec_start(struct codec_api* api, void* parm)
|
||||||
{
|
{
|
||||||
struct plugin_api* rb = (struct plugin_api*)api;
|
struct codec_api* rb = api;
|
||||||
struct codec_api* ci = (struct codec_api*)parm;
|
struct codec_api* ci = api;
|
||||||
unsigned long samplerate,numbytes,totalsamples,samplesdone,nsamples;
|
unsigned long samplerate,numbytes,totalsamples,samplesdone,nsamples;
|
||||||
int channels,bytespersample,bitspersample;
|
int channels,bytespersample,bitspersample;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
@ -45,8 +45,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||||
unsigned char* header;
|
unsigned char* header;
|
||||||
unsigned short* wavbuf;
|
unsigned short* wavbuf;
|
||||||
|
|
||||||
/* Generic plugin initialisation */
|
/* Generic codec initialisation */
|
||||||
TEST_PLUGIN_API(api);
|
TEST_CODEC_API(api);
|
||||||
|
|
||||||
/* if you are using a global api pointer, don't forget to copy it!
|
/* if you are using a global api pointer, don't forget to copy it!
|
||||||
otherwise you will get lovely "I04: IllInstr" errors... :-) */
|
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:
|
next_track:
|
||||||
|
|
||||||
if (codec_init(api, ci)) {
|
if (codec_init(api)) {
|
||||||
return PLUGIN_ERROR;
|
return CODEC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIX: Correctly parse WAV header - we assume canonical 44-byte header */
|
/* FIX: Correctly parse WAV header - we assume canonical 44-byte header */
|
||||||
|
|
||||||
header=ci->request_buffer(&n,44);
|
header=ci->request_buffer(&n,44);
|
||||||
if (n!=44) {
|
if (n!=44) {
|
||||||
return PLUGIN_ERROR;
|
return CODEC_ERROR;
|
||||||
}
|
}
|
||||||
if ((memcmp(header,"RIFF",4)!=0) || (memcmp(&header[8],"WAVEfmt",7)!=0)) {
|
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);
|
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;
|
totalsamples=numbytes/bytespersample;
|
||||||
|
|
||||||
if ((bitspersample!=16) || (channels != 2)) {
|
if ((bitspersample!=16) || (channels != 2)) {
|
||||||
return PLUGIN_ERROR;
|
return CODEC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ci->advance_buffer(44);
|
ci->advance_buffer(44);
|
||||||
|
@ -132,5 +132,5 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||||
if (ci->request_next_track())
|
if (ci->request_next_track())
|
||||||
goto 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 <codecs/libwavpack/wavpack.h>
|
||||||
#include "playback.h"
|
#include "playback.h"
|
||||||
#include "lib/codeclib.h"
|
#include "lib/codeclib.h"
|
||||||
|
|
||||||
static struct plugin_api *rb;
|
static struct codec_api *rb;
|
||||||
static struct codec_api *ci;
|
static struct codec_api *ci;
|
||||||
|
|
||||||
#define BUFFER_SIZE 4096
|
#define BUFFER_SIZE 4096
|
||||||
|
@ -41,18 +41,18 @@ extern char iramstart[];
|
||||||
extern char iramend[];
|
extern char iramend[];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* this is the plugin entry point */
|
/* this is the codec entry point */
|
||||||
enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
enum codec_status codec_start(struct codec_api* api, void* parm)
|
||||||
{
|
{
|
||||||
WavpackContext *wpc;
|
WavpackContext *wpc;
|
||||||
char error [80];
|
char error [80];
|
||||||
int bps, nchans;
|
int bps, nchans;
|
||||||
|
|
||||||
/* Generic plugin initialisation */
|
/* Generic codec initialisation */
|
||||||
TEST_PLUGIN_API(api);
|
TEST_CODEC_API(api);
|
||||||
|
|
||||||
rb = api;
|
rb = api;
|
||||||
ci = (struct codec_api*) parm;
|
ci = api;
|
||||||
|
|
||||||
#ifndef SIMULATOR
|
#ifndef SIMULATOR
|
||||||
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
|
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
|
||||||
|
@ -64,15 +64,15 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||||
|
|
||||||
next_track:
|
next_track:
|
||||||
|
|
||||||
if (codec_init(api, ci))
|
if (codec_init(api))
|
||||||
return PLUGIN_ERROR;
|
return CODEC_ERROR;
|
||||||
|
|
||||||
/* Create a decoder instance */
|
/* Create a decoder instance */
|
||||||
|
|
||||||
wpc = WavpackOpenFileInput (read_callback, error);
|
wpc = WavpackOpenFileInput (read_callback, error);
|
||||||
|
|
||||||
if (!wpc)
|
if (!wpc)
|
||||||
return PLUGIN_ERROR;
|
return CODEC_ERROR;
|
||||||
|
|
||||||
bps = WavpackGetBytesPerSample (wpc);
|
bps = WavpackGetBytesPerSample (wpc);
|
||||||
nchans = WavpackGetReducedChannels (wpc);
|
nchans = WavpackGetReducedChannels (wpc);
|
||||||
|
@ -181,5 +181,5 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parm)
|
||||||
if (ci->request_next_track())
|
if (ci->request_next_track())
|
||||||
goto next_track;
|
goto next_track;
|
||||||
|
|
||||||
return PLUGIN_OK;
|
return CODEC_OK;
|
||||||
}
|
}
|
|
@ -33,7 +33,7 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "sprintf.h"
|
#include "sprintf.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "plugin.h"
|
#include "codecs.h"
|
||||||
#include "wps.h"
|
#include "wps.h"
|
||||||
#include "wps-display.h"
|
#include "wps-display.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
@ -63,13 +63,13 @@
|
||||||
static volatile bool playing;
|
static volatile bool playing;
|
||||||
static volatile bool paused;
|
static volatile bool paused;
|
||||||
|
|
||||||
#define CODEC_VORBIS "/.rockbox/codecs/codecvorbis.rock";
|
#define CODEC_VORBIS "/.rockbox/codecs/vorbis.codec";
|
||||||
#define CODEC_MPA_L3 "/.rockbox/codecs/codecmpa.rock";
|
#define CODEC_MPA_L3 "/.rockbox/codecs/mpa.codec";
|
||||||
#define CODEC_FLAC "/.rockbox/codecs/codecflac.rock";
|
#define CODEC_FLAC "/.rockbox/codecs/flac.codec";
|
||||||
#define CODEC_WAV "/.rockbox/codecs/codecwav.rock";
|
#define CODEC_WAV "/.rockbox/codecs/wav.codec";
|
||||||
#define CODEC_A52 "/.rockbox/codecs/codeca52.rock";
|
#define CODEC_A52 "/.rockbox/codecs/a52.codec";
|
||||||
#define CODEC_MPC "/.rockbox/codecs/codecmpc.rock";
|
#define CODEC_MPC "/.rockbox/codecs/mpc.codec";
|
||||||
#define CODEC_WAVPACK "/.rockbox/codecs/codecwavpack.rock";
|
#define CODEC_WAVPACK "/.rockbox/codecs/wavpack.codec";
|
||||||
|
|
||||||
#define AUDIO_FILL_CYCLE (1024*256)
|
#define AUDIO_FILL_CYCLE (1024*256)
|
||||||
#define AUDIO_DEFAULT_WATERMARK (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;
|
static volatile struct track_info *cur_ti;
|
||||||
|
|
||||||
/* Codec API including function callbacks. */
|
/* 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
|
/* When we change a song and buffer is not in filling state, this
|
||||||
variable keeps information about whether to go a next/previous track. */
|
variable keeps information about whether to go a next/previous track. */
|
||||||
|
@ -1074,7 +1074,7 @@ void codec_thread(void)
|
||||||
switch (ev.id) {
|
switch (ev.id) {
|
||||||
case CODEC_LOAD_DISK:
|
case CODEC_LOAD_DISK:
|
||||||
ci.stop_codec = false;
|
ci.stop_codec = false;
|
||||||
status = codec_load_file((char *)ev.data, &ci);
|
status = codec_load_file((char *)ev.data);
|
||||||
break ;
|
break ;
|
||||||
|
|
||||||
case CODEC_LOAD:
|
case CODEC_LOAD:
|
||||||
|
@ -1089,7 +1089,7 @@ void codec_thread(void)
|
||||||
ci.stop_codec = false;
|
ci.stop_codec = false;
|
||||||
wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf;
|
wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf;
|
||||||
status = codec_load_ram(cur_ti->codecbuf, codecsize,
|
status = codec_load_ram(cur_ti->codecbuf, codecsize,
|
||||||
&ci, &codecbuf[0], wrap);
|
&codecbuf[0], wrap);
|
||||||
break ;
|
break ;
|
||||||
|
|
||||||
#ifndef SIMULATOR
|
#ifndef SIMULATOR
|
||||||
|
@ -1103,7 +1103,7 @@ void codec_thread(void)
|
||||||
switch (ev.id) {
|
switch (ev.id) {
|
||||||
case CODEC_LOAD_DISK:
|
case CODEC_LOAD_DISK:
|
||||||
case CODEC_LOAD:
|
case CODEC_LOAD:
|
||||||
if (status != PLUGIN_OK) {
|
if (status != CODEC_OK) {
|
||||||
logf("Codec failure");
|
logf("Codec failure");
|
||||||
splash(HZ*2, true, "Codec failure");
|
splash(HZ*2, true, "Codec failure");
|
||||||
playing = false;
|
playing = false;
|
||||||
|
|
|
@ -51,60 +51,6 @@ struct track_info {
|
||||||
int playlist_offset; /* File location in playlist */
|
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
|
#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)
|
int plugin_load(const char* plugin, void* parameter)
|
||||||
{
|
{
|
||||||
enum plugin_status (*plugin_start)(struct plugin_api* api, void* param);
|
enum plugin_status (*plugin_start)(struct plugin_api* api, void* param);
|
||||||
|
|
|
@ -403,13 +403,6 @@ struct plugin_api {
|
||||||
#endif
|
#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);
|
int plugin_load(const char* plugin, void* parameter);
|
||||||
void* plugin_get_buffer(int *buffer_size);
|
void* plugin_get_buffer(int *buffer_size);
|
||||||
void* plugin_get_audio_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
|
LDS := plugin.lds
|
||||||
LINKFILE := $(OBJDIR)/pluginlink.lds
|
LINKFILE := $(OBJDIR)/pluginlink.lds
|
||||||
LINKCODEC := $(OBJDIR)/codeclink.lds
|
|
||||||
DEPFILE = $(OBJDIR)/dep-plugins
|
DEPFILE = $(OBJDIR)/dep-plugins
|
||||||
|
|
||||||
# This sets up 'SRC' based on the files mentioned in SOURCES
|
# 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
|
$(OBJDIR)/%.elf: $(OBJDIR)/%.o $(LINKFILE) $(LINKCODEC) $(BUILDDIR)/libplugin.a
|
||||||
$(SILENT)(file=`basename $@`; \
|
$(SILENT)(file=`basename $@`; \
|
||||||
echo "LD $$file"; \
|
echo "LD $$file"; \
|
||||||
match=`grep $$file CODECS`; \
|
$(CC) $(GCCOPTS) -O -nostdlib -o $@ $< -L$(BUILDDIR) $(CODECLIBS) -lplugin -lgcc -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/$*.map)
|
||||||
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)
|
|
||||||
|
|
||||||
$(OBJDIR)/%.rock : $(OBJDIR)/%.elf
|
$(OBJDIR)/%.rock : $(OBJDIR)/%.elf
|
||||||
@echo "OBJCOPY "`basename $@`
|
@echo "OBJCOPY "`basename $@`
|
||||||
|
@ -108,7 +101,7 @@ endif # end of simulator section
|
||||||
include $(TOOLSDIR)/make.inc
|
include $(TOOLSDIR)/make.inc
|
||||||
|
|
||||||
$(BUILDDIR)/libplugin.a:
|
$(BUILDDIR)/libplugin.a:
|
||||||
@echo "MAKE in lib"
|
@echo "MAKE in plugin/lib"
|
||||||
@mkdir -p $(OBJDIR)/lib
|
@mkdir -p $(OBJDIR)/lib
|
||||||
@$(MAKE) -C lib OBJDIR=$(OBJDIR)/lib
|
@$(MAKE) -C lib OBJDIR=$(OBJDIR)/lib
|
||||||
|
|
||||||
|
@ -116,10 +109,6 @@ $(LINKFILE): $(LDS)
|
||||||
@echo "build $@"
|
@echo "build $@"
|
||||||
@cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) $(DEFINES) -E -P - >$@
|
@cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) $(DEFINES) -E -P - >$@
|
||||||
|
|
||||||
$(LINKCODEC): $(LDS)
|
|
||||||
@echo "build $@"
|
|
||||||
@cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) -DCODEC $(INCLUDES) $(TARGET) $(DEFINES) -E -P - >$@
|
|
||||||
|
|
||||||
$(SUBDIRS):
|
$(SUBDIRS):
|
||||||
@echo "MAKE in $@"
|
@echo "MAKE in $@"
|
||||||
@mkdir -p $(OBJDIR)/$@
|
@mkdir -p $(OBJDIR)/$@
|
||||||
|
|
|
@ -67,22 +67,15 @@ alpine_cdc.c
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_HWCODEC == MASNONE /* software codec platforms */
|
#if CONFIG_HWCODEC == MASNONE /* software codec platforms */
|
||||||
|
#if 0
|
||||||
mpa2wav.c
|
mpa2wav.c
|
||||||
a52towav.c
|
a52towav.c
|
||||||
flac2wav.c
|
flac2wav.c
|
||||||
vorbis2wav.c
|
vorbis2wav.c
|
||||||
#ifdef IRIVER_H100
|
|
||||||
codecvorbis.c
|
|
||||||
codecmpa.c
|
|
||||||
codecflac.c
|
|
||||||
codecwav.c
|
|
||||||
codeca52.c
|
|
||||||
codecmpc.c
|
|
||||||
codecwavpack.c
|
|
||||||
#endif
|
|
||||||
wv2wav.c
|
wv2wav.c
|
||||||
mpc2wav.c
|
mpc2wav.c
|
||||||
midi2wav.c
|
midi2wav.c
|
||||||
|
#endif
|
||||||
iriverify.c
|
iriverify.c
|
||||||
#else
|
#else
|
||||||
splitedit.c
|
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
|
#ifdef HAVE_LCD_CHARCELLS
|
||||||
playergfx.c
|
playergfx.c
|
||||||
#endif
|
#endif
|
||||||
|
#if 0
|
||||||
#if CONFIG_HWCODEC == MASNONE /* software codec platforms */
|
#if CONFIG_HWCODEC == MASNONE /* software codec platforms */
|
||||||
xxx2wav.c
|
xxx2wav.c
|
||||||
#ifdef IRIVER_H100
|
|
||||||
codeclib.c
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -48,7 +48,7 @@ sub buildzip {
|
||||||
mkdir ".rockbox/langs", 0777;
|
mkdir ".rockbox/langs", 0777;
|
||||||
mkdir ".rockbox/rocks", 0777;
|
mkdir ".rockbox/rocks", 0777;
|
||||||
mkdir ".rockbox/codecs", 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/`;
|
`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
|
open VIEWERS, "$ROOT/apps/plugins/viewers.config" or
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue