? big-recording-update2.1.patch.txt ? builds ? cvsadd ? cvsexport ? makepatch ? patchup ? test_fps.patch.txt ? uisim-sdl-calls.txt ? unpatch ? x5asm ? firmware/Document4.txt ? tools/codepages ? tools/ipod_fw ? tools/mkboot ? tools/rdf2binary ? tools/uclpack Index: apps/SOURCES =================================================================== RCS file: /cvsroot/rockbox/apps/SOURCES,v retrieving revision 1.52 diff -u -r1.52 SOURCES --- apps/SOURCES 12 Oct 2006 20:45:31 -0000 1.52 +++ apps/SOURCES 16 Oct 2006 23:32:22 -0000 @@ -70,6 +70,9 @@ playback.c codecs.c dsp.c +#ifdef HAVE_RECORDING +enc_config.c +#endif eq.c #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) dsp_cf.S Index: apps/codecs.c =================================================================== RCS file: /cvsroot/rockbox/apps/codecs.c,v retrieving revision 1.34 diff -u -r1.34 codecs.c --- apps/codecs.c 3 Oct 2006 10:38:26 -0000 1.34 +++ apps/codecs.c 16 Oct 2006 23:32:22 -0000 @@ -50,6 +50,7 @@ #include "sound.h" #include "database.h" #include "splash.h" +#include "general.h" #ifdef SIMULATOR #if CONFIG_CODEC == SWCODEC @@ -104,6 +105,7 @@ PREFIX(remove), PREFIX(rename), PREFIX(ftruncate), + PREFIX(fsync), fdprintf, read_line, settings_parseline, @@ -187,6 +189,7 @@ get_time, set_time, plugin_get_audio_buffer, + round_value_to_list32, #if defined(DEBUG) || defined(SIMULATOR) debugf, @@ -213,11 +216,11 @@ false, enc_get_inputs, enc_set_parameters, - enc_alloc_chunk, - enc_free_chunk, - enc_wavbuf_near_empty, - enc_get_wav_data, - &enc_set_header_callback, + enc_get_chunk, + enc_finish_chunk, + enc_pcm_buf_near_empty, + enc_get_pcm_data, + enc_unget_pcm_data #endif /* new stuff at the end, sort into place next time @@ -225,10 +228,10 @@ }; -void codec_get_full_path(char *path, const char *codec_fn) +void codec_get_full_path(char *path, const char *codec_root_fn) { - /* Create full codec path */ - snprintf(path, MAX_PATH-1, CODECS_DIR "/%s", codec_fn); + snprintf(path, MAX_PATH-1, CODECS_DIR "/%s." CODEC_EXTENSION, + codec_root_fn); } int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap, @@ -254,7 +257,11 @@ hdr = (struct codec_header *)codecbuf; if (size <= (signed)sizeof(struct codec_header) - || hdr->magic != CODEC_MAGIC + || (hdr->magic != CODEC_MAGIC +#ifdef HAVE_RECORDING + && hdr->magic != CODEC_ENC_MAGIC +#endif + ) || hdr->target_id != TARGET_ID || hdr->load_addr != codecbuf || hdr->end_addr > codecbuf + CODEC_SIZE) Index: apps/codecs.h =================================================================== RCS file: /cvsroot/rockbox/apps/codecs.h,v retrieving revision 1.40 diff -u -r1.40 codecs.h --- apps/codecs.h 26 Sep 2006 10:10:36 -0000 1.40 +++ apps/codecs.h 16 Oct 2006 23:32:23 -0000 @@ -46,7 +46,7 @@ #include "profile.h" #endif #if (CONFIG_CODEC == SWCODEC) -#if !defined(SIMULATOR) +#if !defined(SIMULATOR) && defined(HAVE_RECORDING) #include "pcm_record.h" #endif #include "dsp.h" @@ -84,15 +84,18 @@ #define PREFIX(_x_) _x_ #endif -#define CODEC_MAGIC 0x52434F44 /* RCOD */ +/* magic for normal codecs */ +#define CODEC_MAGIC 0x52434F44 /* RCOD */ +/* magic for encoder codecs */ +#define CODEC_ENC_MAGIC 0x52454E43 /* RENC */ /* increase this every time the api struct changes */ -#define CODEC_API_VERSION 9 +#define CODEC_API_VERSION 10 /* 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 8 +#define CODEC_MIN_API_VERSION 10 /* codec return codes */ enum codec_status { @@ -176,6 +179,7 @@ int (*PREFIX(remove))(const char* pathname); int (*PREFIX(rename))(const char* path, const char* newname); int (*PREFIX(ftruncate))(int fd, off_t length); + int (*PREFIX(fsync))(int fd); int (*fdprintf)(int fd, const char *fmt, ...); int (*read_line)(int fd, char* buffer, int buffer_size); @@ -232,7 +236,8 @@ /* 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_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); @@ -263,6 +268,10 @@ struct tm* (*get_time)(void); int (*set_time)(const struct tm *tm); void* (*plugin_get_audio_buffer)(int* buffer_size); + int (*round_value_to_list32)(unsigned long value, + const unsigned long list[], + int count, + bool signd); #if defined(DEBUG) || defined(SIMULATOR) void (*debugf)(const char *fmt, ...); @@ -291,18 +300,14 @@ #endif #if defined(HAVE_RECORDING) && !defined(SIMULATOR) - bool enc_codec_loaded; - void (*enc_get_inputs)(int *buffer_size, - int *channels, int *quality); - void (*enc_set_parameters)(int chunk_size, int num_chunks, - int samp_per_chunk, char *head_ptr, int head_size, - int enc_id); - unsigned int* (*enc_alloc_chunk)(void); - void (*enc_free_chunk)(void); - int (*enc_wavbuf_near_empty)(void); - char* (*enc_get_wav_data)(int size); - void (**enc_set_header_callback)(void *head_buffer, - int head_size, int num_samples, bool is_file_header); + volatile int enc_codec_loaded; /* <0=error, 0=pending, >0=ok */ + void (*enc_get_inputs)(struct enc_inputs *inputs); + void (*enc_set_parameters)(struct enc_parameters *params); + struct enc_chunk_hdr * (*enc_get_chunk)(void); + void (*enc_finish_chunk)(void); + int (*enc_pcm_buf_near_empty)(void); + unsigned char * (*enc_get_pcm_data)(size_t size); + size_t (*enc_unget_pcm_data)(size_t size); #endif /* new stuff at the end, sort into place next time @@ -312,34 +317,49 @@ /* codec header */ struct codec_header { - unsigned long magic; + unsigned long magic; /* RCOD or RENC */ unsigned short target_id; unsigned short api_version; unsigned char *load_addr; unsigned char *end_addr; enum codec_status(*entry_point)(struct codec_api*); }; + #ifdef CODEC #ifndef SIMULATOR /* plugin_* is correct, codecs use the plugin linker script */ extern unsigned char plugin_start_addr[]; extern unsigned char plugin_end_addr[]; +/* decoders */ #define CODEC_HEADER \ const struct codec_header __header \ __attribute__ ((section (".header")))= { \ CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ plugin_start_addr, plugin_end_addr, codec_start }; -#else /* SIMULATOR */ +/* encoders */ +#define CODEC_ENC_HEADER \ + const struct codec_header __header \ + __attribute__ ((section (".header")))= { \ + CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ + plugin_start_addr, plugin_end_addr, codec_start }; + +#else /* def SIMULATOR */ +/* decoders */ #define CODEC_HEADER \ const struct codec_header __header = { \ CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ NULL, NULL, codec_start }; -#endif -#endif +/* encoders */ +#define CODEC_ENC_HEADER \ + const struct codec_header __header = { \ + CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ + NULL, NULL, codec_start }; +#endif /* SIMULATOR */ +#endif /* CODEC */ -/* create full codec path from filenames in audio_formats[] +/* create full codec path from root filenames in audio_formats[] assumes buffer size is MAX_PATH */ -void codec_get_full_path(char *path, const char *codec_fn); +void codec_get_full_path(char *path, const char *codec_root_fn); /* defined by the codec loader (codec.c) */ int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap, Index: apps/enc_config.c =================================================================== RCS file: apps/enc_config.c diff -N apps/enc_config.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ apps/enc_config.c 16 Oct 2006 23:32:23 -0000 @@ -0,0 +1,417 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Michael Sevakis + * + * 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 +#include +#include +#include "config.h" +#include "atoi.h" +#include "lang.h" +#include "misc.h" +#include "talk.h" +#include "general.h" +#include "codecs.h" +#include "menu.h" +#include "statusbar.h" +#include "settings.h" +#include "audio.h" +#include "pcm_record.h" +#include "enc_config.h" + +#define MENU_ITEM_FN(fn) \ + ((bool (*)(void))fn) + +#define ENC_MENU_ITEM_FN(fn) \ + ((bool (*)(struct encoder_config *))fn) + +#define CALL_FN_(fn, ...) \ + if (fn) fn(__VA_ARGS__) + +static bool enc_run_menu(int m, const struct menu_item items[], + struct encoder_config *cfg); +static bool enc_no_config_menu(struct encoder_config *cfg); + +/** Function definitions for each codec - add these to enc_data + list following the definitions **/ + +/** mp3_enc.codec **/ + +/* mp3_enc: return encoder capabilities */ +static void mp3_enc_get_caps(const struct encoder_config *cfg, + struct encoder_caps *caps, + bool for_config) +{ + int i; + unsigned long bitr; + + if (!for_config) + { + /* Overall encoder capabilities */ + caps->samplerate_caps = MPEG1_SAMPR_CAPS | MPEG2_SAMPR_CAPS; + caps->channel_caps = CHN_CAP_ALL; + return; + } + + /* Restrict caps based on config */ + i = round_value_to_list32(cfg->mp3_enc.bitrate, mp3_enc_bitr, + MP3_ENC_NUM_BITR, false); + bitr = mp3_enc_bitr[i]; + + /* sample rate caps */ + if ((bitr >= 32 && bitr <= 128) || bitr >= 160) + caps->samplerate_caps |= MPEG1_SAMPR_CAPS; + + if (bitr <= 160) + { + caps->samplerate_caps |= MPEG2_SAMPR_CAPS; + caps->channel_caps |= CHN_CAP_MONO; + } + + caps->channel_caps |= CHN_CAP_STEREO; +} /* mp3_enc_get_caps */ + +/* mp3_enc: return the default configuration */ +static void mp3_enc_default_config(struct encoder_config *cfg) +{ + cfg->mp3_enc.bitrate = 128; /* default that works for all types */ +} /* mp3_enc_default_config */ + +static void mp3_enc_convert_config(struct encoder_config *cfg, + bool to_encoder) +{ + if (to_encoder) + { + if ((unsigned)global_settings.mp3_enc_config.bitrate > MP3_ENC_NUM_BITR) + global_settings.mp3_enc_config.bitrate = MP3_ENC_BITRATE_CFG_DEFAULT; + cfg->mp3_enc.bitrate = mp3_enc_bitr[global_settings.mp3_enc_config.bitrate]; + } + else + { + global_settings.mp3_enc_config.bitrate = + round_value_to_list32(cfg->mp3_enc.bitrate, mp3_enc_bitr, + MP3_ENC_NUM_BITR, false); + } +} /* mp3_enc_convert_config */ + +/* mp3_enc: show the bitrate setting options */ +static bool mp3_enc_bitrate(struct encoder_config *cfg) +{ + static const struct opt_items items[] = + { + /*MPEG */ +#ifdef HAVE_MPEG2_SAMPR + { "8 kBit/s", TALK_ID(8, UNIT_KBIT) }, /* 2 */ + { "16 kBit/s", TALK_ID(16, UNIT_KBIT) }, /* 2 */ + { "24 kBit/s", TALK_ID(24, UNIT_KBIT) }, /* 2 */ +#endif + { "32 kBit/s", TALK_ID(32, UNIT_KBIT) }, /* 1,2 */ + { "40 kBit/s", TALK_ID(40, UNIT_KBIT) }, /* 1,2 */ + { "48 kBit/s", TALK_ID(48, UNIT_KBIT) }, /* 1,2 */ + { "56 kBit/s", TALK_ID(56, UNIT_KBIT) }, /* 1,2 */ + { "64 kBit/s", TALK_ID(64, UNIT_KBIT) }, /* 1,2 */ + { "80 kBit/s", TALK_ID(80, UNIT_KBIT) }, /* 1,2 */ + { "96 kBit/s", TALK_ID(96, UNIT_KBIT) }, /* 1,2 */ + { "112 kBit/s", TALK_ID(112, UNIT_KBIT) }, /* 1,2 */ + { "128 kBit/s", TALK_ID(128, UNIT_KBIT) }, /* 1,2 */ +#ifdef HAVE_MPEG2_SAMPR + { "144 kBit/s", TALK_ID(144, UNIT_KBIT) }, /* 2 */ +#endif + { "160 kBit/s", TALK_ID(160, UNIT_KBIT) }, /* 1,2 */ + + { "192 kBit/s", TALK_ID(192, UNIT_KBIT) }, /* 1 */ + { "224 kBit/s", TALK_ID(224, UNIT_KBIT) }, /* 1 */ + { "256 kBit/s", TALK_ID(256, UNIT_KBIT) }, /* 1 */ + { "320 kBit/s", TALK_ID(320, UNIT_KBIT) }, /* 1 */ + }; + + unsigned long rate_list[ARRAYLEN(items)]; + + /* This is rather constant based upon the build but better than + storing and maintaining yet another list of numbers */ + int n_rates = make_list_from_caps32( + MPEG1_BITR_CAPS | MPEG2_BITR_CAPS, mp3_enc_bitr, + MPEG1_BITR_CAPS +#ifdef HAVE_MPEG2_SAMPR + | MPEG2_BITR_CAPS, +#endif + rate_list); + + int index = round_value_to_list32(cfg->mp3_enc.bitrate, rate_list, + n_rates, false); + bool res = set_option(str(LANG_BITRATE), &index, INT, + items, n_rates, NULL); + cfg->mp3_enc.bitrate = rate_list[index]; + + return res; +} /* mp3_enc_bitrate */ + +/* mp3_enc: show the configuration menu */ +static bool mp3_enc_menu(struct encoder_config *cfg) +{ + static const struct menu_item items[] = + { + { ID2P(LANG_BITRATE), MENU_ITEM_FN(mp3_enc_bitrate) } + }; + + bool result; + int m = menu_init(items, ARRAYLEN(items), NULL, NULL, NULL, NULL); + result = enc_run_menu(m, items, cfg); + menu_exit(m); + return result; +} /* mp3_enc_menu */ + +/** wavpack_enc.codec **/ +/* wavpack_enc: show the configuration menu */ +#if 0 +static bool wavpack_enc_menu(struct encoder_config *cfg); +#endif + +/** wav_enc.codec **/ +/* wav_enc: show the configuration menu */ +#if 0 +static bool wav_enc_menu(struct encoder_config *cfg); +#endif + +/** config function pointers and/or data for each codec **/ +static const struct encoder_data +{ + void (*get_caps)(const struct encoder_config *, struct encoder_caps *, + bool); + void (*default_cfg)(struct encoder_config *); + void (*convert_cfg)(struct encoder_config *, bool to_encoder); + bool (*menu)(struct encoder_config *); +} enc_data[REC_NUM_FORMATS] = +{ + [REC_FORMAT_MPA_L3] = { + mp3_enc_get_caps, + mp3_enc_default_config, + mp3_enc_convert_config, + mp3_enc_menu, + }, + [REC_FORMAT_WAVPACK] = { + NULL, + NULL, + NULL, + enc_no_config_menu, + }, + [REC_FORMAT_PCM_WAV] = { + NULL, + NULL, + NULL, + enc_no_config_menu, + }, +}; + +static inline bool rec_format_ok(int rec_format) +{ + return (unsigned)rec_format < REC_NUM_FORMATS; +} + +static bool enc_run_menu(int m, const struct menu_item items[], + struct encoder_config *cfg) +{ + int selected; + while (1) + { + switch (selected=menu_show(m)) + { + case MENU_SELECTED_EXIT: + return false; + + case MENU_ATTACHED_USB: + return true; + + default: + if (items[selected].function && + ENC_MENU_ITEM_FN(items[selected].function)(cfg)) + return true; + gui_syncstatusbar_draw(&statusbars, true); + } + } +} /* enc_run_menu */ + +/* menu created when encoder has no configuration options */ +static bool enc_no_config_menu(struct encoder_config *cfg) +{ + static const struct menu_item items[] = + { + { ID2P(LANG_NO_SETTINGS), NULL } + }; + int m; + bool result; + + m = menu_init(items, ARRAYLEN(items), NULL, NULL, NULL, NULL); + result = enc_run_menu(m, items, NULL); + menu_exit(m); + + return result; + (void)cfg; +} /* enc_no_config_menu */ + +/* update settings dependent upon encoder settings */ +static void enc_rec_settings_changed(struct encoder_config *cfg) +{ + struct encoder_config enc_config; + struct encoder_caps caps; + long table[MAX(CHN_NUM_MODES, REC_NUM_FREQ)]; + int n; + + if (cfg == NULL) + { + cfg = &enc_config; + cfg->rec_format = global_settings.rec_format; + global_to_encoder_config(cfg); + } + + /* have to sync other settings when encoder settings change */ + if (!enc_get_caps(cfg, &caps, true)) + return; + + /* rec_channels */ + n = make_list_from_caps32(CHN_CAP_ALL, NULL, + caps.channel_caps, table); + + /* no zero check needed: encoder must support at least one + sample rate that recording supports or it shouldn't be in + available in the recording options */ + n = round_value_to_list32(global_settings.rec_channels, + table, n, true); + global_settings.rec_channels = table[n]; + + /* rec_frequency */ + n = make_list_from_caps32(REC_SAMPR_CAPS, rec_freq_sampr, + caps.samplerate_caps, table); + + n = round_value_to_list32( + rec_freq_sampr[global_settings.rec_frequency], + table, n, false); + + global_settings.rec_frequency = round_value_to_list32( + table[n], rec_freq_sampr, REC_NUM_FREQ, false); +} /* enc_rec_settings_changed */ + +/** public stuff **/ +void global_to_encoder_config(struct encoder_config *cfg) +{ + const struct encoder_data *data = &enc_data[cfg->rec_format]; + CALL_FN_(data->convert_cfg, cfg, true); +} /* global_to_encoder_config */ + +void encoder_config_to_global(const struct encoder_config *cfg) +{ + const struct encoder_data *data = &enc_data[cfg->rec_format]; + CALL_FN_(data->convert_cfg, (struct encoder_config *)cfg, false); +} /* encoder_config_to_global */ + +bool enc_get_caps(const struct encoder_config *cfg, + struct encoder_caps *caps, + bool for_config) +{ + /* get_caps expects caps to be zeroed first */ + memset(caps, 0, sizeof (*caps)); + + if (!rec_format_ok(cfg->rec_format)) + return false; + + if (enc_data[cfg->rec_format].get_caps) + { + enc_data[cfg->rec_format].get_caps(cfg, caps, for_config); + } + else + { + /* If no function provided...defaults to all */ + caps->samplerate_caps = SAMPR_CAP_ALL; + caps->channel_caps = CHN_CAP_ALL; + } + + return true; +} /* enc_get_caps */ + +/* Initializes the config struct with default values */ +bool enc_init_config(struct encoder_config *cfg) +{ + if (!rec_format_ok(cfg->rec_format)) + return false; + CALL_FN_(enc_data[cfg->rec_format].default_cfg, cfg); + return true; +} /* enc_init_config */ + +/** Encoder Menus **/ +bool enc_config_menu(struct encoder_config *cfg) +{ + if (!rec_format_ok(cfg->rec_format)) + return false; + return enc_data[cfg->rec_format].menu(cfg); +} /* enc_config_menu */ + +/** Global Settings **/ + +/* Reset all codecs to defaults */ +void enc_global_settings_reset(void) +{ + struct encoder_config cfg; + cfg.rec_format = 0; + + do + { + global_to_encoder_config(&cfg); + enc_init_config(&cfg); + encoder_config_to_global(&cfg); + if (cfg.rec_format == global_settings.rec_format) + enc_rec_settings_changed(&cfg); + } + while (++cfg.rec_format < REC_NUM_FORMATS); +} /* enc_global_settings_reset */ + +/* Apply new settings */ +void enc_global_settings_apply(void) +{ + struct encoder_config cfg; + if (!rec_format_ok(global_settings.rec_format)) + global_settings.rec_format = REC_FORMAT_DEFAULT; + + cfg.rec_format = global_settings.rec_format; + global_to_encoder_config(&cfg); + enc_rec_settings_changed(&cfg); + encoder_config_to_global(&cfg); +} /* enc_global_settings_apply */ + +/* Show an encoder's config menu based on the global_settings. + Modified settings are placed in global_settings.enc_config. */ +bool enc_global_config_menu(void) +{ + struct encoder_config cfg; + + bool res; + + if (!rec_format_ok(global_settings.rec_format)) + global_settings.rec_format = REC_FORMAT_DEFAULT; + + cfg.rec_format = global_settings.rec_format; + + global_to_encoder_config(&cfg); + + res = enc_config_menu(&cfg); + if (!res) + { + enc_rec_settings_changed(&cfg); + encoder_config_to_global(&cfg); + } + + return res; +} /* enc_global_config_menu */ Index: apps/enc_config.h =================================================================== RCS file: apps/enc_config.h diff -N apps/enc_config.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ apps/enc_config.h 16 Oct 2006 23:32:23 -0000 @@ -0,0 +1,73 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Michael Sevakis + * + * 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 ENC_CONFIG_H +#define ENC_CONFIG_H + +#include "misc.h" +#include "enc_base.h" + +/** Capabilities **/ + +/* Capabilities returned by enc_get_caps that depend upon encoder settings */ +struct encoder_caps +{ + unsigned long samplerate_caps; /* Mask composed of SAMPR_CAP_* flags */ + unsigned long channel_caps; /* Mask composed of CHN_CAP_* flags */ +}; + +/* for_config: + * true- the capabilities returned should be contextual based upon the + * settings in the config structure + * false- the overall capabilities are being requested + */ +bool enc_get_caps(const struct encoder_config *cfg, + struct encoder_caps *caps, + bool for_config); + +/** Configuration **/ + +/* These translate to a back between the global format and the per- + instance format */ +void global_to_encoder_config(struct encoder_config *cfg); +void encoder_config_to_global(const struct encoder_config *cfg); + +/* Initializes the config struct with default values. + set afmt member before calling. */ +bool enc_init_config(struct encoder_config *cfg); + +/** Encoder Menus **/ + +/* Shows an encoder's config menu given an encoder config returned by one + of the enc_api functions. Modified settings are not saved to disk but + instead are placed in the structure. Call enc_save_config to commit + the data. */ +bool enc_config_menu(struct encoder_config *cfg); + +/** Global Settings **/ + +/* Reset all codecs to defaults */ +void enc_global_settings_reset(void); + +/* Apply new settings */ +void enc_global_settings_apply(void); + +/* Show an encoder's config menu based on the global_settings. + Modified settings are placed in global_settings.enc_config. */ +bool enc_global_config_menu(void); +#endif /* ENC_CONFIG_H */ Index: apps/eq_menu.c =================================================================== RCS file: /cvsroot/rockbox/apps/eq_menu.c,v retrieving revision 1.26 diff -u -r1.26 eq_menu.c --- apps/eq_menu.c 5 Sep 2006 11:59:02 -0000 1.26 +++ apps/eq_menu.c 16 Oct 2006 23:32:24 -0000 @@ -710,7 +710,8 @@ char filename[MAX_PATH]; int *setting; - create_numbered_filename(filename, EQS_DIR, "eq", ".cfg", 2); + create_numbered_filename(filename, EQS_DIR, "eq", ".cfg", 2 + IF_CNFN_NUM_(, NULL)); /* allow user to modify filename */ while (true) { Index: apps/main.c =================================================================== RCS file: /cvsroot/rockbox/apps/main.c,v retrieving revision 1.190 diff -u -r1.190 main.c --- apps/main.c 5 Oct 2006 10:07:00 -0000 1.190 +++ apps/main.c 16 Oct 2006 23:32:24 -0000 @@ -276,6 +276,9 @@ #ifdef HAVE_ADJUSTABLE_CPU_FREQ set_cpu_frequency(CPUFREQ_NORMAL); +#ifdef CPU_COLDFIRE + coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS); +#endif cpu_boost_id(true, CPUBOOSTID_MAININIT); #endif Index: apps/metadata.c =================================================================== RCS file: /cvsroot/rockbox/apps/metadata.c,v retrieving revision 1.52 diff -u -r1.52 metadata.c --- apps/metadata.c 11 Oct 2006 17:42:33 -0000 1.52 +++ apps/metadata.c 16 Oct 2006 23:32:26 -0000 @@ -88,36 +88,6 @@ long flags; }; -struct format_list -{ - char format; - char extension[5]; -}; - -static const struct format_list formats[] = -{ - { AFMT_MPA_L1, "mp1" }, - { AFMT_MPA_L2, "mp2" }, - { AFMT_MPA_L2, "mpa" }, - { AFMT_MPA_L3, "mp3" }, -#if CONFIG_CODEC == SWCODEC - { AFMT_OGG_VORBIS, "ogg" }, - { AFMT_PCM_WAV, "wav" }, - { AFMT_FLAC, "flac" }, - { AFMT_MPC, "mpc" }, - { AFMT_A52, "a52" }, - { AFMT_A52, "ac3" }, - { AFMT_WAVPACK, "wv" }, - { AFMT_ALAC, "m4a" }, - { AFMT_AAC, "mp4" }, - { AFMT_SHN, "shn" }, - { AFMT_AIFF, "aif" }, - { AFMT_AIFF, "aiff" }, - { AFMT_SID, "sid" }, - { AFMT_ADX, "adx" }, -#endif -}; - #if CONFIG_CODEC == SWCODEC static const unsigned short a52_bitrates[] = { @@ -1514,45 +1484,45 @@ /* Soul Calibur 2 style (type 03) */ DEBUGF("get_adx_metadata: type 03 found\n"); /* check if header is too small for loop data */ - if (chanstart-6 < 0x2c) looping=0; - else { - looping = (buf[0x18]) || - (buf[0x19]) || - (buf[0x1a]) || - (buf[0x1b]); - end_adr = (buf[0x28]<<24) | - (buf[0x29]<<16) | - (buf[0x2a]<<8) | - (buf[0x2b]); - - start_adr = ( - (buf[0x1c]<<24) | - (buf[0x1d]<<16) | - (buf[0x1e]<<8) | - (buf[0x1f]) - )/32*channels*18+chanstart; - } + if (chanstart-6 < 0x2c) looping=0; + else { + looping = (buf[0x18]) || + (buf[0x19]) || + (buf[0x1a]) || + (buf[0x1b]); + end_adr = (buf[0x28]<<24) | + (buf[0x29]<<16) | + (buf[0x2a]<<8) | + (buf[0x2b]); + + start_adr = ( + (buf[0x1c]<<24) | + (buf[0x1d]<<16) | + (buf[0x1e]<<8) | + (buf[0x1f]) + )/32*channels*18+chanstart; + } } else if (!memcmp(buf+0x10,"\x01\xF4\x04\x00",4)) { /* Standard (type 04) */ DEBUGF("get_adx_metadata: type 04 found\n"); /* check if header is too small for loop data */ if (chanstart-6 < 0x38) looping=0; - else { - looping = (buf[0x24]) || - (buf[0x25]) || - (buf[0x26]) || - (buf[0x27]); - end_adr = (buf[0x34]<<24) | - (buf[0x35]<<16) | - (buf[0x36]<<8) | - buf[0x37]; - start_adr = ( - (buf[0x28]<<24) | - (buf[0x29]<<16) | - (buf[0x2a]<<8) | - (buf[0x2b]) - )/32*channels*18+chanstart; - } + else { + looping = (buf[0x24]) || + (buf[0x25]) || + (buf[0x26]) || + (buf[0x27]); + end_adr = (buf[0x34]<<24) | + (buf[0x35]<<16) | + (buf[0x36]<<8) | + buf[0x37]; + start_adr = ( + (buf[0x28]<<24) | + (buf[0x29]<<16) | + (buf[0x2a]<<8) | + (buf[0x2b]) + )/32*channels*18+chanstart; + } } else { DEBUGF("get_adx_metadata: error, couldn't determine ADX type\n"); return false; @@ -1661,15 +1631,25 @@ { return AFMT_UNKNOWN; } - - suffix += 1; - for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) + /* skip '.' */ + suffix++; + + for (i = 1; i < AFMT_NUM_CODECS; i++) { - if (strcasecmp(suffix, formats[i].extension) == 0) + /* search extension list for type */ + const char *ext = audio_formats[i].ext_list; + + do { - return formats[i].format; + if (strcasecmp(suffix, ext) == 0) + { + return i; + } + + ext += strlen(ext) + 1; } + while (*ext != '\0'); } return AFMT_UNKNOWN; Index: apps/misc.c =================================================================== RCS file: /cvsroot/rockbox/apps/misc.c,v retrieving revision 1.66 diff -u -r1.66 misc.c --- apps/misc.c 29 Sep 2006 06:22:43 -0000 1.66 +++ apps/misc.c 16 Oct 2006 23:32:26 -0000 @@ -56,6 +56,8 @@ #include "icons.h" #endif /* End HAVE_LCD_BITMAP */ +#include "misc.h" + /* Format a large-range value for output, using the appropriate unit so that * the displayed value is in the range 1 <= display < 1000 (1024 for "binary" * units) if possible, and 3 significant digits are shown. If a buffer is @@ -112,16 +114,20 @@ } /* Create a filename with a number part in a way that the number is 1 - higher than the highest numbered file matching the same pattern. - It is allowed that buffer and path point to the same memory location, - saving a strcpy(). Path must always be given without trailing slash,. */ + * higher than the highest numbered file matching the same pattern. + * It is allowed that buffer and path point to the same memory location, + * saving a strcpy(). Path must always be given without trailing slash. + * "num" can point to an int specifying the number to use or NULL or a value + * less than zero to number automatically. The final number used will also + * be returned in *num. If *num is >= 0 then *num will be incremented by + * one. */ char *create_numbered_filename(char *buffer, const char *path, const char *prefix, const char *suffix, - int numberlen) + int numberlen IF_CNFN_NUM_(, int *num)) { DIR *dir; struct dirent *entry; - int max_num = 0; + int max_num; int pathlen; int prefixlen = strlen(prefix); char fmtstring[12]; @@ -131,27 +137,48 @@ pathlen = strlen(buffer); - dir = opendir(pathlen ? buffer : "/"); - if (!dir) - return NULL; - - while ((entry = readdir(dir))) +#ifdef IF_CNFN_NUM + if (num && *num >= 0) + { + /* number specified */ + max_num = *num; + } + else +#endif { - int curr_num; + /* automatic numbering */ + max_num = 0; - if (strncasecmp((char *)entry->d_name, prefix, prefixlen) - || strcasecmp((char *)entry->d_name + prefixlen + numberlen, suffix)) - continue; + dir = opendir(pathlen ? buffer : "/"); + if (!dir) + return NULL; + + while ((entry = readdir(dir))) + { + int curr_num; + + if (strncasecmp((char *)entry->d_name, prefix, prefixlen) + || strcasecmp((char *)entry->d_name + prefixlen + numberlen, suffix)) + continue; + + curr_num = atoi((char *)entry->d_name + prefixlen); + if (curr_num > max_num) + max_num = curr_num; + } - curr_num = atoi((char *)entry->d_name + prefixlen); - if (curr_num > max_num) - max_num = curr_num; + closedir(dir); } - closedir(dir); + + max_num++; snprintf(fmtstring, sizeof(fmtstring), "/%%s%%0%dd%%s", numberlen); snprintf(buffer + pathlen, MAX_PATH - pathlen, fmtstring, prefix, - max_num + 1, suffix); + max_num, suffix); + +#ifdef IF_CNFN_NUM + if (num) + *num = max_num; +#endif return buffer; } @@ -159,13 +186,22 @@ #ifdef CONFIG_RTC /* Create a filename with a date+time part. It is allowed that buffer and path point to the same memory location, - saving a strcpy(). Path must always be given without trailing slash. */ + saving a strcpy(). Path must always be given without trailing slash. + unique_time as true makes the function wait until the current time has + changed. */ char *create_datetime_filename(char *buffer, const char *path, - const char *prefix, const char *suffix) + const char *prefix, const char *suffix, + bool unique_time) { struct tm *tm = get_time(); + static struct tm last_tm; int pathlen; + while (unique_time && !memcmp(get_time(), &last_tm, sizeof (struct tm))) + sleep(HZ/10); + + last_tm = *tm; + if (buffer != path) strncpy(buffer, path, MAX_PATH); @@ -307,9 +343,10 @@ #endif #ifdef CONFIG_RTC - create_datetime_filename(filename, "", "dump ", ".bmp"); + create_datetime_filename(filename, "", "dump ", ".bmp", false); #else - create_numbered_filename(filename, "", "dump_", ".bmp", 4); + create_numbered_filename(filename, "", "dump_", ".bmp", 4 + IF_CNFN_NUM_(, NULL)); #endif fh = creat(filename, O_WRONLY); @@ -466,6 +503,18 @@ return true; } +/* read and parse a line in one step */ +int settings_read_parse_line(struct settings_rpl_params *p) +{ + if (read_line(p->fd, p->line, sizeof(p->line)) <= 0) + return -1; + + if (!settings_parseline(p->line, &p->name, &p->value)) + return 0; + + return 1; +} + static void system_flush(void) { tree_flush(); Index: apps/misc.h =================================================================== RCS file: /cvsroot/rockbox/apps/misc.h,v retrieving revision 1.16 diff -u -r1.16 misc.h --- apps/misc.h 4 Dec 2005 15:23:46 -0000 1.16 +++ apps/misc.h 16 Oct 2006 23:32:26 -0000 @@ -19,21 +19,46 @@ #ifndef MISC_H #define MISC_H +#include + /* Format a large-range value for output, using the appropriate unit so that * the displayed value is in the range 1 <= display < 1000 (1024 for "binary" * units) if possible, and 3 significant digits are shown. If a buffer is * given, the result is snprintf()'d into that buffer, otherwise the result is * voiced.*/ -void output_dyn_value(char *buf, int buf_size, int value, - const unsigned char **units, bool bin_scale); +char *output_dyn_value(char *buf, int buf_size, int value, + const unsigned char **units, bool bin_scale); +/* Create a filename with a number part in a way that the number is 1 + * higher than the highest numbered file matching the same pattern. + * It is allowed that buffer and path point to the same memory location, + * saving a strcpy(). Path must always be given without trailing slash. + * + * "num" can point to an int specifying the number to use or NULL or a value + * less than zero to number automatically. The final number used will also + * be returned in *num. If *num is >= 0 then *num will be incremented by + * one. */ +#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) && !defined(CONFIG_RTC) +/* this feature is needed by SWCODEC recording without a RTC to prevent + disk access when changing files */ +#define IF_CNFN_NUM_(...) __VA_ARGS__ +#define IF_CNFN_NUM +#else +#define IF_CNFN_NUM_(...) +#endif char *create_numbered_filename(char *buffer, const char *path, const char *prefix, const char *suffix, - int numberlen); + int numberlen IF_CNFN_NUM_(, int *num)); #ifdef CONFIG_RTC +/* Create a filename with a date+time part. + It is allowed that buffer and path point to the same memory location, + saving a strcpy(). Path must always be given without trailing slash. + unique_time as true makes the function wait until the current time has + changed. */ char *create_datetime_filename(char *buffer, const char *path, - const char *prefix, const char *suffix); -#endif + const char *prefix, const char *suffix, + bool unique_time); +#endif /* CONFIG_RTC */ /* Read (up to) a line of text from fd into buffer and return number of bytes * read (which may be larger than the number of bytes stored in buffer). If @@ -50,9 +75,23 @@ #endif bool settings_parseline(char* line, char** name, char** value); + +/* Read and parse a line in one step. + * returns: -1 = read failed or EOF + * 0 = parsed comment + * 1 = parsed name/value pair + */ +struct settings_rpl_params +{ + int fd; /* file number (set before calling) */ + char line[128]; /* line buffer */ + char *name; /* pointer to value name within line[] */ + char *value; /* pointer to value within line[] */ +}; +int settings_read_parse_line(struct settings_rpl_params *params); long default_event_handler_ex(long event, void (*callback)(void *), void *parameter); long default_event_handler(long event); void car_adapter_mode_init(void); extern int show_logo(void); -#endif +#endif /* MISC_H */ Index: apps/playback.c =================================================================== RCS file: /cvsroot/rockbox/apps/playback.c,v retrieving revision 1.364 diff -u -r1.364 playback.c --- apps/playback.c 15 Oct 2006 11:57:51 -0000 1.364 +++ apps/playback.c 16 Oct 2006 23:32:28 -0000 @@ -55,7 +55,9 @@ #include "playback.h" #include "pcmbuf.h" #include "pcm_playback.h" +#ifdef HAVE_RECORDING #include "pcm_record.h" +#endif #include "buffer.h" #include "dsp.h" #include "abrepeat.h" @@ -337,34 +339,39 @@ v1first = _v1first; } -void audio_load_encoder(int enc_id) +bool audio_load_encoder(int afmt) { #if defined(HAVE_RECORDING) && !defined(SIMULATOR) - const char *enc_fn = get_codec_filename(enc_id | CODEC_TYPE_ENCODER); + const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER); if (!enc_fn) - return; + return false; audio_remove_encoder(); LOGFQUEUE("audio > codec Q_ENCODER_LOAD_DISK"); + + ci.enc_codec_loaded = 0; /* clear any previous error condition */ queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (void *)enc_fn); - while (!ci.enc_codec_loaded) + while (ci.enc_codec_loaded == 0) yield(); + + return ci.enc_codec_loaded > 0; +#else + (void)afmt; + return true; #endif - return; - (void)enc_id; } /* audio_load_encoder */ void audio_remove_encoder(void) { #if defined(HAVE_RECORDING) && !defined(SIMULATOR) - /* force encoder codec unload (if previously loaded) */ - if (!ci.enc_codec_loaded) + /* force encoder codec unload (if currently loaded) */ + if (ci.enc_codec_loaded <= 0) return; ci.stop_codec = true; - while (ci.enc_codec_loaded) + while (ci.enc_codec_loaded > 0) yield(); #endif } /* audio_remove_encoder */ @@ -546,6 +553,9 @@ void audio_error_clear(void) { +#if defined(HAVE_RECORDING) && !defined(SIMULATOR) + pcm_rec_error_clear(); +#endif } int audio_status(void) @@ -786,21 +796,30 @@ conf_watermark = bytes; } -static const char * get_codec_filename(int enc_spec) +static const char * get_codec_filename(int cod_spec) { const char *fname; - int type = enc_spec & CODEC_TYPE_MASK; - int afmt = enc_spec & CODEC_AFMT_MASK; + +#ifdef HAVE_RECORDING + int type = cod_spec & CODEC_TYPE_MASK; + int afmt = cod_spec & CODEC_AFMT_MASK; if ((unsigned)afmt >= AFMT_NUM_CODECS) type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK); - fname = (type == CODEC_TYPE_DECODER) ? - audio_formats[afmt].codec_fn : audio_formats[afmt].codec_enc_fn; + fname = (type == CODEC_TYPE_ENCODER) ? + audio_formats[afmt].codec_enc_root_fn : + audio_formats[afmt].codec_root_fn; logf("%s: %d - %s", (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder", afmt, fname ? fname : ""); +#else /* !HAVE_RECORDING */ + if ((unsigned)cod_spec >= AFMT_NUM_CODECS) + cod_spec = AFMT_UNKNOWN; + fname = audio_formats[cod_spec].codec_root_fn; + logf("Codec: %d - %s", cod_spec, fname ? fname : ""); +#endif /* HAVE_RECORDING */ return fname; } /* get_codec_filename */ @@ -1863,6 +1882,24 @@ } break; +#if defined(HAVE_RECORDING) && !defined(SIMULATOR) + case Q_ENCODER_LOAD_DISK: + LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK"); + + if (status == CODEC_OK) + break; + + logf("Encoder failure"); + gui_syncsplash(HZ*2, true, "Encoder failure"); + + if (ci.enc_codec_loaded < 0) + break; + + logf("Encoder failed to load"); + ci.enc_codec_loaded = -1; + break; +#endif + default: LOGFQUEUE("codec < default"); Index: apps/plugin.c =================================================================== RCS file: /cvsroot/rockbox/apps/plugin.c,v retrieving revision 1.187 diff -u -r1.187 plugin.c --- apps/plugin.c 14 Oct 2006 01:32:58 -0000 1.187 +++ apps/plugin.c 16 Oct 2006 23:32:28 -0000 @@ -313,6 +313,7 @@ _ctype_, atoi, strchr, + strtok_r, strcat, memchr, memcmp, @@ -343,7 +344,14 @@ #if CONFIG_CODEC == SWCODEC pcm_play_data, pcm_play_stop, + &audio_master_sampr_list[0], + &hw_freq_sampr[0], pcm_set_frequency, +#ifdef HAVE_RECORDING + &rec_freq_sampr[0], + pcm_set_monitor, +#endif + pcm_apply_settings, pcm_is_playing, pcm_play_pause, #endif @@ -467,7 +475,6 @@ /* new stuff at the end, sort into place next time the API gets incompatible */ - strtok_r, #ifdef HAVE_WHEEL_POSITION wheel_status, wheel_send_events, Index: apps/plugin.h =================================================================== RCS file: /cvsroot/rockbox/apps/plugin.h,v retrieving revision 1.196 diff -u -r1.196 plugin.h --- apps/plugin.h 14 Oct 2006 01:32:58 -0000 1.196 +++ apps/plugin.h 16 Oct 2006 23:32:29 -0000 @@ -105,12 +105,12 @@ #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ -#define PLUGIN_API_VERSION 32 +#define PLUGIN_API_VERSION 33 /* 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 PLUGIN_MIN_API_VERSION 30 +#define PLUGIN_MIN_API_VERSION 33 /* plugin return codes */ enum plugin_status { @@ -374,6 +374,7 @@ const unsigned char *_ctype_; int (*atoi)(const char *str); char *(*strchr)(const char *s, int c); + char* (*strtok_r)(char *ptr, const char *sep, char **end); char *(*strcat)(char *s1, const char *s2); void *(*memchr)(const void *s1, int c, size_t n); int (*memcmp)(const void *s1, const void *s2, size_t n); @@ -405,7 +406,14 @@ void (*pcm_play_data)(void (*get_more)(unsigned char** start, size_t*size), unsigned char* start, size_t size); void (*pcm_play_stop)(void); + const unsigned long *audio_master_sampr_list; + const unsigned long *hw_freq_sampr; void (*pcm_set_frequency)(unsigned int frequency); +#ifdef HAVE_RECORDING + const unsigned long *rec_freq_sampr; + void (*pcm_set_monitor)(int monitor); +#endif + void (*pcm_apply_settings)(bool reset); bool (*pcm_is_playing)(void); void (*pcm_play_pause)(bool play); #endif @@ -546,8 +554,6 @@ /* new stuff at the end, sort into place next time the API gets incompatible */ - char* (*strtok_r)(char *ptr, const char *sep, char **end); - #ifdef HAVE_WHEEL_POSITION int (*wheel_status)(void); void (*wheel_send_events)(bool send); Index: apps/settings.c =================================================================== RCS file: /cvsroot/rockbox/apps/settings.c,v retrieving revision 1.428 diff -u -r1.428 settings.c --- apps/settings.c 11 Oct 2006 09:12:23 -0000 1.428 +++ apps/settings.c 16 Oct 2006 23:32:30 -0000 @@ -90,7 +90,10 @@ #include "pcmbuf.h" #include "pcm_playback.h" #include "dsp.h" +#ifdef HAVE_RECORDING +#include "enc_config.h" #endif +#endif /* CONFIG_CODEC == SWCODEC */ #ifdef HAVE_WM8758 #include "eq_menu.h" @@ -365,7 +368,7 @@ {4, S_O(scroll_speed), 9, "scroll speed", NULL }, /* 0...15 */ {8, S_O(scroll_delay), 100, "scroll delay", NULL }, /* 0...250 */ {8, S_O(bidir_limit), 50, "bidir limit", NULL }, /* 0...200 */ - + #ifdef HAVE_REMOTE_LCD {4, S_O(remote_scroll_speed), 9, "remote scroll speed", NULL }, /* 0...15 */ {8, S_O(remote_scroll_step), 6, "remote scroll step", NULL }, /* 1...160 */ @@ -495,11 +498,12 @@ #endif }, {5, S_O(rec_prerecord_time), 0, "prerecording time", NULL }, /* 0...30 */ + {1, S_O(rec_new_file_flush), false, "rec new file flush", NULL }, {1, S_O(rec_directory), 0, /* rec_base_directory */ "rec directory", REC_BASE_DIR ",current" }, #ifdef CONFIG_BACKLIGHT {2, S_O(cliplight), 0, "cliplight", "off,main,both,remote" }, -#endif +#endif #if CONFIG_CODEC == MAS3587F {4, S_O(rec_mic_gain), 8, "rec mic gain", NULL }, {4, S_O(rec_left_gain), 2 /* 0dB */, "rec left gain", NULL }, /* 0...15 */ @@ -510,7 +514,7 @@ {1, S_O(rec_editable), false, "editable recordings", off_on }, #endif /* CONFIG_CODEC == MAS3587F */ -#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) +#if CONFIG_CODEC == SWCODEC #ifdef HAVE_UDA1380 {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */ #endif @@ -520,16 +524,16 @@ #endif {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */ {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */ -#if 0 /* Till samplerates are added for SWCODEC */ - {3, S_O(rec_frequency), 0, /* 0=44.1kHz */ - "rec frequency", "44,48,32,22,24,16" }, -#else - {3, S_O(rec_frequency), 0, /* 0=44.1kHz */ - "rec frequency", "44" }, -#endif - - {4, S_O(rec_quality), 4 /* MP3 L3 192 kBit/s */, "rec quality", NULL }, -#endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */ + {REC_FREQ_CFG_NUM_BITS, S_O(rec_frequency), REC_FREQ_DEFAULT, + "rec frequency", REC_FREQ_CFG_VAL_LIST }, + {REC_FORMAT_CFG_NUM_BITS ,S_O(rec_format), REC_FORMAT_DEFAULT, + "rec format", REC_FORMAT_CFG_VAL_LIST }, + /* mp3_enc settings */ + {5,S_O(mp3_enc_config.bitrate), MP3_ENC_BITRATE_CFG_DEFAULT, + "mp3_enc bitrate", MP3_ENC_BITRATE_CFG_VALUE_LIST }, + /* wavpack_enc settings */ + /* wav_enc settings */ +#endif /* CONFIG_CODEC == SWCODEC */ /* values for the trigger */ {8 | SIGNED, S_O(rec_start_thres), -35, "trigger start threshold", NULL}, @@ -619,7 +623,7 @@ #ifdef HAVE_WM8758 {1, S_O(eq_hw_enabled), false, "eq hardware enabled", off_on }, - + {2, S_O(eq_hw_band0_cutoff), 1, "eq hardware band 0 cutoff", "80Hz,105Hz,135Hz,175Hz" }, {5|SIGNED, S_O(eq_hw_band0_gain), 0, "eq hardware band 0 gain", NULL }, @@ -1287,6 +1291,11 @@ lcd_set_sleep_after_backlight_off(global_settings.lcd_sleep_after_backlight_off); #endif #endif /* CONFIG_BACKLIGHT */ + + /* This should stay last */ +#if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC + enc_global_settings_apply(); +#endif } @@ -1367,7 +1376,7 @@ } #ifdef HAVE_RECORDING - global_settings.recscreen_on = false; + global_settings.recscreen_on = false; #endif #ifdef HAVE_LCD_CONTRAST @@ -1533,19 +1542,17 @@ bool settings_load_config(const char* file) { - int fd; - char line[128]; + struct settings_rpl_params rpl; + int res; - fd = open(file, O_RDONLY); - if (fd < 0) + rpl.fd = open(file, O_RDONLY); + if (rpl.fd < 0) return false; - while (read_line(fd, line, sizeof line) > 0) + while ((res = settings_read_parse_line(&rpl)) >= 0) { - char* name; - char* value; - const struct bit_entry* table[2] = { rtc_bits, hd_bits }; - const int ta_size[2] = { + static const struct bit_entry* table[2] = { rtc_bits, hd_bits }; + static const int ta_size[2] = { sizeof(rtc_bits)/sizeof(rtc_bits[0]), sizeof(hd_bits)/sizeof(hd_bits[0]) }; @@ -1553,66 +1560,65 @@ int last_pos = 1; /* at which position did we succeed */ int pos; /* currently returned position */ - if (!settings_parseline(line, &name, &value)) + if (res == 0) continue; /* check for the string values */ - if (!strcasecmp(name, "wps")) { + if (!strcasecmp(rpl.name, "wps")) { #ifdef HAVE_LCD_COLOR unload_wps_backdrop(); #endif int fd2; - if ((fd2 = open(value, O_RDONLY)) >= 0) { + if ((fd2 = open(rpl.value, O_RDONLY)) >= 0) { close(fd2); - set_file(value, (char *)global_settings.wps_file, MAX_FILENAME); + set_file(rpl.value, (char *)global_settings.wps_file, MAX_FILENAME); } } #if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1) - else if (!strcasecmp(name, "rwps")) { + else if (!strcasecmp(rpl.name, "rwps")) { int fd2; - if ((fd2 = open(value, O_RDONLY)) >= 0) { + if ((fd2 = open(rpl.value, O_RDONLY)) >= 0) { close(fd2); - set_file(value, (char *)global_settings.rwps_file, MAX_FILENAME); + set_file(rpl.value, (char *)global_settings.rwps_file, MAX_FILENAME); } } #endif - else if (!strcasecmp(name, "lang")) { - if (!lang_load(value)) + else if (!strcasecmp(rpl.name, "lang")) { + if (!lang_load(rpl.value)) { - set_file(value, (char *)global_settings.lang_file, MAX_FILENAME); + set_file(rpl.value, (char *)global_settings.lang_file, MAX_FILENAME); talk_init(); /* use voice of same language */ } } #ifdef CONFIG_TUNER - else if (!strcasecmp(name, "fmr")) { - set_file(value, global_settings.fmr_file, MAX_FILENAME); + else if (!strcasecmp(rpl.name, "fmr")) { + set_file(rpl.value, global_settings.fmr_file, MAX_FILENAME); } #endif #ifdef HAVE_LCD_BITMAP - else if (!strcasecmp(name, "font")) { - if (font_load(value)) - set_file(value, (char *)global_settings.font_file, MAX_FILENAME); + else if (!strcasecmp(rpl.name, "font")) { + if (font_load(rpl.value)) + set_file(rpl.value, (char *)global_settings.font_file, MAX_FILENAME); } #endif #ifdef HAVE_LCD_COLOR - else if (!strcasecmp(name, "backdrop")) { - if (load_main_backdrop(value)) { - set_file(value, (char *)global_settings.backdrop_file, MAX_FILENAME); + else if (!strcasecmp(rpl.name, "backdrop")) { + if (load_main_backdrop(rpl.value)) { + set_file(rpl.value, (char *)global_settings.backdrop_file, MAX_FILENAME); show_main_backdrop(); } } #endif #ifdef HAVE_LCD_BITMAP - else if (!strcasecmp(name, "keyboard")) { - if (!load_kbd(value)) - set_file(value, (char *)global_settings.kbd_file, MAX_FILENAME); + else if (!strcasecmp(rpl.name, "keyboard")) { + if (!load_kbd(rpl.value)) + set_file(rpl.value, (char *)global_settings.kbd_file, MAX_FILENAME); } #endif - /* check for scalar values, using the two tables */ pos = load_cfg_table(table[last_table], ta_size[last_table], - name, value, last_pos); + rpl.name, rpl.value, last_pos); if (pos) /* success */ { last_pos = pos; /* remember as a position hint for next round */ @@ -1622,7 +1628,7 @@ last_table = 1-last_table; /* try other table */ last_pos = 1; /* search from start */ pos = load_cfg_table(table[last_table], ta_size[last_table], - name, value, last_pos); + rpl.name, rpl.value, last_pos); if (pos) /* success */ { last_pos = pos; /* remember as a position hint for next round */ @@ -1630,7 +1636,7 @@ } } - close(fd); + close(rpl.fd); settings_apply(); settings_save(); return true; @@ -1713,13 +1719,13 @@ } } - bool settings_save_config(void) { int fd; char filename[MAX_PATH]; - create_numbered_filename(filename, ROCKBOX_DIR, "config", ".cfg", 2); + create_numbered_filename(filename, ROCKBOX_DIR, "config", ".cfg", 2 + IF_CNFN_NUM_(, NULL)); /* allow user to modify filename */ while (true) { @@ -1847,7 +1853,7 @@ global_settings.mdb_enable = sound_default(SOUND_MDB_ENABLE); global_settings.superbass = sound_default(SOUND_SUPERBASS); #endif -#ifdef HAVE_LCD_CONTRAST +#ifdef HAVE_LCD_CONTRAST global_settings.contrast = lcd_default_contrast(); #endif #ifdef HAVE_LCD_REMOTE @@ -1873,6 +1879,10 @@ global_settings.kbd_file[0] = '\0'; #endif global_settings.hold_lr_for_scroll_in_list = true; + +#if defined (HAVE_RECORDING) && CONFIG_CODEC == SWCODEC + enc_global_settings_reset(); +#endif } bool set_bool(const char* string, bool* variable ) @@ -1936,12 +1946,12 @@ void (*formatter)(char* dest, int dest_length, int variable, const char* unit); /* used for BOOL and "choice" settings */ - struct opt_items* options; + struct opt_items* options; }; - + char * value_setting_get_name_cb(int selected_item,void * data, char *buffer) { - struct value_setting_data* cb_data = + struct value_setting_data* cb_data = (struct value_setting_data*)data; if (cb_data->type == INT && !cb_data->options) { @@ -1953,14 +1963,14 @@ } else strcpy(buffer,P2STR(cb_data->options[selected_item].string)); return buffer; -} +} #define type_fromvoidptr(type, value) \ (type == INT)? \ (int)(*(int*)(value)) \ : \ (bool)(*(bool*)(value)) bool do_set_setting(const unsigned char* string, void *variable, - int nb_items,int selected, + int nb_items,int selected, struct value_setting_data *cb_data, void (*function)(int)) { @@ -1968,33 +1978,33 @@ bool done = false; struct gui_synclist lists; int oldvalue; - + if (cb_data->type == INT) oldvalue = *(int*)variable; else oldvalue = *(bool*)variable; - + gui_synclist_init(&lists,value_setting_get_name_cb,(void*)cb_data,false,1); gui_synclist_set_title(&lists, (char*)string, NOICON); gui_synclist_set_icon_callback(&lists,NULL); gui_synclist_set_nb_items(&lists,nb_items); gui_synclist_limit_scroll(&lists,true); gui_synclist_select_item(&lists, selected); - + if (global_settings.talk_menu) { if (cb_data->type == INT && !cb_data->options) talk_unit(cb_data->voice_unit, *(int*)variable); else talk_id(cb_data->options[selected].voice_id, false); } - + gui_synclist_draw(&lists); while (!done) { - - action = get_action(CONTEXT_LIST,TIMEOUT_BLOCK); + + action = get_action(CONTEXT_LIST,TIMEOUT_BLOCK); if (action == ACTION_NONE) continue; - + if (gui_synclist_do_button(&lists,action)) { if (global_settings.talk_menu) @@ -2002,23 +2012,23 @@ int value; if (cb_data->type == INT && !cb_data->options) { - value = cb_data->max - + value = cb_data->max - gui_synclist_get_sel_pos(&lists)*cb_data->step; talk_unit(cb_data->voice_unit, value); } - else + else { value = gui_synclist_get_sel_pos(&lists); talk_id(cb_data->options[value].voice_id, false); } } if (cb_data->type == INT && !cb_data->options) - *(int*)variable = cb_data->max - + *(int*)variable = cb_data->max - gui_synclist_get_sel_pos(&lists)*cb_data->step; else if (cb_data->type == BOOL) *(bool*)variable = gui_synclist_get_sel_pos(&lists) ? true : false; else *(int*)variable = gui_synclist_get_sel_pos(&lists); - } + } else if (action == ACTION_STD_CANCEL) { gui_syncsplash(HZ/2,true,str(LANG_MENU_SETTING_CANCEL)); @@ -2061,7 +2071,7 @@ The type separation is necessary since int and bool are fundamentally different and bit-incompatible types and can not share the same access - code. */ + code. */ bool set_option(const char* string, void* variable, enum optiontype type, const struct opt_items* options, int numoptions, void (*function)(int)) { Index: apps/settings.h =================================================================== RCS file: /cvsroot/rockbox/apps/settings.h,v retrieving revision 1.247 diff -u -r1.247 settings.h --- apps/settings.h 9 Oct 2006 10:54:16 -0000 1.247 +++ apps/settings.h 16 Oct 2006 23:32:31 -0000 @@ -29,6 +29,10 @@ #include "tagcache.h" #include "button.h" +#if CONFIG_CODEC == SWCODEC +#include "audio.h" +#endif + #ifdef HAVE_BACKLIGHT_BRIGHTNESS #include "backlight.h" /* for [MIN|MAX]_BRIGHTNESS_SETTING */ #endif @@ -142,20 +146,37 @@ int crossfade_fade_out_mixmode; /* Fade out mode (0=crossfade,1=mix) */ #endif +#ifdef HAVE_RECORDING +#if CONFIG_CODEC == SWCODEC + /* Encoder Settings Start - Keep these together */ + int rec_format; /* record format index + * 0=REC_FORMAT_MPA_L3 (AMFT_MPA_L3) + * 1=REC_FORMAT_WAVPACK (AMFT_WAVPACK) + * 2=REC_FORMAT_PCM_WAV (AFMT_PCM_WAV) + */ + struct mp3_enc_config mp3_enc_config; +#if 0 /* These currently contain no members but their places in line + should be held */ + struct wavpack_enc_config wavpack_enc_config; + struct wav_enc_config wav_enc_config; +#endif + /* Encoder Settings End */ +#else int rec_quality; /* 0-7 */ - int rec_source; /* 0=mic, 1=line, 2=S/PDIF */ - int rec_frequency; /* 0 = 44.1kHz +#endif /* CONFIG_CODEC == SWCODEC */ + int rec_source; /* 0=mic, 1=line, 2=S/PDIF, 2 or 3=FM Radio */ + int rec_frequency; /* 0 = 44.1kHz (depends on target) 1 = 48kHz 2 = 32kHz 3 = 22.05kHz 4 = 24kHz 5 = 16kHz */ int rec_channels; /* 0=Stereo, 1=Mono */ - int rec_mic_gain; /* 0-15 */ - int rec_left_gain; /* 0-15 */ - int rec_right_gain; /* 0-15 */ - bool rec_editable; /* true means that the bit reservoir is off */ - bool recscreen_on; /* true if using the recording screen */ + int rec_mic_gain; /* depends on target */ + int rec_left_gain; /* depends on target */ + int rec_right_gain; /* depands on target */ + bool rec_editable; /* true means that the bit reservoir is off */ + bool recscreen_on; /* true if using the recording screen */ /* note: timesplit setting is not saved */ int rec_timesplit; /* 0 = off, @@ -172,6 +193,8 @@ int rec_split_method; /* time/filesize */ int rec_prerecord_time; /* In seconds, 0-30, 0 means OFF */ + bool rec_new_file_flush; /* true means to start new files on disk as + soon as the first data is available */ int rec_directory; /* 0=base dir, 1=current dir */ bool rec_startup; /* true means start Rockbox in recording screen */ int cliplight; /* 0 = off @@ -205,6 +228,7 @@ int rec_agc_maxgain_line; /* AGC maximum line-in gain */ int rec_agc_cliptime; /* 0.2, 0.4, 0.6, 0.8, 1s */ #endif +#endif /* HAVE_RECORDING */ /* device settings */ @@ -579,7 +603,7 @@ /* argument bits for settings_load() */ #define SETTINGS_RTC 1 /* only the settings from the RTC nonvolatile RAM */ -#define SETTINGS_HD 2 /* only the settings fron the disk sector */ +#define SETTINGS_HD 2 /* only the settings from the disk sector */ #define SETTINGS_ALL 3 /* both */ /* repeat mode options */ Index: apps/sound_menu.c =================================================================== RCS file: /cvsroot/rockbox/apps/sound_menu.c,v retrieving revision 1.117 diff -u -r1.117 sound_menu.c --- apps/sound_menu.c 27 Sep 2006 21:36:49 -0000 1.117 +++ apps/sound_menu.c 16 Oct 2006 23:32:31 -0000 @@ -54,6 +54,10 @@ #include "dsp.h" #include "eq_menu.h" #include "pcmbuf.h" +#ifdef HAVE_RECORDING +#include "enc_config.h" +#endif +#include "general.h" #endif #include "action.h" @@ -323,28 +327,7 @@ n_opts, NULL ); } -/* To be removed when we add support for sample rates and channel settings */ -#if CONFIG_CODEC == SWCODEC -static bool recquality(void) -{ - static const struct opt_items names[] = { - { "MP3 64 kBit/s", TALK_ID( 64, UNIT_KBIT) }, - { "MP3 96 kBit/s", TALK_ID( 96, UNIT_KBIT) }, - { "MP3 128 kBit/s", TALK_ID( 128, UNIT_KBIT) }, - { "MP3 160 kBit/s", TALK_ID( 160, UNIT_KBIT) }, - { "MP3 192 kBit/s", TALK_ID( 192, UNIT_KBIT) }, - { "MP3 224 kBit/s", TALK_ID( 224, UNIT_KBIT) }, - { "MP3 320 kBit/s", TALK_ID( 320, UNIT_KBIT) }, - { "WV 900 kBit/s", TALK_ID( 900, UNIT_KBIT) }, - { "WAV 1411 kBit/s", TALK_ID(1411, UNIT_KBIT) } - }; - - return set_option(str(LANG_RECORDING_QUALITY), - &global_settings.rec_quality, INT, - names, sizeof (names)/sizeof(struct opt_items), - NULL ); -} -#elif CONFIG_CODEC == MAS3587F +#if CONFIG_CODEC == MAS3587F static bool recquality(void) { return set_int(str(LANG_RECORDING_QUALITY), "", UNIT_INT, @@ -359,33 +342,191 @@ } #endif /* CONFIG_CODEC == MAS3587F */ +#if CONFIG_CODEC == SWCODEC +/* Makes an options list from a source list of options and indexes */ +void make_options_from_indexes(const struct opt_items *src_names, + const long *src_indexes, + int n_indexes, + struct opt_items *dst_names) +{ + while (--n_indexes >= 0) + dst_names[n_indexes] = src_names[src_indexes[n_indexes]]; +} /* make_options_from_indexes */ + +static bool recformat(void) +{ + static const struct opt_items names[REC_NUM_FORMATS] = { + [REC_FORMAT_MPA_L3] = { STR(LANG_AFMT_MPA_L3) }, + [REC_FORMAT_WAVPACK] = { STR(LANG_AFMT_WAVPACK) }, + [REC_FORMAT_PCM_WAV] = { STR(LANG_AFMT_PCM_WAV) }, + }; + + int rec_format = global_settings.rec_format; + bool res = set_option(str(LANG_RECORDING_FORMAT), &rec_format, INT, + names, REC_NUM_FORMATS, NULL ); + + if (rec_format != global_settings.rec_format) + { + global_settings.rec_format = rec_format; + enc_global_settings_apply(); + } + + return res; +} /* recformat */ + +#endif /* CONFIG_CODEC == SWCODEC */ + static bool recfrequency(void) { - static const struct opt_items names[] = { - { "44.1kHz", TALK_ID(44, UNIT_KHZ) }, -#if CONFIG_CODEC != SWCODEC /* This is temporary */ - { "48kHz", TALK_ID(48, UNIT_KHZ) }, - { "32kHz", TALK_ID(32, UNIT_KHZ) }, - { "22.05kHz", TALK_ID(22, UNIT_KHZ) }, - { "24kHz", TALK_ID(24, UNIT_KHZ) }, - { "16kHz", TALK_ID(16, UNIT_KHZ) } -#endif +#if CONFIG_CODEC == MAS3587F + static const struct opt_items names[6] = { + { "44.1kHz", TALK_ID(44, UNIT_KHZ) }, + { "48kHz", TALK_ID(48, UNIT_KHZ) }, + { "32kHz", TALK_ID(32, UNIT_KHZ) }, + { "22.05kHz", TALK_ID(22, UNIT_KHZ) }, + { "24kHz", TALK_ID(24, UNIT_KHZ) }, + { "16kHz", TALK_ID(16, UNIT_KHZ) } }; return set_option(str(LANG_RECORDING_FREQUENCY), &global_settings.rec_frequency, INT, - names, sizeof(names)/sizeof(*names), NULL ); -} + names, 6, NULL ); +#endif /* CONFIG_CODEC == MAS3587F */ + +#if CONFIG_CODEC == SWCODEC + static const struct opt_items names[REC_NUM_FREQ] = { + REC_HAVE_96_([REC_FREQ_96] = { "96kHz", TALK_ID(96, UNIT_KHZ) },) + REC_HAVE_88_([REC_FREQ_88] = { "88.2kHz", TALK_ID(88, UNIT_KHZ) },) + REC_HAVE_64_([REC_FREQ_64] = { "64kHz", TALK_ID(64, UNIT_KHZ) },) + REC_HAVE_48_([REC_FREQ_48] = { "48kHz", TALK_ID(48, UNIT_KHZ) },) + REC_HAVE_44_([REC_FREQ_44] = { "44.1kHz", TALK_ID(44, UNIT_KHZ) },) + REC_HAVE_32_([REC_FREQ_32] = { "32kHz", TALK_ID(32, UNIT_KHZ) },) + REC_HAVE_24_([REC_FREQ_24] = { "24kHz", TALK_ID(24, UNIT_KHZ) },) + REC_HAVE_22_([REC_FREQ_22] = { "22.05kHz", TALK_ID(22, UNIT_KHZ) },) + REC_HAVE_16_([REC_FREQ_16] = { "16kHz", TALK_ID(16, UNIT_KHZ) },) + REC_HAVE_12_([REC_FREQ_12] = { "12kHz", TALK_ID(12, UNIT_KHZ) },) + REC_HAVE_11_([REC_FREQ_11] = { "11.025kHz", TALK_ID(11, UNIT_KHZ) },) + REC_HAVE_8_( [REC_FREQ_8 ] = { "8kHz", TALK_ID( 8, UNIT_KHZ) },) + }; + + struct opt_items opts[REC_NUM_FREQ]; + unsigned long table[REC_NUM_FREQ]; + int n_opts; + int rec_frequency; + bool ret; + +#ifdef HAVE_SPDIF_IN + if (global_settings.rec_source == AUDIO_SRC_SPDIF) + { + /* Inform user that frequency follows the source's frequency */ + opts[0].string = ID2P(LANG_SOURCE_FREQUENCY); + opts[0].voice_id = LANG_SOURCE_FREQUENCY; + n_opts = 1; + rec_frequency = 0; + } + else +#endif + { + struct encoder_caps caps; + struct encoder_config cfg; + + cfg.rec_format = global_settings.rec_format; + global_to_encoder_config(&cfg); + + if (!enc_get_caps(&cfg, &caps, true)) + return false; + + /* Construct samplerate menu based upon encoder settings */ + n_opts = make_list_from_caps32(REC_SAMPR_CAPS, NULL, + caps.samplerate_caps, table); + + if (n_opts == 0) + return false; /* No common flags...?? */ + + make_options_from_indexes(names, table, n_opts, opts); + + /* Find closest rate that the potentially restricted list + comes to */ + make_list_from_caps32(REC_SAMPR_CAPS, rec_freq_sampr, + caps.samplerate_caps, table); + + rec_frequency = round_value_to_list32( + rec_freq_sampr[global_settings.rec_frequency], + table, n_opts, false); + } + + ret = set_option(str(LANG_RECORDING_FREQUENCY), + &rec_frequency, INT, opts, n_opts, NULL ); + + if (!ret +#ifdef HAVE_SPDIF_IN + && global_settings.rec_source != AUDIO_SRC_SPDIF +#endif + ) + { + /* Translate back to full index */ + global_settings.rec_frequency = + round_value_to_list32(table[rec_frequency], + rec_freq_sampr, + REC_NUM_FREQ, + false); + } + + return ret; +#endif /* CONFIG_CODEC == SWCODEC */ +} /* recfrequency */ static bool recchannels(void) { - static const struct opt_items names[] = { - { STR(LANG_CHANNEL_STEREO) }, - { STR(LANG_CHANNEL_MONO) } + static const struct opt_items names[CHN_NUM_MODES] = { + [CHN_MODE_STEREO] = { STR(LANG_CHANNEL_STEREO) }, + [CHN_MODE_MONO] = { STR(LANG_CHANNEL_MONO) } }; +#if CONFIG_CODEC == MAS3587F return set_option(str(LANG_RECORDING_CHANNELS), &global_settings.rec_channels, INT, - names, 2, NULL ); + names, CHN_NUM_MODES, NULL ); +#endif /* CONFIG_CODEC == MAS3587F */ + +#if CONFIG_CODEC == SWCODEC + struct opt_items opts[CHN_NUM_MODES]; + long table[CHN_NUM_MODES]; + struct encoder_caps caps; + struct encoder_config cfg; + int n_opts; + int rec_channels; + bool ret; + + cfg.rec_format = global_settings.rec_format; + global_to_encoder_config(&cfg); + + if (!enc_get_caps(&cfg, &caps, true)) + return false; + + n_opts = make_list_from_caps32(CHN_CAP_ALL, NULL, + caps.channel_caps, table); + + rec_channels = round_value_to_list32(global_settings.rec_channels, + table, n_opts, false); + + make_options_from_indexes(names, table, n_opts, opts); + + ret = set_option(str(LANG_RECORDING_CHANNELS), &rec_channels, + INT, opts, n_opts, NULL ); + + if (!ret) + global_settings.rec_channels = table[rec_channels]; + + return ret; +#endif /* CONFIG_CODEC == SWCODEC */ +} + +#if CONFIG_CODEC == SWCODEC +static bool recnewfileflush(void) +{ + return set_bool(str(LANG_RECORD_NEW_FILE_FLUSH), + &global_settings.rec_new_file_flush); } +#endif static bool rectimesplit(void) { @@ -1042,58 +1183,62 @@ action_signalscreenchange(); return retval; } -#endif +#endif /* !defined(SIMULATOR) && CONFIG_CODEC == MAS3587F */ bool recording_menu(bool no_source) { - int m; - int i = 0; - struct menu_item items[13]; - bool result; - -#if CONFIG_CODEC == MAS3587F || CONFIG_CODEC == SWCODEC - items[i].desc = ID2P(LANG_RECORDING_QUALITY); - items[i++].function = recquality; -#endif - items[i].desc = ID2P(LANG_RECORDING_FREQUENCY); - items[i++].function = recfrequency; - if(!no_source) { - items[i].desc = ID2P(LANG_RECORDING_SOURCE); - items[i++].function = recsource; - } - items[i].desc = ID2P(LANG_RECORDING_CHANNELS); - items[i++].function = recchannels; + static const struct menu_item static_items[] = { +#if CONFIG_CODEC == MAS3587F + { ID2P(LANG_RECORDING_QUALITY), recquality }, +#endif +#if CONFIG_CODEC == SWCODEC + { ID2P(LANG_RECORDING_FORMAT), recformat }, + { ID2P(LANG_ENCODER_SETTINGS), enc_global_config_menu }, +#endif + { ID2P(LANG_RECORDING_FREQUENCY), recfrequency }, + { ID2P(LANG_RECORDING_SOURCE), recsource }, /* not shown if no_source */ + { ID2P(LANG_RECORDING_CHANNELS), recchannels }, #if CONFIG_CODEC == MAS3587F - items[i].desc = ID2P(LANG_RECORDING_EDITABLE); - items[i++].function = receditable; + { ID2P(LANG_RECORDING_EDITABLE), receditable }, #endif - items[i].desc = ID2P(LANG_RECORD_TIMESPLIT); - items[i++].function = filesplitoptionsmenu; - items[i].desc = ID2P(LANG_RECORD_PRERECORD_TIME); - items[i++].function = recprerecord; - items[i].desc = ID2P(LANG_RECORD_DIRECTORY); - items[i++].function = recdirectory; - items[i].desc = ID2P(LANG_RECORD_STARTUP); - items[i++].function = reconstartup; + { ID2P(LANG_RECORD_TIMESPLIT), filesplitoptionsmenu }, + { ID2P(LANG_RECORD_PRERECORD_TIME), recprerecord }, +#if CONFIG_CODEC == SWCODEC + { ID2P(LANG_RECORD_NEW_FILE_FLUSH), recnewfileflush }, +#endif + { ID2P(LANG_RECORD_DIRECTORY), recdirectory }, + { ID2P(LANG_RECORD_STARTUP), reconstartup }, #ifdef CONFIG_BACKLIGHT - items[i].desc = ID2P(LANG_CLIP_LIGHT); - items[i++].function = cliplight; + { ID2P(LANG_CLIP_LIGHT), cliplight }, #endif #if !defined(SIMULATOR) && CONFIG_CODEC == MAS3587F - items[i].desc = ID2P(LANG_RECORD_TRIGGER); - items[i++].function = rectrigger; + { ID2P(LANG_RECORD_TRIGGER), rectrigger }, #endif #ifdef HAVE_AGC - items[i].desc = ID2P(LANG_RECORD_AGC_PRESET); - items[i++].function = agc_preset; - items[i].desc = ID2P(LANG_RECORD_AGC_CLIPTIME); - items[i++].function = agc_cliptime; + { ID2P(LANG_RECORD_AGC_PRESET), agc_preset }, + { ID2P(LANG_RECORD_AGC_CLIPTIME), agc_cliptime }, #endif + }; - m=menu_init( items, i, NULL, NULL, NULL, NULL); + struct menu_item items[ARRAYLEN(static_items)]; + int i, n_items; + int m; + + bool result; + + for (i = 0, n_items = 0; i < (int)ARRAYLEN(items); i++) + { + const struct menu_item *mi = &static_items[i]; + if (no_source && mi->function == recsource) + continue; + items[n_items++] = *mi; + } + + m = menu_init(items, n_items, NULL, NULL, NULL, NULL); result = menu_run(m); menu_exit(m); return result; -} -#endif +} /* recording_menu */ + +#endif /* HAVE_RECORDING */ Index: apps/status.c =================================================================== RCS file: /cvsroot/rockbox/apps/status.c,v retrieving revision 1.86 diff -u -r1.86 status.c --- apps/status.c 28 Aug 2006 22:38:39 -0000 1.86 +++ apps/status.c 16 Oct 2006 23:32:32 -0000 @@ -46,7 +46,7 @@ #ifdef CONFIG_TUNER #include "radio.h" #endif -#if CONFIG_CODEC == SWCODEC +#if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC #include "pcm_record.h" #endif @@ -87,10 +87,6 @@ } #ifdef HAVE_RECORDING -#if CONFIG_CODEC == SWCODEC - audio_stat = pcm_rec_status(); -#endif - if(audio_stat & AUDIO_STATUS_RECORD) { if(audio_stat & AUDIO_STATUS_PAUSE) Index: apps/tree.c =================================================================== RCS file: /cvsroot/rockbox/apps/tree.c,v retrieving revision 1.449 diff -u -r1.449 tree.c --- apps/tree.c 5 Oct 2006 10:07:02 -0000 1.449 +++ apps/tree.c 16 Oct 2006 23:32:32 -0000 @@ -58,7 +58,9 @@ #include "misc.h" #include "filetree.h" #include "tagtree.h" +#ifdef HAVE_RECORDING #include "recorder/recording.h" +#endif #include "rtc.h" #include "dircache.h" #include "tagcache.h" Index: apps/codecs/mp3_enc.c =================================================================== RCS file: /cvsroot/rockbox/apps/codecs/mp3_enc.c,v retrieving revision 1.3 diff -u -r1.3 mp3_enc.c --- apps/codecs/mp3_enc.c 9 Sep 2006 01:35:12 -0000 1.3 +++ apps/codecs/mp3_enc.c 16 Oct 2006 23:32:35 -0000 @@ -32,9 +32,26 @@ #ifndef SIMULATOR +#include #include "codeclib.h" -CODEC_HEADER +CODEC_ENC_HEADER + +#define ENC_PADDING_FRAMES1 2 +#define ENC_PADDING_FRAMES2 4 +#define ENC_DELAY_SAMP 576 +#define ENC_DELAY_SIZE (ENC_DELAY_SAMP*4) +#define SAMP_PER_FRAME1 1152 +#define SAMP_PER_FRAME2 576 +#define PCM_CHUNK_SIZE1 (SAMP_PER_FRAME1*4) +#define PCM_CHUNK_SIZE2 (SAMP_PER_FRAME2*4) +#define SAMPL2 576 +#define SBLIMIT 32 +#define HTN 16 +#define memcpy ci->memcpy +#define memset ci->memset +#define putlong(c, s) if(s+sz <= 32) { cc = (cc << s) | c; sz+= s; } \ + else { putbits(cc, sz); cc = c; sz = s; } #ifdef USE_IRAM extern char iramcopy[]; @@ -44,25 +61,8 @@ extern char iend[]; #endif - -#define SAMP_PER_FRAME 1152 -#define SAMPL2 576 -#define SBLIMIT 32 -#define HTN 16 -#define memcpy ci->memcpy -#define memset ci->memset -#define putlong(c, s) if(s+sz <= 32) { cc = (cc << s) | c; sz+= s; } \ - else { putbits(cc, sz); cc = c; sz = s; } - -enum e_byte_order { order_unknown, order_bigEndian, order_littleEndian }; - -typedef unsigned long uint32; -typedef unsigned short uint16; -typedef unsigned char uint8; - - typedef struct { - int type; /* 0=(22.05,24,16kHz) 1=(44.1,48,32kHz) */ + int type; /* 0=(MPEG2 - 22.05,24,16kHz) 1=(MPEG1 - 44.1,48,32kHz) */ int mode; /* 0=stereo, 1=jstereo, 2=dual, 3=mono */ int bitrate; int padding; @@ -73,21 +73,20 @@ /* Side information */ typedef struct { - uint32 part2_3_length; - int count1; /* number of 0-1-quadruples */ - uint32 global_gain; - uint32 table_select[4]; - uint32 region_0_1; - uint32 address1; - uint32 address2; - uint32 address3; - long quantStep; - long additStep; - long max_val; + uint32_t part2_3_length; + int count1; /* number of 0-1-quadruples */ + uint32_t global_gain; + uint32_t table_select[4]; + uint32_t region_0_1; + uint32_t address1; + uint32_t address2; + uint32_t address3; + long quantStep; + long additStep; + long max_val; } side_info_t; typedef struct { - enum e_byte_order byte_order; side_info_t cod_info[2][2]; mpeg_t mpg; long frac_per_frame; @@ -98,19 +97,18 @@ int ResvSize; int channels; int granules; - int resample; long samplerate; } config_t; typedef struct { - int bitpos; /* current bitpos for writing */ - uint32 bbuf[263]; + int bitpos; /* current bitpos for writing */ + uint32_t bbuf[263]; } BF_Data; struct huffcodetab { - int len; /* max. index */ - const uint8 *table; /* pointer to array[len][len] */ - const uint8 *hlen; /* pointer to array[len][len] */ + int len; /* max. index */ + const uint8_t *table; /* pointer to array[len][len] */ + const uint8_t *hlen; /* pointer to array[len][len] */ }; struct huffcodebig { @@ -127,102 +125,105 @@ #define shft_n(x,n) ((x) >> n) #define SQRT 724 /* sqrt(2) * 512 */ -short mfbuf [2*(1152+512)] IBSS_ATTR; /* 3328 Bytes */ -int sb_data [2][2][18][SBLIMIT] IBSS_ATTR; /* 13824 Bytes */ -int mdct_freq [SAMPL2] IBSS_ATTR; /* 9216 Bytes */ -short enc_data [SAMPL2] IBSS_ATTR; /* 4608 Bytes */ -uint32 scalefac [23] IBSS_ATTR; /* 92 Bytes */ -BF_Data CodedData IBSS_ATTR; /* 1056 Bytes */ -int ca [8] IBSS_ATTR; /* 32 Bytes */ -int cs [8] IBSS_ATTR; /* 32 Bytes */ -int cx [9] IBSS_ATTR; /* 36 Bytes */ -int win [18][4] IBSS_ATTR; /* 288 Bytes */ -short enwindow [15*27+24] IBSS_ATTR; /* 862 Bytes */ -short int2idx [4096] IBSS_ATTR; /* 8192 Bytes */ -uint8 ht_count [2][2][16] IBSS_ATTR; /* 64 Bytes */ -uint32 tab01 [ 16] IBSS_ATTR; /* 64 Bytes */ -uint32 tab23 [ 9] IBSS_ATTR; /* 36 Bytes */ -uint32 tab56 [ 16] IBSS_ATTR; /* 64 Bytes */ -uint32 tab1315 [256] IBSS_ATTR; /* 1024 Bytes */ -uint32 tab1624 [256] IBSS_ATTR; /* 1024 Bytes */ -uint32 tab789 [ 36] IBSS_ATTR; /* 144 Bytes */ -uint32 tabABC [ 64] IBSS_ATTR; /* 256 Bytes */ -uint8 t1HB [ 4] IBSS_ATTR; -uint8 t2HB [ 9] IBSS_ATTR; -uint8 t3HB [ 9] IBSS_ATTR; -uint8 t5HB [ 16] IBSS_ATTR; -uint8 t6HB [ 16] IBSS_ATTR; -uint8 t7HB [ 36] IBSS_ATTR; -uint8 t8HB [ 36] IBSS_ATTR; -uint8 t9HB [ 36] IBSS_ATTR; -uint8 t10HB [ 64] IBSS_ATTR; -uint8 t11HB [ 64] IBSS_ATTR; -uint8 t12HB [ 64] IBSS_ATTR; -uint8 t13HB [256] IBSS_ATTR; -uint8 t15HB [256] IBSS_ATTR; -uint16 t16HB [256] IBSS_ATTR; -uint16 t24HB [256] IBSS_ATTR; -uint8 t1l [ 8] IBSS_ATTR; -uint8 t2l [ 9] IBSS_ATTR; -uint8 t3l [ 9] IBSS_ATTR; -uint8 t5l [ 16] IBSS_ATTR; -uint8 t6l [ 16] IBSS_ATTR; -uint8 t7l [ 36] IBSS_ATTR; -uint8 t8l [ 36] IBSS_ATTR; -uint8 t9l [ 36] IBSS_ATTR; -uint8 t10l [ 64] IBSS_ATTR; -uint8 t11l [ 64] IBSS_ATTR; -uint8 t12l [ 64] IBSS_ATTR; -uint8 t13l [256] IBSS_ATTR; -uint8 t15l [256] IBSS_ATTR; -uint8 t16l [256] IBSS_ATTR; -uint8 t24l [256] IBSS_ATTR; -struct huffcodetab ht [HTN] IBSS_ATTR; +static short mfbuf [2*(1152+512)] IBSS_ATTR; /* 3328 Bytes */ +static int sb_data [2][2][18][SBLIMIT] IBSS_ATTR; /* 13824 Bytes */ +static int mdct_freq [SAMPL2] IBSS_ATTR; /* 9216 Bytes */ +static short enc_data [SAMPL2] IBSS_ATTR; /* 4608 Bytes */ +static uint32_t scalefac [23] IBSS_ATTR; /* 92 Bytes */ +static BF_Data CodedData IBSS_ATTR; /* 1056 Bytes */ +static int ca [8] IBSS_ATTR; /* 32 Bytes */ +static int cs [8] IBSS_ATTR; /* 32 Bytes */ +static int cx [9] IBSS_ATTR; /* 36 Bytes */ +static int win [18][4] IBSS_ATTR; /* 288 Bytes */ +static short enwindow [15*27+24] IBSS_ATTR; /* 862 Bytes */ +static short int2idx [4096] IBSS_ATTR; /* 8192 Bytes */ +static uint8_t ht_count [2][2][16] IBSS_ATTR; /* 64 Bytes */ +static uint32_t tab01 [ 16] IBSS_ATTR; /* 64 Bytes */ +static uint32_t tab23 [ 9] IBSS_ATTR; /* 36 Bytes */ +static uint32_t tab56 [ 16] IBSS_ATTR; /* 64 Bytes */ +static uint32_t tab1315 [256] IBSS_ATTR; /* 1024 Bytes */ +static uint32_t tab1624 [256] IBSS_ATTR; /* 1024 Bytes */ +static uint32_t tab789 [ 36] IBSS_ATTR; /* 144 Bytes */ +static uint32_t tabABC [ 64] IBSS_ATTR; /* 256 Bytes */ +static uint8_t t1HB [ 4] IBSS_ATTR; +static uint8_t t2HB [ 9] IBSS_ATTR; +static uint8_t t3HB [ 9] IBSS_ATTR; +static uint8_t t5HB [ 16] IBSS_ATTR; +static uint8_t t6HB [ 16] IBSS_ATTR; +static uint8_t t7HB [ 36] IBSS_ATTR; +static uint8_t t8HB [ 36] IBSS_ATTR; +static uint8_t t9HB [ 36] IBSS_ATTR; +static uint8_t t10HB [ 64] IBSS_ATTR; +static uint8_t t11HB [ 64] IBSS_ATTR; +static uint8_t t12HB [ 64] IBSS_ATTR; +static uint8_t t13HB [256] IBSS_ATTR; +static uint8_t t15HB [256] IBSS_ATTR; +static uint16_t t16HB [256] IBSS_ATTR; +static uint16_t t24HB [256] IBSS_ATTR; +static uint8_t t1l [ 8] IBSS_ATTR; +static uint8_t t2l [ 9] IBSS_ATTR; +static uint8_t t3l [ 9] IBSS_ATTR; +static uint8_t t5l [ 16] IBSS_ATTR; +static uint8_t t6l [ 16] IBSS_ATTR; +static uint8_t t7l [ 36] IBSS_ATTR; +static uint8_t t8l [ 36] IBSS_ATTR; +static uint8_t t9l [ 36] IBSS_ATTR; +static uint8_t t10l [ 64] IBSS_ATTR; +static uint8_t t11l [ 64] IBSS_ATTR; +static uint8_t t12l [ 64] IBSS_ATTR; +static uint8_t t13l [256] IBSS_ATTR; +static uint8_t t15l [256] IBSS_ATTR; +static uint8_t t16l [256] IBSS_ATTR; +static uint8_t t24l [256] IBSS_ATTR; +static struct huffcodetab ht [HTN] IBSS_ATTR; + +static unsigned pcm_chunk_size IBSS_ATTR; +static unsigned samp_per_frame IBSS_ATTR; -static config_t cfg; +static config_t cfg IBSS_ATTR; static struct codec_api *ci; -static int enc_channels; +static char *res_buffer; -static const uint8 ht_count_const[2][2][16] = +static const uint8_t ht_count_const[2][2][16] = { { { 1, 5, 4, 5, 6, 5, 4, 4, 7, 3, 6, 0, 7, 2, 3, 1 }, /* table0 */ { 1, 5, 5, 7, 5, 8, 7, 9, 5, 7, 7, 9, 7, 9, 9,10 } }, /* hleng0 */ { {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, /* table1 */ { 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 } } }; /* hleng1 */ -static const uint8 t1HB_const[4] = {1,1,1,0}; -static const uint8 t2HB_const[9] = {1,2,1,3,1,1,3,2,0}; -static const uint8 t3HB_const[9] = {3,2,1,1,1,1,3,2,0}; -static const uint8 t5HB_const[16] = {1,2,6,5,3,1,4,4,7,5,7,1,6,1,1,0}; -static const uint8 t6HB_const[16] = {7,3,5,1,6,2,3,2,5,4,4,1,3,3,2,0}; +static const uint8_t t1HB_const[4] = {1,1,1,0}; +static const uint8_t t2HB_const[9] = {1,2,1,3,1,1,3,2,0}; +static const uint8_t t3HB_const[9] = {3,2,1,1,1,1,3,2,0}; +static const uint8_t t5HB_const[16] = {1,2,6,5,3,1,4,4,7,5,7,1,6,1,1,0}; +static const uint8_t t6HB_const[16] = {7,3,5,1,6,2,3,2,5,4,4,1,3,3,2,0}; -static const uint8 t7HB_const[36] = +static const uint8_t t7HB_const[36] = { 1, 2,10,19,16,10, 3, 3, 7,10, 5, 3,11, 4,13,17, 8, 4, 12,11,18,15,11, 2, 7, 6, 9,14, 3, 1, 6, 4, 5, 3, 2, 0 }; -static const uint8 t8HB_const[36] = +static const uint8_t t8HB_const[36] = { 3, 4, 6,18,12, 5, 5, 1, 2,16, 9, 3, 7, 3, 5,14, 7, 3, 19,17,15,13,10, 4,13, 5, 8,11, 5, 1,12, 4, 4, 1, 1, 0 }; -static const uint8 t9HB_const[36] = +static const uint8_t t9HB_const[36] = { 7, 5, 9,14,15, 7, 6, 4, 5, 5, 6, 7, 7, 6, 8, 8, 8, 5, 15, 6, 9,10, 5, 1,11, 7, 9, 6, 4, 1,14, 4, 6, 2, 6, 0 }; -static const uint8 t10HB_const[64] = +static const uint8_t t10HB_const[64] = {1,2,10,23,35,30,12,17,3,3,8,12,18,21,12,7,11,9,15,21,32, 40,19,6,14,13,22,34,46,23,18,7,20,19,33,47,27,22,9,3,31,22, 41,26,21,20,5,3,14,13,10,11,16,6,5,1,9,8,7,8,4,4,2,0 }; -static const uint8 t11HB_const[64] = +static const uint8_t t11HB_const[64] = {3,4,10,24,34,33,21,15,5,3,4,10,32,17,11,10,11,7,13,18,30, 31,20,5,25,11,19,59,27,18,12,5,35,33,31,58,30,16,7,5,28,26, 32,19,17,15,8,14,14,12,9,13,14,9,4,1,11,4,6,6,6,3,2,0 }; -static const uint8 t12HB_const[64] = +static const uint8_t t12HB_const[64] = {9,6,16,33,41,39,38,26,7,5,6,9,23,16,26,11,17,7,11,14,21, 30,10,7,17,10,15,12,18,28,14,5,32,13,22,19,18,16,9,5,40,17, 31,29,17,13,4,2,27,12,11,15,10,7,4,1,27,12,8,12,6,3,1,0 }; -static const uint8 t13HB_const[256] = +static const uint8_t t13HB_const[256] = {1,5,14,21,34,51,46,71,42,52,68,52,67,44,43,19,3,4,12,19,31,26,44,33,31,24,32, 24,31,35,22,14,15,13,23,36,59,49,77,65,29,40,30,40,27,33,42,16,22,20,37,61,56, 79,73,64,43,76,56,37,26,31,25,14,35,16,60,57,97,75,114,91,54,73,55,41,48,53, @@ -234,7 +235,7 @@ 45,21,34,64,56,50,49,45,31,19,12,15,10,7,6,3,48,23,20,39,36,35,53,21,16,23,13, 10,6,1,4,2,16,15,17,27,25,20,29,11,17,12,16,8,1,1,0,1 }; -static const uint8 t15HB_const[256] = +static const uint8_t t15HB_const[256] = {7,12,18,53,47,76,124,108,89,123,108,119,107,81,122,63,13,5,16,27,46,36,61,51, 42,70,52,83,65,41,59,36,19,17,15,24,41,34,59,48,40,64,50,78,62,80,56,33,29,28, 25,43,39,63,55,93,76,59,93,72,54,75,50,29,52,22,42,40,67,57,95,79,72,57,89,69, @@ -246,7 +247,7 @@ 24,16,22,13,14,7,91,44,39,38,34,63,52,45,31,52,28,19,14,8,9,3,123,60,58,53,47, 43,32,22,37,24,17,12,15,10,2,1,71,37,34,30,28,20,17,26,21,16,10,6,8,6,2,0}; -static const uint16 t16HB_const[256] = +static const uint16_t t16HB_const[256] = {1,5,14,44,74,63,110,93,172,149,138,242,225,195,376,17,3,4,12,20,35,62,53,47, 83,75,68,119,201,107,207,9,15,13,23,38,67,58,103,90,161,72,127,117,110,209, 206,16,45,21,39,69,64,114,99,87,158,140,252,212,199,387,365,26,75,36,68,65, @@ -261,7 +262,7 @@ 358,711,709,866,1734,871,3458,870,434,0,12,10,7,11,10,17,11,9,13,12,10,7,5,3, 1,3}; -static const uint16 t24HB_const[256] = +static const uint16_t t24HB_const[256] = {15,13,46,80,146,262,248,434,426,669,653,649,621,517,1032,88,14,12,21,38,71, 130,122,216,209,198,327,345,319,297,279,42,47,22,41,74,68,128,120,221,207,194, 182,340,315,295,541,18,81,39,75,70,134,125,116,220,204,190,178,325,311,293, @@ -276,7 +277,7 @@ 374,369,365,361,357,2,1033,280,278,274,267,264,259,382,378,372,367,363,360, 358,356,0,43,20,19,17,15,13,11,9,7,6,4,7,5,3,1,3}; -static const uint32 tab1315_const[256] = +static const uint32_t tab1315_const[256] = { 0x010003,0x050005,0x070006,0x080008,0x090008,0x0a0009,0x0a000a,0x0b000a, 0x0a000a,0x0b000b,0x0c000b,0x0c000c,0x0d000c,0x0d000c,0x0e000d,0x0e000e, 0x040005,0x060005,0x080007,0x090008,0x0a0009,0x0a0009,0x0b000a,0x0b000a, @@ -310,18 +311,18 @@ 0x0d000d,0x0e000d,0x0f000d,0x10000d,0x10000d,0x10000d,0x11000d,0x10000e, 0x11000e,0x11000e,0x12000e,0x12000e,0x15000f,0x14000f,0x15000f,0x12000f }; -static const uint32 tab01_const[16] = +static const uint32_t tab01_const[16] = { 0x10004,0x50005,0x50005,0x70006,0x50005,0x80006,0x70006,0x90007, 0x50005,0x70006,0x70006,0x90007,0x70006,0x90007,0x90007,0xa0008 }; -static const uint32 tab23_const[ 9] = +static const uint32_t tab23_const[ 9] = { 0x10002,0x40003,0x70007,0x40004,0x50004,0x70007,0x60006,0x70007,0x80008 }; -static const uint32 tab56_const[16] = +static const uint32_t tab56_const[16] = { 0x10003,0x40004,0x70006,0x80008,0x40004,0x50004,0x80006,0x90007, 0x70005,0x80006,0x90007,0xa0008,0x80007,0x80007,0x90008,0xa0009 }; -static const uint32 tab789_const[36] = +static const uint32_t tab789_const[36] = {0x00100803,0x00401004,0x00701c06,0x00902407,0x00902409,0x00a0280a,0x00401004, 0x00601005,0x00801806,0x00902807,0x00902808,0x00a0280a,0x00701c05,0x00701806, 0x00902007,0x00a02808,0x00a02809,0x00b02c0a,0x00802407,0x00902807,0x00a02808, @@ -329,7 +330,7 @@ 0x00b0300a,0x00c0300b,0x00902809,0x00a02809,0x00b02c0a,0x00c02c0a,0x00c0340b, 0x00c0340b}; -static const uint32 tabABC_const[64] = +static const uint32_t tabABC_const[64] = {0x00100804,0x00401004,0x00701806,0x00902008,0x00a02409,0x00a0280a,0x00a0240a, 0x00b0280a,0x00401004,0x00601405,0x00801806,0x00902007,0x00a02809,0x00b02809, 0x00a0240a,0x00a0280a,0x00701806,0x00801c06,0x00902007,0x00a02408,0x00b02809, @@ -341,7 +342,7 @@ 0x00a0240a,0x00a0240a,0x00b0280a,0x00c02c0b,0x00c0300b,0x00d0300b,0x00d0300b, 0x00d0300c}; -static const uint32 tab1624_const[256] = +static const uint32_t tab1624_const[256] = {0x00010004,0x00050005,0x00070007,0x00090008,0x000a0009,0x000a000a,0x000b000a, 0x000b000b,0x000c000b,0x000c000c,0x000c000c,0x000d000c,0x000d000c,0x000d000c, 0x000e000d,0x000a000a,0x00040005,0x00060006,0x00080007,0x00090008,0x000a0009, @@ -380,34 +381,34 @@ 0x000c0009,0x000c0009,0x000c0009,0x000d0009,0x000d0009,0x000d0009,0x000d000a, 0x000d000a,0x000d000a,0x000d000a,0x000a0006}; -static const uint8 t1l_const[8] = {1,3,2,3,1,4,3,5}; -static const uint8 t2l_const[9] = {1,3,6,3,3,5,5,5,6}; -static const uint8 t3l_const[9] = {2,2,6,3,2,5,5,5,6}; -static const uint8 t5l_const[16] = {1,3,6,7,3,3,6,7,6,6,7,8,7,6,7,8}; -static const uint8 t6l_const[16] = {3,3,5,7,3,2,4,5,4,4,5,6,6,5,6,7}; +static const uint8_t t1l_const[8] = {1,3,2,3,1,4,3,5}; +static const uint8_t t2l_const[9] = {1,3,6,3,3,5,5,5,6}; +static const uint8_t t3l_const[9] = {2,2,6,3,2,5,5,5,6}; +static const uint8_t t5l_const[16] = {1,3,6,7,3,3,6,7,6,6,7,8,7,6,7,8}; +static const uint8_t t6l_const[16] = {3,3,5,7,3,2,4,5,4,4,5,6,6,5,6,7}; -static const uint8 t7l_const[36] = +static const uint8_t t7l_const[36] = {1,3,6,8,8,9,3,4,6,7,7,8,6,5,7,8,8,9,7,7,8,9,9,9,7,7,8,9,9,10,8,8,9,10,10,10}; -static const uint8 t8l_const[36] = +static const uint8_t t8l_const[36] = {2,3,6,8,8,9,3,2,4,8,8,8,6,4,6,8,8,9,8,8,8,9,9,10,8,7,8,9,10,10,9,8,9,9,11,11}; -static const uint8 t9l_const[36] = +static const uint8_t t9l_const[36] = {3,3,5,6,8,9,3,3,4,5,6,8,4,4,5,6,7,8,6,5,6,7,7,8,7,6,7,7,8,9,8,7,8,8,9,9}; -static const uint8 t10l_const[64] = +static const uint8_t t10l_const[64] = {1,3,6,8,9,9,9,10,3,4,6,7,8,9,8,8,6,6,7,8,9,10,9,9,7,7,8,9,10,10,9,10,8,8,9,10, 10,10,10,10,9,9,10,10,11,11,10,11,8,8,9,10,10,10,11,11,9,8,9,10,10,11,11,11}; -static const uint8 t11l_const[64] = +static const uint8_t t11l_const[64] = {2,3,5,7,8,9,8,9,3,3,4,6,8,8,7,8,5,5,6,7,8,9,8,8,7,6,7,9,8,10,8,9,8,8,8,9,9,10, 9,10,8,8,9,10,10,11,10,11,8,7,7,8,9,10,10,10,8,7,8,9,10,10,10,10}; -static const uint8 t12l_const[64] = +static const uint8_t t12l_const[64] = {4,3,5,7,8,9,9,9,3,3,4,5,7,7,8,8,5,4,5,6,7,8,7,8,6,5,6,6,7,8,8,8,7,6,7,7,8, 8,8,9,8,7,8,8,8,9,8,9,8,7,7,8,8,9,9,10,9,8,8,9,9,9,9,10}; -static const uint8 t13l_const[256] = +static const uint8_t t13l_const[256] = {1,4,6,7,8,9,9,10,9,10,11,11,12,12,13,13,3,4,6,7,8,8,9,9,9,9,10,10,11,12,12,12, 6,6,7,8,9,9,10,10,9,10,10,11,11,12,13,13,7,7,8,9,9,10,10,10,10,11,11,11,11,12, 13,13,8,7,9,9,10,10,11,11,10,11,11,12,12,13,13,14,9,8,9,10,10,10,11,11,11,11, @@ -419,7 +420,7 @@ 16,16,13,12,12,13,13,13,15,14,14,17,15,15,15,17,16,16,12,12,13,14,14,14,15,14, 15,15,16,16,19,18,19,16}; -static const uint8 t15l_const[256] = +static const uint8_t t15l_const[256] = {3,4,5,7,7,8,9,9,9,10,10,11,11,11,12,13,4,3,5,6,7,7,8,8,8,9,9,10,10,10,11,11,5, 5,5,6,7,7,8,8,8,9,9,10,10,11,11,11,6,6,6,7,7,8,8,9,9,9,10,10,10,11,11,11,7,6, 7,7,8,8,9,9,9,9,10,10,10,11,11,11,8,7,7,8,8,8,9,9,9,9,10,10,11,11,11,12,9,7,8, @@ -430,7 +431,7 @@ 11,11,11,11,12,12,12,12,12,13,13,12,11,11,11,11,11,11,11,12,12,12,12,13,13,12, 13,12,11,11,11,11,11,11,12,12,12,12,12,13,13,13,13}; -static const uint8 t16l_const[256] = +static const uint8_t t16l_const[256] = {1,4,6,8,9,9,10,10,11,11,11,12,12,12,13,9,3,4,6,7,8,9,9,9,10,10,10,11,12,11,12, 8,6,6,7,8,9,9,10,10,11,10,11,11,11,12,12,9,8,7,8,9,9,10,10,10,11,11,12,12,12, 13,13,10,9,8,9,9,10,10,11,11,11,12,12,12,13,13,13,9,9,8,9,9,10,11,11,12,11,12, @@ -442,7 +443,7 @@ 17,15,11,13,13,11,12,14,14,13,14,14,15,16,15,17,15,14,11,9,8,8,9,9,10,10,10, 11,11,11,11,11,11,11,8}; -static const uint8 t24l_const[256] = +static const uint8_t t24l_const[256] = {4,4,6,7,8,9,9,10,10,11,11,11,11,11,12,9,4,4,5,6,7,8,8,9,9,9,10,10,10,10,10,8, 6,5,6,7,7,8,8,9,9,9,9,10,10,10,11,7,7,6,7,7,8,8,8,9,9,9,9,10,10,10,10,7,8,7,7, 8,8,8,8,9,9,9,10,10,10,10,11,7,9,7,8,8,8,8,9,9,9,9,10,10,10,10,10,7,9,8,8,8,8, @@ -491,8 +492,8 @@ static const struct { - uint32 region0_cnt; - uint32 region1_cnt; + uint32_t region0_cnt; + uint32_t region1_cnt; } subdv_table[23] = { {0, 0}, /* 0 bands */ {0, 0}, /* 1 bands */ @@ -519,7 +520,7 @@ {6, 7}, /* 22 bands */ }; -static const uint32 sfBand[6][23] = +static const uint32_t sfBand[6][23] = { /* Table B.2.b: 22.05 kHz */ {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, @@ -747,9 +748,13 @@ { 0, 1, 16, 17, 8, 9, 24, 25, 4, 5, 20, 21, 12, 13, 28, 29, 2, 3, 18, 19,10,11, 26, 27, 6, 7, 22, 23, 14, 15, 30, 31 }; -static const int bitr_index[2][15] = -{ {0, 8,16,24,32,40,48,56, 64, 80, 96,112,128,144,160}, - {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320} }; +static const long sampr_index[2][3] = +{ { 22050, 24000, 16000 }, /* MPEG 2 */ + { 44100, 48000, 32000 } }; /* MPEG 1 */ + +static const long bitr_index[2][15] = +{ {0, 8,16,24,32,40,48,56, 64, 80, 96,112,128,144,160}, /* MPEG 2 */ + {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320} }; /* MPEG 1 */ static const int num_bands[3][15] = { {0,10,10,10,10,12,14,16, 20, 22, 24, 26, 28, 30, 32}, @@ -837,35 +842,55 @@ { 134, -146,-3352,-3072 } }; /* forward declarations */ -int HuffmanCode( short *ix, int *xr, uint32 begin, uint32 end, int table); -int HuffmanCod1( short *ix, int *xr, uint32 begin, uint32 end, int table); -void putbits(uint32 val, uint32 nbit); -int find_best_2( short *ix, uint32 start, uint32 end, const uint32 *table, - uint32 len, int *bits); -int find_best_3( short *ix, uint32 start, uint32 end, const uint32 *table, - uint32 len, int *bits); -int count_bit1 ( short *ix, uint32 start, uint32 end, int *bits ); -int count_bigv ( short *ix, uint32 start, uint32 end, int table0, int table1, - int *bits); +static int HuffmanCode( short *ix, int *xr, uint32_t begin, uint32_t end, int table); +static int HuffmanCod1( short *ix, int *xr, uint32_t begin, uint32_t end, int table); +static void putbits(uint32_t val, uint32_t nbit); +static int find_best_2( short *ix, uint32_t start, uint32_t end, const uint32_t *table, + uint32_t len, int *bits); +static int find_best_3( short *ix, uint32_t start, uint32_t end, const uint32_t *table, + uint32_t len, int *bits); +static int count_bit1 ( short *ix, uint32_t start, uint32_t end, int *bits ); +static int count_bigv ( short *ix, uint32_t start, uint32_t end, int table0, int table1, + int *bits); -void encodeSideInfo( side_info_t si[2][2] ) +static void encodeSideInfo( side_info_t si[2][2] ) { int gr, ch, header; - uint32 cc=0, sz=0; - - header = 0xfff00000; - header |= cfg.mpg.type << 19; /* mp3 type: 1 */ - header |= 1 << 17; /* mp3 layer: 1 */ - header |= 1 << 16; /* mp3 crc: 0 */ + uint32_t cc=0, sz=0; + + /* + * MPEG header layout: + * AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM + * A (31-21) = frame sync + * B (20-19) = MPEG type + * C (18-17) = MPEG layer + * D (16) = protection bit + * E (15-12) = bitrate index + * F (11-10) = samplerate index + * G (9) = padding bit + * H (8) = private bit + * I (7-6) = channel mode + * J (5-4) = mode extension (jstereo only) + * K (3) = copyright bit + * L (2) = original + * M (1-0) = emphasis + */ + + header = (0xfff00000) | /* frame sync (AAAAAAAAA AAA) + mp3 type (upper): 1 (B) */ + (0x01 << 17) | /* mp3 layer: 01 (CC) */ + ( 0x1 << 16) | /* mp3 crc: 1 (D) */ + ( 0x1 << 2); /* mp3 org: 1 (L) */ + header |= cfg.mpg.type << 19; header |= cfg.mpg.bitr_id << 12; header |= cfg.mpg.smpl_id << 10; header |= cfg.mpg.padding << 9; header |= cfg.mpg.mode << 6; - header |= 1 << 2; /* mp3 original: 1 */ + /* no emphasis (bits 0-1) */ putbits( header, 32 ); - if(cfg.mpg.type) + if(cfg.mpg.type == 1) { /* MPEG1 */ if(cfg.channels == 2) { putlong( 0, 20); } else { putlong( 0, 18); } @@ -910,7 +935,7 @@ /* Note the discussion of huffmancodebits() on pages 28 and 29 of the IS, as well as the definitions of the side information on pages 26 and 27. */ -void Huffmancodebits( short *ix, int *xr, side_info_t *gi ) +static void Huffmancodebits( short *ix, int *xr, side_info_t *gi ) { int region1 = gi->address1; int region2 = gi->address2; @@ -944,10 +969,10 @@ } } -int HuffmanCod1( short *ix, int *xr, uint32 begin, uint32 end, int tbl) +int HuffmanCod1( short *ix, int *xr, uint32_t begin, uint32_t end, int tbl) { - uint32 cc=0, sz=0; - uint32 i, d, p; + uint32_t cc=0, sz=0; + uint32_t i, d, p; int sumbit=0, s=0, l=0, v, w, x, y; #define sgnv (xr[i+0] < 0 ? 1 : 0) #define sgnw (xr[i+1] < 0 ? 1 : 0) @@ -995,10 +1020,10 @@ } /* Implements the pseudocode of page 98 of the IS */ -int HuffmanCode( short *ix, int *xr, uint32 begin, uint32 end, int table) +int HuffmanCode( short *ix, int *xr, uint32_t begin, uint32_t end, int table) { - uint32 cc=0, sz=0, code; - uint32 i, xl=0, yl=0, idx; + uint32_t cc=0, sz=0, code; + uint32_t i, xl=0, yl=0, idx; int x, y, bit, sumbit=0; #define sign_x (xr[i+0] < 0 ? 1 : 0) #define sign_y (xr[i+1] < 0 ? 1 : 0) @@ -1008,9 +1033,9 @@ if( table > 15 ) { /* ESC-table is used */ - uint32 linbits = ht_big[table-16].linbits; - uint16 *hffcode = table < 24 ? t16HB : t24HB; - uint8 *hlen = table < 24 ? t16l : t24l; + uint32_t linbits = ht_big[table-16].linbits; + uint16_t *hffcode = table < 24 ? t16HB : t24HB; + uint8_t *hlen = table < 24 ? t16l : t24l; for(i=begin; i> 5; val = val & (0xffffffff >> (32 - nbit)); - /* data fit in one uint32 */ + /* data fit in one uint32_t */ if(((new_bitpos - 1) >> 5) == ptrpos) CodedData.bbuf[ptrpos] |= val << ((32 - new_bitpos) & 31); else @@ -1114,9 +1139,9 @@ /* of the Huffman tables as defined in the IS (Table B.7), and will not */ /* work with any arbitrary tables. */ /***************************************************************************/ -int choose_table( short *ix, uint32 begin, uint32 end, int *bits ) +int choose_table( short *ix, uint32_t begin, uint32_t end, int *bits ) { - uint32 i; + uint32_t i; int max, table0, table1; for(i=begin,max=0; icount1 = 0; @@ -1899,276 +1924,275 @@ out[16] = ct - st; } -static int find_bitrate_index(int type, int bitrate) +static int find_bitrate_index(int type, int bitrate, bool stereo) { - int i; - - for(i=0;i<14;i++) - if(bitrate == bitr_index[type][i]) - break; + if (type == 1 && !stereo && bitrate > 160) + bitrate = 160; - return i; + return ci->round_value_to_list32(bitrate, + &bitr_index[type][1], 14, true) + 1; } static int find_samplerate_index(long freq, int *mp3_type) -{ /* MPEG 2 */ /* MPEG 1 */ - static long mpeg[2][3] = { {22050, 24000, 16000}, {44100, 48000, 32000} }; - int mpg, rate; - - /* set default values: MPEG1 at 44100/s */ - *mp3_type = 1; - - for(mpg=0; mpg<2; mpg++) - for(rate=0; rate<3; rate++) - if(freq == mpeg[mpg][rate]) - { *mp3_type = mpg; return rate; } +{ + int mpeg = freq >= (32000+24000)/2 ? 1 : 0; + int i = ci->round_value_to_list32(freq, sampr_index[mpeg], 3, true); + *mp3_type = mpeg; + return i; +} + +bool init_mp3_encoder_engine(int sample_rate, + int num_channels, + struct encoder_config *enc_cfg) +{ + const bool stereo = num_channels > 1; + uint32_t avg_byte_per_frame; + + cfg.channels = stereo ? 2 : 1; + cfg.mpg.mode = stereo ? 0 : 3; /* 0=stereo, 3=mono */ + cfg.mpg.smpl_id = find_samplerate_index(sample_rate, &cfg.mpg.type); + cfg.samplerate = sampr_index[cfg.mpg.type][cfg.mpg.smpl_id]; + cfg.mpg.bitr_id = find_bitrate_index(cfg.mpg.type, + enc_cfg->mp3_enc.bitrate, + stereo); + cfg.mpg.bitrate = bitr_index[cfg.mpg.type][cfg.mpg.bitr_id]; + cfg.mpg.num_bands = num_bands[stereo ? cfg.mpg.type : 2][cfg.mpg.bitr_id]; - return 0; -} + if (cfg.mpg.type == 1) + { + cfg.granules = 2; + pcm_chunk_size = PCM_CHUNK_SIZE1; + samp_per_frame = SAMP_PER_FRAME1; + } + else + { + cfg.granules = 1; + pcm_chunk_size = PCM_CHUNK_SIZE2; + samp_per_frame = SAMP_PER_FRAME2; + } -void init_mp3_encoder_engine(bool stereo, int quality, int sample_rate) -{ - /* keep in sync with rec_quality_info_afmt in id3.h/.c */ - static int bitr_s[9] = { 64, 96, 128, 160, 192, 224, 320, 64, 64 }; - static int bitr_m[9] = { 64, 96, 128, 160, 160, 160, 160, 64, 64 }; - uint32 avg_byte_per_frame; + memcpy(scalefac, sfBand[cfg.mpg.smpl_id + 3*cfg.mpg.type], sizeof(scalefac)); + memset(mfbuf , 0 , sizeof(mfbuf )); + memset(mdct_freq , 0 , sizeof(mdct_freq )); + memset(enc_data , 0 , sizeof(enc_data )); + memset(sb_data , 0 , sizeof(sb_data )); + memset(&CodedData, 0 , sizeof(CodedData )); + memcpy(ca , ca_const , sizeof(ca )); + memcpy(cs , cs_const , sizeof(cs )); + memcpy(cx , cx_const , sizeof(cx )); + memcpy(win , win_const , sizeof(win )); + memcpy(enwindow , enwindow_const , sizeof(enwindow )); + memcpy(int2idx , int2idx_const , sizeof(int2idx )); + memcpy(ht_count , ht_count_const , sizeof(ht_count )); + memcpy( tab01 , tab01_const , sizeof(tab01 )); + memcpy( tab23 , tab23_const , sizeof(tab23 )); + memcpy( tab56 , tab56_const , sizeof(tab56 )); + memcpy( tab1315 , tab1315_const , sizeof(tab1315 )); + memcpy( tab1624 , tab1624_const , sizeof(tab1624 )); + memcpy( tab789 , tab789_const , sizeof(tab789 )); + memcpy( tabABC , tabABC_const , sizeof(tabABC )); + memcpy( t1HB , t1HB_const , sizeof(t1HB )); + memcpy( t2HB , t2HB_const , sizeof(t2HB )); + memcpy( t3HB , t3HB_const , sizeof(t3HB )); + memcpy( t5HB , t5HB_const , sizeof(t5HB )); + memcpy( t6HB , t6HB_const , sizeof(t6HB )); + memcpy( t7HB , t7HB_const , sizeof(t7HB )); + memcpy( t8HB , t8HB_const , sizeof(t8HB )); + memcpy( t9HB , t9HB_const , sizeof(t9HB )); + memcpy(t10HB , t10HB_const , sizeof(t10HB )); + memcpy(t11HB , t11HB_const , sizeof(t11HB )); + memcpy(t12HB , t12HB_const , sizeof(t12HB )); + memcpy(t13HB , t13HB_const , sizeof(t13HB )); + memcpy(t15HB , t15HB_const , sizeof(t15HB )); + memcpy(t16HB , t16HB_const , sizeof(t16HB )); + memcpy(t24HB , t24HB_const , sizeof(t24HB )); + memcpy( t1l , t1l_const , sizeof(t1l )); + memcpy( t2l , t2l_const , sizeof(t2l )); + memcpy( t3l , t3l_const , sizeof(t3l )); + memcpy( t5l , t5l_const , sizeof(t5l )); + memcpy( t6l , t6l_const , sizeof(t6l )); + memcpy( t7l , t7l_const , sizeof(t7l )); + memcpy( t8l , t8l_const , sizeof(t8l )); + memcpy( t9l , t9l_const , sizeof(t9l )); + memcpy(t10l , t10l_const , sizeof(t10l )); + memcpy(t11l , t11l_const , sizeof(t11l )); + memcpy(t12l , t12l_const , sizeof(t12l )); + memcpy(t13l , t13l_const , sizeof(t13l )); + memcpy(t15l , t15l_const , sizeof(t15l )); + memcpy(t16l , t16l_const , sizeof(t16l )); + memcpy(t24l , t24l_const , sizeof(t24l )); + memcpy(ht , ht_const , sizeof(ht )); + + ht[ 0].table = NULL; ht[ 0].hlen = NULL; /* Apparently not used */ + ht[ 1].table = t1HB; ht[ 1].hlen = t1l; + ht[ 2].table = t2HB; ht[ 2].hlen = t2l; + ht[ 3].table = t3HB; ht[ 3].hlen = t3l; + ht[ 4].table = NULL; ht[ 4].hlen = NULL; /* Apparently not used */ + ht[ 5].table = t5HB; ht[ 5].hlen = t5l; + ht[ 6].table = t6HB; ht[ 6].hlen = t6l; + ht[ 7].table = t7HB; ht[ 7].hlen = t7l; + ht[ 8].table = t8HB; ht[ 8].hlen = t8l; + ht[ 9].table = t9HB; ht[ 9].hlen = t9l; + ht[10].table = t10HB; ht[10].hlen = t10l; + ht[11].table = t11HB; ht[11].hlen = t11l; + ht[12].table = t12HB; ht[12].hlen = t12l; + ht[13].table = t13HB; ht[13].hlen = t13l; + ht[14].table = NULL; ht[14].hlen = NULL; /* Apparently not used */ + ht[15].table = t15HB; ht[15].hlen = t15l; + + /* Figure average number of 'bytes' per frame */ + avg_byte_per_frame = SAMPL2 * 16000 * cfg.mpg.bitrate / (2 - cfg.mpg.type); + avg_byte_per_frame = avg_byte_per_frame / cfg.samplerate; + cfg.byte_per_frame = avg_byte_per_frame / 64; + cfg.frac_per_frame = avg_byte_per_frame & 63; + cfg.slot_lag = 0; + cfg.sideinfo_len = 32 + (cfg.mpg.type ? (cfg.channels == 1 ? 136 : 256) + : (cfg.channels == 1 ? 72 : 136)); + + return true; +} + +static void to_mono_mm(void) ICODE_ATTR; +static void to_mono_mm(void) +{ + /* |llllllllllllllll|rrrrrrrrrrrrrrrr| => + * |mmmmmmmmmmmmmmmm|mmmmmmmmmmmmmmmm| + */ + uint32_t *samp = (uint32_t *)&mfbuf[2*512]; + uint32_t *samp_end = samp + samp_per_frame; - if(quality == 0 && stereo && sample_rate >= 32000) - { /* use MPEG2 format */ - sample_rate >>= 1; - cfg.resample = 1; - cfg.granules = 1; - } - else - { /* use MPEG1 format */ - cfg.resample = 0; - cfg.granules = 2; - } - - cfg.byte_order = order_bigEndian; - cfg.samplerate = sample_rate; - cfg.channels = stereo ? 2 : 1; - cfg.mpg.mode = stereo ? 0 : 3; /* 0=stereo, 3=mono */ - cfg.mpg.bitrate = stereo ? bitr_s[quality] : bitr_m[quality]; - cfg.mpg.smpl_id = find_samplerate_index(cfg.samplerate, &cfg.mpg.type); - cfg.mpg.bitr_id = find_bitrate_index(cfg.mpg.type, cfg.mpg.bitrate); - cfg.mpg.num_bands = num_bands[stereo ? cfg.mpg.type : 2][cfg.mpg.bitr_id]; - - memcpy(scalefac, sfBand[cfg.mpg.smpl_id + 3*cfg.mpg.type], sizeof(scalefac)); - memset(mfbuf , 0 , sizeof(mfbuf )); - memset(mdct_freq , 0 , sizeof(mdct_freq )); - memset(enc_data , 0 , sizeof(enc_data )); - memset(sb_data , 0 , sizeof(sb_data )); - memset(&CodedData, 0 , sizeof(CodedData )); - memcpy(ca , ca_const , sizeof(ca )); - memcpy(cs , cs_const , sizeof(cs )); - memcpy(cx , cx_const , sizeof(cx )); - memcpy(win , win_const , sizeof(win )); - memcpy(enwindow , enwindow_const , sizeof(enwindow )); - memcpy(int2idx , int2idx_const , sizeof(int2idx )); - memcpy(ht_count , ht_count_const , sizeof(ht_count )); - memcpy( tab01 , tab01_const , sizeof(tab01 )); - memcpy( tab23 , tab23_const , sizeof(tab23 )); - memcpy( tab56 , tab56_const , sizeof(tab56 )); - memcpy( tab1315 , tab1315_const , sizeof(tab1315 )); - memcpy( tab1624 , tab1624_const , sizeof(tab1624 )); - memcpy( tab789 , tab789_const , sizeof(tab789 )); - memcpy( tabABC , tabABC_const , sizeof(tabABC )); - memcpy( t1HB , t1HB_const , sizeof(t1HB )); - memcpy( t2HB , t2HB_const , sizeof(t2HB )); - memcpy( t3HB , t3HB_const , sizeof(t3HB )); - memcpy( t5HB , t5HB_const , sizeof(t5HB )); - memcpy( t6HB , t6HB_const , sizeof(t6HB )); - memcpy( t7HB , t7HB_const , sizeof(t7HB )); - memcpy( t8HB , t8HB_const , sizeof(t8HB )); - memcpy( t9HB , t9HB_const , sizeof(t9HB )); - memcpy(t10HB , t10HB_const , sizeof(t10HB )); - memcpy(t11HB , t11HB_const , sizeof(t11HB )); - memcpy(t12HB , t12HB_const , sizeof(t12HB )); - memcpy(t13HB , t13HB_const , sizeof(t13HB )); - memcpy(t15HB , t15HB_const , sizeof(t15HB )); - memcpy(t16HB , t16HB_const , sizeof(t16HB )); - memcpy(t24HB , t24HB_const , sizeof(t24HB )); - memcpy( t1l , t1l_const , sizeof(t1l )); - memcpy( t2l , t2l_const , sizeof(t2l )); - memcpy( t3l , t3l_const , sizeof(t3l )); - memcpy( t5l , t5l_const , sizeof(t5l )); - memcpy( t6l , t6l_const , sizeof(t6l )); - memcpy( t7l , t7l_const , sizeof(t7l )); - memcpy( t8l , t8l_const , sizeof(t8l )); - memcpy( t9l , t9l_const , sizeof(t9l )); - memcpy(t10l , t10l_const , sizeof(t10l )); - memcpy(t11l , t11l_const , sizeof(t11l )); - memcpy(t12l , t12l_const , sizeof(t12l )); - memcpy(t13l , t13l_const , sizeof(t13l )); - memcpy(t15l , t15l_const , sizeof(t15l )); - memcpy(t16l , t16l_const , sizeof(t16l )); - memcpy(t24l , t24l_const , sizeof(t24l )); - memcpy(ht , ht_const , sizeof(ht )); - - ht[ 0].table = NULL; ht[ 0].hlen = NULL; /* Apparently not used */ - ht[ 1].table = t1HB; ht[ 1].hlen = t1l; - ht[ 2].table = t2HB; ht[ 2].hlen = t2l; - ht[ 3].table = t3HB; ht[ 3].hlen = t3l; - ht[ 4].table = NULL; ht[ 4].hlen = NULL; /* Apparently not used */ - ht[ 5].table = t5HB; ht[ 5].hlen = t5l; - ht[ 6].table = t6HB; ht[ 6].hlen = t6l; - ht[ 7].table = t7HB; ht[ 7].hlen = t7l; - ht[ 8].table = t8HB; ht[ 8].hlen = t8l; - ht[ 9].table = t9HB; ht[ 9].hlen = t9l; - ht[10].table = t10HB; ht[10].hlen = t10l; - ht[11].table = t11HB; ht[11].hlen = t11l; - ht[12].table = t12HB; ht[12].hlen = t12l; - ht[13].table = t13HB; ht[13].hlen = t13l; - ht[14].table = NULL; ht[14].hlen = NULL; /* Apparently not used */ - ht[15].table = t15HB; ht[15].hlen = t15l; - - /* Figure average number of 'bytes' per frame */ - avg_byte_per_frame = SAMPL2 * 16000 * cfg.mpg.bitrate / (2 - cfg.mpg.type); - avg_byte_per_frame = avg_byte_per_frame / cfg.samplerate; - cfg.byte_per_frame = avg_byte_per_frame / 64; - cfg.frac_per_frame = avg_byte_per_frame & 63; - cfg.slot_lag = 0; - cfg.sideinfo_len = 32 + (cfg.mpg.type ? (cfg.channels == 1 ? 136 : 256) - : (cfg.channels == 1 ? 72 : 136)); -} + inline void to_mono(uint32_t **samp) + { + int32_t lr = **samp; + int32_t m = ((int16_t)lr + (lr >> 16)) >> 1; + *(*samp)++ = (m << 16) | (uint16_t)m; + } /* to_mono */ + do + { + to_mono(&samp); + to_mono(&samp); + to_mono(&samp); + to_mono(&samp); + to_mono(&samp); + to_mono(&samp); + to_mono(&samp); + to_mono(&samp); + } + while (samp < samp_end); +} /* to_mono_mm */ -enum codec_status codec_start(struct codec_api* api) +#ifdef ROCKBOX_LITTLE_ENDIAN +/* Swaps a frame to big endian */ +static inline void byte_swap_frame32(uint32_t *dst, uint32_t *src, + size_t size) ICODE_ATTR; +static inline void byte_swap_frame32(uint32_t *dst, uint32_t *src, + size_t size) { - int i, ii, gr, k, ch, shift, gr_cnt; - int max, min; - long *buffer; - int chunk_size, num_chunks; - int enc_buffer_size; - int enc_quality; - uint32 *mp3_chunk_ptr; - bool cpu_boosted = true; /* start boosted */ + uint32_t *src_end = SKIPBYTES(src, size); - /* Generic codec initialisation */ - ci = api; + do + { + *dst++ = swap32(*src++); + *dst++ = swap32(*src++); + *dst++ = swap32(*src++); + *dst++ = swap32(*src++); + *dst++ = swap32(*src++); + *dst++ = swap32(*src++); + *dst++ = swap32(*src++); + *dst++ = swap32(*src++); + } + while(src < src_end); +} /* byte_swap_frame32 */ +#endif /* ROCKBOX_LITTLE_ENDIAN */ + +static void encode_frame(char *buffer, struct enc_chunk_hdr *chunk) ICODE_ATTR; +static void encode_frame(char *buffer, struct enc_chunk_hdr *chunk) +{ + int gr, gr_cnt; + int max, min; + + /* encode one mp3 frame in this loop */ + CodedData.bitpos = 0; + memset(CodedData.bbuf, 0, sizeof(CodedData.bbuf)); + + if ((cfg.slot_lag += cfg.frac_per_frame) >= 64) + { /* Padding for this frame */ + cfg.slot_lag -= 64; + cfg.mpg.padding = 1; + } + else + cfg.mpg.padding = 0; -#ifdef USE_IRAM - memcpy(iramstart, iramcopy, iramend - iramstart); - memset(iedata, 0, iend - iedata); -#endif + cfg.mean_bits = (8 * cfg.byte_per_frame + 8 * cfg.mpg.padding + - cfg.sideinfo_len) / cfg.granules / cfg.channels; - if(ci->enc_get_inputs == NULL || - ci->enc_set_parameters == NULL || - ci->enc_alloc_chunk == NULL || - ci->enc_free_chunk == NULL || - ci->enc_wavbuf_near_empty == NULL || - ci->enc_get_wav_data == NULL || - ci->enc_set_header_callback == NULL ) - return CODEC_ERROR; + /* shift out old samples */ + memcpy(mfbuf, mfbuf + 2*cfg.granules*576, 4*512); - ci->cpu_boost(true); - - *ci->enc_set_header_callback = NULL; - ci->enc_get_inputs(&enc_buffer_size, &enc_channels, &enc_quality); + if (chunk->flags & CHUNKF_START_FILE) + { + /* prefix silent samples for encoder delay */ + memset(mfbuf + 2*512, 0, ENC_DELAY_SIZE); + /* read new samples to iram for further processing */ + memcpy(mfbuf + 2*512 + ENC_DELAY_SIZE/2, + buffer, pcm_chunk_size - ENC_DELAY_SIZE); + chunk->num_pcm = samp_per_frame - ENC_DELAY_SAMP; + } + else + { + /* read new samples to iram for further processing */ + memcpy(mfbuf + 2*512, buffer, pcm_chunk_size); + chunk->num_pcm = samp_per_frame; + } - init_mp3_encoder_engine(enc_channels == 2, enc_quality, 44100); + if (cfg.channels == 1) + to_mono_mm(); - /* must be 4byte aligned */ - chunk_size = (sizeof(long) + cfg.byte_per_frame + 1 + 3) & ~3; - num_chunks = enc_buffer_size / chunk_size; - - /* inform the main program about the buffer dimensions */ - ci->enc_set_parameters(chunk_size, num_chunks, SAMP_PER_FRAME, - NULL, 0, AFMT_MPA_L3); + cfg.ResvSize = 0; + gr_cnt = cfg.granules * cfg.channels; + CodedData.bitpos = cfg.sideinfo_len; /* leave space for mp3 header */ -#ifdef CPU_COLDFIRE - asm volatile ("move.l #0, %macsr"); /* integer mode */ -#endif + for(gr=0; grenc_codec_loaded = true; + /* 16bit packed wav data can be windowed efficiently on coldfire */ + window_subband1(wk, sb_data[0][1-gr][0], sb_data[1][1-gr][0]); - /* main encoding loop */ - while(!ci->stop_codec) - { - while((buffer = (long*)ci->enc_get_wav_data(SAMP_PER_FRAME*4)) != NULL) + for(ch=0; chstop_codec) - break; + int ii, k, shift; + + wk = mfbuf + 2*286 + gr*1152 + ch; - if(ci->enc_wavbuf_near_empty() == 0) + /* 36864=4*18*16*32 */ + for(k=0; k<18; k++, wk+=64) { - if(!cpu_boosted) + window_subband2(wk, sb_data[ch][1-gr][k]); + /* Compensate for inversion in the analysis filter */ + if(k & 1) { - ci->cpu_boost(true); - cpu_boosted = true; + int band; + for(band=1; band<32; band+=2) + sb_data[ch][1-gr][k][band] *= -1; } } - /* encode one mp3 frame in this loop */ - CodedData.bitpos = 0; - memset(CodedData.bbuf, 0, sizeof(CodedData.bbuf)); - - if((cfg.slot_lag += cfg.frac_per_frame) >= 64) - { /* Padding for this frame */ - cfg.slot_lag -= 64; - cfg.mpg.padding = 1; - } - else - cfg.mpg.padding = 0; - - cfg.mean_bits = (8 * cfg.byte_per_frame + 8 * cfg.mpg.padding - - cfg.sideinfo_len) / cfg.granules / cfg.channels; - - /* shift out old samples */ - memcpy(mfbuf, mfbuf + 2*cfg.granules*576, 4*512); - /* read new samples to iram for further processing */ - memcpy((uint32*)(mfbuf + 2*512), buffer, 4*SAMP_PER_FRAME); - - if(cfg.resample) /* downsample to half of original */ - for(i=2*512; i<2*512+2*SAMP_PER_FRAME; i+=4) - { - mfbuf[i/2+512] = (short)(((int)mfbuf[i+0] + mfbuf[i+2]) >> 1); - mfbuf[i/2+513] = (short)(((int)mfbuf[i+1] + mfbuf[i+3]) >> 1); - } - - if(cfg.channels == 1) /* mix left and right channels to mono */ - for(i=2*512; i<2*512+2*SAMP_PER_FRAME; i+=2) - mfbuf[i] = mfbuf[i+1] = (short)(((int)mfbuf[i] + mfbuf[i+1]) >> 1); - - cfg.ResvSize = 0; - gr_cnt = cfg.granules * cfg.channels; - CodedData.bitpos = cfg.sideinfo_len; /* leave space for mp3 header */ - - for(gr=0; gr=0; --k) - { - int bu, bd; - bu = shft15(mdct[k]) * ca[k] + shft15(mdct[-1-k]) * cs[k]; - bd = shft15(mdct[k]) * cs[k] - shft15(mdct[-1-k]) * ca[k]; - mdct[-1-k] = bu; - mdct[ k ] = bd; - } - } - - max = min = 0; - for(k=0; k<576; k++) - { + { + for(k=7; k>=0; --k) + { + int bu, bd; + bu = shft15(mdct[k]) * ca[k] + + shft15(mdct[-1-k]) * cs[k]; + bd = shft15(mdct[k]) * cs[k] - + shft15(mdct[-1-k]) * ca[k]; + mdct[-1-k] = bu; + mdct[ k ] = bd; + } + } + } + + max = min = 0; + for(k=0; k<576; k++) + { mdct_freq[k] = shft13(mdct_freq[k]); if(max < mdct_freq[k]) max = mdct_freq[k]; if(min > mdct_freq[k]) min = mdct_freq[k]; - } + } - max = (max > -min) ? max : -min; - cfg.cod_info[gr][ch].max_val = (long)max; + max = (max > -min) ? max : -min; + cfg.cod_info[gr][ch].max_val = (long)max; - /* calc new shift for higher integer precision */ - for(k=0; max<(0x3c00>>k); k++); + /* calc new shift for higher integer precision */ + for(k=0; max<(0x3c00>>k); k++); shift = 12 - k; - } + } + + cfg.cod_info[gr][ch].quantStep += + cfg.cod_info[gr][ch].additStep; - cfg.cod_info[gr][ch].quantStep += cfg.cod_info[gr][ch].additStep; + /* bit and noise allocation */ + iteration_loop(mdct_freq, &cfg.cod_info[gr][ch], + gr_cnt--); + /* write the frame to the bitstream */ + Huffmancodebits(enc_data, mdct_freq, + &cfg.cod_info[gr][ch]); - /* bit and noise allocation */ - iteration_loop(mdct_freq, &cfg.cod_info[gr][ch], gr_cnt--); - /* write the frame to the bitstream */ - Huffmancodebits(enc_data, mdct_freq, &cfg.cod_info[gr][ch]); - - cfg.cod_info[gr][ch].quantStep -= cfg.cod_info[gr][ch].additStep; - - if(cfg.granules == 1) - memcpy(sb_data[ch][0], sb_data[ch][1], sizeof(sb_data[ch][0])); - } + cfg.cod_info[gr][ch].quantStep -= + cfg.cod_info[gr][ch].additStep; + + if(cfg.granules == 1) + { + memcpy(sb_data[ch][0], sb_data[ch][1], + sizeof(sb_data[ch][0])); } + } + } - mp3_chunk_ptr = (uint32*)ci->enc_alloc_chunk(); - mp3_chunk_ptr[0] = cfg.byte_per_frame + cfg.mpg.padding; //(CodedData.bitpos + 7) >> 3; - /* finish this chunk by adding sideinfo header data */ - CodedData.bitpos = 0; - encodeSideInfo( cfg.cod_info ); - - /* allocate mp3 chunk, set chunk size, copy chunk to enc_buffer */ - memcpy(&mp3_chunk_ptr[1], CodedData.bbuf, mp3_chunk_ptr[0]); - ci->enc_free_chunk(); + chunk->enc_size = cfg.byte_per_frame + cfg.mpg.padding; - ci->yield(); + /* finish this chunk by adding sideinfo header data */ + CodedData.bitpos = 0; + encodeSideInfo( cfg.cod_info ); + +#ifdef ROCKBOX_BIG_ENDIAN + /* copy chunk to enc_buffer */ + memcpy(chunk->enc_data, CodedData.bbuf, chunk->enc_size); +#else + /* swap frame to big endian */ + byte_swap_frame32(chunk->enc_data, CodedData.bbuf, chunk->enc_size); +#endif +} /* encode_frame */ + +/* called very often - inline */ +static inline bool is_file_data_ok(struct enc_file_event_data *filed) ICODE_ATTR; +static inline bool is_file_data_ok(struct enc_file_event_data *filed) +{ + return filed->rec_file >= 0 && (long)filed->chunk->flags >= 0; +} /* is_event_ok */ + +/* called very often - inline */ +static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR; +static inline bool on_write_chunk(struct enc_file_event_data *data) +{ + if (!is_file_data_ok(data)) + return false; + + if (data->chunk->enc_data == NULL) + { +#ifdef ROCKBOX_HAS_LOGF + ci->logf("mp3 enc: NULL data"); +#endif + return true; + } + + if (ci->write(data->rec_file, data->chunk->enc_data, + data->chunk->enc_size) != (ssize_t)data->chunk->enc_size) + return false; + + data->num_pcm_samples += data->chunk->num_pcm; + return true; +} /* on_write_chunk */ + +static bool on_start_file(struct enc_file_event_data *data) +{ + if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0') + return false; + + data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC); + + if (data->rec_file < 0) + return false; + + /* reset sample count */ + data->num_pcm_samples = 0; + return true; +} /* on_start_file */ + +static bool on_end_file(struct enc_file_event_data *data) +{ + if (!is_file_data_ok(data)) + return false; + + ci->fsync(data->rec_file); + ci->close(data->rec_file); + data->rec_file = -1; + + return true; +} /* on_end_file */ + +static void on_rec_new_stream(struct enc_buffer_event_data *data) +{ + int num_frames = cfg.mpg.type == 1 ? + ENC_PADDING_FRAMES1 : ENC_PADDING_FRAMES2; + + if (data->flags & CHUNKF_END_FILE) + { + /* add silent frames to end - encoder will also be flushed for start + of next file if any */ + memset(res_buffer, 0, pcm_chunk_size); + + /* the initial chunk given for the end is at enc_wr_index */ + while (num_frames-- > 0) + { + data->chunk->enc_data = ENC_CHUNK_SKIP_HDR(data->chunk->enc_data, + data->chunk); + + encode_frame(res_buffer, data->chunk); + data->chunk->num_pcm = samp_per_frame; + + ci->enc_finish_chunk(); + data->chunk = ci->enc_get_chunk(); + } + } + else if (data->flags & CHUNKF_PRERECORD) + { + /* nothing to add and we cannot change prerecorded data */ + } + else if (data->flags & CHUNKF_START_FILE) + { + /* starting fresh ... be sure to flush encoder first */ + struct enc_chunk_hdr *chunk = ENC_CHUNK_HDR(res_buffer); + + chunk->flags = 0; + chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); + + while (num_frames-- > 0) + { + memset(chunk->enc_data, 0, pcm_chunk_size); + encode_frame(chunk->enc_data, chunk); } + } +} /* on_rec_new_stream */ + +static void enc_events_callback(enum enc_events event, void *data) ICODE_ATTR; +static void enc_events_callback(enum enc_events event, void *data) +{ + if (event == ENC_WRITE_CHUNK) + { + if (on_write_chunk((struct enc_file_event_data *)data)) + return; + } + else if (event == ENC_START_FILE) + { + if (on_start_file((struct enc_file_event_data *)data)) + return; + } + else if (event == ENC_END_FILE) + { + if (on_end_file((struct enc_file_event_data *)data)) + return; + } + else if (event == ENC_REC_NEW_STREAM) + { + on_rec_new_stream((struct enc_buffer_event_data *)data); + return; + } + else + { + return; + } + + ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR; +} /* enc_events_callback */ - if(ci->enc_wavbuf_near_empty()) +static bool enc_init(void) +{ + struct enc_inputs inputs; + struct enc_parameters params; + + if (ci->enc_get_inputs == NULL || + ci->enc_set_parameters == NULL || + ci->enc_get_chunk == NULL || + ci->enc_finish_chunk == NULL || + ci->enc_pcm_buf_near_empty == NULL || + ci->enc_get_pcm_data == NULL || + ci->enc_unget_pcm_data == NULL ) + return false; + + ci->enc_get_inputs(&inputs); + + if (inputs.config->afmt != AFMT_MPA_L3) + return false; + + init_mp3_encoder_engine(inputs.sample_rate, inputs.num_channels, + inputs.config); + + /* configure the buffer system */ + params.afmt = AFMT_MPA_L3; + params.chunk_size = cfg.byte_per_frame + 1; + params.enc_sample_rate = cfg.samplerate; + /* need enough reserved bytes to hold one frame of pcm samples + hdr + for padding and flushing */ + params.reserve_bytes = ENC_CHUNK_HDR_SIZE + pcm_chunk_size; + params.events_callback = enc_events_callback; + ci->enc_set_parameters(¶ms); + + res_buffer = params.reserve_buffer; + +#ifdef CPU_COLDFIRE + asm volatile ("move.l #0, %macsr"); /* integer mode */ +#endif + + return true; +} /* enc_init */ + +enum codec_status codec_start(struct codec_api* api) +{ + bool cpu_boosted; + + /* Generic codec initialisation */ + ci = api; + +#ifdef USE_IRAM + memcpy(iramstart, iramcopy, iramend - iramstart); + memset(iedata, 0, iend - iedata); +#endif + + if (!enc_init()) + { + ci->enc_codec_loaded = -1; + return CODEC_ERROR; + } + + /* main application waits for this flag during encoder loading */ + ci->enc_codec_loaded = 1; + + ci->cpu_boost(true); + cpu_boosted = true; + + /* main encoding loop */ + while (!ci->stop_codec) + { + char *buffer; + + while ((buffer = ci->enc_get_pcm_data(pcm_chunk_size)) != NULL) { - if(cpu_boosted) + struct enc_chunk_hdr *chunk; + + if (ci->stop_codec) + break; + + if (!cpu_boosted && ci->enc_pcm_buf_near_empty() == 0) + { + ci->cpu_boost(true); + cpu_boosted = true; + } + + chunk = ci->enc_get_chunk(); + chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); + + encode_frame(buffer, chunk); + + if (chunk->num_pcm < samp_per_frame) { - ci->cpu_boost(false); - cpu_boosted = false; + ci->enc_unget_pcm_data(pcm_chunk_size - chunk->num_pcm*4); + chunk->num_pcm = samp_per_frame; } + + ci->enc_finish_chunk(); + + ci->yield(); } + + if (cpu_boosted && ci->enc_pcm_buf_near_empty()) + { + ci->cpu_boost(false); + cpu_boosted = false; + } + ci->yield(); } - if(cpu_boosted) /* set initial boost state */ + if (cpu_boosted) /* set initial boost state */ ci->cpu_boost(false); /* reset parameters to initial state */ - ci->enc_set_parameters(0, 0, 0, 0, 0, 0); + ci->enc_set_parameters(NULL); /* main application waits for this flag during encoder removing */ - ci->enc_codec_loaded = false; + ci->enc_codec_loaded = 0; return CODEC_OK; -} +} /* codec_start */ -#endif +#endif /* ndef SIMULATOR */ Index: apps/codecs/wav_enc.c =================================================================== RCS file: /cvsroot/rockbox/apps/codecs/wav_enc.c,v retrieving revision 1.1 diff -u -r1.1 wav_enc.c --- apps/codecs/wav_enc.c 28 Aug 2006 22:38:39 -0000 1.1 +++ apps/codecs/wav_enc.c 16 Oct 2006 23:32:35 -0000 @@ -19,154 +19,379 @@ #ifndef SIMULATOR +#include #include "codeclib.h" -CODEC_HEADER +CODEC_ENC_HEADER + +#ifdef USE_IRAM +extern char iramcopy[]; +extern char iramstart[]; +extern char iramend[]; +extern char iedata[]; +extern char iend[]; +#endif + +struct riff_header +{ + uint8_t riff_id[4]; /* 00h - "RIFF" */ + uint32_t riff_size; /* 04h - sz following headers + data_size */ + /* format header */ + uint8_t format[4]; /* 08h - "WAVE" */ + uint8_t format_id[4]; /* 0Ch - "fmt " */ + uint32_t format_size; /* 10h - 16 for PCM (sz format data) */ + /* format data */ + uint16_t audio_format; /* 14h - 1=PCM */ + uint16_t num_channels; /* 16h - 1=M, 2=S, etc. */ + uint32_t sample_rate; /* 18h - HZ */ + uint32_t byte_rate; /* 1Ch - num_channels*sample_rate*bits_per_sample/8 */ + uint16_t block_align; /* 20h - num_channels*bits_per_samples/8 */ + uint16_t bits_per_sample; /* 22h - 8=8 bits, 16=16 bits, etc. */ + /* Not for audio_format=1 (PCM) */ +/* unsigned short extra_param_size; 24h - size of extra data */ +/* unsigned char *extra_params; */ + /* data header */ + uint8_t data_id[4]; /* 24h - "data" */ + uint32_t data_size; /* 28h - num_samples*num_channels*bits_per_sample/8 */ +/* unsigned char *data; 2ch - actual sound data */ +}; + +#define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */ +#define RIFF_FMT_DATA_SIZE 16 /* audio_format -> bits_per_sample */ +#define RIFF_DATA_HEADER_SIZE 8 /* data_id -> data_size */ + +#define PCM_DEPTH_BYTES 2 +#define PCM_DEPTH_BITS 16 +#define PCM_SAMP_PER_CHUNK 2048 +#define PCM_CHUNK_SIZE (PCM_SAMP_PER_CHUNK*4) static struct codec_api *ci; -static int enc_channels; +static int num_channels; +uint32_t sample_rate; +uint32_t enc_size; + +static const struct riff_header riff_header = +{ + /* "RIFF" header */ + { 'R', 'I', 'F', 'F' }, /* riff_id */ + 0, /* riff_size (*) */ + /* format header */ + { 'W', 'A', 'V', 'E' }, /* format */ + { 'f', 'm', 't', ' ' }, /* format_id */ + H_TO_LE32(16), /* format_size */ + /* format data */ + H_TO_LE16(1), /* audio_format */ + 0, /* num_channels (*) */ + 0, /* sample_rate (*) */ + 0, /* byte_rate (*) */ + 0, /* block_align (*) */ + H_TO_LE16(PCM_DEPTH_BITS), /* bits_per_sample */ + /* data header */ + { 'd', 'a', 't', 'a' }, /* data_id */ + 0 /* data_size (*) */ + /* (*) updated during ENC_END_FILE event */ +}; + +/* called version often - inline */ +static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR; +static inline bool is_file_data_ok(struct enc_file_event_data *data) +{ + return data->rec_file >= 0 && (long)data->chunk->flags >= 0; +} /* is_file_data_ok */ + +/* called version often - inline */ +static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR; +static inline bool on_write_chunk(struct enc_file_event_data *data) +{ + if (!is_file_data_ok(data)) + return false; + + if (data->chunk->enc_data == NULL) + { +#ifdef ROCKBOX_HAS_LOGF + ci->logf("wav enc: NULL data"); +#endif + return true; + } + + if (ci->write(data->rec_file, data->chunk->enc_data, + data->chunk->enc_size) != (ssize_t)data->chunk->enc_size) + return false; + + data->num_pcm_samples += data->chunk->num_pcm; + return true; +} /* on_write_chunk */ -#define CHUNK_SIZE 8192 +static bool on_start_file(struct enc_file_event_data *data) +{ + if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0') + return false; + + data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC); -static unsigned char wav_header[44] = -{'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',16, - 0,0,0,1,0,2,0,0x44,0xac,0,0,0x10,0xb1,2,0,4,0,16,0,'d','a','t','a',0,0,0,0}; + if (data->rec_file < 0) + return false; -static unsigned char wav_header_mono[44] = -{'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',16, - 0,0,0,1,0,1,0,0x44,0xac,0,0,0x88,0x58,1,0,2,0,16,0,'d','a','t','a',0,0,0,0}; + /* reset sample count */ + data->num_pcm_samples = 0; -/* update file header info callback function (called by main application) */ -void enc_set_header(void *head_buffer, /* ptr to the file header data */ - int head_size, /* size of this header data */ - int num_pcm_samples, /* amount of processed pcm samples */ - bool is_file_header) + /* write template header */ + if (ci->write(data->rec_file, &riff_header, sizeof (riff_header)) + != sizeof (riff_header)) + { + return false; + } + + data->new_enc_size += sizeof (riff_header); + return true; +} /* on_start_file */ + +static bool on_end_file(struct enc_file_event_data *data) { - int num_file_bytes = num_pcm_samples * 2 * enc_channels; + /* update template header */ + struct riff_header hdr; + uint32_t data_size; - if(is_file_header) + if (!is_file_data_ok(data)) + return false; + + if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 || + ci->read(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr)) { - /* update file header before file closing */ - if((int)sizeof(wav_header) < head_size) + return false; + } + + data_size = data->num_pcm_samples*num_channels*PCM_DEPTH_BYTES; + + /* "RIFF" header */ + hdr.riff_size = htole32(RIFF_FMT_HEADER_SIZE + RIFF_FMT_DATA_SIZE + + RIFF_DATA_HEADER_SIZE + data_size); + + /* format data */ + hdr.num_channels = htole16(num_channels); + hdr.sample_rate = htole32(sample_rate); + hdr.byte_rate = htole32(sample_rate*num_channels* PCM_DEPTH_BYTES); + hdr.block_align = htole16(num_channels*PCM_DEPTH_BYTES); + + /* data header */ + hdr.data_size = htole32(data_size); + + if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 || + ci->write(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr)) + { + return false; + } + + ci->fsync(data->rec_file); + ci->close(data->rec_file); + data->rec_file = -1; + + return true; +} /* on_end_file */ + +static void enc_events_callback(enum enc_events event, void *data) ICODE_ATTR; +static void enc_events_callback(enum enc_events event, void *data) +{ + if (event == ENC_WRITE_CHUNK) + { + if (on_write_chunk((struct enc_file_event_data *)data)) + return; + } + else if (event == ENC_START_FILE) + { + if (on_start_file((struct enc_file_event_data *)data)) + return; + } + else if (event == ENC_END_FILE) + { + if (on_end_file((struct enc_file_event_data *)data)) + return; + } + else + { + return; + } + + ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR; +} /* enc_events_callback */ + +/* convert native pcm samples to wav format samples */ +static void chunk_to_wav_format(uint32_t *src, uint32_t *dst) ICODE_ATTR; +static void chunk_to_wav_format(uint32_t *src, uint32_t *dst) +{ + if (num_channels == 1) + { + /* On big endian: + * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| + * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| => + * |mmmmmmmmMMMMMMMM|mmmmmmmmMMMMMMMM| + * + * On little endian: + * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| + * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| => + * |mmmmmmmmMMMMMMMM|mmmmmmmmMMMMMMMM| + */ + uint32_t *src_end = src + PCM_SAMP_PER_CHUNK; + + inline void to_mono(uint32_t **src, uint32_t **dst) + { + int32_t lr1, lr2; + + lr1 = *(*src)++; + lr1 = ((int16_t)lr1 + (lr1 >> 16)) >> 1; + + lr2 = *(*src)++; + lr2 = ((int16_t)lr2 + (lr2 >> 16)) >> 1; + *(*dst)++ = swap_odd_even_be32((lr1 << 16) | (uint16_t)lr2); + } /* to_mono */ + + do { - /* update wave header size entries: special to WAV format */ - *(long*)(head_buffer+ 4) = htole32(num_file_bytes + 36); - *(long*)(head_buffer+40) = htole32(num_file_bytes); + to_mono(&src, &dst); + to_mono(&src, &dst); + to_mono(&src, &dst); + to_mono(&src, &dst); + to_mono(&src, &dst); + to_mono(&src, &dst); + to_mono(&src, &dst); + to_mono(&src, &dst); } + while (src < src_end); } -} + else + { +#ifdef ROCKBOX_BIG_ENDIAN + /* |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| => + * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| + */ + uint32_t *src_end = src + PCM_SAMP_PER_CHUNK; -/* main codec entry point */ -enum codec_status codec_start(struct codec_api* api) + do + { + *dst++ = swap_odd_even32(*src++); + *dst++ = swap_odd_even32(*src++); + *dst++ = swap_odd_even32(*src++); + *dst++ = swap_odd_even32(*src++); + *dst++ = swap_odd_even32(*src++); + *dst++ = swap_odd_even32(*src++); + *dst++ = swap_odd_even32(*src++); + *dst++ = swap_odd_even32(*src++); + } + while (src < src_end); +#else + /* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| => + * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| + */ + ci->memcpy(dst, src, PCM_CHUNK_SIZE); +#endif + } +} /* chunk_to_wav_format */ + +static bool init_encoder(void) { - int i; - long lr; - unsigned long t; - unsigned long *src; - unsigned long *dst; - int chunk_size, num_chunks, samp_per_chunk; - int enc_buffer_size; - int enc_quality; - bool cpu_boosted = true; /* start boosted */ + struct enc_inputs inputs; + struct enc_parameters params; - ci = api; // copy to global api pointer + if (ci->enc_get_inputs == NULL || + ci->enc_set_parameters == NULL || + ci->enc_get_chunk == NULL || + ci->enc_finish_chunk == NULL || + ci->enc_pcm_buf_near_empty == NULL || + ci->enc_get_pcm_data == NULL ) + return false; - if(ci->enc_get_inputs == NULL || - ci->enc_set_parameters == NULL || - ci->enc_alloc_chunk == NULL || - ci->enc_free_chunk == NULL || - ci->enc_wavbuf_near_empty == NULL || - ci->enc_get_wav_data == NULL || - ci->enc_set_header_callback == NULL ) - return CODEC_ERROR; + ci->enc_get_inputs(&inputs); - ci->cpu_boost(true); + if (inputs.config->afmt != AFMT_PCM_WAV) + return false; - *ci->enc_set_header_callback = enc_set_header; - ci->enc_get_inputs(&enc_buffer_size, &enc_channels, &enc_quality); + sample_rate = inputs.sample_rate; + num_channels = inputs.num_channels; /* configure the buffer system */ - chunk_size = sizeof(long) + CHUNK_SIZE * enc_channels / 2; - num_chunks = enc_buffer_size / chunk_size; - samp_per_chunk = CHUNK_SIZE / 4; - - /* inform the main program about buffer dimensions and other params */ - ci->enc_set_parameters(chunk_size, num_chunks, samp_per_chunk, - (enc_channels == 2) ? wav_header : wav_header_mono, - sizeof(wav_header), AFMT_PCM_WAV); + params.afmt = AFMT_PCM_WAV; + enc_size = PCM_CHUNK_SIZE*inputs.num_channels / 2; + params.chunk_size = enc_size; + params.enc_sample_rate = sample_rate; + params.reserve_bytes = 0; + params.events_callback = enc_events_callback; + ci->enc_set_parameters(¶ms); + + return true; +} /* init_encoder */ + +/* main codec entry point */ +enum codec_status codec_start(struct codec_api* api) +{ + bool cpu_boosted; + + ci = api; // copy to global api pointer + +#ifdef USE_IRAM + ci->memcpy(iramstart, iramcopy, iramend - iramstart); + ci->memset(iedata, 0, iend - iedata); +#endif + + if (!init_encoder()) + { + ci->enc_codec_loaded = -1; + return CODEC_ERROR; + } /* main application waits for this flag during encoder loading */ - ci->enc_codec_loaded = true; + ci->enc_codec_loaded = 1; + + ci->cpu_boost(true); + cpu_boosted = true; /* main encoding loop */ - while(!ci->stop_codec) + while (!ci->stop_codec) { - while((src = (unsigned long*)ci->enc_get_wav_data(CHUNK_SIZE)) != NULL) + uint32_t *src; + + while ((src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL) { - if(ci->stop_codec) + struct enc_chunk_hdr *chunk; + + if (ci->stop_codec) break; - if(ci->enc_wavbuf_near_empty() == 0) + if (!cpu_boosted && ci->enc_pcm_buf_near_empty() == 0) { - if(!cpu_boosted) - { - ci->cpu_boost(true); - cpu_boosted = true; - } + ci->cpu_boost(true); + cpu_boosted = true; } - dst = (unsigned long*)ci->enc_alloc_chunk(); - *dst++ = CHUNK_SIZE * enc_channels / 2; /* set size info */ + chunk = ci->enc_get_chunk(); + chunk->enc_size = enc_size; + chunk->num_pcm = PCM_SAMP_PER_CHUNK; + chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); - if(enc_channels == 2) - { - /* swap byte order & copy to destination */ - for (i=0; i> 8) & 0xff00ff) | ((t << 8) & 0xff00ff00); - } - } - else - { - /* mix left/right, swap byte order & copy to destination */ - for (i=0; i>16) + (lr>>16)) >> 1; /* left+right */ - t = (lr << 16); - lr = (long)*src++; - lr = (((lr<<16)>>16) + (lr>>16)) >> 1; /* left+right */ - t |= lr & 0xffff; - *dst++ = ((t >> 8) & 0xff00ff) | ((t << 8) & 0xff00ff00); - } - } + chunk_to_wav_format(src, (uint32_t *)chunk->enc_data); - ci->enc_free_chunk(); + ci->enc_finish_chunk(); ci->yield(); } - if(ci->enc_wavbuf_near_empty()) + if (cpu_boosted && ci->enc_pcm_buf_near_empty() != 0) { - if(cpu_boosted) - { - ci->cpu_boost(false); - cpu_boosted = false; - } + ci->cpu_boost(false); + cpu_boosted = false; } ci->yield(); } - if(cpu_boosted) /* set initial boost state */ + if (cpu_boosted) /* set initial boost state */ ci->cpu_boost(false); /* reset parameters to initial state */ - ci->enc_set_parameters(0, 0, 0, 0, 0, 0); + ci->enc_set_parameters(NULL); /* main application waits for this flag during encoder removing */ - ci->enc_codec_loaded = false; + ci->enc_codec_loaded = 0; return CODEC_OK; -} -#endif +} /* codec_start */ + +#endif /* ndef SIMULATOR */ Index: apps/codecs/wavpack_enc.c =================================================================== RCS file: /cvsroot/rockbox/apps/codecs/wavpack_enc.c,v retrieving revision 1.2 diff -u -r1.2 wavpack_enc.c --- apps/codecs/wavpack_enc.c 23 Sep 2006 14:38:04 -0000 1.2 +++ apps/codecs/wavpack_enc.c 16 Oct 2006 23:32:35 -0000 @@ -22,201 +22,474 @@ #include "codeclib.h" #include "libwavpack/wavpack.h" -CODEC_HEADER +CODEC_ENC_HEADER -typedef unsigned long uint32; -typedef unsigned short uint16; -typedef unsigned char uint8; - -static unsigned char wav_header_ster [46] = -{33,22,'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',16, - 0,0,0,1,0,2,0,0x44,0xac,0,0,0x10,0xb1,2,0,4,0,16,0,'d','a','t','a',0,0,0,0}; - -static unsigned char wav_header_mono [46] = -{33,22,'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',16, - 0,0,0,1,0,1,0,0x44,0xac,0,0,0x88,0x58,1,0,2,0,16,0,'d','a','t','a',0,0,0,0}; +#ifdef USE_IRAM +extern char iramcopy[]; +extern char iramstart[]; +extern char iramend[]; +extern char iedata[]; +extern char iend[]; +#endif + +/** Types **/ +typedef struct +{ + uint8_t type; /* Type of metadata */ + uint8_t word_size; /* Size of metadata in words */ +} WavpackMetadataHeader; +struct riff_header +{ + uint8_t riff_id[4]; /* 00h - "RIFF" */ + uint32_t riff_size; /* 04h - sz following headers + data_size */ + /* format header */ + uint8_t format[4]; /* 08h - "WAVE" */ + uint8_t format_id[4]; /* 0Ch - "fmt " */ + uint32_t format_size; /* 10h - 16 for PCM (sz format data) */ + /* format data */ + uint16_t audio_format; /* 14h - 1=PCM */ + uint16_t num_channels; /* 16h - 1=M, 2=S, etc. */ + uint32_t sample_rate; /* 18h - HZ */ + uint32_t byte_rate; /* 1Ch - num_channels*sample_rate*bits_per_sample/8 */ + uint16_t block_align; /* 20h - num_channels*bits_per_samples/8 */ + uint16_t bits_per_sample; /* 22h - 8=8 bits, 16=16 bits, etc. */ + /* Not for audio_format=1 (PCM) */ +/* unsigned short extra_param_size; 24h - size of extra data */ +/* unsigned char *extra_params; */ + /* data header */ + uint8_t data_id[4]; /* 24h - "data" */ + uint32_t data_size; /* 28h - num_samples*num_channels*bits_per_sample/8 */ +/* unsigned char *data; 2ch - actual sound data */ +}; + +#define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */ +#define RIFF_FMT_DATA_SIZE 16 /* audio_format -> bits_per_sample */ +#define RIFF_DATA_HEADER_SIZE 8 /* data_id -> data_size */ + +#define PCM_DEPTH_BITS 16 +#define PCM_DEPTH_BYTES 2 +#define PCM_SAMP_PER_CHUNK 5000 +#define PCM_CHUNK_SIZE (4*PCM_SAMP_PER_CHUNK) + +/** Data **/ static struct codec_api *ci; -static int enc_channels; +static int8_t input_buffer[PCM_CHUNK_SIZE*2] IBSS_ATTR; +static WavpackConfig config IBSS_ATTR; +static WavpackContext *wpc; +static int32_t data_size, input_size, input_step IBSS_ATTR; + +static const WavpackMetadataHeader wvpk_mdh = +{ + ID_RIFF_HEADER, + sizeof (struct riff_header) / sizeof (uint16_t), +}; + +static const struct riff_header riff_header = +{ + /* "RIFF" header */ + { 'R', 'I', 'F', 'F' }, /* riff_id */ + 0, /* riff_size (*) */ + /* format header */ + { 'W', 'A', 'V', 'E' }, /* format */ + { 'f', 'm', 't', ' ' }, /* format_id */ + H_TO_LE32(16), /* format_size */ + /* format data */ + H_TO_LE16(1), /* audio_format */ + 0, /* num_channels (*) */ + 0, /* sample_rate (*) */ + 0, /* byte_rate (*) */ + 0, /* block_align (*) */ + H_TO_LE16(PCM_DEPTH_BITS), /* bits_per_sample */ + /* data header */ + { 'd', 'a', 't', 'a' }, /* data_id */ + 0 /* data_size (*) */ + /* (*) updated during ENC_END_FILE event */ +}; + +static void chunk_to_int32(int32_t *src) ICODE_ATTR; +static void chunk_to_int32(int32_t *src) +{ + int32_t *dst = (int32_t *)input_buffer + PCM_SAMP_PER_CHUNK; + int32_t *src_end = dst + PCM_SAMP_PER_CHUNK; + + /* copy to IRAM before converting data */ + memcpy(dst, src, PCM_CHUNK_SIZE); -#define CHUNK_SIZE 20000 + src = dst; + dst = (int32_t *)input_buffer; -static long input_buffer[CHUNK_SIZE/2] IBSS_ATTR; + if (config.num_channels == 1) + { + /* + * |llllllllllllllll|rrrrrrrrrrrrrrrr| => + * |mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm| + */ + inline void to_int32(int32_t **src, int32_t **dst) + { + int32_t t = *(*src)++; + /* endianness irrelevant */ + *(*dst)++ = ((int16_t)t + (t >> 16)) >> 1; + } /* to_int32 */ -/* update file header info callback function */ -void enc_set_header(void *head_buffer, /* ptr to the file header data */ - int head_size, /* size of this header data */ - int num_pcm_sampl, /* amount of processed pcm samples */ - bool is_file_header) /* update file/chunk header */ -{ - if(is_file_header) - { - /* update file header before file closing */ - if(sizeof(WavpackHeader) + sizeof(wav_header_mono) < (unsigned)head_size) - { - char* riff_header = (char*)head_buffer + sizeof(WavpackHeader); - char* wv_header = (char*)head_buffer + sizeof(wav_header_mono); - int num_file_bytes = num_pcm_sampl * 2 * enc_channels; - unsigned long ckSize; - - /* RIFF header and WVPK header have to be swapped */ - /* copy wavpack header to file start position */ - ci->memcpy(head_buffer, wv_header, sizeof(WavpackHeader)); - wv_header = head_buffer; /* recalc wavpack header position */ - - if(enc_channels == 2) - ci->memcpy(riff_header, wav_header_ster, sizeof(wav_header_ster)); - else - ci->memcpy(riff_header, wav_header_mono, sizeof(wav_header_mono)); - - /* update the Wavpack header first chunk size & total frame count */ - ckSize = htole32(((WavpackHeader*)wv_header)->ckSize) - + sizeof(wav_header_mono); - ((WavpackHeader*)wv_header)->total_samples = htole32(num_pcm_sampl); - ((WavpackHeader*)wv_header)->ckSize = htole32(ckSize); - - /* update the RIFF WAV header size entries */ - *(long*)(riff_header+ 6) = htole32(num_file_bytes + 36); - *(long*)(riff_header+42) = htole32(num_file_bytes); + do + { + /* read 10 longs and write 10 longs */ + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); } + while(src < src_end); + + return; } else { - /* update timestamp (block_index) */ - ((WavpackHeader*)head_buffer)->block_index = htole32(num_pcm_sampl); + /* + * |llllllllllllllll|rrrrrrrrrrrrrrrr| => + * |llllllllllllllllllllllllllllllll|rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr| + */ + inline void to_int32(int32_t **src, int32_t **dst) + { + int32_t t = *(*src)++; +#ifdef ROCKBOX_BIG_ENDIAN + *(*dst)++ = t >> 16, *(*dst)++ = (int16_t)t; +#else + *(*dst)++ = (int16_t)t, *(*dst)++ = t >> 16; +#endif + } /* to_int32 */ + + do + { + /* read 10 longs and write 20 longs */ + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + to_int32(&src, &dst); + } + while (src < src_end); + + return; } -} +} /* chunk_to_int32 */ +/* called very often - inline */ +static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR; +static inline bool is_file_data_ok(struct enc_file_event_data *data) +{ + return data->rec_file >= 0 && (long)data->chunk->flags >= 0; +} /* is_file_data_ok */ -enum codec_status codec_start(struct codec_api* api) +/* called very often - inline */ +static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR; +static inline bool on_write_chunk(struct enc_file_event_data *data) +{ + if (!is_file_data_ok(data)) + return false; + + if (data->chunk->enc_data == NULL) + { +#ifdef ROCKBOX_HAS_LOGF + ci->logf("wvpk enc: NULL data"); +#endif + return true; + } + + /* update timestamp (block_index) */ + ((WavpackHeader *)data->chunk->enc_data)->block_index = + htole32(data->num_pcm_samples); + + if (ci->write(data->rec_file, data->chunk->enc_data, + data->chunk->enc_size) != (ssize_t)data->chunk->enc_size) + return false; + + data->num_pcm_samples += data->chunk->num_pcm; + return true; +} /* on_write_chunk */ + +static bool on_start_file(struct enc_file_event_data *data) +{ + if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0') + return false; + + data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC); + + if (data->rec_file < 0) + return false; + + /* reset sample count */ + data->num_pcm_samples = 0; + + /* write template headers */ + if (ci->write(data->rec_file, &wvpk_mdh, sizeof (wvpk_mdh)) + != sizeof (wvpk_mdh) || + ci->write(data->rec_file, &riff_header, sizeof (riff_header)) + != sizeof (riff_header)) + { + return false; + } + + data->new_enc_size += sizeof(wvpk_mdh) + sizeof(riff_header); + return true; +} /* on_start_file */ + +static bool on_end_file(struct enc_file_event_data *data) +{ + struct + { + WavpackMetadataHeader wpmdh; + struct riff_header rhdr; + WavpackHeader wph; + } __attribute__ ((__packed__)) h; + + uint32_t data_size; + + if (!is_file_data_ok(data)) + return false; + + /* read template headers at start */ + if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 || + ci->read(data->rec_file, &h, sizeof (h)) != sizeof (h)) + return false; + + data_size = data->num_pcm_samples*config.num_channels*PCM_DEPTH_BYTES; + + /** "RIFF" header **/ + h.rhdr.riff_size = htole32(RIFF_FMT_HEADER_SIZE + + RIFF_FMT_DATA_SIZE + RIFF_DATA_HEADER_SIZE + data_size); + + /* format data */ + h.rhdr.num_channels = htole16(config.num_channels); + h.rhdr.sample_rate = htole32(config.sample_rate); + h.rhdr.byte_rate = htole32(config.sample_rate*config.num_channels* + PCM_DEPTH_BYTES); + h.rhdr.block_align = htole16(config.num_channels*PCM_DEPTH_BYTES); + + /* data header */ + h.rhdr.data_size = htole32(data_size); + + /** Wavpack header **/ + h.wph.ckSize = htole32(letoh32(h.wph.ckSize) + sizeof (h.wpmdh) + + sizeof (h.rhdr)); + h.wph.total_samples = htole32(data->num_pcm_samples); + + /* MDH|RIFF|WVPK => WVPK|MDH|RIFF */ + if (ci->lseek(data->rec_file, 0, SEEK_SET) + != 0 || + ci->write(data->rec_file, &h.wph, sizeof (h.wph)) + != sizeof (h.wph) || + ci->write(data->rec_file, &h.wpmdh, sizeof (h.wpmdh)) + != sizeof (h.wpmdh) || + ci->write(data->rec_file, &h.rhdr, sizeof (h.rhdr)) + != sizeof (h.rhdr)) + { + return false; + } + + ci->fsync(data->rec_file); + ci->close(data->rec_file); + data->rec_file = -1; + + return true; +} /* on_end_file */ + +static void enc_events_callback(enum enc_events event, void *data) ICODE_ATTR; +static void enc_events_callback(enum enc_events event, void *data) +{ + if (event == ENC_WRITE_CHUNK) + { + if (on_write_chunk((struct enc_file_event_data *)data)) + return; + } + else if (event == ENC_START_FILE) + { + /* write metadata header and RIFF header */ + if (on_start_file((struct enc_file_event_data *)data)) + return; + } + else if (event == ENC_END_FILE) + { + if (on_end_file((struct enc_file_event_data *)data)) + return; + } + else + { + return; + } + + ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR; +} /* enc_events_callback */ + +static bool init_encoder(void) { - int i; - long t; - uint32 *src; - uint32 *dst; - int chunk_size, num_chunks, samp_per_chunk; - int enc_buffer_size; - int enc_quality; - WavpackConfig config; - WavpackContext *wpc; - bool cpu_boosted = true; /* start boosted */ + struct enc_inputs inputs; + struct enc_parameters params; - ci = api; // copy to global api pointer - codec_init(ci); - if(ci->enc_get_inputs == NULL || - ci->enc_set_parameters == NULL || - ci->enc_alloc_chunk == NULL || - ci->enc_free_chunk == NULL || - ci->enc_wavbuf_near_empty == NULL || - ci->enc_get_wav_data == NULL || - ci->enc_set_header_callback == NULL ) - return CODEC_ERROR; + if (ci->enc_get_inputs == NULL || + ci->enc_set_parameters == NULL || + ci->enc_get_chunk == NULL || + ci->enc_finish_chunk == NULL || + ci->enc_pcm_buf_near_empty == NULL || + ci->enc_get_pcm_data == NULL || + ci->enc_unget_pcm_data == NULL ) + return false; + + ci->enc_get_inputs(&inputs); + + if (inputs.config->afmt != AFMT_WAVPACK) + return false; + + memset(&config, 0, sizeof (config)); + config.bits_per_sample = PCM_DEPTH_BITS; + config.bytes_per_sample = PCM_DEPTH_BYTES; + config.sample_rate = inputs.sample_rate; + config.num_channels = inputs.num_channels; - ci->cpu_boost(true); + wpc = WavpackOpenFileOutput(); - *ci->enc_set_header_callback = enc_set_header; - ci->enc_get_inputs(&enc_buffer_size, &enc_channels, &enc_quality); + if (!WavpackSetConfiguration(wpc, &config, -1)) + return false; /* configure the buffer system */ - chunk_size = sizeof(long) + CHUNK_SIZE * enc_channels / 2; - num_chunks = enc_buffer_size / chunk_size; - samp_per_chunk = CHUNK_SIZE / 4; - - /* inform the main program about buffer dimensions and other params */ - /* add wav_header_mono as place holder to file start position */ - /* wav header and wvpk header have to be reordered later */ - ci->enc_set_parameters(chunk_size, num_chunks, samp_per_chunk, - wav_header_mono, sizeof(wav_header_mono), - AFMT_WAVPACK); - - wpc = WavpackOpenFileOutput (); - - memset (&config, 0, sizeof (config)); - config.bits_per_sample = 16; - config.bytes_per_sample = 2; - config.sample_rate = 44100; - config.num_channels = enc_channels; + params.afmt = AFMT_WAVPACK; + input_size = PCM_CHUNK_SIZE*inputs.num_channels / 2; + data_size = 105*input_size / 100; + input_size *= 2; + input_step = input_size / 4; + params.chunk_size = data_size; + params.enc_sample_rate = inputs.sample_rate; + params.reserve_bytes = 0; + params.events_callback = enc_events_callback; + + ci->enc_set_parameters(¶ms); + + return true; +} /* init_encoder */ + +enum codec_status codec_start(struct codec_api* api) +{ + bool cpu_boosted; - if (!WavpackSetConfiguration (wpc, &config, 1)) + ci = api; /* copy to global api pointer */ + +#ifdef USE_IRAM + ci->memcpy(iramstart, iramcopy, iramend - iramstart); + ci->memset(iedata, 0, iend - iedata); +#endif + + /* initialize params and config */ + if (!init_encoder()) + { + ci->enc_codec_loaded = -1; return CODEC_ERROR; + } /* main application waits for this flag during encoder loading */ - ci->enc_codec_loaded = true; + ci->enc_codec_loaded = 1; + + ci->cpu_boost(true); + cpu_boosted = true; /* main encoding loop */ - while(!ci->stop_codec) + while (!ci->stop_codec) { - while((src = (uint32*)ci->enc_get_wav_data(CHUNK_SIZE)) != NULL) + uint8_t *src; + + while ((src = ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL) { - if(ci->stop_codec) + struct enc_chunk_hdr *chunk; + bool abort_chunk; + uint8_t *dst; + uint8_t *src_end; + + if (ci->stop_codec) break; - if(ci->enc_wavbuf_near_empty() == 0) + abort_chunk = true; + + if (!cpu_boosted && ci->enc_pcm_buf_near_empty() == 0) { - if(!cpu_boosted) - { - ci->cpu_boost(true); - cpu_boosted = true; - } + ci->cpu_boost(true); + cpu_boosted = true; } - dst = (uint32*)ci->enc_alloc_chunk() + 1; + chunk = ci->enc_get_chunk(); - WavpackStartBlock (wpc, (uint8*)dst, (uint8*)dst + CHUNK_SIZE); + /* reset counts and pointer */ + chunk->enc_size = 0; + chunk->num_pcm = 0; + chunk->enc_data = NULL; - if(enc_channels == 2) - { - for (i=0; i> 16; - input_buffer[2*i + 1] = (short)t; - } - } - else + WavpackStartBlock(wpc, dst, dst + data_size); + + chunk_to_int32((uint32_t*)src); + src = input_buffer; + src_end = src + input_size; + + /* encode chunk in four steps yielding between each */ + do { - for (i=0; i>16) + (t>>16)) >> 1; /* left+right */ - - input_buffer[i] = t; + chunk->num_pcm += PCM_SAMP_PER_CHUNK/4; + ci->yield(); + /* could've been stopped in some way */ + abort_chunk = ci->stop_codec || + (chunk->flags & CHUNKF_ABORT); } - } - - if (!WavpackPackSamples (wpc, input_buffer, CHUNK_SIZE/4)) - return CODEC_ERROR; - /* finish the chunk and store chunk size info */ - dst[-1] = WavpackFinishBlock (wpc); + src += input_step; + } + while (!abort_chunk && src < src_end); - ci->enc_free_chunk(); - ci->yield(); + if (!abort_chunk) + { + chunk->enc_data = dst; + if (chunk->num_pcm < PCM_SAMP_PER_CHUNK) + ci->enc_unget_pcm_data(PCM_CHUNK_SIZE - chunk->num_pcm*4); + /* finish the chunk and store chunk size info */ + chunk->enc_size = WavpackFinishBlock(wpc); + ci->enc_finish_chunk(); + } } - if(ci->enc_wavbuf_near_empty()) + if (cpu_boosted && ci->enc_pcm_buf_near_empty() != 0) { - if(cpu_boosted) - { - ci->cpu_boost(false); - cpu_boosted = false; - } + ci->cpu_boost(false); + cpu_boosted = false; } + ci->yield(); } - if(cpu_boosted) /* set initial boost state */ + if (cpu_boosted) /* set initial boost state */ ci->cpu_boost(false); /* reset parameters to initial state */ - ci->enc_set_parameters(0, 0, 0, 0, 0, 0); + ci->enc_set_parameters(NULL); /* main application waits for this flag during encoder removing */ - ci->enc_codec_loaded = false; + ci->enc_codec_loaded = 0; return CODEC_OK; -} -#endif +} /* codec_start */ + +#endif /* ndef SIMULATOR */ Index: apps/codecs/libwavpack/bits.c =================================================================== RCS file: /cvsroot/rockbox/apps/codecs/libwavpack/bits.c,v retrieving revision 1.5 diff -u -r1.5 bits.c --- apps/codecs/libwavpack/bits.c 26 Mar 2006 22:54:15 -0000 1.5 +++ apps/codecs/libwavpack/bits.c 16 Oct 2006 23:32:36 -0000 @@ -15,6 +15,7 @@ // the malloc() system is provided. #include "wavpack.h" +#include "system.h" #include @@ -118,19 +119,16 @@ void little_endian_to_native (void *data, char *format) { uchar *cp = (uchar *) data; - int32_t temp; while (*format) { switch (*format) { case 'L': - temp = cp [0] + ((int32_t) cp [1] << 8) + ((int32_t) cp [2] << 16) + ((int32_t) cp [3] << 24); - * (int32_t *) cp = temp; + *(long *)cp = letoh32(*(long *)cp); cp += 4; break; case 'S': - temp = cp [0] + (cp [1] << 8); - * (short *) cp = (short) temp; + *(short *)cp = letoh16(*(short *)cp); cp += 2; break; @@ -148,28 +146,22 @@ void native_to_little_endian (void *data, char *format) { uchar *cp = (uchar *) data; - int32_t temp; while (*format) { switch (*format) { case 'L': - temp = * (int32_t *) cp; - *cp++ = (uchar) temp; - *cp++ = (uchar) (temp >> 8); - *cp++ = (uchar) (temp >> 16); - *cp++ = (uchar) (temp >> 24); + *(long *)cp = htole32(*(long *)cp); + cp += 4; break; case 'S': - temp = * (short *) cp; - *cp++ = (uchar) temp; - *cp++ = (uchar) (temp >> 8); + *(short *)cp = htole16(*(short *)cp); + cp += 2; break; default: if (*format >= '0' && *format <= '9') cp += *format - '0'; - break; } Index: apps/gui/statusbar.c =================================================================== RCS file: /cvsroot/rockbox/apps/gui/statusbar.c,v retrieving revision 1.32 diff -u -r1.32 statusbar.c --- apps/gui/statusbar.c 26 Sep 2006 11:56:58 -0000 1.32 +++ apps/gui/statusbar.c 16 Oct 2006 23:32:36 -0000 @@ -124,19 +124,6 @@ #endif #define STATUSBAR_TIME_X_END(statusbar_width) statusbar_width - 1 - \ STATUSBAR_DISK_WIDTH -#if defined(HAVE_RECORDING) -/* analogue frequency numbers taken from the order of frequencies in sample_rate */ -#define FREQ_44 7 -#define FREQ_48 8 -#define FREQ_32 6 -#define FREQ_22 4 -#define FREQ_24 5 -#define FREQ_16 3 -#ifdef HAVE_SPDIF_IN -#define SOURCE_SPDIF 2 -#endif -#endif - struct gui_syncstatusbar statusbars; void gui_statusbar_init(struct gui_statusbar * bar) @@ -600,41 +587,113 @@ #endif #ifdef HAVE_RECORDING -void gui_statusbar_icon_recording_info(struct screen * display) +#if CONFIG_CODEC == SWCODEC +/** + * Write a number to the display using bitmaps and return new position + */ +static int write_bitmap_number(struct screen * display, int value, + int x, int y) { -#if (CONFIG_CODEC != SWCODEC) || (defined(SIMULATOR) && defined(HAVE_SPDIF_IN)) - char buffer[3]; + char buf[12], *ptr; + snprintf(buf, sizeof(buf), "%d", value); + + for (ptr = buf; *ptr != '\0'; ptr++, x += BM_GLYPH_WIDTH) + display->mono_bitmap(bitmap_glyphs_4x8[*ptr - '0'], x, y, + BM_GLYPH_WIDTH, STATUSBAR_HEIGHT); + return x; +} + +/** + * Write format info bitmaps - right justified + */ +static void gui_statusbar_write_format_info(struct screen * display) +{ + /* Can't fit info for sw codec targets in statusbar using FONT_SYSFIXED + so must use icons */ + int rec_format = global_settings.rec_format; + unsigned bitrk = 0; /* compiler warns about unitialized use !! */ + int xpos = STATUSBAR_ENCODER_X_POS; + int width = STATUSBAR_ENCODER_WIDTH; + const unsigned char *bm = bitmap_formats_18x8[rec_format]; + + if (rec_format == REC_FORMAT_MPA_L3) + { + /* Special handling for mp3 */ + bitrk = global_settings.mp3_enc_config.bitrate; + bitrk = mp3_enc_bitr[bitrk]; + + width = BM_MPA_L3_M_WIDTH; + + /* Slide 'M' to right if fewer than three digits used */ + if (bitrk > 999) + bitrk = 999; /* neurotic safety check if corrupted */ + else + { + if (bitrk < 100) + xpos += BM_GLYPH_WIDTH; + if (bitrk < 10) + xpos += BM_GLYPH_WIDTH; + } + } + + + /* Show bitmap - clipping right edge if needed */ + display->mono_bitmap_part(bm, 0, 0, STATUSBAR_ENCODER_WIDTH, + xpos, STATUSBAR_Y_POS, width, STATUSBAR_HEIGHT); + + if (rec_format == REC_FORMAT_MPA_L3) + { + xpos += BM_MPA_L3_M_WIDTH; /* to right of 'M' */ + write_bitmap_number(display, bitrk, xpos, STATUSBAR_Y_POS); + } +} + +/** + * Write sample rate using bitmaps - left justified + */ +static void gui_statusbar_write_samplerate_info(struct screen * display) +{ + unsigned long samprk; + int xpos; + +#ifdef SIMULATOR + samprk = 44100; +#else +#ifdef HAVE_SPDIF_IN + if (global_settings.rec_source == AUDIO_SRC_SPDIF) + /* Use rate in use, not current measured rate if it changed */ + samprk = pcm_rec_sample_rate(); + else #endif + samprk = rec_freq_sampr[global_settings.rec_frequency]; +#endif /* SIMULATOR */ + + samprk /= 1000; + if (samprk > 99) + samprk = 99; /* Limit to 3 glyphs */ + + xpos = write_bitmap_number(display, (unsigned)samprk, + STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS); + + /* write the 'k' */ + display->mono_bitmap(bitmap_glyphs_4x8[Glyph_4x8_k], xpos, + STATUSBAR_Y_POS, BM_GLYPH_WIDTH, + STATUSBAR_HEIGHT); +} +#endif /* CONFIG_CODEC == SWCODEC */ + +void gui_statusbar_icon_recording_info(struct screen * display) +{ #if CONFIG_CODEC != SWCODEC + char buffer[3]; int width, height; - static char* const sample_rate[12] = - { - "8", - "11", - "12", - "16", - "22", - "24", - "32", - "44", - "48", - "64", - "88", - "96" - }; - display->setfont(FONT_SYSFIXED); -#endif +#endif /* CONFIG_CODEC != SWCODEC */ /* Display Codec info in statusbar */ #if CONFIG_CODEC == SWCODEC - /* Can't fit info for sw codec targets in statusbar using FONT_SYSFIXED - so must use icons */ - display->mono_bitmap(bitmap_icons_18x8[global_settings.rec_quality], - STATUSBAR_ENCODER_X_POS, STATUSBAR_Y_POS, - STATUSBAR_ENCODER_WIDTH, STATUSBAR_HEIGHT); -#else - + gui_statusbar_write_format_info(display); +#else /* !SWCODEC */ display->mono_bitmap(bitmap_icons_5x8[Icon_q], STATUSBAR_ENCODER_X_POS + 8, STATUSBAR_Y_POS, 5, STATUSBAR_HEIGHT); @@ -643,56 +702,37 @@ display->getstringsize(buffer, &width, &height); if (height <= STATUSBAR_HEIGHT) display->putsxy(STATUSBAR_ENCODER_X_POS + 13, STATUSBAR_Y_POS, buffer); -#endif +#endif /* CONFIG_CODEC == SWCODEC */ /* Display Samplerate info in statusbar */ -#if defined(HAVE_SPDIF_IN) - if (global_settings.rec_source == SOURCE_SPDIF) +#if CONFIG_CODEC == SWCODEC + /* SWCODEC targets use bitmaps for glyphs */ + gui_statusbar_write_samplerate_info(display); +#else /* !SWCODEC */ + /* hwcodec targets have sysfont characters */ +#ifdef HAVE_SPDIF_IN + if (global_settings.rec_source == AUDIO_SRC_SPDIF) { -#if (CONFIG_CODEC != MAS3587F) && !defined(SIMULATOR) - display->mono_bitmap(bitmap_icons_12x8[audio_get_spdif_sample_rate()], - STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS, - STATUSBAR_RECFREQ_WIDTH, STATUSBAR_HEIGHT); -#else /* Can't measure S/PDIF sample rate on Archos/Sim yet */ snprintf(buffer, sizeof(buffer), "--"); -#endif } else #endif /* HAVE_SPDIF_IN */ { - /* Analogue frequency in wrong order so remap settings numbers */ - int freq = global_settings.rec_frequency; - if (freq == 0) - freq = FREQ_44; - else if (freq == 1) - freq = FREQ_48; - else if (freq == 2) - freq = FREQ_32; - else if (freq == 3) - freq = FREQ_22; - else if (freq == 4) - freq = FREQ_24; - else if (freq == 5) - freq = FREQ_16; - -#if CONFIG_CODEC == SWCODEC - /* samplerate icons for swcodec targets*/ - display->mono_bitmap(bitmap_icons_12x8[freq], - STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS, - STATUSBAR_RECFREQ_WIDTH, STATUSBAR_HEIGHT); - } -#else - /* hwcodec targets have sysfont characters */ - snprintf(buffer, sizeof(buffer), "%s", sample_rate[freq]); - display->getstringsize(buffer, &width, &height); + static char const * const freq_strings[12] = + { "44", "48", "32", "22", "24", "16" }; + snprintf(buffer, sizeof(buffer), "%s", + freq_strings[global_settings.rec_frequency]); } - if (height <= STATUSBAR_HEIGHT) - display->putsxy(STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS, buffer); + display->getstringsize(buffer, &width, &height); + + if (height <= STATUSBAR_HEIGHT) + display->putsxy(STATUSBAR_RECFREQ_X_POS, STATUSBAR_Y_POS, buffer); + + display->setfont(FONT_UI); +#endif /* CONFIG_CODEC == SWCODEC */ - display->setfont(FONT_UI); -#endif /* Display Channel status in status bar */ if(global_settings.rec_channels) { Index: apps/lang/english.lang =================================================================== RCS file: /cvsroot/rockbox/apps/lang/english.lang,v retrieving revision 1.285 diff -u -r1.285 english.lang --- apps/lang/english.lang 9 Oct 2006 11:22:42 -0000 1.285 +++ apps/lang/english.lang 16 Oct 2006 23:32:39 -0000 @@ -9780,7 +9780,7 @@ id: VOICE_KBIT_PER_SEC - desc: spoken only, for file extension + desc: spoken only, a unit postfix user: *: "" @@ -9940,3 +9940,129 @@ *: "Random" + + id: LANG_RECORDING_FORMAT + desc: audio format item in recording menu + user: + + *: "Format" + + + *: "Format" + + + *: "Format" + + + + id: LANG_AFMT_MPA_L3 + desc: audio format description + user: + + *: "MPEG Layer 3" + + + *: "MPEG Layer 3" + + + *: "MPEG Layer 3" + + + + id: LANG_AFMT_PCM_WAV + desc: audio format description + user: + + *: "PCM Wave" + + + *: "PCM Wave" + + + *: "PCM Wave" + + + + id: LANG_AFMT_WAVPACK + desc: audio format description + user: + + *: "WavPack" + + + *: "WavPack" + + + *: "WavPack" + + + + id: LANG_ENCODER_SETTINGS + desc: encoder settings + user: + + *: "Encoder Settings" + + + *: "Encoder Settings" + + + *: "Encoder Settings" + + + + id: LANG_NO_SETTINGS + desc: when something has settings in a certain context + user: + + *: "(No Settings)" + + + *: "(No Settings)" + + + *: "No settings available" + + + + id: LANG_SOURCE_FREQUENCY + desc: when recording source frequency setting must follow source + user: + + *: "Source Frequency" + + + *: "Source Frequency" + + + *: "Source Frequency" + + + + id: LANG_BITRATE + desc: bits-kilobits per unit time + user: + + *: "Bitrate" + + + *: "Bitrate" + + + *: "Bitrate" + + + + id: LANG_RECORD_NEW_FILE_FLUSH + desc: start new files on disk immediately + user: + + *: "Create New Files Immediately" + + + *: "Create New Files Immediately" + + + *: "Create New Files Immediately" + + Index: apps/plugins/SOURCES =================================================================== RCS file: /cvsroot/rockbox/apps/plugins/SOURCES,v retrieving revision 1.140 diff -u -r1.140 SOURCES --- apps/plugins/SOURCES 16 Oct 2006 01:27:08 -0000 1.140 +++ apps/plugins/SOURCES 16 Oct 2006 23:32:39 -0000 @@ -22,6 +22,10 @@ vbrfix.c viewer.c +#ifdef CPU_COLDFIRE +sampr_test.c +#endif + #if ((CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)) && !defined(SIMULATOR) wavplay.c #endif Index: apps/plugins/sampr_test.c =================================================================== RCS file: apps/plugins/sampr_test.c diff -N apps/plugins/sampr_test.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ apps/plugins/sampr_test.c 16 Oct 2006 23:32:40 -0000 @@ -0,0 +1,282 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Michael Sevakis + * + * 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" + +PLUGIN_HEADER + +struct plugin_api *rb; + +enum +{ + TONE_SINE = 0, + TONE_TRIANGLE, + TONE_SAWTOOTH, + TONE_SQUARE, + NUM_WAVEFORMS +}; + +static const short A441[NUM_WAVEFORMS][100] = +{ + [TONE_SINE] = + { + 0, 2057, 4106, 6139, 8148, + 10125, 12062, 13951, 15785, 17557, + 19259, 20886, 22430, 23886, 25247, + 26509, 27666, 28713, 29648, 30465, + 31163, 31737, 32186, 32508, 32702, + 32767, 32702, 32508, 32186, 31737, + 31163, 30465, 29648, 28713, 27666, + 26509, 25247, 23886, 22430, 20886, + 19259, 17557, 15785, 13951, 12062, + 10125, 8148, 6139, 4106, 2057, + 0, -2057, -4106, -6139, -8148, + -10125, -12062, -13951, -15785, -17557, + -19259, -20886, -22430, -23886, -25247, + -26509, -27666, -28713, -29648, -30465, + -31163, -31737, -32186, -32508, -32702, + -32767, -32702, -32508, -32186, -31737, + -31163, -30465, -29648, -28713, -27666, + -26509, -25247, -23886, -22430, -20886, + -19259, -17557, -15785, -13951, -12062, + -10125, -8148, -6139, -4106, -2057, + }, + [TONE_TRIANGLE] = + { + 0, 1310, 2621, 3932, 5242, + 6553, 7864, 9174, 10485, 11796, + 13106, 14417, 15728, 17038, 18349, + 19660, 20970, 22281, 23592, 24902, + 26213, 27524, 28834, 30145, 31456, + 32767, 31456, 30145, 28834, 27524, + 26213, 24902, 23592, 22281, 20970, + 19660, 18349, 17038, 15728, 14417, + 13106, 11796, 10485, 9174, 7864, + 6553, 5242, 3932, 2621, 1310, + 0, -1310, -2621, -3932, -5242, + -6553, -7864, -9174, -10485, -11796, + -13106, -14417, -15728, -17038, -18349, + -19660, -20970, -22281, -23592, -24902, + -26213, -27524, -28834, -30145, -31456, + -32767, -31456, -30145, -28834, -27524, + -26213, -24902, -23592, -22281, -20970, + -19660, -18349, -17038, -15728, -14417, + -13106, -11796, -10485, -9174, -7864, + -6553, -5242, -3932, -2621, -1310, + }, + [TONE_SAWTOOTH] = + { + -32767, -32111, -31456, -30800, -30145, + -29490, -28834, -28179, -27524, -26868, + -26213, -25558, -24902, -24247, -23592, + -22936, -22281, -21626, -20970, -20315, + -19660, -19004, -18349, -17694, -17038, + -16383, -15728, -15072, -14417, -13762, + -13106, -12451, -11796, -11140, -10485, + -9830, -9174, -8519, -7864, -7208, + -6553, -5898, -5242, -4587, -3932, + -3276, -2621, -1966, -1310, -655, + 0, 655, 1310, 1966, 2621, + 3276, 3932, 4587, 5242, 5898, + 6553, 7208, 7864, 8519, 9174, + 9830, 10485, 11140, 11796, 12451, + 13106, 13762, 14417, 15072, 15728, + 16383, 17038, 17694, 18349, 19004, + 19660, 20315, 20970, 21626, 22281, + 22936, 23592, 24247, 24902, 25558, + 26213, 26868, 27524, 28179, 28834, + 29490, 30145, 30800, 31456, 32111, + }, + [TONE_SQUARE] = + { + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + -32767, -32767, -32767, -32767, -32767, + } +}; + +void play_waveform(int waveform) +{ + static struct opt_items names[HW_NUM_FREQ] = + { + HW_HAVE_96_([HW_FREQ_96] = { "96kHz", NULL },) + HW_HAVE_88_([HW_FREQ_88] = { "88.2kHz", NULL },) + HW_HAVE_64_([HW_FREQ_64] = { "64kHz", NULL },) + HW_HAVE_48_([HW_FREQ_48] = { "48kHz", NULL },) + HW_HAVE_44_([HW_FREQ_44] = { "44.1kHz", NULL },) + HW_HAVE_32_([HW_FREQ_32] = { "32kHz", NULL },) + HW_HAVE_24_([HW_FREQ_24] = { "24kHz", NULL },) + HW_HAVE_22_([HW_FREQ_22] = { "22.05kHz", NULL },) + HW_HAVE_16_([HW_FREQ_16] = { "16kHz", NULL },) + HW_HAVE_12_([HW_FREQ_12] = { "12kHz", NULL },) + HW_HAVE_11_([HW_FREQ_11] = { "11.025kHz", NULL },) + HW_HAVE_8_( [HW_FREQ_8 ] = { "8kHz", NULL },) + }; + + /* 50 cycles of wavform */ + static long audio[5000]; + + unsigned long freq = HW_FREQ_DEFAULT; + + void init_audio(int type) + { + int i; + int amps[NUM_WAVEFORMS] = + { + [TONE_SINE] = 8191, + [TONE_TRIANGLE] = 5119, + [TONE_SAWTOOTH] = 2047, + [TONE_SQUARE] = 1535 + }; + + /* Initialize one cycle of the waveform */ + for (i = 0; i < 100; i++) + { + short val = amps[type]*A441[type][i]/32767; + audio[i] = (val << 16) | (unsigned short)val; + } + + /* Duplicate it 49 more times */ + for (i = 1; i < 50; i++) + { + rb->memcpy(audio + i*100, audio, 100*sizeof(long)); + } + } + + void get_more(unsigned char **start, size_t *size) + { + *start = (unsigned char *)audio; + *size = sizeof (audio); + } + + void set_frequency(int index) + { + rb->pcm_set_frequency(rb->hw_freq_sampr[index]); + rb->pcm_apply_settings(false); + } + + if (rb->pcm_is_playing()) + { + rb->audio_stop(); + + while (rb->pcm_is_playing()) + rb->yield(); + } + + rb->cpu_boost(true); + + rb->pcm_set_frequency(rb->hw_freq_sampr[freq]); +#ifdef HAVE_RECORDING + rb->pcm_set_monitor(PCM_MONITOR_PLAYBACK); +#endif + rb->pcm_apply_settings(true); + + init_audio(waveform); + rb->pcm_play_data(get_more, NULL, 0); + + rb->set_option("Sample Rate", &freq, INT, names, + HW_NUM_FREQ, set_frequency); + + rb->pcm_play_stop(); + + while (rb->pcm_is_playing()) + rb->yield(); + + rb->cpu_boost(false); + + /* restore default */ + rb->pcm_set_frequency(-1); +#ifdef HAVE_RECORDING + rb->pcm_set_monitor(-1); +#endif +} + +int set_waveform(int waveform) +{ + static struct opt_items names[NUM_WAVEFORMS] = + { + [TONE_SINE] = { "Sine", NULL }, + [TONE_TRIANGLE] = { "Triangle", NULL }, + [TONE_SAWTOOTH] = { "Sawtooth", NULL }, + [TONE_SQUARE] = { "Square", NULL }, + }; + + rb->set_option("Waveform", &waveform, INT, names, + NUM_WAVEFORMS, NULL); + + return waveform; +} + +/* Tests hardware sample rate switching */ +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + static const struct menu_item items[] = + { + { "Set Waveform", NULL }, + { "Play Waveform", NULL }, + { "Quit", NULL }, + }; + + bool exit = false; + int waveform = TONE_SINE; + + rb = api; + + int m = rb->menu_init(items, ARRAYLEN(items), + NULL, NULL, NULL, NULL); + + while (!exit) + { + int result = rb->menu_show(m); + + switch (result) + { + case 0: + waveform = set_waveform(waveform); + break; + case 1: + play_waveform(waveform); + break; + case 2: + exit = true; + break; + } + } + + rb->menu_exit(m); + + return PLUGIN_OK; + (void)parameter; +} Index: apps/recorder/icons.c =================================================================== RCS file: /cvsroot/rockbox/apps/recorder/icons.c,v retrieving revision 1.86 diff -u -r1.86 icons.c --- apps/recorder/icons.c 13 Oct 2006 04:16:49 -0000 1.86 +++ apps/recorder/icons.c 16 Oct 2006 23:32:40 -0000 @@ -30,12 +30,17 @@ const unsigned char bitmap_icons_5x8[][5] = { - [Icon_Lock_Main] ={0x78,0x7f,0x49,0x7f,0x78}, /* Lock Main */ - [Icon_Lock_Remote]={0x78,0x7f,0x49,0x7f,0x78}, /* Lock Remote */ - [Icon_Stereo]={0x7f, 0x1c, 0x00, 0x1c, 0x7f}, /* Stereo recording */ - [Icon_Mono]={0x00, 0x1c, 0x7f, 0x00, 0x00}, /* Mono recording */ + [Icon_Lock_Main] = + {0x78, 0x7f, 0x49, 0x7f, 0x78}, /* Lock Main */ + [Icon_Lock_Remote] = + {0x78, 0x7f, 0x49, 0x7f, 0x78}, /* Lock Remote */ + [Icon_Stereo] = + {0x7f, 0x22, 0x1c, 0x22, 0x7f}, /* Stereo recording */ + [Icon_Mono] = + {0x00, 0x1c, 0x22, 0x7f, 0x00}, /* Mono recording */ #if CONFIG_CODEC != SWCODEC - [Icon_q]={0x1e, 0x21, 0x31, 0x21, 0x5e} /* Q icon */ + [Icon_q] = + {0x1e, 0x21, 0x31, 0x21, 0x5e} /* Q icon */ #endif }; @@ -81,45 +86,52 @@ {0x7f,0x04,0x4e,0x5f,0x44,0x38,0x7f} /* Repeat-AB playmode */ }; -#if CONFIG_CODEC == SWCODEC -const unsigned char bitmap_icons_18x8[][18] = +#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) +const unsigned char bitmap_glyphs_4x8[][4] = { - {0x00, 0x00, 0x00, 0x00,0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x3e, 0x2a, - 0x3a, 0x00, 0x0e, 0x08, 0x3e, 0x00}, /* mp3 64kbps */ - {0x00, 0x00, 0x00, 0x00,0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x0e, 0x0a, - 0x3e, 0x00, 0x3e, 0x2a, 0x3a, 0x00}, /* mp3 96kbps */ - {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x3a, 0x2a, - 0x2e, 0x00, 0x3e, 0x2a, 0x3e, 0x00}, /* mp3 128kbps */ - {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x3e, 0x2a, - 0x3a, 0x00, 0x3e, 0x22, 0x3e, 0x00}, /* mp3 160kbps */ - {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x0e, 0x0a, - 0x3e, 0x00, 0x3a, 0x2a, 0x2e, 0x00}, /* mp3 192kbps */ - {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3a, 0x2a, - 0x2e, 0x00, 0x0e, 0x08, 0x3e, 0x00}, /* mp3 224kbps */ - {0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x22, 0x2a, 0x36, 0x00, 0x3a, 0x2a, - 0x2e, 0x00, 0x3e, 0x22, 0x3e, 0x00}, /* mp3 320kbps */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x1e, 0x20, 0x18, 0x20, 0x1e, - 0x00, 0x1e, 0x20, 0x18, 0x06, 0x00}, /* wv */ - {0x00, 0x00, 0x1e, 0x20, 0x18, 0x20, 0x1e, 0x00, 0x3c, 0x12, 0x12, 0x3c, - 0x00, 0x1e, 0x20, 0x18, 0x06, 0x00} /* wav */ + /* Keep digits together and first! */ + [0] = + {0x00, 0x3e, 0x22, 0x3e}, /* 0 */ + [1] = + {0x00, 0x24, 0x3e, 0x20}, /* 1 */ + [2] = + {0x00, 0x3a, 0x2a, 0x2e}, /* 2 */ + [3] = + {0x00, 0x22, 0x2a, 0x36}, /* 3 */ + [4] = + {0x00, 0x0e, 0x08, 0x3e}, /* 4 */ + [5] = + {0x00, 0x2e, 0x2a, 0x3a}, /* 5 */ + [6] = + {0x00, 0x3e, 0x2a, 0x3a}, /* 6 */ + [7] = + {0x00, 0x02, 0x02, 0x3e}, /* 7 */ + [8] = + {0x00, 0x3e, 0x2a, 0x3e}, /* 8 */ + [9] = + {0x00, 0x0e, 0x0a, 0x3e}, /* 9 */ + [10 ... Glyph_4x8Last-1] = + {0x00, 0x00, 0x00, 0x00}, /* auto-blank */ + [Glyph_4x8_k] = + {0x00, 0x3e, 0x10, 0x28}, /* k */ }; -const unsigned char bitmap_icons_12x8[][12] = +const unsigned char bitmap_formats_18x8[Format_18x8Last][18]= { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 8khz */ - {0x00, 0x24, 0x3e, 0x20, 0x00, 0x24, 0x3e, 0x20, 0x00, 0x3e, 0x10, 0x28}, /* 11khz */ - {0x00, 0x24, 0x3e, 0x20, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3e, 0x10, 0x28}, /* 12khz */ - {0x00, 0x24, 0x3e, 0x20, 0x00, 0x3e, 0x2a, 0x3a, 0x00, 0x3e, 0x10, 0x28}, /* 16khz */ - {0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3e, 0x10, 0x28}, /* 22khz */ - {0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 24khz */ - {0x00, 0x22, 0x2a, 0x36, 0x00, 0x3a, 0x2a, 0x2e, 0x00, 0x3e, 0x10, 0x28}, /* 32khz */ - {0x00, 0x0e, 0x08, 0x3e, 0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 44.1khz */ - {0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 48khz */ - {0x00, 0x3e, 0x2a, 0x3a, 0x00, 0x0e, 0x08, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 64khz */ - {0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x2a, 0x3e, 0x00, 0x3e, 0x10, 0x28}, /* 88.2khz */ - {0x00, 0x0e, 0x0a, 0x3e, 0x00, 0x3e, 0x2a, 0x3a, 0x00, 0x3e, 0x10, 0x28} /* 96khz */ + [0 ... Format_18x8Last-1] = /* auto-blank */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ___ */ + [Format_18x8_MPA_L3] = + {0x00, 0x3e, 0x04, 0x08, 0x04, 0x3e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* M__ */ + [Format_18x8_WAVPACK] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x20, + 0x18, 0x20, 0x1e, 0x00, 0x0e, 0x10, 0x20, 0x10, 0x0e}, /* _WV */ + [Format_18x8_PCM_WAV] = + {0x00, 0x1e, 0x20, 0x18, 0x20, 0x1e, 0x00, 0x3c, 0x0a, + 0x0a, 0x0a, 0x3c, 0x00, 0x0e, 0x10, 0x20, 0x10, 0x0e}, /* WAV */ }; -#endif +#endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */ /* Disk/MMC activity */ const unsigned char bitmap_icon_disk[12] = Index: apps/recorder/icons.h =================================================================== RCS file: /cvsroot/rockbox/apps/recorder/icons.h,v retrieving revision 1.66 diff -u -r1.66 icons.h --- apps/recorder/icons.h 13 Oct 2006 04:16:49 -0000 1.66 +++ apps/recorder/icons.h 16 Oct 2006 23:32:41 -0000 @@ -89,44 +89,40 @@ Icon7x8Last }; -#if CONFIG_CODEC == SWCODEC -enum icons_12x8 { - Icon_8000, - Icon_11025, - Icon_12000, - Icon_16000, - Icon_22050, - Icon_24000, - Icon_32000, - Icon_44100, - Icon_48000, - Icon_64000, - Icon_88200, - Icon_96000, - Icon12x8Last +#if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) +#define BM_GLYPH_WIDTH 4 +enum Glyphs_4x8 { + Glyph_4x8_0 = 0, + Glyph_4x8_1, + Glyph_4x8_2, + Glyph_4x8_3, + Glyph_4x8_4, + Glyph_4x8_5, + Glyph_4x8_6, + Glyph_4x8_7, + Glyph_4x8_8, + Glyph_4x8_9, + Glyph_4x8_k, + Glyph_4x8Last }; +extern const unsigned char bitmap_glyphs_4x8[Glyph_4x8Last][4]; -enum icons_18x8 { - Icon_mp364, - Icon_mp396, - Icon_mp3128, - Icon_mp3160, - Icon_mp3192, - Icon_mp3224, - Icon_mp3320, - Icon_wv, - Icon_wav, - Icon18x8Last +#define BM_MPA_L3_M_WIDTH 6 +#ifdef ID3_H +/* This enum is redundant but sort of in keeping with the style */ +enum rec_format_18x8 { + Format_18x8_MPA_L3 = REC_FORMAT_MPA_L3, + Format_18x8_WAVPACK = REC_FORMAT_WAVPACK, + Format_18x8_PCM_WAV = REC_FORMAT_PCM_WAV, + Format_18x8Last = REC_NUM_FORMATS }; -#endif +extern const unsigned char bitmap_formats_18x8[Format_18x8Last][18]; +#endif /* ID3_H */ +#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */ extern const unsigned char bitmap_icons_5x8[Icon5x8Last][5]; extern const unsigned char bitmap_icons_6x8[Icon6x8Last][6]; extern const unsigned char bitmap_icons_7x8[Icon7x8Last][7]; -#if CONFIG_CODEC == SWCODEC -extern const unsigned char bitmap_icons_12x8[Icon12x8Last][12]; -extern const unsigned char bitmap_icons_18x8[Icon18x8Last][18]; -#endif extern const unsigned char bitmap_icon_disk[]; #define STATUSBAR_X_POS 0 Index: apps/recorder/radio.c =================================================================== RCS file: /cvsroot/rockbox/apps/recorder/radio.c,v retrieving revision 1.113 diff -u -r1.113 radio.c --- apps/recorder/radio.c 12 Oct 2006 19:27:00 -0000 1.113 +++ apps/recorder/radio.c 16 Oct 2006 23:32:41 -0000 @@ -386,6 +386,7 @@ unsigned int last_seconds = 0; #if CONFIG_CODEC != SWCODEC int hours, minutes; + struct audio_recording_options rec_options; #endif bool keep_playing = false; bool statusbar = global_settings.statusbar; @@ -436,12 +437,9 @@ peak_meter_enabled = true; - rec_set_recording_options(global_settings.rec_frequency, - global_settings.rec_quality, - AUDIO_SRC_LINEIN, 0, - global_settings.rec_channels, - global_settings.rec_editable, - global_settings.rec_prerecord_time); + rec_init_recording_options(&rec_options); + rec_options.rec_source = AUDIO_SRC_LINEIN; + rec_set_recording_options(&rec_options); audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN); @@ -881,7 +879,7 @@ } else { - if(global_settings.rec_prerecord_time) + if(rec_options.rec_prerecord_time) { snprintf(buf, 32, "%s %02d", str(LANG_RECORD_PRERECORD), seconds%60); @@ -1173,7 +1171,8 @@ if(!opendir(FMPRESET_PATH)) /* Check if there is preset folder */ mkdir(FMPRESET_PATH, 0); - create_numbered_filename(filepreset,FMPRESET_PATH,"preset",".fmr",2); + create_numbered_filename(filepreset, FMPRESET_PATH, "preset", + ".fmr", 2 IF_CNFN_NUM_(, NULL)); while(bad_file_name) { @@ -1534,12 +1533,10 @@ #if CONFIG_CODEC != SWCODEC if (!ret) { - rec_set_recording_options(global_settings.rec_frequency, - global_settings.rec_quality, - AUDIO_SRC_LINEIN, 0, - global_settings.rec_channels, - global_settings.rec_editable, - global_settings.rec_prerecord_time); + struct audio_recording_options rec_options; + rec_init_recording_options(&rec_options); + rec_options.rec_source = AUDIO_SRC_LINEIN; + rec_set_recording_options(&rec_options); } #endif Index: apps/recorder/recording.c =================================================================== RCS file: /cvsroot/rockbox/apps/recorder/recording.c,v retrieving revision 1.143 diff -u -r1.143 recording.c --- apps/recorder/recording.c 1 Oct 2006 10:04:40 -0000 1.143 +++ apps/recorder/recording.c 16 Oct 2006 23:32:43 -0000 @@ -30,8 +30,10 @@ #include "mpeg.h" #include "audio.h" #if CONFIG_CODEC == SWCODEC -#include "pcm_record.h" +#include "thread.h" +#include "pcm_playback.h" #include "playback.h" +#include "enc_config.h" #endif #ifdef HAVE_UDA1380 #include "uda1380.h" @@ -73,36 +75,40 @@ #define PM_HEIGHT ((LCD_HEIGHT >= 72) ? 2 : 1) +#if CONFIG_KEYPAD == RECORDER_PAD bool f2_rec_screen(void); bool f3_rec_screen(void); +#endif #define MAX_FILE_SIZE 0x7F800000 /* 2 GB - 4 MB */ int screen_update = NB_SCREENS; bool remote_display_on = true; -const char* const freq_str[6] = -{ - "44.1kHz", - "48kHz", - "32kHz", - "22.05kHz", - "24kHz", - "16kHz" -}; +/** File name creation **/ #if CONFIG_CODEC == SWCODEC -#define REC_ENCODER_ID(q) \ - rec_quality_info_afmt[q] -#define REC_QUALITY_LABEL(q) \ - (audio_formats[REC_ENCODER_ID(q)].label) -#define REC_FILE_ENDING(q) \ - (audio_formats[REC_ENCODER_ID(q)].ext) -#else + +#ifdef IF_CNFN_NUM +/* current file number to assist in creating unique numbered filenames + without actually having to create the file on disk */ +static int file_number = -1; +#endif /* IF_CNFN_NUM */ + +#define REC_FILE_ENDING(rec_format) \ + (audio_formats[rec_format_afmt[rec_format]].ext_list) + +#else /* CONFIG_CODEC != SWCODEC */ + /* default record file extension for HWCODEC */ -#define REC_QUALITY_LABEL(q) "MP3" -#define REC_FILE_ENDING(q) ".mp3" -#endif +#define REC_FILE_ENDING(rec_format) \ + (audio_formats[AFMT_MPA_L3].ext_list) + +#endif /* CONFIG_CODEC == SWCODEC */ + +/* path for current file */ +static char path_buffer[MAX_PATH]; +/** Automatic Gain Control (AGC) **/ #ifdef HAVE_AGC /* Timing counters: * peak_time is incremented every 0.2s, every 2nd run of record screen loop. @@ -496,20 +502,24 @@ char *rec_create_filename(char *buffer) { + char ext[16]; + if(global_settings.rec_directory) getcwd(buffer, MAX_PATH); else strncpy(buffer, rec_base_directory, MAX_PATH); + snprintf(ext, sizeof(ext), ".%s", + REC_FILE_ENDING(global_settings.rec_format)); #ifdef CONFIG_RTC - create_datetime_filename(buffer, buffer, "R", - REC_FILE_ENDING(global_settings.rec_quality)); + /* We'll wait at least up to the start of the next second so no duplicate + names are created */ + return create_datetime_filename(buffer, buffer, "R", ext, true); #else - create_numbered_filename(buffer, buffer, "rec_", - REC_FILE_ENDING(global_settings.rec_quality), 4); + return create_numbered_filename(buffer, buffer, "rec_", ext, 4 + IF_CNFN_NUM_(, &file_number)); #endif - return buffer; } int rec_create_directory(void) @@ -557,9 +567,15 @@ /** * Selects an audio source for recording or playback - * powers/unpowers related devices. + * powers/unpowers related devices and sets up monitoring. * Here because it calls app code and used only for HAVE_RECORDING atm. * Would like it in pcm_record.c. + * + * Behaves like a firmware function in that it does not use global settings + * to determine the state. + * + * The order of setting monitoring may need tweaking dependent upon the + * selected source to get the smoothest transition. */ #if defined(HAVE_UDA1380) #define ac_disable_recording uda1380_disable_recording @@ -571,7 +587,13 @@ #define ac_set_monitor tlv320_set_monitor #endif -void rec_set_source(int source, int flags) +#ifdef HAVE_SPDIF_IN +#define rec_spdif_set_monitor(m) audio_spdif_set_monitor(m) +#else +#define rec_spdif_set_monitor(m) +#endif + +void rec_set_source(int source, unsigned flags) { /* Prevent pops from unneeded switching */ static int last_source = AUDIO_SRC_PLAYBACK; @@ -586,7 +608,9 @@ /** Do power up/down of associated device(s) **/ + /** SPDIF **/ #ifdef HAVE_SPDIF_IN + /* Always boost for SPDIF */ if ((source == AUDIO_SRC_SPDIF) != (source == last_source)) rec_boost(source == AUDIO_SRC_SPDIF); @@ -595,10 +619,11 @@ both optical in and out is controlled by the same power source, which is the case on H1x0. */ spdif_power_enable((source == AUDIO_SRC_SPDIF) || - global_settings.spdif_enable); + audio_get_spdif_power_setting()); #endif #endif + /** Tuner **/ #ifdef CONFIG_TUNER /* Switch radio off or on per source and flags. */ if (source != AUDIO_SRC_FMRADIO) @@ -625,6 +650,7 @@ break; ac_enable_recording(true); /* source mic */ pcm_rec_mux(0); /* line in */ + rec_spdif_set_monitor(false); break; case AUDIO_SRC_LINEIN: /* recording only */ @@ -632,29 +658,20 @@ break; pcm_rec_mux(0); /* line in */ ac_enable_recording(false); /* source line */ + rec_spdif_set_monitor(false); break; #ifdef HAVE_SPDIF_IN case AUDIO_SRC_SPDIF: /* recording only */ - if (recording) - { - /* This was originally done in audio_set_recording_options only */ -#ifdef HAVE_SPDIF_POWER - EBU1CONFIG = global_settings.spdif_enable ? (1 << 2) : 0; - /* Input source is EBUin1, Feed-through monitoring if desired */ -#else - EBU1CONFIG = (1 << 2); - /* Input source is EBUin1, Feed-through monitoring */ -#endif - } - - if (source != last_source) - uda1380_disable_recording(); + if (source == last_source) + break; + ac_disable_recording(); + audio_spdif_set_monitor(true); break; #endif /* HAVE_SPDIF_IN */ #ifdef HAVE_FMRADIO_IN - case AUDIO_SRC_FMRADIO: + case AUDIO_SRC_FMRADIO: /* recording and playback */ if (!recording) { audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), @@ -687,6 +704,11 @@ tlv320_set_monitor(true); /* analog bypass */ } #endif + +#ifdef HAVE_SPDIF_IN + if (recording) + audio_spdif_set_monitor(false); +#endif break; /* #elif defined(CONFIG_TUNER) */ /* Have radio but cannot record it */ @@ -702,33 +724,49 @@ } /* rec_set_source */ #endif /* CONFIG_CODEC == SWCODEC && !defined(SIMULATOR) */ -/* steal the mp3 buffer then actually set options */ -void rec_set_recording_options(int frequency, int quality, - int source, int source_flags, - int channel_mode, bool editable, - int prerecord_time) +void rec_init_recording_options(struct audio_recording_options *options) +{ + options->rec_source = global_settings.rec_source; + options->rec_frequency = global_settings.rec_frequency; + options->rec_channels = global_settings.rec_channels; + options->rec_prerecord_time = global_settings.rec_prerecord_time; +#if CONFIG_CODEC == SWCODEC + options->rec_new_file_flush = global_settings.rec_new_file_flush; + options->rec_source_flags = 0; + options->enc_config.rec_format = global_settings.rec_format; + global_to_encoder_config(&options->enc_config); +#else + options->rec_quality = global_settings.rec_quality; + options->rec_editable = global_settings.rec_editable; +#endif +} + +void rec_set_recording_options(struct audio_recording_options *options) { #if CONFIG_CODEC != SWCODEC if (global_settings.rec_prerecord_time) #endif talk_buffer_steal(); /* will use the mp3 buffer */ +#ifdef HAVE_SPDIF_IN +#ifdef HAVE_SPDIF_POWER + audio_set_spdif_power_setting(global_settings.spdif_enable); +#endif +#endif + #if CONFIG_CODEC == SWCODEC - rec_set_source(source, source_flags | SRCF_RECORDING); -#else - (void)source_flags; + rec_set_source(options->rec_source, + options->rec_source_flags | SRCF_RECORDING); #endif - audio_set_recording_options(frequency, quality, source, - channel_mode, editable, prerecord_time); + audio_set_recording_options(options); } -static char path_buffer[MAX_PATH]; - /* steals mp3 buffer, creates unique filename and starts recording */ void rec_record(void) { talk_buffer_steal(); /* we use the mp3 buffer */ + IF_CNFN_NUM_(file_number = -1;) /* Hit disk for number */ audio_record(rec_create_filename(path_buffer)); } @@ -831,6 +869,8 @@ ID2P(LANG_GIGABYTE) }; + struct audio_recording_options rec_options; + global_settings.recscreen_on = true; cursor = 0; #if (CONFIG_LED == LED_REAL) && !defined(SIMULATOR) @@ -840,6 +880,9 @@ #if CONFIG_CODEC == SWCODEC audio_stop(); voice_stop(); + /* make sure audio is really finished */ + while (pcm_is_playing()) + yield(); /* recording_menu gets messed up: so reset talk_menu */ talk_menu = global_settings.talk_menu; global_settings.talk_menu = 0; @@ -860,13 +903,8 @@ peak_meter_get_peakhold(&peak_l, &peak_r); #endif - rec_set_recording_options(global_settings.rec_frequency, - global_settings.rec_quality, - global_settings.rec_source, - 0, - global_settings.rec_channels, - global_settings.rec_editable, - global_settings.rec_prerecord_time); + rec_init_recording_options(&rec_options); + rec_set_recording_options(&rec_options); set_gain(); settings_apply_trigger(); @@ -1255,14 +1293,8 @@ audio_close_recording(); audio_init_recording(talk_get_bufsize()); #endif - rec_set_recording_options( - global_settings.rec_frequency, - global_settings.rec_quality, - global_settings.rec_source, - 0, - global_settings.rec_channels, - global_settings.rec_editable, - global_settings.rec_prerecord_time); + rec_init_recording_options(&rec_options); + rec_set_recording_options(&rec_options); if(rec_create_directory() > 0) have_recorded = true; @@ -1739,11 +1771,7 @@ } } /* end while(!done) */ -#if CONFIG_CODEC == SWCODEC - audio_stat = pcm_rec_status(); -#else audio_stat = audio_status(); -#endif if (audio_stat & AUDIO_STATUS_ERROR) { gui_syncsplash(0, true, str(LANG_SYSFONT_DISK_FULL)); @@ -1804,11 +1832,22 @@ #if CONFIG_KEYPAD == RECORDER_PAD bool f2_rec_screen(void) { + static const char* const freq_str[6] = + { + "44.1kHz", + "48kHz", + "32kHz", + "22.05kHz", + "24kHz", + "16kHz" + }; + bool exit = false; bool used = false; int w, h, i; char buf[32]; int button; + struct audio_recording_options rec_options; FOR_NB_SCREENS(i) { @@ -1919,13 +1958,8 @@ } } - rec_set_recording_options(global_settings.rec_frequency, - global_settings.rec_quality, - global_settings.rec_source, - 0, - global_settings.rec_channels, - global_settings.rec_editable, - global_settings.rec_prerecord_time); + rec_init_recording_options(&rec_options); + rec_set_recording_options(&rec_options); set_gain(); @@ -1948,6 +1982,8 @@ str(LANG_SYSFONT_RECORDING_SRC_LINE), str(LANG_SYSFONT_RECORDING_SRC_DIGITAL) }; + struct audio_recording_options rec_options; + FOR_NB_SCREENS(i) { screens[i].setfont(FONT_SYSFIXED); @@ -2019,13 +2055,8 @@ } } - rec_set_recording_options(global_settings.rec_frequency, - global_settings.rec_quality, - global_settings.rec_source, - 0, - global_settings.rec_channels, - global_settings.rec_editable, - global_settings.rec_prerecord_time); + rec_init_recording_options(&rec_options); + rec_set_recording_options(&rec_options); set_gain(); @@ -2066,23 +2097,30 @@ } #if CONFIG_CODEC == SWCODEC -void rec_set_source(int source, int flags) +void rec_set_source(int source, unsigned flags) { source = source; flags = flags; } -#endif -void audio_set_recording_options(int frequency, int quality, - int source, int channel_mode, - bool editable, int prerecord_time) +#ifdef HAVE_SPDIF_IN +#ifdef HAVE_SPDIF_POWER +void audio_set_spdif_power_setting(bool on) { - frequency = frequency; - quality = quality; - source = source; - channel_mode = channel_mode; - editable = editable; - prerecord_time = prerecord_time; + on = on; +} + +bool audio_get_spdif_power_setting(void) +{ + return true; +} +#endif /* HAVE_SPDIF_POWER */ +#endif /* HAVE_SPDIF_IN */ +#endif /* CONFIG_CODEC == SWCODEC */ + +void audio_set_recording_options(struct audio_recording_options *options) +{ + options = options; } void audio_set_recording_gain(int left, int right, int type) Index: apps/recorder/recording.h =================================================================== RCS file: /cvsroot/rockbox/apps/recorder/recording.h,v retrieving revision 1.5 diff -u -r1.5 recording.h --- apps/recorder/recording.h 28 Aug 2006 22:38:40 -0000 1.5 +++ apps/recorder/recording.h 16 Oct 2006 23:32:43 -0000 @@ -32,15 +32,16 @@ #define SRCF_FMRADIO_PLAYING 0x0000 /* default */ #define SRCF_FMRADIO_PAUSED 0x2000 #endif -void rec_set_source(int source, int flags); +void rec_set_source(int source, unsigned flags); #endif /* CONFIG_CODEC == SW_CODEC */ +/* Initializes a recording_options structure with global settings. + pass returned data to audio_set_recording_options or + rec_set_recording_options */ +void rec_init_recording_options(struct audio_recording_options *options); /* steals mp3 buffer, sets source and then options */ -/* SRCF_RECORDING is implied */ -void rec_set_recording_options(int frequency, int quality, - int source, int source_flags, - int channel_mode, bool editable, - int prerecord_time); +/* SRCF_RECORDING is implied for SWCODEC */ +void rec_set_recording_options(struct audio_recording_options *options); /* steals mp3 buffer, creates unique filename and starts recording */ void rec_record(void); Index: bootloader/main.c =================================================================== RCS file: /cvsroot/rockbox/bootloader/main.c,v retrieving revision 1.36 diff -u -r1.36 main.c --- bootloader/main.c 4 Sep 2006 16:06:11 -0000 1.36 +++ bootloader/main.c 16 Oct 2006 23:32:43 -0000 @@ -204,6 +204,7 @@ kernel_init(); set_cpu_frequency(CPUFREQ_NORMAL); + coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS); set_irq_level(0); lcd_init(); @@ -311,6 +312,9 @@ #ifdef HAVE_ADJUSTABLE_CPU_FREQ /* Set up waitstates for the peripherals */ set_cpu_frequency(0); /* PLL off */ +#ifdef CPU_COLDFIRE + coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS); +#endif #endif #ifdef HAVE_UDA1380 Index: firmware/SOURCES =================================================================== RCS file: /cvsroot/rockbox/firmware/SOURCES,v retrieving revision 1.119 diff -u -r1.119 SOURCES --- firmware/SOURCES 16 Oct 2006 17:21:35 -0000 1.119 +++ firmware/SOURCES 16 Oct 2006 23:32:43 -0000 @@ -4,6 +4,7 @@ #endif backlight.c buffer.c +general.c common/atoi.c common/crc32.c common/ctype.c @@ -212,9 +213,13 @@ pcm_playback.c #endif #if CONFIG_CODEC == SWCODEC +pcm_sampr.c +#ifdef HAVE_RECORDING +enc_base.c +#endif replaygain.c #endif -#if defined(CPU_COLDFIRE) && !defined(SIMULATOR) +#if defined(CPU_COLDFIRE) && !defined(SIMULATOR) && !defined(BOOTLOADER) pcm_record.c #endif sound.c Index: firmware/enc_base.c =================================================================== RCS file: firmware/enc_base.c diff -N firmware/enc_base.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ firmware/enc_base.c 16 Oct 2006 23:32:43 -0000 @@ -0,0 +1,46 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Michael Sevakis + * + * 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 "config.h" +#include "audio.h" + +/** mp3_enc.codec **/ + +/* These are in descending order rather than in MPEG frequency index + order */ +const unsigned long mp3_enc_sampr[MP3_ENC_NUM_SAMPR] = +{ + 48000, 44100, 32000, /* MPEG 1 */ + 24000, 22050, 16000, /* MPEG 2 */ +#if 0 + 12000, 11025, 8000, /* MPEG 2.5 */ +#endif +}; + +/* All bitrates used in the MPA L3 standard */ +const unsigned long mp3_enc_bitr[MP3_ENC_NUM_BITR] = +{ + 8, 16, 24, 32, 40, 48, 56, 64, 80, + 96, 112, 128, 144, 160, 192, 224, 256, 320 +}; + +/** wavpack_enc.codec **/ + +/** wav_enc.codec **/ + +/** public functions **/ Index: firmware/general.c =================================================================== RCS file: firmware/general.c diff -N firmware/general.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ firmware/general.c 16 Oct 2006 23:32:43 -0000 @@ -0,0 +1,77 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Michael Sevakis + * + * 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 +#include "config.h" +#include "general.h" + +int round_value_to_list32(unsigned long value, + const unsigned long list[], + int count, + bool signd) +{ + unsigned long dmin = ULONG_MAX; + int idmin = -1, i; + + for (i = 0; i < count; i++) + { + unsigned long diff; + + if (list[i] == value) + { + idmin = i; + break; + } + + if (signd ? ((long)list[i] < (long)value) : (list[i] < value)) + diff = value - list[i]; + else + diff = list[i] - value; + + if (diff < dmin) + { + dmin = diff; + idmin = i; + } + } + + return idmin; +} /* round_value_to_list32 */ + +/* Number of bits set in src_mask should equal src_list length */ +int make_list_from_caps32(unsigned long src_mask, + const unsigned long *src_list, + unsigned long caps_mask, + unsigned long *caps_list) +{ + int i, count; + unsigned long mask; + + for (mask = src_mask, count = 0, i = 0; + mask != 0; + src_mask = mask, i++) + { + unsigned long test_bit; + mask &= mask - 1; /* Zero lowest bit set */ + test_bit = mask ^ src_mask; /* Isolate the bit */ + if (test_bit & caps_mask) /* Add item if caps has test bit set */ + caps_list[count++] = src_list ? src_list[i] : (unsigned long)i; + } + + return count; +} /* make_list_from_caps32 */ Index: firmware/id3.c =================================================================== RCS file: /cvsroot/rockbox/firmware/id3.c,v retrieving revision 1.134 diff -u -r1.134 id3.c --- firmware/id3.c 25 Sep 2006 16:13:05 -0000 1.134 +++ firmware/id3.c 16 Oct 2006 23:32:44 -0000 @@ -44,6 +44,89 @@ #include "replaygain.h" #include "rbunicode.h" +/** Database of audio formats **/ +const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = +{ + /* Unknown file format */ + [AFMT_UNKNOWN] = + AFMT_ENTRY("???", NULL, NULL, NULL ), + + /* MPEG Audio layer 1 */ + [AFMT_MPA_L1] = + AFMT_ENTRY("MP1", "mpa", NULL, "mp1\0" ), + /* MPEG Audio layer 2 */ + [AFMT_MPA_L2] = + AFMT_ENTRY("MP2", "mpa", NULL, "mpa\0mp2\0" ), + /* MPEG Audio layer 3 */ + [AFMT_MPA_L3] = + AFMT_ENTRY("MP3", "mpa", "mp3_enc", "mp3\0" ), + + /* Audio Interchange File Format */ + [AFMT_AIFF] = + AFMT_ENTRY("AIFF", "aiff", NULL, "aiff\0aif\0"), + +#if CONFIG_CODEC == SWCODEC + /* Uncompressed PCM in a WAV file */ + [AFMT_PCM_WAV] = + AFMT_ENTRY("WAV", "wav", "wav_enc", "wav\0" ), + /* Ogg Vorbis */ + [AFMT_OGG_VORBIS] = + AFMT_ENTRY("Ogg", "vorbis", NULL, "ogg\0" ), + /* FLAC */ + [AFMT_FLAC] = + AFMT_ENTRY("FLAC", "flac", NULL, "flac\0" ), + /* Musepack */ + [AFMT_MPC] = + AFMT_ENTRY("MPC", "mpc", NULL, "mpc\0" ), + /* A/52 (aka AC3) audio */ + [AFMT_A52] = + AFMT_ENTRY("AC3", "a52", NULL, "a52\0ac3\0" ), + /* WavPack */ + [AFMT_WAVPACK] = + AFMT_ENTRY("WV", "wavpack", "wavpack_enc", "wv\0" ), + /* Apple Lossless Audio Codec */ + [AFMT_ALAC] = + AFMT_ENTRY("ALAC", "alac", NULL, "m4a\0" ), + /* Advanced Audio Coding in M4A container */ + [AFMT_AAC] = + AFMT_ENTRY("AAC", "aac", NULL, "mp4\0" ), + /* Shorten */ + [AFMT_SHN] = + AFMT_ENTRY("SHN", "shorten", NULL, "shn\0" ), + /* SID File Format */ + [AFMT_SID] = + AFMT_ENTRY("SID", "sid", NULL, "sid\0" ), + /* ADX File Format */ + [AFMT_ADX] = + AFMT_ENTRY("ADX", "adx", NULL, "adx\0" ), +#endif +}; + +#if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) +/* get REC_FORMAT_* corresponding AFMT_* */ +const int rec_format_afmt[REC_NUM_FORMATS] = +{ + /* give AFMT_UNKNOWN by default */ + [0 ... REC_NUM_FORMATS-1] = AFMT_UNKNOWN, + /* add new entries below this line */ + [REC_FORMAT_MPA_L3] = AFMT_MPA_L3, + [REC_FORMAT_WAVPACK] = AFMT_WAVPACK, + [REC_FORMAT_PCM_WAV] = AFMT_PCM_WAV, +}; + +/* get AFMT_* corresponding REC_FORMAT_* */ +const int afmt_rec_format[AFMT_NUM_CODECS] = +{ + /* give -1 by default */ + [0 ... AFMT_NUM_CODECS-1] = -1, + /* add new entries below this line */ + [AFMT_MPA_L3] = REC_FORMAT_MPA_L3, + [AFMT_WAVPACK] = REC_FORMAT_WAVPACK, + [AFMT_PCM_WAV] = REC_FORMAT_PCM_WAV, +}; +#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */ +/****/ + #define UNSYNC(b0,b1,b2,b3) (((long)(b0 & 0x7F) << (3*7)) | \ ((long)(b1 & 0x7F) << (2*7)) | \ ((long)(b2 & 0x7F) << (1*7)) | \ @@ -85,61 +168,6 @@ "Synthpop" }; -/* database of audio formats */ -const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = -{ - /* Unknown file format */ - AFMT_ENTRY("???", NULL, NULL, NULL ), - /* MPEG Audio layer 1 */ - AFMT_ENTRY("MP1", "mpa.codec", NULL, NULL ), - /* MPEG Audio layer 2 */ - AFMT_ENTRY("MP2", "mpa.codec", NULL, NULL ), - /* MPEG Audio layer 3 */ - AFMT_ENTRY("MP3", "mpa.codec", "mp3_enc.codec", ".mp3"), -#if CONFIG_CODEC == SWCODEC - /* Uncompressed PCM in a WAV file */ - AFMT_ENTRY("WAV", "wav.codec", "wav_enc.codec", ".wav"), - /* Ogg Vorbis */ - AFMT_ENTRY("Ogg", "vorbis.codec", NULL, NULL ), - /* FLAC */ - AFMT_ENTRY("FLAC", "flac.codec", NULL, NULL ), - /* Musepack */ - AFMT_ENTRY("MPC", "mpc.codec", NULL, NULL ), - /* A/52 (aka AC3) audio */ - AFMT_ENTRY("AC3", "a52.codec", NULL, NULL ), - /* WavPack */ - AFMT_ENTRY("WV", "wavpack.codec", "wavpack_enc.codec", ".wv" ), - /* Apple Lossless Audio Codec */ - AFMT_ENTRY("ALAC", "alac.codec", NULL, NULL ), - /* Advanced Audio Coding in M4A container */ - AFMT_ENTRY("AAC", "aac.codec", NULL, NULL ), - /* Shorten */ - AFMT_ENTRY("SHN", "shorten.codec", NULL, NULL ), - /* Audio Interchange File Format */ - AFMT_ENTRY("AIFF", "aiff.codec", NULL, NULL ), - /* SID File Format */ - AFMT_ENTRY("SID", "sid.codec", NULL, NULL ), - /* ADX File Format */ - AFMT_ENTRY("ADX", "adx.codec", NULL, NULL ), -#endif -}; - -#if CONFIG_CODEC == SWCODEC -/* recording quality to AFMT_* */ -const int rec_quality_info_afmt[9] = -{ - AFMT_MPA_L3, /* MPEG L3 64 kBit/s */ - AFMT_MPA_L3, /* MPEG L3 96 kBit/s */ - AFMT_MPA_L3, /* MPEG L3 128 kBit/s */ - AFMT_MPA_L3, /* MPEG L3 160 kBit/s */ - AFMT_MPA_L3, /* MPEG L3 192 kBit/s */ - AFMT_MPA_L3, /* MPEG L3 224 kBit/s */ - AFMT_MPA_L3, /* MPEG L3 320 kBit/s */ - AFMT_WAVPACK, /* WavPack 909 kBit/s */ - AFMT_PCM_WAV, /* PCM Wav 1411 kBit/s */ -}; -#endif /* SWCODEC */ - char* id3_get_genre(const struct mp3entry* id3) { if( id3->genre_string ) Index: firmware/mpeg.c =================================================================== RCS file: /cvsroot/rockbox/firmware/mpeg.c,v retrieving revision 1.361 diff -u -r1.361 mpeg.c --- firmware/mpeg.c 16 Sep 2006 16:18:07 -0000 1.361 +++ firmware/mpeg.c 16 Oct 2006 23:32:46 -0000 @@ -2442,34 +2442,32 @@ resume_recording(); } -void audio_set_recording_options(int frequency, int quality, - int source, int channel_mode, - bool editable, int prerecord_time) +void audio_set_recording_options(struct audio_recording_options *options) { bool is_mpeg1; - is_mpeg1 = (frequency < 3)?true:false; + is_mpeg1 = (options->rec_frequency < 3)?true:false; rec_version_index = is_mpeg1?3:2; - rec_frequency_index = frequency % 3; + rec_frequency_index = options->rec_frequency % 3; - shadow_encoder_control = (quality << 17) | + shadow_encoder_control = (options->rec_quality << 17) | (rec_frequency_index << 10) | ((is_mpeg1?1:0) << 9) | - (((channel_mode * 2 + 1) & 3) << 6) | + (((options->rec_channels * 2 + 1) & 3) << 6) | (1 << 5) /* MS-stereo */ | (1 << 2) /* Is an original */; mas_writemem(MAS_BANK_D0, MAS_D0_ENCODER_CONTROL, &shadow_encoder_control,1); DEBUGF("mas_writemem(MAS_BANK_D0, ENCODER_CONTROL, %x)\n", shadow_encoder_control); - shadow_soft_mute = editable?4:0; + shadow_soft_mute = options->rec_editable?4:0; mas_writemem(MAS_BANK_D0, MAS_D0_SOFT_MUTE, &shadow_soft_mute,1); DEBUGF("mas_writemem(MAS_BANK_D0, SOFT_MUTE, %x)\n", shadow_soft_mute); shadow_io_control_main = ((1 << 10) | /* Monitoring ON */ - ((source < 2)?1:2) << 8) | /* Input select */ + ((options->rec_source < 2)?1:2) << 8) | /* Input select */ (1 << 5) | /* SDO strobe invert */ ((is_mpeg1?0:1) << 3) | (1 << 2) | /* Inverted SIBC clock signal */ @@ -2478,7 +2476,7 @@ DEBUGF("mas_writemem(MAS_BANK_D0, IO_CONTROL_MAIN, %x)\n", shadow_io_control_main); - if(source == AUDIO_SRC_MIC) + if(options->rec_source == AUDIO_SRC_MIC) { /* Copy left channel to right (mono mode) */ mas_codec_writereg(8, 0x8000); @@ -2489,7 +2487,7 @@ mas_codec_writereg(8, 0); } - prerecording_max_seconds = prerecord_time; + prerecording_max_seconds = options->rec_prerecord_time; if(prerecording_max_seconds) { prerecording = true; Index: firmware/pcm_playback.c =================================================================== RCS file: /cvsroot/rockbox/firmware/pcm_playback.c,v retrieving revision 1.119 diff -u -r1.119 pcm_playback.c --- firmware/pcm_playback.c 10 Oct 2006 19:12:05 -0000 1.119 +++ firmware/pcm_playback.c 16 Oct 2006 23:32:47 -0000 @@ -43,6 +43,7 @@ #include #include #include "pcm_playback.h" +#include "audio.h" #include "lcd.h" #include "button.h" #include "file.h" @@ -82,21 +83,158 @@ return 0; } #else + #ifdef CPU_COLDFIRE +#define HAVE_PCM_SET_MONITOR +#define HAVE_PCM_APPLY_SETTINGS +#define HAVE_PCM_SAMPLERATE_SWITCHING + #ifdef HAVE_SPDIF_OUT #define EBU_DEFPARM ((7 << 12) | (3 << 8) | (1 << 5) | (5 << 2)) #endif -#define IIS_DEFPARM(freq) ((freq << 12) | 0x300 | 4 << 2) #define IIS_RESET 0x800 #ifdef IAUDIO_X5 #define SET_IIS_CONFIG(x) IIS1CONFIG = (x); +#define IIS_CONFIG IIS1CONFIG #else #define SET_IIS_CONFIG(x) IIS2CONFIG = (x); +#define IIS_CONFIG IIS2CONFIG +#endif + +#define FPARM_CLOCKSEL 0 +#if CONFIG_CPU == MCF5249 && defined(HAVE_UDA1380) +#define FPARM_UDA1380_FSEL 1 +static const unsigned char pcm_freq_parms[HW_NUM_FREQ][2] = +{ + [HW_FREQ_88] = { 0x0c, 0x03 }, + [HW_FREQ_44] = { 0x06, 0x02 }, + [HW_FREQ_22] = { 0x04, 0x01 }, + [HW_FREQ_11] = { 0x02, 0x00 }, +}; +#endif + +#if CONFIG_CPU == MCF5250 && defined(HAVE_TLV320) +#define FPARM_CLSEL 1 +#define FPARM_TLV320_FSEL 2 +static const unsigned char pcm_freq_parms[HW_NUM_FREQ][3] = +{ + [HW_FREQ_88] = { 0x0c, 0x01, 0x02 }, + [HW_FREQ_44] = { 0x06, 0x01, 0x01 }, + [HW_FREQ_22] = { 0x04, 0x01, 0x00 }, + [HW_FREQ_11] = { 0x02, 0x02, 0x00 }, +}; +#endif + +static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ +static const unsigned char *freq_ent = pcm_freq_parms[HW_FREQ_DEFAULT]; +#ifndef IAUDIO_X5 +static bool pcm_record = false; +#endif +/* set frequency used by the audio hardware */ +void pcm_set_frequency(unsigned int frequency) +{ + int index; + + switch(frequency) + { + case SAMPR_11: + index = HW_FREQ_11; + break; + case SAMPR_22: + index = HW_FREQ_22; + break; + default: + case SAMPR_44: + index = HW_FREQ_44; + break; + case SAMPR_88: + index = HW_FREQ_88; + break; + } + + /* remember table entry and rate */ + freq_ent = pcm_freq_parms[index]; + pcm_freq = hw_freq_sampr[index]; +} + +/** monitoring selection **/ +static unsigned pcm_monitor = PCM_MONITOR_PLAYBACK; + +/* Raw values for 10, 9, 8 */ +static const unsigned char pcm_txsrc_select[PCM_NUM_MONITOR_SOURCES] = +{ + [PCM_MONITOR_PLAYBACK] = 3, /* PDOR3 */ + [PCM_MONITOR_RECORDING] = 4, /* IIS1 RcvData */ +#ifdef HAVE_SPDIF_IN + [PCM_MONITOR_SPDIF] = 7, /* EBU1 RcvData */ #endif +}; -static int pcm_freq = 0x6; /* 44.1 is default */ +void pcm_set_monitor(int monitor) +{ + if ((unsigned)monitor >= PCM_NUM_MONITOR_SOURCES) + monitor = PCM_MONITOR_PLAYBACK; + pcm_monitor = monitor; +} + +#ifndef IAUDIO_X5 +void pcm_enable_recording(bool enable) +{ + pcm_record = enable; +} +#endif + +#if 0 +/* quick change of monitoring source */ +void pcm_change_monitor(int monitor) +{ + /* just update monitoring immediately */ + if ((unsigned)monitor >= PCM_NUM_MONITOR_SOURCES) + monitor = PCM_MONITOR_PLAYBACK; + SET_IIS_CONFIG((IIS_CONFIG & ~((1 << 16) | (7 << 8))) | + (pcm_txsrc_select[monitor] << 8)); +} +#endif + +/* apply audio settings */ +void pcm_apply_settings(bool reset) +{ + /* Playback must prevent pops and record monitoring won't work at all + adding IIS_RESET when setting IIS_CONFIG. Use a different method for + each. */ + if (reset && (pcm_monitor != PCM_MONITOR_PLAYBACK)) + { + /* Not playback - reset first */ + SET_IIS_CONFIG(IIS_RESET); + reset = false; + } + +#ifndef IAUDIO_X5 + IIS1CONFIG = IIS_RESET; + if (pcm_record) + { + /* Turn on clock to receive data from the uda */ + /* SCLK,LRCK = Audio Clk/2,4,8,16, TXSRC = Digital Zero, + LRCK = 64bclk/wclk */ + IIS1CONFIG = (freq_ent[FPARM_CLOCKSEL] << 12) | (4 << 2); + } +#endif + +#ifdef HAVE_TLV320 + coldfire_set_pllcr_audio_bits((freq_ent[FPARM_CLSEL] << 28) | (1 << 22)); + tlv320_set_frequency(freq_ent[FPARM_TLV320_FSEL]); +#endif +#ifdef HAVE_UDA1380 + uda1380_set_frequency(freq_ent[FPARM_UDA1380_FSEL]); +#endif + + SET_IIS_CONFIG((freq_ent[FPARM_CLOCKSEL] << 12) | + (pcm_txsrc_select[pcm_monitor] << 8) | + (4 << 2) | /* 64 bit clocks / word clock */ + (reset ? IIS_RESET : 0)); +} int peak_left = 0, peak_right = 0; @@ -119,7 +257,7 @@ BCR0 = size; /* Bytes to transfer */ /* Enable the FIFO and force one write to it */ - SET_IIS_CONFIG(IIS_DEFPARM(pcm_freq)); + pcm_apply_settings(false); /* Also send the audio to S/PDIF */ #ifdef HAVE_SPDIF_OUT EBU1CONFIG = EBU_DEFPARM; @@ -135,39 +273,12 @@ DCR0 = 0; DSR0 = 1; /* Reset the FIFO */ - SET_IIS_CONFIG(IIS_RESET | IIS_DEFPARM(pcm_freq)); + pcm_apply_settings(true); #ifdef HAVE_SPDIF_OUT EBU1CONFIG = IIS_RESET | EBU_DEFPARM; #endif } -/* sets frequency of input to DAC */ -void pcm_set_frequency(unsigned int frequency) -{ - switch(frequency) - { - case 11025: - pcm_freq = 0x2; -#ifdef HAVE_UDA1380 - uda1380_set_nsorder(3); -#endif - break; - case 22050: - pcm_freq = 0x4; -#ifdef HAVE_UDA1380 - uda1380_set_nsorder(3); -#endif - break; - case 44100: - default: - pcm_freq = 0x6; -#ifdef HAVE_UDA1380 - uda1380_set_nsorder(5); -#endif - break; - } -} - size_t pcm_get_bytes_waiting(void) { return (BCR0 & 0xffffff); @@ -236,10 +347,14 @@ ICR6 = 0x1c; IMR &= ~(1<<14); /* bit 14 is DMA0 */ - pcm_set_frequency(44100); + pcm_set_frequency(-1); + pcm_set_monitor(-1); /* Prevent pops (resets DAC to zero point) */ - SET_IIS_CONFIG(IIS_DEFPARM(pcm_freq) | IIS_RESET); + SET_IIS_CONFIG((freq_ent[FPARM_CLOCKSEL] << 12) | + (pcm_txsrc_select[pcm_monitor] << 8) | + (4 << 2) | + IIS_RESET); #if defined(HAVE_UDA1380) /* Initialize default register values. */ @@ -280,7 +395,7 @@ #define FIFO_FREE_COUNT 4 /* TODO: make this sensible */ #endif -static int pcm_freq = 44100; /* 44.1 is default */ +static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ /* NOTE: The order of these two variables is important if you use the iPod assembler optimised fiq handler, so don't change it. */ @@ -361,7 +476,7 @@ void pcm_set_frequency(unsigned int frequency) { - pcm_freq=frequency; + pcm_freq = HW_SAMPR_DEFAULT; } size_t pcm_get_bytes_waiting(void) @@ -536,7 +651,7 @@ short __attribute__((section(".dmabuf"))) dma_buf_left[DMA_BUF_SAMPLES]; short __attribute__((section(".dmabuf"))) dma_buf_right[DMA_BUF_SAMPLES]; -static int pcm_freq = 44100; /* 44.1 is default */ +static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */ unsigned short* p IBSS_ATTR; size_t p_size IBSS_ATTR; @@ -685,7 +800,7 @@ void pcm_set_frequency(unsigned int frequency) { - pcm_freq=frequency; + pcm_freq = HW_SAMPR_DEFAULT; } size_t pcm_get_bytes_waiting(void) { @@ -702,6 +817,22 @@ #endif +/* dummy functions for those not actually supporting all this yet */ +#ifndef HAVE_PCM_APPLY_SETTINGS +void pcm_apply_settings(bool reset) +{ + (void)reset; +} +#endif + +#ifndef HAVE_PCM_SET_MONITOR +void pcm_set_monitor(int monitor) +{ + (void)monitor; +} +#endif +/** **/ + void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size), unsigned char* start, size_t size) { @@ -752,7 +883,7 @@ #ifdef CPU_COLDFIRE /* Enable the FIFO and force one write to it */ - SET_IIS_CONFIG(IIS_DEFPARM(pcm_freq)); + pcm_apply_settings(false); #ifdef HAVE_SPDIF_OUT EBU1CONFIG = EBU_DEFPARM; #endif @@ -813,7 +944,7 @@ #ifdef CPU_COLDFIRE /* Disable DMA peripheral request. */ DCR0 &= ~DMA_EEXT; - SET_IIS_CONFIG(IIS_RESET | IIS_DEFPARM(pcm_freq)); + pcm_apply_settings(true); #ifdef HAVE_SPDIF_OUT EBU1CONFIG = IIS_RESET | EBU_DEFPARM; #endif Index: firmware/pcm_record.c =================================================================== RCS file: /cvsroot/rockbox/firmware/pcm_record.c,v retrieving revision 1.34 diff -u -r1.34 pcm_record.c --- firmware/pcm_record.c 5 Oct 2006 10:07:02 -0000 1.34 +++ firmware/pcm_record.c 16 Oct 2006 23:32:48 -0000 @@ -31,8 +31,10 @@ #include "cpu.h" #include "i2c.h" #include "power.h" +#include "ata.h" #ifdef HAVE_UDA1380 #include "uda1380.h" +#include "general.h" #endif #ifdef HAVE_TLV320 #include "tlv320.h" @@ -54,32 +56,6 @@ #include "id3.h" #include "pcm_record.h" -extern int boost_counter; /* used for boost check */ - -/***************************************************************************/ - -static bool is_recording; /* We are recording */ -static bool is_paused; /* We have paused */ -static bool is_error; /* An error has occured */ - -static unsigned long num_rec_bytes; /* Num bytes recorded */ -static unsigned long num_file_bytes; /* Num bytes written to current file */ -static int error_count; /* Number of DMA errors */ -static unsigned long num_pcm_samples; /* Num pcm samples written to current file */ - -static long record_start_time; /* current_tick when recording was started */ -static long pause_start_time; /* current_tick when pause was started */ -static unsigned int sample_rate; /* Sample rate at time of recording start */ -static int rec_source; /* Current recording source */ - -static int wav_file; -static char recording_filename[MAX_PATH]; - -static volatile bool init_done, close_done, record_done; -static volatile bool stop_done, pause_done, resume_done, new_file_done; - -static int peak_left, peak_right; - #ifdef IAUDIO_X5 #define SET_IIS_PLAY(x) IIS1CONFIG = (x); #define SET_IIS_REC(x) IIS1CONFIG = (x); @@ -87,128 +63,183 @@ #define SET_IIS_PLAY(x) IIS2CONFIG = (x); #define SET_IIS_REC(x) IIS1CONFIG = (x); #endif - + +#define IIS_RESET 0x800 + +/***************************************************************************/ + +/** General recording state **/ +static bool is_recording; /* We are recording */ +static bool is_paused; /* We have paused */ +static bool is_stopping = false; /* We are currently stopping */ +static bool is_error; /* An error has occured */ +static int error_count; /* Number of DMA errors */ + +/** Stats on encoded data for current file **/ +static size_t num_rec_bytes; /* Num bytes recorded */ +static unsigned long num_rec_samples; /* Number of PCM samples recorded */ + +/** Stats on encoded data for all file from start to stop **/ +static unsigned long long accum_rec_bytes; /* total size written to chunks */ +static unsigned long long accum_pcm_samples; /* total pcm count processed */ + +/* Keeps data about current file and is sent as event data for codec */ +static struct enc_file_event_data rec_fdata IDATA_ATTR = { + .chunk = NULL, + .new_enc_size = 0, + .new_num_pcm = 0, + .rec_file = -1, + .num_pcm_samples = 0 +}; + +/** These apply to current settings **/ +static int rec_source; /* current rec_source setting */ +static int rec_frequency; /* current frequency setting */ +static unsigned long sample_rate; /* Sample rate in HZ */ +static int num_channels; /* Current number of channels */ +static bool rec_new_file_flush; /* Flush file immediately */ +static struct encoder_config enc_config; /* Current encoder configuration */ + /**************************************************************************** - use 2 circular buffers of same size: - rec_buffer=DMA output buffer: chunks (8192 Bytes) of raw pcm audio data + use 2 circular buffers: + pcm_buffer=DMA output buffer: chunks (8192 Bytes) of raw pcm audio data enc_buffer=encoded audio buffer: storage for encoder output data Flow: - 1. when entering recording_screen DMA feeds the ringbuffer rec_buffer + 1. when entering recording_screen DMA feeds the ringbuffer pcm_buffer 2. if enough pcm data are available the encoder codec does encoding of pcm chunks (4-8192 Bytes) into ringbuffer enc_buffer in codec_thread 3. pcmrec_callback detects enc_buffer 'near full' and writes data to disk - Functions calls: - 1.main: codec_load_encoder(); start the encoder - 2.encoder: enc_get_inputs(); get encoder buffsize, mono/stereo, quality - 3.encoder: enc_set_parameters(); set the encoder parameters (max.chunksize) - 4.encoder: enc_get_wav_data(); get n bytes of unprocessed pcm data - 5.encoder: enc_wavbuf_near_empty();if true: reduce cpu_boost + Functions calls (basic encoder steps): + 1.main: audio_load_encoder(); start the encoder + 2.encoder: enc_get_inputs(); get encoder recording settings + 3.encoder: enc_set_parameters(); set the encoder parameters + 4.encoder: enc_get_pcm_data(); get n bytes of unprocessed pcm data + 5.encoder: enc_pcm_buf_near_empty(); if 1: reduce cpu_boost 6.encoder: enc_alloc_chunk(); get a ptr to next enc chunk 7.encoder: compress and store data to enc chunk 8.encoder: enc_free_chunk(); inform main about chunk process finished 9.encoder: repeat 4. to 8. - A.main: enc_set_header_callback(); create the current format header (file) + A.pcmrec: enc_events_callback(); called for certain events ****************************************************************************/ -#define NUM_CHUNKS 256 /* Power of 2 */ -#define CHUNK_SIZE 8192 /* Power of 2 */ -#define MAX_FEED_SIZE 20000 /* max pcm size passed to encoder */ -#define CHUNK_MASK (NUM_CHUNKS * CHUNK_SIZE - 1) -#define WRITE_THRESHOLD (44100 * 5 / enc_samp_per_chunk) /* 5sec */ -#define GET_CHUNK(x) (long*)(&rec_buffer[x]) -#define GET_ENC_CHUNK(x) (long*)(&enc_buffer[enc_chunk_size*(x)]) - -static int audio_enc_id; /* current encoder id */ -static unsigned char *rec_buffer; /* Circular recording buffer */ -static unsigned char *enc_buffer; /* Circular encoding buffer */ -static unsigned char *enc_head_buffer; /* encoder header buffer */ -static int enc_head_size; /* used size in header buffer */ -static int write_pos; /* Current chunk pos for DMA writing */ -static int read_pos; /* Current chunk pos for encoding */ -static long pre_record_ticks;/* pre-record time expressed in ticks */ -static int enc_wr_index; /* Current encoding chunk write index */ -static int enc_rd_index; /* Current encoding chunk read index */ -static int enc_chunk_size; /* maximum encoder chunk size */ -static int enc_num_chunks; /* number of chunks in ringbuffer */ -static int enc_buffer_size; /* encode buffer size */ -static int enc_channels; /* 1=mono 2=stereo */ -static int enc_quality; /* mp3: 64,96,128,160,192,320 kBit */ -static int enc_samp_per_chunk;/* pcm samples per encoder chunk */ -static bool wav_queue_empty; /* all wav chunks processed? */ -static unsigned long avrg_bit_rate; /* average bit rates from chunks */ -static unsigned long curr_bit_rate; /* cumulated bit rates from chunks */ -static unsigned long curr_chunk_cnt; /* number of processed chunks */ - -void (*enc_set_header_callback)(void *head_buffer, int head_size, - int num_pcm_samples, bool is_file_header); + +/** buffer parameters where incoming PCM data is placed **/ +#define PCM_NUM_CHUNKS 256 /* Power of 2 */ +#define PCM_CHUNK_SIZE 8192 /* Power of 2 */ +#define PCM_CHUNK_MASK (PCM_NUM_CHUNKS*PCM_CHUNK_SIZE - 1) + +#define GET_PCM_CHUNK(offset) ((long *)(pcm_buffer + (offset))) +#define GET_ENC_CHUNK(index) ENC_CHUNK_HDR(enc_buffer + enc_chunk_size*(index)) + +#define INC_ENC_INDEX(index) \ + { if (++index >= enc_num_chunks) index = 0; } +#define DEC_ENC_INDEX(index) \ + { if (--index < 0) index = enc_num_chunks - 1; } + +static unsigned char *pcm_buffer; /* circular recording buffer */ +static unsigned char *enc_buffer; /* circular encoding buffer */ +static volatile int dma_wr_pos; /* current DMA write pos */ +static int pcm_rd_pos; /* current PCM read pos */ +static volatile bool dma_lock; /* lock DMA write position */ +static unsigned long pre_record_ticks;/* pre-record time in ticks */ +static int enc_wr_index; /* encoder chunk write index */ +static int enc_rd_index; /* encoder chunk read index */ +static int enc_num_chunks; /* number of chunks in ringbuffer */ +static size_t enc_chunk_size; /* maximum encoder chunk size */ +static size_t enc_data_size; /* maximum data size for encoder */ +static unsigned long enc_sample_rate; /* sample rate used by encoder */ +static bool wav_queue_empty; /* all wav chunks processed? */ + +/** file flushing **/ +static int write_threshold; /* max chunk limit for data flush */ +static int panic_threshold; /* boost thread prio when here */ +static int spinup_time = -1;/* last ata_spinup_time */ +static bool flush_next_data; /* flush the next data ready */ + +/** encoder events **/ +static void (*enc_events_callback)(enum enc_events event, void *data); + +/** Path queue for files to write **/ +#define FNQ_MIN_NUM_PATHS 16 /* minimum number of paths to hold */ +static unsigned char *fn_queue; /* pointer to first filename */ +static ssize_t fnq_size; /* capacity of queue in bytes */ +static int fnq_rd_pos; /* current read position */ +static int fnq_wr_pos; /* current write position */ + +/** Peakmeter peaks **/ +static int peak_left = 0, peak_right = 0; /* current peaks */ +static unsigned char *peak_ptr; /***************************************************************************/ static struct event_queue pcmrec_queue; -static long pcmrec_stack[2*DEFAULT_STACK_SIZE/sizeof(long)]; +static long pcmrec_stack[3*DEFAULT_STACK_SIZE/sizeof(long)]; static const char pcmrec_thread_name[] = "pcmrec"; static void pcmrec_thread(void); static void pcmrec_dma_start(void); static void pcmrec_dma_stop(void); -static void close_wave(void); -/* Event IDs */ -#define PCMREC_INIT 1 /* Enable recording */ -#define PCMREC_CLOSE 2 - -#define PCMREC_START 3 /* Start a new recording */ -#define PCMREC_STOP 4 /* Stop the current recording */ -#define PCMREC_PAUSE 10 -#define PCMREC_RESUME 11 -#define PCMREC_NEW_FILE 12 -#define PCMREC_SET_GAIN 13 +/* Event values which are also single-bit flags */ +#define PCMREC_INIT 0x00000001 /* enable recording */ +#define PCMREC_CLOSE 0x00000002 -/*******************************************************************/ -/* Functions that are not executing in the pcmrec_thread first */ -/*******************************************************************/ +#define PCMREC_START 0x00000004 /* start recording (when stopped) */ +#define PCMREC_STOP 0x00000008 /* stop the current recording */ +#define PCMREC_PAUSE 0x00000010 /* pause the current recording */ +#define PCMREC_RESUME 0x00000020 /* resume the current recording */ +#define PCMREC_NEW_FILE 0x00000040 /* start new file (when recording) */ +#define PCMREC_SET_GAIN 0x00000080 +#define PCMREC_FLUSH_NUM 0x00000100 /* flush a number of files out */ +#define PCMREC_FINISH_STOP 0x00000200 /* finish the stopping recording */ -/* Creates pcmrec_thread */ -void pcm_rec_init(void) -{ - queue_init(&pcmrec_queue, true); - create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), - pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING)); -} +/* mask for signaling events */ +static volatile long pcm_thread_event_mask; +static void pcm_thread_sync_post(long event, void *data) +{ + pcm_thread_event_mask &= ~event; + queue_post(&pcmrec_queue, event, data); + while(!(event & pcm_thread_event_mask)) + yield(); +} /* pcm_thread_sync_post */ -int audio_get_encoder_id(void) +static inline void pcm_thread_signal_event(long event) { - return audio_enc_id; -} + pcm_thread_event_mask |= event; +} /* pcm_thread_signal_event */ -/* Initializes recording: - * - Set up the UDA1380/TLV320 for recording - * - Prepare for DMA transfers - */ - -void audio_init_recording(unsigned int buffer_offset) +static inline void pcm_thread_unsignal_event(long event) { - (void)buffer_offset; + pcm_thread_event_mask &= ~event; +} /* pcm_thread_unsignal_event */ - init_done = false; - queue_post(&pcmrec_queue, PCMREC_INIT, 0); - - while(!init_done) - sleep_thread(1); -} +static inline bool pcm_thread_event_state(long signaled, long unsignaled) +{ + return ((signaled | unsignaled) & pcm_thread_event_mask) == signaled; +} /* pcm_thread_event_state */ -void audio_close_recording(void) +static void pcm_thread_wait_for_stop(void) { - close_done = false; - queue_post(&pcmrec_queue, PCMREC_CLOSE, 0); - - while(!close_done) - sleep_thread(1); + if (is_stopping) + { + logf("waiting for stop to finsish"); + while (is_stopping) + yield(); + } +} /* pcm_thread_wait_for_stop */ - audio_remove_encoder(); -} +/*******************************************************************/ +/* Functions that are not executing in the pcmrec_thread first */ +/*******************************************************************/ + +/** pcm_rec_* group **/ + +void pcm_rec_error_clear(void) +{ + is_error = false; +} /* pcm_rec_error_clear */ unsigned long pcm_rec_status(void) { @@ -216,165 +247,296 @@ if (is_recording) ret |= AUDIO_STATUS_RECORD; + if (is_paused) ret |= AUDIO_STATUS_PAUSE; + if (is_error) ret |= AUDIO_STATUS_ERROR; - if (!is_recording && pre_record_ticks && init_done && !close_done) + + if (!is_recording && pre_record_ticks && + pcm_thread_event_state(PCMREC_INIT, PCMREC_CLOSE)) ret |= AUDIO_STATUS_PRERECORD; return ret; -} +} /* pcm_rec_status */ int pcm_rec_current_bitrate(void) { - return avrg_bit_rate; -} + if (accum_pcm_samples == 0) + return 0; -unsigned long audio_recorded_time(void) + return (int)(8*accum_rec_bytes*enc_sample_rate / (1000*accum_pcm_samples)); +} /* pcm_rec_current_bitrate */ + +int pcm_rec_encoder_afmt(void) { - if (is_recording) + return enc_config.afmt; +} /* pcm_rec_encoder_afmt */ + +int pcm_rec_rec_format(void) +{ + return afmt_rec_format[enc_config.afmt]; +} /* pcm_rec_rec_format */ + +unsigned long pcm_rec_sample_rate(void) +{ + /* Which is better ?? */ +#if 0 + return enc_sample_rate; +#endif + return sample_rate; +} /* audio_get_sample_rate */ + +/** + * Creates pcmrec_thread + */ +void pcm_rec_init(void) +{ + queue_init(&pcmrec_queue, true); + create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), + pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING)); +} /* pcm_rec_init */ + +/** + * Return peaks - Looks at every 4th sample but over the entire available + * block of samples since the last calculation for accuracy when recording. + */ +void pcm_rec_get_peaks(int *left, int *right) +{ + unsigned char *ptr, *ptr_end; + + if (dma_lock) { - if (is_paused) - return pause_start_time - record_start_time; - else - return current_tick - record_start_time; + ptr = pcm_buffer + dma_wr_pos; + ptr_end = ptr + PCM_CHUNK_SIZE; } + else + { + unsigned long end_pos = DAR1; /* snapshot DMA address */ + ptr = (unsigned char *)((long)peak_ptr & ~0xf); + ptr_end = (unsigned char *)(end_pos & ~0xf); + } + + if (ptr_end >= pcm_buffer + PCM_CHUNK_SIZE*PCM_NUM_CHUNKS) + ptr_end -= PCM_CHUNK_SIZE*PCM_NUM_CHUNKS; + + if (ptr != ptr_end) + { + long peak1_p = 0, peak1_n = 0; /* L +,- */ + long peak2_p = 0, peak2_n = 0; /* R +,- */ + + /* peak one sample per line */ + do + { + long value = *(long *)ptr; + long ch; + + ch = value >> 16; + if (ch < peak1_n) + peak1_n = ch; + else if (ch > peak1_p) + peak1_p = ch; + + ch = (short)value; + if (ch > peak2_p) + peak2_p = ch; + else if (ch < peak2_n) + peak2_n = ch; + + ptr += 16; + if (ptr >= pcm_buffer + PCM_CHUNK_SIZE*PCM_NUM_CHUNKS) + ptr = pcm_buffer; + } + while (ptr != ptr_end); + + peak_ptr = ptr; + + /* save peaks */ +#ifdef ROCKBOX_BIG_ENDIAN + /* left channel in peak1 */ + peak_left = MAX(peak1_p, -peak1_n); + peak_right = MAX(peak2_p, -peak2_n); +#else + /* right channel in peak1 */ + peak_left = MAX(peak2_p, -peak2_n); + peak_right = MAX(peak1_p, -peak1_n); +#endif + } + + if (left) + *left = peak_left; + + if (right) + *right = peak_right; +} /* pcm_rec_get_peaks */ + +/** audio_* group **/ + +/** + * Initializes recording: + * - Set up the UDA1380/TLV320 for recording + * - Prepare for DMA transfers + */ +void audio_init_recording(unsigned int buffer_offset) +{ + (void)buffer_offset; + pcm_thread_wait_for_stop(); + pcm_thread_sync_post(PCMREC_INIT, NULL); +} /* audio_init_recording */ + +void audio_close_recording(void) +{ + pcm_thread_wait_for_stop(); + pcm_thread_sync_post(PCMREC_CLOSE, NULL); + audio_remove_encoder(); + /* reset pcm to defaults */ + pcm_set_frequency(-1); + pcm_set_monitor(-1); + pcm_enable_recording(false); + pcm_apply_settings(true); +} /* audio_close_recording */ + +unsigned long audio_recorded_time(void) +{ + if (!is_recording || enc_sample_rate == 0) + return 0; - return 0; -} + /* return actual recorded time a la encoded data even if encoder rate + doesn't match the pcm rate */ + return (long)(HZ*(unsigned long long)num_rec_samples / enc_sample_rate); +} /* audio_recorded_time */ unsigned long audio_num_recorded_bytes(void) { - if (is_recording) - return num_rec_bytes; + if (!is_recording) + return 0; - return 0; -} + return num_rec_bytes; +} /* audio_num_recorded_bytes */ #ifdef HAVE_SPDIF_IN -/* Only the last six of these are standard rates, but all sample rates are - * possible, so we support some other common ones as well. - */ -static unsigned long spdif_sample_rates[] = { - 8000, 11025, 12000, 16000, 22050, 24000, - 32000, 44100, 48000, 64000, 88200, 96000 -}; - -/* Return SPDIF sample rate. Since we base our reading on the actual SPDIF - * sample rate (which might be a bit inaccurate), we round off to the closest - * sample rate that is supported by SPDIF. +/* Return SPDIF sample rate index in audio_master_sampr_list. Since we base + * our reading on the actual SPDIF sample rate (which might be a bit + * inaccurate), we round off to the closest sample rate that is supported by + * SPDIF. */ -unsigned long audio_get_spdif_sample_rate(void) +static unsigned long measure_spdif_sample_rate(void) { - int i = 0; - unsigned long measured_rate; - const int upper_bound = sizeof(spdif_sample_rates)/sizeof(long) - 1; - /* The following formula is specified in MCF5249 user's manual section * 17.6.1. The 3*(1 << 13) part will need changing if the setup of the * PHASECONFIG register is ever changed. The 128 divide is because of the * fact that the SPDIF clock is the sample rate times 128. */ - measured_rate = (unsigned long)((unsigned long long)FREQMEAS*CPU_FREQ/ - ((1 << 15)*3*(1 << 13))/128); - /* Find which SPDIF sample rate we're closest to. */ - while (spdif_sample_rates[i] < measured_rate && i < upper_bound) ++i; - if (i > 0 && i < upper_bound) - { - long diff1 = measured_rate - spdif_sample_rates[i - 1]; - long diff2 = spdif_sample_rates[i] - measured_rate; + return (unsigned long)((unsigned long long)FREQMEAS*CPU_FREQ / + ((1 << 15)*3*(1 << 13)) / 128); +} /* measure_spdif_sample_rate */ - if (diff2 > diff1) --i; - } - return i; -} -#endif +int audio_get_spdif_sample_rate(void) +{ + unsigned long measured_rate = measure_spdif_sample_rate(); + /* Find which SPDIF sample rate we're closest to. */ + return round_value_to_list32(measured_rate, audio_master_sampr_list, + SAMPR_NUM_FREQ, false); +} /* audio_get_spdif_sample_rate */ -#if 0 -/* not needed atm */ #ifdef HAVE_SPDIF_POWER static bool spdif_power_setting; void audio_set_spdif_power_setting(bool on) { spdif_power_setting = on; -} +} /* audio_set_spdif_power_setting */ + +bool audio_get_spdif_power_setting(void) +{ + return spdif_power_setting; +} /* audio_get_spdif_power_setting */ #endif + +void audio_spdif_set_monitor(bool monitor_spdif) +{ + EBU1CONFIG = IIS_RESET; /* Reset before reprogram */ + + if (monitor_spdif) + { +#ifdef HAVE_SPDIF_POWER + EBU1CONFIG = spdif_power_setting ? (1 << 2) : 0; + /* Input source is EBUin1, Feed-through monitoring if desired */ +#else + EBU1CONFIG = (1 << 2); + /* Input source is EBUin1, Feed-through monitoring */ #endif + } + else + { + /* SCLK2, TXSRC = IIS1recv, validity, normal operation */ + EBU1CONFIG = (7 << 12) | (4 << 8) | (1 << 5) | (5 << 2); + } +} /* audio_spdif_set_monitor */ + +#endif /* HAVE_SPDIF_IN */ /** * Sets recording parameters * * This functions starts feeding the CPU with audio data over the I2S bus */ -void audio_set_recording_options(int frequency, int quality, - int source, int channel_mode, - bool editable, int prerecord_time) -{ - /* TODO: */ - (void)editable; - - /* NOTE: Coldfire UDA based recording does not yet support anything other - * than 44.1kHz sampling rate, so we limit it to that case here now. SPDIF - * based recording will overwrite this value with the proper sample rate in - * audio_record(), and will not be affected by this. - */ - frequency = 44100; - enc_quality = quality; - rec_source = source; - enc_channels = channel_mode == CHN_MODE_MONO ? 1 : 2; - pre_record_ticks = prerecord_time * HZ; - - switch (source) - { - case AUDIO_SRC_MIC: - case AUDIO_SRC_LINEIN: -#ifdef HAVE_FMRADIO_IN - case AUDIO_SRC_FMRADIO: -#endif - /* Generate int. when 6 samples in FIFO, PDIR2 src = IIS1recv */ - DATAINCONTROL = 0xc020; - break; - -#ifdef HAVE_SPDIF_IN - case AUDIO_SRC_SPDIF: - /* Int. when 6 samples in FIFO. PDIR2 source = ebu1RcvData */ - DATAINCONTROL = 0xc038; - break; -#endif /* HAVE_SPDIF_IN */ - } - - sample_rate = frequency; +void audio_set_recording_options(struct audio_recording_options *options) +{ + pcm_thread_wait_for_stop(); - /* Monitoring: route the signals through the coldfire audio interface. */ + rec_frequency = options->rec_frequency; + rec_source = options->rec_source; + num_channels = options->rec_channels == 1 ? 1 : 2; + pre_record_ticks = options->rec_prerecord_time * HZ; + rec_new_file_flush = options->rec_new_file_flush; + enc_config = options->enc_config; + enc_config.afmt = rec_format_afmt[enc_config.rec_format]; - SET_IIS_PLAY(0x800); /* Reset before reprogram */ - #ifdef HAVE_SPDIF_IN - if (source == AUDIO_SRC_SPDIF) + if (rec_source == AUDIO_SRC_SPDIF) { - /* SCLK2 = Audioclk/4 (can't use EBUin clock), TXSRC = EBU1rcv, 64 bclk/wclk */ - IIS2CONFIG = (6 << 12) | (7 << 8) | (4 << 2); - /* S/PDIF feed-through already configured */ + unsigned long sr; + int index; + + /* Int. when 6 samples in FIFO. PDIR2 source = ebu1RcvData */ + DATAINCONTROL = 0xc038; + /* Must measure SPDIF sample rate before configuring codecs */ + sr = measure_spdif_sample_rate(); + /* Round to master list for SPDIF rate */ + index = round_value_to_list32(sr, audio_master_sampr_list, + SAMPR_NUM_FREQ, false); + sample_rate = audio_master_sampr_list[index]; + /* Round to HW playback rates for monitoring */ + index = round_value_to_list32(sr, hw_freq_sampr, + HW_NUM_FREQ, false); + pcm_set_frequency(hw_freq_sampr[index]); + pcm_set_monitor(PCM_MONITOR_SPDIF); + pcm_enable_recording(false); + /* Encoders with a limited number of rates do their own rounding */ } else +#endif { - /* SCLK2 follow IIS1 (UDA clock), TXSRC = IIS1rcv, 64 bclk/wclk */ - IIS2CONFIG = (8 << 12) | (4 << 8) | (4 << 2); - - EBU1CONFIG = 0x800; /* Reset before reprogram */ - /* SCLK2, TXSRC = IIS1recv, validity, normal operation */ - EBU1CONFIG = (7 << 12) | (4 << 8) | (1 << 5) | (5 << 2); + /* Int. when 6 samples in FIFO, PDIR2 src = IIS1recv */ + DATAINCONTROL = 0xc020; + sample_rate = rec_freq_sampr[rec_frequency]; + pcm_set_frequency(sample_rate); + pcm_set_monitor(PCM_MONITOR_RECORDING); + pcm_enable_recording(true); } -#else - /* SCLK2 follow IIS1 (UDA clock), TXSRC = IIS1rcv, 64 bclk/wclk */ - SET_IIS_PLAY( (8 << 12) | (4 << 8) | (4 << 2) ); -#endif - audio_load_encoder(rec_quality_info_afmt[quality]); -} + /* Apply monitoring settings to hardware */ + pcm_apply_settings(true); + dma_lock = true; + + if (!audio_load_encoder(enc_config.afmt)) + is_error = true; + + dma_lock = false; +} /* audio_set_recording_options */ /** * Note that microphone is mono, only left value is used @@ -391,8 +553,7 @@ #elif defined (HAVE_TLV320) tlv320_set_recvol(left, right, type); #endif -} - +} /* audio_set_recording_gain */ /** * Start recording @@ -401,210 +562,437 @@ */ void audio_record(const char *filename) { - if (is_recording) - { - logf("record while recording"); - return; - } - - strncpy(recording_filename, filename, MAX_PATH - 1); - recording_filename[MAX_PATH - 1] = 0; + logf("audio_record: %s", filename); -#ifdef HAVE_SPDIF_IN - if (rec_source == AUDIO_SRC_SPDIF) - sample_rate = audio_get_spdif_sample_rate(); -#endif - - record_done = false; - queue_post(&pcmrec_queue, PCMREC_START, 0); - - while(!record_done) - sleep_thread(1); -} + pcm_thread_wait_for_stop(); + pcm_thread_sync_post(PCMREC_START, (void *)filename); + logf("audio_record_done"); +} /* audio_record */ void audio_new_file(const char *filename) { - logf("pcm_new_file"); - - new_file_done = false; - - strncpy(recording_filename, filename, MAX_PATH - 1); - recording_filename[MAX_PATH - 1] = 0; - - queue_post(&pcmrec_queue, PCMREC_NEW_FILE, 0); - - while(!new_file_done) - sleep_thread(1); - - logf("pcm_new_file done"); -} + logf("audio_new_file: %s", filename); + + pcm_thread_wait_for_stop(); + pcm_thread_sync_post(PCMREC_NEW_FILE, (void *)filename); + + logf("audio_new_file done"); +} /* audio_new_file */ -/** - * - */ void audio_stop_recording(void) { - if (!is_recording) - return; + logf("audio_stop_recording"); - logf("pcm_stop"); - - is_paused = true; /* fix pcm write ptr at current position */ - stop_done = false; - queue_post(&pcmrec_queue, PCMREC_STOP, 0); + pcm_thread_wait_for_stop(); - while(!stop_done) - sleep_thread(1); + if (is_recording) + dma_lock = true; /* fix DMA write ptr at current position */ + + pcm_thread_sync_post(PCMREC_STOP, NULL); - logf("pcm_stop done"); -} + logf("audio_stop_recording done"); +} /* audio_stop_recording */ void audio_pause_recording(void) + { + logf("audio_pause_recording"); + + pcm_thread_wait_for_stop(); + + if (is_recording) + dma_lock = true; /* fix DMA write ptr at current position */ + + pcm_thread_sync_post(PCMREC_PAUSE, NULL); + logf("audio_pause_recording done"); +} /* audio_pause_recording */ + +void audio_resume_recording(void) { - if (!is_recording) + logf("audio_resume_recording"); + + pcm_thread_wait_for_stop(); + pcm_thread_sync_post(PCMREC_RESUME, NULL); + + logf("audio_resume_recording done"); +} /* audio_resume_recording */ + +/***************************************************************************/ +/* */ +/* Functions that execute in the context of pcmrec_thread */ +/* */ +/***************************************************************************/ + +/** Filename Queue **/ + +/* returns true if the queue is empty */ +static inline bool pcmrec_fnq_is_empty(void) +{ + return fnq_rd_pos == fnq_wr_pos; +} /* pcmrec_fnq_is_empty */ + +/* empties the filename queue */ +static inline void pcmrec_fnq_set_empty(void) +{ + fnq_rd_pos = fnq_wr_pos; +} /* pcmrec_fnq_set_empty */ + +/* returns true if the queue is full */ +static bool pcmrec_fnq_is_full(void) +{ + ssize_t size = fnq_wr_pos - fnq_rd_pos; + if (size < 0) + size += fnq_size; + + return size >= fnq_size - MAX_PATH; +} /* pcmrec_fnq_is_full */ + +/* queue another filename - will overwrite oldest one if full */ +static bool pcmrec_fnq_add_filename(const char *filename) +{ + strncpy(fn_queue + fnq_wr_pos, filename, MAX_PATH); + + if ((fnq_wr_pos += MAX_PATH) >= fnq_size) + fnq_wr_pos = 0; + + if (fnq_rd_pos != fnq_wr_pos) + return true; + + /* queue full */ + if ((fnq_rd_pos += MAX_PATH) >= fnq_size) + fnq_rd_pos = 0; + + return true; +} /* pcmrec_fnq_add_filename */ + +/* replace the last filename added */ +static bool pcmrec_fnq_replace_tail(const char *filename) +{ + int pos; + + if (pcmrec_fnq_is_empty()) + return false; + + pos = fnq_wr_pos - MAX_PATH; + if (pos < 0) + pos = fnq_size - MAX_PATH; + + strncpy(fn_queue + pos, filename, MAX_PATH); + + return true; +} /* pcmrec_fnq_replace_tail */ + +/* pulls the next filename from the queue */ +static bool pcmrec_fnq_get_filename(char *filename) +{ + if (pcmrec_fnq_is_empty()) + return false; + + if (filename) + strncpy(filename, fn_queue + fnq_rd_pos, MAX_PATH); + + if ((fnq_rd_pos += MAX_PATH) >= fnq_size) + fnq_rd_pos = 0; + + return true; +} /* pcmrec_fnq_get_filename */ + +/* close the file number pointed to by fd_p */ +static void pcmrec_close_file(int *fd_p) +{ + if (*fd_p < 0) + return; /* preserve error */ + + close(*fd_p); + *fd_p = -1; +} /* pcmrec_close_file */ + +/** Data Flushing **/ + +/* called after callback to update sizes if codec added data to file since + * the encoder may have added or removed data */ +static inline void pcmrec_update_sizes_inl(size_t prev_enc_size, + unsigned long prev_num_pcm) +{ + if (rec_fdata.new_enc_size != prev_enc_size) { - logf("pause when not recording"); - return; + ssize_t size_diff = rec_fdata.new_enc_size - prev_enc_size; + num_rec_bytes += size_diff; + accum_rec_bytes += size_diff; } - if (is_paused) + + if (rec_fdata.new_num_pcm != prev_num_pcm) { - logf("pause when paused"); - return; + unsigned long pcm_diff = rec_fdata.new_num_pcm - prev_num_pcm; + num_rec_samples += pcm_diff; + accum_pcm_samples += pcm_diff; } - - pause_done = false; - queue_post(&pcmrec_queue, PCMREC_PAUSE, 0); +} /* pcmrec_update_sizes_inl */ - while(!pause_done) - sleep_thread(1); -} +static void pcmrec_update_sizes(size_t prev_enc_size, + unsigned long prev_num_pcm) +{ + pcmrec_update_sizes_inl(prev_enc_size, prev_num_pcm); +} /* pcmrec_update_sizes */ -void audio_resume_recording(void) +static void pcmrec_start_file(void) { - if (!is_paused) + size_t enc_size = rec_fdata.new_enc_size; + unsigned long num_pcm = rec_fdata.new_num_pcm; + int curr_rec_file = rec_fdata.rec_file; + char filename[MAX_PATH]; + + /* must always pull the filename that matches with this queue */ + if (!pcmrec_fnq_get_filename(filename)) { - logf("resume when not paused"); - return; + logf("start file: fnq empty"); + *filename = '\0'; + is_error = true; + } + else if (is_error) + { + logf("start file: is_error already"); + } + else if (curr_rec_file >= 0) + { + /* Any previous file should have been closed */ + logf("start file: file already open"); + is_error = true; } - - resume_done = false; - queue_post(&pcmrec_queue, PCMREC_RESUME, 0); - while(!resume_done) - sleep_thread(1); -} + if (is_error) + rec_fdata.chunk->flags |= CHUNKF_ERROR; -/* return peaks as int, so convert from short first - note that peak values are always positive */ -void pcm_rec_get_peaks(int *left, int *right) + /* encoder can set error flag here and should increase + enc_new_size and pcm_new_size to reflect additional + data written if any */ + rec_fdata.filename = filename; + enc_events_callback(ENC_START_FILE, &rec_fdata); + + if (!is_error && (rec_fdata.chunk->flags & CHUNKF_ERROR)) + { + logf("start file: enc error"); + is_error = true; + } + + if (is_error) + { + pcmrec_close_file(&curr_rec_file); + /* Write no more to this file */ + rec_fdata.chunk->flags |= CHUNKF_END_FILE; + } + else + { + pcmrec_update_sizes(enc_size, num_pcm); + } + + rec_fdata.chunk->flags &= ~CHUNKF_START_FILE; +} /* pcmrec_start_file */ + +static inline void pcmrec_write_chunk(void) { - if (left) - *left = peak_left; - if (right) - *right = peak_right; - peak_left = 0; - peak_right = 0; -} + size_t enc_size = rec_fdata.new_enc_size; + unsigned long num_pcm = rec_fdata.new_num_pcm; -/***************************************************************************/ -/* Functions that executes in the context of pcmrec_thread */ -/***************************************************************************/ + if (is_error) + rec_fdata.chunk->flags |= CHUNKF_ERROR; + + enc_events_callback(ENC_WRITE_CHUNK, &rec_fdata); + + if ((long)rec_fdata.chunk->flags >= 0) + { + pcmrec_update_sizes_inl(enc_size, num_pcm); + } + else if (!is_error) + { + logf("wr chk enc error %d %d", + rec_fdata.chunk->enc_size, rec_fdata.chunk->num_pcm); + is_error = true; + } +} /* pcmrec_write_chunk */ + +static void pcmrec_end_file(void) +{ + /* all data in output buffer for current file will have been + written and encoder can now do any nescessary steps to + finalize the written file */ + size_t enc_size = rec_fdata.new_enc_size; + unsigned long num_pcm = rec_fdata.new_num_pcm; + + enc_events_callback(ENC_END_FILE, &rec_fdata); + + if (!is_error) + { + if (rec_fdata.chunk->flags & CHUNKF_ERROR) + { + logf("end file: enc error"); + is_error = true; + } + else + { + pcmrec_update_sizes(enc_size, num_pcm); + } + } + + /* Force file close if error */ + if (is_error) + pcmrec_close_file(&rec_fdata.rec_file); + + rec_fdata.chunk->flags &= ~CHUNKF_END_FILE; +} /* pcmrec_end_file */ /** * Process the chunks * * This function is called when queue_get_w_tmo times out. * - * Other functions can also call this function with flush = true when - * they want to save everything in the buffers to disk. + * Set flush_num to the number of files to flush to disk. + * flush_num = -1 to flush all available chunks to disk. + * flush_num = 0 normal write thresholding + * flush_num = 1 or greater - all available chunks of current file plus + * flush_num file starts if first chunk has been processed. * */ -static void pcmrec_callback(bool flush) +static void pcmrec_flush(unsigned flush_num) { - int i, num_ready, size_yield; - long *enc_chunk, chunk_size; - - if (!is_recording && !flush) - return; + static unsigned long last_flush_tick = 0; + unsigned long start_tick; + int num_ready, num; + int prio; + int i; num_ready = enc_wr_index - enc_rd_index; if (num_ready < 0) num_ready += enc_num_chunks; - /* calculate an estimate of recorded bytes */ - num_rec_bytes = num_file_bytes + num_ready * /* enc_chunk_size */ - ((avrg_bit_rate * 1000 / 8 * enc_samp_per_chunk + 22050) / 44100); + num = num_ready; - /* near full state reached: less than 5sec remaining space */ - if (enc_num_chunks - num_ready < WRITE_THRESHOLD || flush) + if (flush_num == 0) { - logf("writing: %d (%d)", num_ready, flush); - - cpu_boost_id(true, CPUBOOSTID_PCMRECORD); + if (!is_recording) + return; - size_yield = 0; - for (i=0; i 10*HZ) + st = 10*HZ; + + write_threshold = enc_num_chunks - + (int)(((5ull*HZ + st)*4ull*sample_rate + (enc_chunk_size-1)) / + (enc_chunk_size*HZ)); + + if (write_threshold < 0) + write_threshold = 0; + else if (write_threshold > panic_threshold) + write_threshold = panic_threshold; - /* safety net: if size entry got corrupted => limit */ - if (chunk_size > (long)(enc_chunk_size - sizeof(long))) - chunk_size = enc_chunk_size - sizeof(long); + logf("new wr thresh: %d", write_threshold); + } - if (enc_set_header_callback != NULL) - enc_set_header_callback(enc_chunk, enc_chunk_size, - num_pcm_samples, false); + if (num_ready < write_threshold) + return; - if (write(wav_file, enc_chunk, chunk_size) != chunk_size) - { - close_wave(); - logf("pcmrec: write err"); - is_error = true; - break; - } + /* if we're getting called too much and this isn't forced, + boost stat */ + if (current_tick - last_flush_tick < HZ/2) + num = panic_threshold; + } - num_file_bytes += chunk_size; - num_pcm_samples += enc_samp_per_chunk; - size_yield += chunk_size; - - if (size_yield >= 32768) - { /* yield when 32kB written */ - size_yield = 0; - yield(); - } + start_tick = current_tick; + prio = -1; + + logf("writing: %d (%d)", num_ready, flush_num); + + cpu_boost_id(true, CPUBOOSTID_PCMRECORD); + + for (i = 0; i < num_ready; i++) + { + if (prio == -1 && (num >= panic_threshold || + current_tick - start_tick > 10*HZ)) + { + /* losing ground - boost priority until finished */ + logf("pcmrec: boost priority"); + prio = thread_set_priority(NULL, thread_get_priority(NULL)-1); + } + + rec_fdata.chunk = GET_ENC_CHUNK(enc_rd_index); + rec_fdata.new_enc_size = rec_fdata.chunk->enc_size; + rec_fdata.new_num_pcm = rec_fdata.chunk->num_pcm; + + if (rec_fdata.chunk->flags & CHUNKF_START_FILE) + { + pcmrec_start_file(); + if (--flush_num == 0) + i = num_ready; /* stop on next loop - must write this + chunk if it has data */ + } + + pcmrec_write_chunk(); + + if (rec_fdata.chunk->flags & CHUNKF_END_FILE) + pcmrec_end_file(); - enc_rd_index = (enc_rd_index + 1) % enc_num_chunks; + INC_ENC_INDEX(enc_rd_index); + + if (is_error) + break; + + if (prio == -1) + { + num = enc_wr_index - enc_rd_index; + if (num < 0) + num += enc_num_chunks; } - /* sync file */ - fsync(wav_file); + /* no yielding, the file apis called in the codecs do that */ + } /* end for */ + + /* sync file */ + if (rec_fdata.rec_file >= 0) + fsync(rec_fdata.rec_file); - cpu_boost_id(false, CPUBOOSTID_PCMRECORD); + cpu_boost_id(false, CPUBOOSTID_PCMRECORD); - logf("done"); + if (prio != -1) + { + /* return to original priority */ + logf("pcmrec: unboost priority"); + thread_set_priority(NULL, prio); } -} + + last_flush_tick = current_tick; /* save tick when we left */ + logf("done"); +} /* pcmrec_flush */ /* Abort dma transfer */ static void pcmrec_dma_stop(void) { DCR1 = 0; - error_count++; + DSR1 = 1; /* Clear interrupt */ + IPR |= (1 << 15); /* Clear pending interrupt request */ - DSR1 = 1; /* Clear interrupt */ - IPR |= (1<<15); /* Clear pending interrupt request */ + /* clear peaks */ + peak_left = peak_right = 0; + peak_ptr = (unsigned char *)DAR1; logf("dma1 stopped"); -} +} /* pcmrec_dma_stop */ static void pcmrec_dma_start(void) { - DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ - SAR1 = (unsigned long)&PDIR2; /* Source address */ - BCR1 = CHUNK_SIZE; /* Bytes to transfer */ + DAR1 = (unsigned long)GET_PCM_CHUNK(dma_wr_pos); /* Destination address */ + SAR1 = (unsigned long)&PDIR2; /* Source address */ + BCR1 = PCM_CHUNK_SIZE; /* Bytes to transfer */ + + peak_ptr = (unsigned char *)DAR1; /* Start the DMA transfer.. */ #ifdef HAVE_SPDIF_IN @@ -615,7 +1003,7 @@ DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_DSIZE(3) | DMA_START; logf("dma1 started"); -} +} /* pcmrec_dma_start */ /* DMA1 Interrupt is called when the DMA has finished transfering a chunk */ void DMA1(void) __attribute__ ((interrupt_handler, section(".icode"))); @@ -632,231 +1020,416 @@ logf("dma1 err: 0x%x", res); - DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ - BCR1 = CHUNK_SIZE; - DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC | DMA_START; - /* Flush recorded data to disk and stop recording */ queue_post(&pcmrec_queue, PCMREC_STOP, NULL); - } -#ifdef HAVE_SPDIF_IN - else if ((rec_source == AUDIO_SRC_SPDIF) && - (INTERRUPTSTAT & 0x01c00000)) /* valnogood, symbolerr, parityerr */ + } + else { - INTERRUPTCLEAR = 0x03c00000; - error_count++; +#ifdef HAVE_SPDIF_IN + if ((rec_source == AUDIO_SRC_SPDIF) && + (INTERRUPTSTAT & 0x01c00000)) /* valnogood, symbolerr, parityerr */ + { + INTERRUPTCLEAR = 0x03c00000; + error_count++; - logf("spdif err"); + logf("spdif err"); + } + else +#endif + /* advance write position */ + if (!dma_lock) + dma_wr_pos = (dma_wr_pos + PCM_CHUNK_SIZE) & PCM_CHUNK_MASK; - DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ - BCR1 = CHUNK_SIZE; + /* Destination address */ + DAR1 = (unsigned long)GET_PCM_CHUNK(dma_wr_pos); + BCR1 = PCM_CHUNK_SIZE; /* Destination size */ } -#endif - else - { - long peak_l, peak_r; - long *ptr, j; - ptr = GET_CHUNK(write_pos); + IPR |= (1 << 15); /* Clear pending interrupt request */ +} /* DMA1 */ + +/** + * Marks a new stream in the buffer and gives the encoder a chance for special + * handling of transition from one to the next. The encoder may change the + * chunk that ends the old stream by requesting more chunks and similiarly for + * the new but must always advance the position though the interface. It can + * later reject any data it cares to when writing the file but should mark the + * chunk so it can recognize this. ENC_WRITE_CHUNK event must be able to accept + * a NULL data pointer without error as well. + */ +static void pcmrec_new_stream(const char *filename, /* next file name */ + unsigned long flags, /* CHUNKF_* flags */ + int pre_index) /* index for prerecorded data */ +{ + logf("pcmrec_new_stream"); - if (!is_paused) /* advance write position */ - write_pos = (write_pos + CHUNK_SIZE) & CHUNK_MASK; + struct enc_buffer_event_data data; + bool (*fnq_add_fn)(const char *) = NULL; + struct enc_chunk_hdr *start = NULL; - DAR1 = (unsigned long)GET_CHUNK(write_pos); /* Destination address */ - BCR1 = CHUNK_SIZE; + int get_chunk_index(struct enc_chunk_hdr *chunk) + { + return ((char *)chunk - (char *)enc_buffer) / enc_chunk_size; + } - peak_l = peak_r = 0; + struct enc_chunk_hdr * get_prev_chunk(int index) + { + DEC_ENC_INDEX(index); + return GET_ENC_CHUNK(index); + } - /* only peak every 4th sample */ - for (j=0; j peak_l) peak_l = value; - else if (-value > peak_l) peak_l = -value; + data.pre_chunk = NULL; + data.chunk = GET_ENC_CHUNK(enc_wr_index); - value <<= 16; - if (value > peak_r) peak_r = value; - else if (-value > peak_r) peak_r = -value; -#else - if (value > peak_r) peak_r = value; - else if (-value > peak_r) peak_r = -value; + /* end chunk */ + if (flags & CHUNKF_END_FILE) + { + data.chunk->flags &= CHUNKF_START_FILE | CHUNKF_END_FILE; - value <<= 16; - if (value > peak_l) peak_l = value; - else if (-value > peak_l) peak_l = -value; -#endif + /* queue empty - still could be a pending file where all data + so far has been written */ + if (data.chunk->flags & CHUNKF_START_FILE) + { + /* cannot start and end on same unprocessed chunk */ + logf("file end on start"); + flags &= ~CHUNKF_END_FILE; + } + else if (enc_rd_index == enc_wr_index) + { + /* all data flushed but file not ended - chunk will be left + empty */ + logf("end on dead end"); + data.chunk->flags = 0; + data.chunk->enc_size = 0; + data.chunk->num_pcm = 0; + data.chunk->enc_data = NULL; + INC_ENC_INDEX(enc_wr_index); + data.chunk = GET_ENC_CHUNK(enc_wr_index); } + else + { + /* chunk if file has already been ended */ + struct enc_chunk_hdr *last = get_prev_chunk(enc_wr_index); - peak_left = (int)(peak_l >> 16); - peak_right = (int)(peak_r >> 16); + if (last->flags & CHUNKF_END_FILE) + { + /* end already processed and marked - can't end twice */ + logf("file end again"); + flags &= ~CHUNKF_END_FILE; + } + } } - IPR |= (1<<15); /* Clear pending interrupt request */ -} + /* start chunk */ + if (flags & CHUNKF_START_FILE) + { + bool pre = flags & CHUNKF_PRERECORD; -/* Create WAVE file and write header */ -/* Sets returns 0 if success, -1 on failure */ -static int start_wave(void) -{ - wav_file = open(recording_filename, O_RDWR|O_CREAT|O_TRUNC); + if (pre) + { + logf("stream prerecord start"); + start = data.pre_chunk = GET_ENC_CHUNK(pre_index); + start->flags &= CHUNKF_START_FILE | CHUNKF_PRERECORD; + } + else + { + logf("stream normal start"); + start = data.chunk; + start->flags &= CHUNKF_START_FILE; + } - if (wav_file < 0) - { - wav_file = -1; - logf("rec: create failed: %d", wav_file); - is_error = true; - return -1; - } - - /* add main file header (enc_head_size=0 for encoders without) */ - if (enc_head_size != write(wav_file, enc_head_buffer, enc_head_size)) - { - close(wav_file); - wav_file = -1; - logf("rec: write failed"); - is_error = true; - return -1; + /* if encoder hasn't yet processed the last start - abort the start + of the previous file queued or else it will be empty and invalid */ + if (start->flags & CHUNKF_START_FILE) + { + logf("replacing fnq tail: %s", filename); + fnq_add_fn = pcmrec_fnq_replace_tail; + } + else + { + logf("adding filename: %s", filename); + fnq_add_fn = pcmrec_fnq_add_filename; + } } - return 0; -} + data.flags = flags; + enc_events_callback(ENC_REC_NEW_STREAM, &data); -/* Update header and set correct length values */ -static void close_wave(void) -{ - unsigned char head[100]; /* assume maximum 100 bytes for file header */ - int size_read; + if (flags & CHUNKF_END_FILE) + { + int i = get_chunk_index(data.chunk); + get_prev_chunk(i)->flags |= CHUNKF_END_FILE; + } - if (wav_file != -1) + if (start) { - /* update header before closing the file (wav+wv encoder will do) */ - if (enc_set_header_callback != NULL) + if (!(flags & CHUNKF_PRERECORD)) { - lseek(wav_file, 0, SEEK_SET); - /* try to read the head size (but we'll accept less) */ - size_read = read(wav_file, head, sizeof(head)); + /* get stats on data added to start - sort of a prerecord operation */ + int i = get_chunk_index(data.chunk); + struct enc_chunk_hdr *chunk = data.chunk; + + logf("start data: %d %d", i, enc_wr_index); - enc_set_header_callback(head, size_read, num_pcm_samples, true); - lseek(wav_file, 0, SEEK_SET); - write(wav_file, head, size_read); + num_rec_bytes = 0; + num_rec_samples = 0; + + while (i != enc_wr_index) + { + num_rec_bytes += chunk->enc_size; + num_rec_samples += chunk->num_pcm; + INC_ENC_INDEX(i); + chunk = GET_ENC_CHUNK(i); + } + + start->flags &= ~CHUNKF_START_FILE; + start = data.chunk; + } + + start->flags |= CHUNKF_START_FILE; + + /* flush one file out if full and adding */ + if (fnq_add_fn == pcmrec_fnq_add_filename && pcmrec_fnq_is_full()) + { + logf("fnq full: flushing 1"); + pcmrec_flush(1); } - close(wav_file); - wav_file = -1; + + fnq_add_fn(filename); } -} +} /* pcmrec_new_stream */ -static void pcmrec_start(void) +static void pcmrec_start(const char *filename) { - long max_pre_chunks, pre_ticks, max_pre_ticks; + unsigned long pre_ticks; + int rd_start; + unsigned spinup_time; - logf("pcmrec_start"); + logf("pcmrec_start: %s", filename); - if (is_recording) + if (is_recording) { logf("already recording"); - record_done = true; - return; + goto already_recording; + } + +#ifdef HAVE_SPDIF_IN + if (rec_source == AUDIO_SRC_SPDIF) + { + /* see if sample rate has changed since previously loading + encoder - if so, restart encoder with new rate discarding any + now invalid prerecorded data */ + unsigned long spdif_sr = measure_spdif_sample_rate(); + int index = round_value_to_list32(spdif_sr, audio_master_sampr_list, + SAMPR_NUM_FREQ, false); + unsigned long sr = audio_master_sampr_list[index]; + + if (sr != sample_rate) + { + dma_lock = true; + while(!wav_queue_empty) + yield(); + + sample_rate = sr; + + if (!audio_load_encoder(enc_config.afmt)) + { + is_error = true; + return; + } + + /* adjust monitoring frequency */ + index = round_value_to_list32(spdif_sr, hw_freq_sampr, + HW_NUM_FREQ, false); + pcm_set_frequency(hw_freq_sampr[index]); + pcm_apply_settings(false); + } + } +#endif + + num_rec_bytes = 0; + num_rec_samples = 0; + accum_rec_bytes = 0; + accum_pcm_samples = 0; + spinup_time = -1; + + rd_start = enc_wr_index; + pre_ticks = 0; + + if (pre_record_ticks) + { + int i; + + /* calculate number of available chunks */ + unsigned long avail_pre_chunks = (enc_wr_index - enc_rd_index + + enc_num_chunks) % enc_num_chunks; + + /* Get exact measure of recorded data as number of samples aren't + nescessarily going to be the max for each chunk */ + for (i = rd_start; avail_pre_chunks-- > 0;) + { + struct enc_chunk_hdr *chunk; + unsigned long chunk_ticks; + + DEC_ENC_INDEX(i); + + chunk = GET_ENC_CHUNK(i); + + /* must have data to be counted */ + if (chunk->enc_data == NULL) + continue; + + chunk_ticks = chunk->num_pcm*HZ / enc_sample_rate; + + rd_start = i; + pre_ticks += chunk_ticks; + num_rec_bytes += chunk->enc_size; + num_rec_samples += chunk->num_pcm; + + /* stop here if enough already */ + if (pre_ticks >= pre_record_ticks) + break; + } + + accum_rec_bytes = num_rec_bytes; + accum_pcm_samples = num_rec_samples; } - if (wav_file != -1) - close_wave(); + enc_rd_index = rd_start; - if (start_wave() != 0) + /* filename queue should be empty */ + if (!pcmrec_fnq_is_empty()) { - /* failed to create the file */ - record_done = true; - return; + logf("fnq: not empty!"); + pcmrec_fnq_set_empty(); } - /* calculate maximum available chunks & resulting ticks */ - max_pre_chunks = (enc_wr_index - enc_rd_index + - enc_num_chunks) % enc_num_chunks; - if (max_pre_chunks > enc_num_chunks - WRITE_THRESHOLD) - max_pre_chunks = enc_num_chunks - WRITE_THRESHOLD; - max_pre_ticks = max_pre_chunks * HZ * enc_samp_per_chunk / 44100; - - /* limit prerecord if not enough data available */ - pre_ticks = pre_record_ticks > max_pre_ticks ? - max_pre_ticks : pre_record_ticks; - max_pre_chunks = 44100 * pre_ticks / HZ / enc_samp_per_chunk; - enc_rd_index = (enc_wr_index - max_pre_chunks + - enc_num_chunks) % enc_num_chunks; - - record_start_time = current_tick - pre_ticks; - - num_rec_bytes = enc_num_chunks * CHUNK_SIZE; - num_file_bytes = 0; - num_pcm_samples = 0; - pause_start_time = 0; - - is_paused = false; - is_recording = true; - record_done = true; -} + /* prevent flush at this point as encoder could + force a flush by releasing more chunks */ + flush_next_data = false; + + dma_lock = false; + is_paused = false; + is_recording = true; + + pcmrec_new_stream(filename, + CHUNKF_START_FILE | + (pre_ticks > 0 ? CHUNKF_PRERECORD : 0), + enc_rd_index); + + /* re-enable next chunk flush */ + flush_next_data = rec_new_file_flush; + +already_recording: + pcm_thread_signal_event(PCMREC_START); + logf("pcmrec_start done"); +} /* pcmrec_start */ static void pcmrec_stop(void) { logf("pcmrec_stop"); - if (is_recording) + if (!is_recording) + { + logf("not recording"); + goto not_recording_or_stopping; + } + else if (is_stopping) + { + logf("already stopping"); + goto not_recording_or_stopping; + } + + is_stopping = true; + dma_lock = true; /* lock dma write position */ + queue_post(&pcmrec_queue, PCMREC_FINISH_STOP, NULL); + +not_recording_or_stopping: + pcm_thread_signal_event(PCMREC_STOP); + logf("pcmrec_stop done"); +} /* pcmrec_stop */ + +static void pcmrec_finish_stop(void) +{ + logf("pcmrec_finish_stop"); + + if (!is_stopping) { - /* wait for encoding finish */ - is_paused = true; - while(!wav_queue_empty) - sleep_thread(1); + logf("not stopping"); + goto not_stopping; + } + + /* stop automatic flushing */ + flush_next_data = false; - is_recording = false; + /* flush all available data first to avoid overflow while waiting + for encoding to finish */ + pcmrec_flush(-1); - /* Flush buffers to file */ - pcmrec_callback(true); - close_wave(); + /* wait for encoder to finish remaining data */ + if (!is_error) + { + while (!wav_queue_empty) + yield(); } - is_paused = false; - stop_done = true; + /* end stream at last data */ + pcmrec_new_stream(NULL, CHUNKF_END_FILE, 0); - logf("pcmrec_stop done"); -} + /* flush anything else encoder added */ + pcmrec_flush(-1); + + /* remove any pending file start not yet processed - should be at + most one at enc_wr_index */ + pcmrec_fnq_get_filename(NULL); + /* encoder should abort any chunk it was in midst of processing */ + GET_ENC_CHUNK(enc_wr_index)->flags = CHUNKF_ABORT; + + /* filename queue should be empty */ + if (!pcmrec_fnq_is_empty()) + { + logf("fnq: not empty!"); + pcmrec_fnq_set_empty(); + } + + /* be absolutely sure the file is closed */ + if (is_error) + pcmrec_close_file(&rec_fdata.rec_file); + rec_fdata.rec_file = -1; -static void pcmrec_new_file(void) + is_recording = false; + is_paused = false; + is_stopping = false; + dma_lock = false; + +not_stopping: + logf("pcmrec_finish_stop done"); +} /* pcmrec_finish_stop */ + +static void pcmrec_new_file(const char *filename) { - logf("pcmrec_new_file"); + logf("pcmrec_new_file: %s", filename); if (!is_recording) { logf("not recording"); - new_file_done = true; - return; + goto not_recording; } - - /* Since pcmrec_callback() blocks until the data has been written, - here is a good approximation when recording to the new file starts - */ - record_start_time = current_tick; - - if (is_paused) - pause_start_time = record_start_time; - - /* Flush what we got in buffers to file */ - pcmrec_callback(true); - - close_wave(); - num_rec_bytes = 0; - num_file_bytes = 0; - num_pcm_samples = 0; - - /* start the new file */ - if (start_wave() != 0) - { - logf("new_file failed"); - pcmrec_stop(); - } + flush_next_data = false; + num_rec_bytes = 0; + num_rec_samples = 0; + + pcmrec_new_stream(filename, + CHUNKF_START_FILE | CHUNKF_END_FILE, + 0); + + flush_next_data = rec_new_file_flush; - new_file_done = true; +not_recording: + pcm_thread_signal_event(PCMREC_NEW_FILE); logf("pcmrec_new_file done"); -} +} /* pcmrec_new_file */ static void pcmrec_pause(void) { @@ -864,43 +1437,46 @@ if (!is_recording) { - logf("pause: not recording"); - pause_done = true; - return; + logf("not recording"); + goto not_recording_or_paused; } - - pause_start_time = current_tick; - is_paused = true; - pause_done = true; - - logf("pcmrec_pause done"); -} + else if (is_paused) + { + logf("already paused"); + goto not_recording_or_paused; + } + + dma_lock = true; /* fix DMA write pointer at current position */ + is_paused = true; +not_recording_or_paused: + pcm_thread_signal_event(PCMREC_PAUSE); + logf("pcmrec_pause done"); +} /* pcmrec_pause */ static void pcmrec_resume(void) { logf("pcmrec_resume"); - if (!is_paused) + if (!is_recording) { - logf("resume: not paused"); - resume_done = true; - return; + logf("not recording"); + goto not_recording_or_not_paused; } - - is_paused = false; - is_recording = true; - - /* Compensate for the time we have been paused */ - if (pause_start_time) + else if (!is_paused) { - record_start_time += current_tick - pause_start_time; - pause_start_time = 0; + logf("not paused"); + goto not_recording_or_not_paused; } - - resume_done = true; + + is_paused = false; + is_recording = true; + dma_lock = false; + +not_recording_or_not_paused: + pcm_thread_signal_event(PCMREC_RESUME); logf("pcmrec_resume done"); -} +} /* pcmrec_resume */ /** * audio_init_recording calls this function using PCMREC_INIT @@ -908,66 +1484,75 @@ */ static void pcmrec_init(void) { - wav_file = -1; - read_pos = 0; - write_pos = 0; - enc_wr_index = 0; - enc_rd_index = 0; - - avrg_bit_rate = 0; - curr_bit_rate = 0; - curr_chunk_cnt = 0; - - peak_left = 0; - peak_right = 0; - - num_rec_bytes = 0; - num_file_bytes = 0; - num_pcm_samples = 0; - record_start_time = 0; - pause_start_time = 0; - - close_done = false; - is_recording = false; - is_paused = false; - is_error = false; + rec_fdata.rec_file = -1; - rec_buffer = (unsigned char*)(((long)audiobuf + 15) & ~15); - enc_buffer = rec_buffer + NUM_CHUNKS * CHUNK_SIZE + MAX_FEED_SIZE; - /* 8000Bytes at audiobufend */ - enc_buffer_size = audiobufend - enc_buffer - 8000; - - SET_IIS_PLAY(0x800); /* Stop any playback */ - AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */ - DATAINCONTROL = 0xc000; /* Generate Interrupt when 6 samples in fifo */ - - DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */ - DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */ - DMAROUTE = (DMAROUTE & 0xffff00ff) | DMA1_REQ_AUDIO_2; - ICR7 = 0x1c; /* Enable interrupt at level 7, priority 0 */ - IMR &= ~(1<<15); /* bit 15 is DMA1 */ + /* pcm FIFO */ + dma_lock = true; + pcm_rd_pos = 0; + dma_wr_pos = 0; + + /* encoder FIFO */ + enc_wr_index = 0; + enc_rd_index = 0; + flush_next_data = false; + + /* filename queue */ + fnq_rd_pos = 0; + fnq_wr_pos = 0; + + /* peaks */ + peak_left = 0; + peak_right = 0; + + /* stats */ + num_rec_bytes = 0; + num_rec_samples = 0; + accum_rec_bytes = 0; + accum_pcm_samples = 0; + + pcm_thread_unsignal_event(PCMREC_CLOSE); + is_recording = false; + is_paused = false; + is_stopping = false; + is_error = false; + + /* Line align pcm_buffer 2^4=16 bytes */ + pcm_buffer = (unsigned char *)ALIGN_UP_P2((unsigned)audiobuf, 4); + enc_buffer = pcm_buffer + ALIGN_UP_P2(PCM_NUM_CHUNKS*PCM_CHUNK_SIZE + + PCM_MAX_FEED_SIZE, 2); + + SET_IIS_PLAY(IIS_RESET); /* Stop any playback */ + AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */ + DATAINCONTROL = 0xc000; /* Generate Interrupt when 6 samples in fifo */ + + DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */ + DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */ + DMAROUTE = (DMAROUTE & 0xffff00ff) | DMA1_REQ_AUDIO_2; + ICR7 = 0x1c; /* Enable interrupt at level 7, priority 0 */ + IMR &= ~(1 << 15); /* bit 15 is DMA1 */ #ifdef HAVE_SPDIF_IN - PHASECONFIG = 0x34; /* Gain = 3*2^13, source = EBUIN */ + PHASECONFIG = 0x34; /* Gain = 3*2^13, source = EBUIN */ #endif pcmrec_dma_start(); - init_done = 1; -} + pcm_thread_signal_event(PCMREC_INIT); +} /* pcmrec_init */ static void pcmrec_close(void) { DMAROUTE = (DMAROUTE & 0xffff00ff); - ICR7 = 0x00; /* Disable interrupt */ - IMR |= (1<<15); /* bit 15 is DMA1 */ + ICR7 = 0x00; /* Disable interrupt */ + IMR |= (1 << 15); /* bit 15 is DMA1 */ pcmrec_dma_stop(); /* Reset PDIR2 data flow */ DATAINCONTROL = 0x200; - close_done = true; - init_done = false; -} + + pcm_thread_unsignal_event(PCMREC_INIT); + pcm_thread_signal_event(PCMREC_CLOSE); +} /* pcmrec_close */ static void pcmrec_thread(void) { @@ -977,9 +1562,22 @@ error_count = 0; - while(1) + while (1) { - queue_wait_w_tmo(&pcmrec_queue, &ev, HZ / 4); + if (is_recording) + { + queue_wait_w_tmo(&pcmrec_queue, &ev, HZ/5); + + if (ev.id == SYS_TIMEOUT) + { + pcmrec_flush(0); /* flush if getting full */ + continue; + } + } + else + { + queue_wait(&pcmrec_queue, &ev); + } switch (ev.id) { @@ -992,13 +1590,17 @@ break; case PCMREC_START: - pcmrec_start(); + pcmrec_start((const char *)ev.data); break; case PCMREC_STOP: pcmrec_stop(); break; + case PCMREC_FINISH_STOP: + pcmrec_finish_stop(); + break; + case PCMREC_PAUSE: pcmrec_pause(); break; @@ -1008,11 +1610,11 @@ break; case PCMREC_NEW_FILE: - pcmrec_new_file(); + pcmrec_new_file((const char *)ev.data); break; - case SYS_TIMEOUT: - pcmrec_callback(false); + case PCMREC_FLUSH_NUM: + pcmrec_flush((unsigned)ev.data); break; case SYS_USB_CONNECTED: @@ -1026,8 +1628,9 @@ } } - logf("thread pcmrec done"); -} + /* This should never be reached */ + panicf("thread pcmrec return"); +} /* pcmrec_thread */ /* Select VINL & VINR source: 0=Line-in, 1=FM Radio */ void pcm_rec_mux(int source) @@ -1060,8 +1663,7 @@ /* iAudio x5 */ #endif -} - +} /* pcm_rec_mux */ /****************************************************************************/ /* */ @@ -1069,94 +1671,226 @@ /* */ /****************************************************************************/ -/* pass the encoder buffer pointer/size, mono/stereo, quality to the encoder */ -void enc_get_inputs(int *buffer_size, int *channels, int *quality) +/* pass the encoder settings to the encoder */ +void enc_get_inputs(struct enc_inputs *inputs) { - *buffer_size = enc_buffer_size; - *channels = enc_channels; - *quality = enc_quality; -} + inputs->sample_rate = sample_rate; + inputs->num_channels = num_channels; + inputs->config = &enc_config; +} /* enc_get_inputs */ -/* set the encoder dimensions (called by encoder codec at initialization) */ -void enc_set_parameters(int chunk_size, int num_chunks, int samp_per_chunk, - char *head_ptr, int head_size, int enc_id) +/* set the encoder dimensions (called by encoder codec at initialization and + termination) */ +void enc_set_parameters(struct enc_parameters *params) { - /* set read_pos just in front of current write_pos */ - read_pos = (write_pos - CHUNK_SIZE) & CHUNK_MASK; + size_t enc_buffer_size; + size_t enc_reserve_bytes; + + logf("enc_set_parameters"); + + if (!params) + { + logf("reset"); + /* Encoder is terminating */ + memset(&enc_config, 0, sizeof (enc_config)); + enc_sample_rate = 0; + return; + } + + enc_sample_rate = params->enc_sample_rate; + logf("enc sampr: %d", enc_sample_rate); + + /* set read position at DMA write position */ + pcm_rd_pos = dma_wr_pos; + peak_ptr = pcm_buffer + dma_wr_pos; + + enc_config.afmt = params->afmt; + /* addition of the header is always implied - chunk size 4-byte aligned */ + enc_chunk_size = + ALIGN_UP_P2(ENC_CHUNK_HDR_SIZE + params->chunk_size, 2); + enc_data_size = enc_chunk_size - ENC_CHUNK_HDR_SIZE; + enc_events_callback = params->events_callback; + + logf("chunk size: %d", enc_chunk_size); + + /*** Configure the buffers ***/ + + /* Layout of audiobuf: + * [ax] = possible alignment x multiple + * [sx] = possible size alignment of x multiple + * audiobuf->|[a16]|[s4]:PCM Buffer+PCM Wrap|[s4 each]:Encoder Chunks|-> + * |[[s4]:Reserved Bytes]|Filename Queue->|[space]|->audiobufend + */ + enc_reserve_bytes = ALIGN_UP_P2(params->reserve_bytes, 2); + logf("reserve bytes: %d", enc_reserve_bytes); + + enc_buffer_size = audiobufend - enc_buffer - + enc_reserve_bytes - FNQ_MIN_NUM_PATHS*MAX_PATH; + + enc_num_chunks = enc_buffer_size / enc_chunk_size; + logf("num chunks: %d", enc_num_chunks); + + /* get real amount used by encoder chunks */ + enc_buffer_size = enc_num_chunks*enc_chunk_size; + logf("total chks size: %d", enc_buffer_size); + + /* panic boost thread priority at 1 second remaining */ + panic_threshold = enc_num_chunks - + (4*sample_rate + (enc_chunk_size-1)) / enc_chunk_size; + if (panic_threshold < 0) + panic_threshold = 0; + + logf("panic thresh: %d", panic_threshold); + + /** set OUT parameters **/ + params->enc_buffer = enc_buffer; + params->buf_chunk_size = enc_chunk_size; + params->num_chunks = enc_num_chunks; + + /* calculate reserve buffer start and return pointer to encoder */ + params->reserve_buffer = NULL; + if (enc_reserve_bytes > 0) + { + params->reserve_buffer = enc_buffer + enc_buffer_size; + enc_buffer_size += enc_reserve_bytes; + } + + /* place filename queue at end of buffer using up whatever remains */ + fnq_rd_pos = 0; /* reset */ + fnq_wr_pos = 0; /* reset */ + fn_queue = enc_buffer + enc_buffer_size; + fnq_size = ALIGN_DOWN(audiobufend - fn_queue, MAX_PATH); + logf("fnq files: %d", fnq_size / MAX_PATH); - enc_rd_index = 0; /* reset */ - enc_wr_index = 0; /* reset */ - enc_chunk_size = chunk_size; /* max chunk size */ - enc_num_chunks = num_chunks; /* total number of chunks */ - enc_samp_per_chunk = samp_per_chunk; /* pcm samples / encoderchunk */ - enc_head_buffer = head_ptr; /* optional file header data (wav) */ - enc_head_size = head_size; /* optional file header data (wav) */ - audio_enc_id = enc_id; /* AFMT_* id */ -} + /* init all chunk headers and reset indexes */ + enc_rd_index = 0; + for (enc_wr_index = enc_num_chunks; enc_wr_index > 0; ) + GET_ENC_CHUNK(--enc_wr_index)->flags = 0; +} /* enc_set_parameters */ -/* allocate encoder chunk */ -unsigned int *enc_alloc_chunk(void) +/* return encoder chunk at current write position */ +struct enc_chunk_hdr * enc_get_chunk(void) { - return (unsigned int*)(enc_buffer + enc_wr_index * enc_chunk_size); -} + struct enc_chunk_hdr *chunk = GET_ENC_CHUNK(enc_wr_index); + chunk->flags &= CHUNKF_START_FILE; + + if (!is_recording) + chunk->flags |= CHUNKF_PRERECORD; + + return chunk; +} /* enc_get_chunk */ -/* free previously allocated encoder chunk */ -void enc_free_chunk(void) +/* releases the current chunk into the available chunks */ +void enc_finish_chunk(void) { - unsigned long *enc_chunk; + struct enc_chunk_hdr *chunk = GET_ENC_CHUNK(enc_wr_index); - enc_chunk = GET_ENC_CHUNK(enc_wr_index); - curr_chunk_cnt++; -/* curr_bit_rate += *enc_chunk * 44100 * 8 / (enc_samp_per_chunk * 1000); */ - curr_bit_rate += *enc_chunk * 441 * 8 / (enc_samp_per_chunk * 10 ); - avrg_bit_rate = (curr_bit_rate + curr_chunk_cnt / 2) / curr_chunk_cnt; + /* encoder may have set error flag or written too much data */ + if ((long)chunk->flags < 0 || chunk->enc_size > enc_data_size) + { + is_error = true; - /* advance enc_wr_index to the next chunk */ - enc_wr_index = (enc_wr_index + 1) % enc_num_chunks; +#ifdef ROCKBOX_HAS_LOGF + if (chunk->enc_size > enc_data_size) + { + /* illegal to scribble over next chunk */ + logf("finish chk ovf: %d>%d", chunk->enc_size, enc_data_size); + } + else + { + /* encoder set error flag */ + logf("finish chk enc error"); + } +#endif + } - /* buffer full: advance enc_rd_index (for prerecording purpose) */ - if (enc_rd_index == enc_wr_index) + /* advance enc_wr_index to the next encoder chunk */ + INC_ENC_INDEX(enc_wr_index); + + if (enc_rd_index != enc_wr_index) + { + num_rec_bytes += chunk->enc_size; + accum_rec_bytes += chunk->enc_size; + num_rec_samples += chunk->num_pcm; + accum_pcm_samples += chunk->num_pcm; + } + else if (is_recording) /* buffer full */ + { + /* keep current position */ + logf("enc_buffer ovf"); + DEC_ENC_INDEX(enc_wr_index); + } + else { - enc_rd_index = (enc_rd_index + 1) % enc_num_chunks; + /* advance enc_rd_index for prerecording */ + INC_ENC_INDEX(enc_rd_index); } -} -/* checks near empty state on wav input buffer */ -int enc_wavbuf_near_empty(void) + if (!flush_next_data) + return; + + /* flush out first data of new file which also creates it */ + flush_next_data = false; + queue_post(&pcmrec_queue, PCMREC_FLUSH_NUM, (void *)1ul); +} /* enc_finish_chunk */ + +/* checks near empty state on pcm input buffer */ +int enc_pcm_buf_near_empty(void) { /* less than 1sec raw data? => unboost encoder */ - if (((write_pos - read_pos) & CHUNK_MASK) < 44100*4) - return 1; - else - return 0; -} + size_t avail = (dma_wr_pos - pcm_rd_pos) & PCM_CHUNK_MASK; + return avail < (sample_rate << 2) ? 1 : 0; +} /* enc_pcm_buf_near_empty */ /* passes a pointer to next chunk of unprocessed wav data */ -char *enc_get_wav_data(int size) +/* TODO: this really should give the actual size returned */ +unsigned char * enc_get_pcm_data(size_t size) { - char *ptr; - int avail; + size_t avail = (dma_wr_pos - pcm_rd_pos) & PCM_CHUNK_MASK; /* limit the requested pcm data size */ - if(size > MAX_FEED_SIZE) - size = MAX_FEED_SIZE; - - avail = (write_pos - read_pos) & CHUNK_MASK; + if (size > PCM_MAX_FEED_SIZE) + size = PCM_MAX_FEED_SIZE; if (avail >= size) { - ptr = rec_buffer + read_pos; - read_pos = (read_pos + size) & CHUNK_MASK; + unsigned char *ptr = pcm_buffer + pcm_rd_pos; + pcm_rd_pos = (pcm_rd_pos + size) & PCM_CHUNK_MASK; /* ptr must point to continous data at wraparound position */ - if (read_pos < size) - memcpy(rec_buffer + NUM_CHUNKS * CHUNK_SIZE, - rec_buffer, read_pos); + if ((size_t)pcm_rd_pos < size) + memcpy(pcm_buffer + PCM_NUM_CHUNKS*PCM_CHUNK_SIZE, + pcm_buffer, pcm_rd_pos); wav_queue_empty = false; return ptr; } + /* not enough data available - encoder should idle */ wav_queue_empty = true; return NULL; -} +} /* enc_get_pcm_data */ + +/* puts some pcm data back in the queue */ +size_t enc_unget_pcm_data(size_t size) +{ + /* can't let DMA advance write position when doing this */ + int level = set_irq_level(HIGHEST_IRQ_LEVEL); + + if (pcm_rd_pos != dma_wr_pos) + { + /* disallow backing up into current DMA write chunk */ + size_t old_avail = (pcm_rd_pos - dma_wr_pos - PCM_CHUNK_SIZE) + & PCM_CHUNK_MASK; + + /* limit size to amount of old data remaining */ + if (size > old_avail) + size = old_avail; + + pcm_rd_pos = (pcm_rd_pos - size) & PCM_CHUNK_MASK; + } + + set_irq_level(level); + + return size; +} /* enc_unget_pcm_data */ Index: firmware/pcm_sampr.c =================================================================== RCS file: firmware/pcm_sampr.c diff -N firmware/pcm_sampr.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ firmware/pcm_sampr.c 16 Oct 2006 23:32:48 -0000 @@ -0,0 +1,76 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 Michael Sevakis + * + * 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 "config.h" +#include "pcm_sampr.h" + +/* Master list of all "standard" rates supported. */ +const unsigned long audio_master_sampr_list[SAMPR_NUM_FREQ] = +{ + [0 ... SAMPR_NUM_FREQ-1] = -1, /* any gaps set to -1 */ + [FREQ_96] = SAMPR_96, + [FREQ_88] = SAMPR_88, + [FREQ_64] = SAMPR_64, + [FREQ_48] = SAMPR_48, + [FREQ_44] = SAMPR_44, + [FREQ_32] = SAMPR_32, + [FREQ_24] = SAMPR_24, + [FREQ_22] = SAMPR_22, + [FREQ_16] = SAMPR_16, + [FREQ_12] = SAMPR_12, + [FREQ_11] = SAMPR_11, + [FREQ_8 ] = SAMPR_8, +}; + +/* List of all hardware rates supported (set or subset of master list) */ +const unsigned long hw_freq_sampr[HW_NUM_FREQ] = +{ + [0 ... HW_NUM_FREQ-1] = -1, + HW_HAVE_96_([HW_FREQ_96] = SAMPR_96,) + HW_HAVE_88_([HW_FREQ_88] = SAMPR_88,) + HW_HAVE_64_([HW_FREQ_64] = SAMPR_64,) + HW_HAVE_48_([HW_FREQ_48] = SAMPR_48,) + HW_HAVE_44_([HW_FREQ_44] = SAMPR_44,) + HW_HAVE_32_([HW_FREQ_32] = SAMPR_32,) + HW_HAVE_24_([HW_FREQ_24] = SAMPR_24,) + HW_HAVE_22_([HW_FREQ_22] = SAMPR_22,) + HW_HAVE_16_([HW_FREQ_16] = SAMPR_16,) + HW_HAVE_12_([HW_FREQ_12] = SAMPR_12,) + HW_HAVE_11_([HW_FREQ_11] = SAMPR_11,) + HW_HAVE_8_( [HW_FREQ_8 ] = SAMPR_8 ,) +}; + +#ifdef HAVE_RECORDING +/* List of recording supported sample rates (set or subset of master list) */ +const unsigned long rec_freq_sampr[REC_NUM_FREQ] = +{ + [0 ... REC_NUM_FREQ-1] = -1, + REC_HAVE_96_([REC_FREQ_96] = SAMPR_96,) + REC_HAVE_88_([REC_FREQ_88] = SAMPR_88,) + REC_HAVE_64_([REC_FREQ_64] = SAMPR_64,) + REC_HAVE_48_([REC_FREQ_48] = SAMPR_48,) + REC_HAVE_44_([REC_FREQ_44] = SAMPR_44,) + REC_HAVE_32_([REC_FREQ_32] = SAMPR_32,) + REC_HAVE_24_([REC_FREQ_24] = SAMPR_24,) + REC_HAVE_22_([REC_FREQ_22] = SAMPR_22,) + REC_HAVE_16_([REC_FREQ_16] = SAMPR_16,) + REC_HAVE_12_([REC_FREQ_12] = SAMPR_12,) + REC_HAVE_11_([REC_FREQ_11] = SAMPR_11,) + REC_HAVE_8_( [REC_FREQ_8 ] = SAMPR_8 ,) +}; +#endif /* HAVE_RECORDING */ Index: firmware/system.c =================================================================== RCS file: /cvsroot/rockbox/firmware/system.c,v retrieving revision 1.124 diff -u -r1.124 system.c --- firmware/system.c 12 Oct 2006 20:22:15 -0000 1.124 +++ firmware/system.c 16 Oct 2006 23:32:49 -0000 @@ -667,6 +667,12 @@ return oldmode; } +/* allow setting of audio clock related bits */ +void coldfire_set_pllcr_audio_bits(long bits) +{ + PLLCR = (PLLCR & ~0x70c00000) | (bits & 0x70c00000); +} + #ifndef TARGET_TREE #if MEM < 32 #define MAX_REFRESH_TIMER 59 @@ -703,7 +709,7 @@ PLLCR &= ~1; /* Bypass mode */ timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); RECALC_DELAYS(CPUFREQ_MAX); - PLLCR = 0x11c56005; + PLLCR = 0x01056005 | (PLLCR & 0x70c00000); CSCR0 = 0x00001180; /* Flash: 4 wait states */ CSCR1 = 0x00000980; /* LCD: 2 wait states */ #if CONFIG_USBOTG == USBOTG_ISP1362 @@ -730,7 +736,7 @@ PLLCR &= ~1; /* Bypass mode */ timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); RECALC_DELAYS(CPUFREQ_NORMAL); - PLLCR = 0x13c5e005; + PLLCR = 0x0305e005 | (PLLCR & 0x70c00000); CSCR0 = 0x00000580; /* Flash: 1 wait state */ CSCR1 = 0x00000180; /* LCD: 0 wait states */ #if CONFIG_USBOTG == USBOTG_ISP1362 @@ -756,7 +762,8 @@ PLLCR &= ~1; /* Bypass mode */ timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, true); RECALC_DELAYS(CPUFREQ_DEFAULT); - PLLCR = 0x10c00200; /* Power down PLL, but keep CLSEL and CRSEL */ + /* Power down PLL, but keep CLSEL and CRSEL */ + PLLCR = 0x00000200 | (PLLCR & 0x70c00000); CSCR0 = 0x00000180; /* Flash: 0 wait states */ CSCR1 = 0x00000180; /* LCD: 0 wait states */ #if CONFIG_USBOTG == USBOTG_ISP1362 Index: firmware/thread.c =================================================================== RCS file: /cvsroot/rockbox/firmware/thread.c,v retrieving revision 1.67 diff -u -r1.67 thread.c --- firmware/thread.c 15 Oct 2006 11:57:52 -0000 1.67 +++ firmware/thread.c 16 Oct 2006 23:32:49 -0000 @@ -191,15 +191,15 @@ * Store non-volatile context. *--------------------------------------------------------------------------- */ -#define store_context(addr) \ +#define store_context(addr) \ __asm__ volatile ( \ - "push r0,r1\n\t" \ - "push r2,r3\n\t" \ - "push r4,r5\n\t" \ - "push r6,r7\n\t" \ - "push a8,a9\n\t" \ - "push a10,a11\n\t" \ - "push a12,a13\n\t" \ + "push r0,r1\n\t" \ + "push r2,r3\n\t" \ + "push r4,r5\n\t" \ + "push r6,r7\n\t" \ + "push a8,a9\n\t" \ + "push a10,a11\n\t" \ + "push a12,a13\n\t" \ "push a14\n\t" \ "ldw @[%0+0], a15\n\t" : : "a" (addr) ); @@ -213,20 +213,20 @@ (addr)->started = 1; \ __asm__ volatile ( \ "ldw a15, @[%0+0]\n\t" \ - "ldw a14, @[%0+4]\n\t" \ - "jmp a14\n\t" : : "a" (addr) \ - ); \ + "ldw a14, @[%0+4]\n\t" \ + "jmp a14\n\t" : : "a" (addr) \ + ); \ } else \ __asm__ volatile ( \ - "ldw a15, @[%0+0]\n\t" \ - "pop a14\n\t" \ + "ldw a15, @[%0+0]\n\t" \ + "pop a14\n\t" \ "pop a13,a12\n\t" \ "pop a11,a10\n\t" \ - "pop a9,a8\n\t" \ - "pop r7,r6\n\t" \ - "pop r5,r4\n\t" \ - "pop r3,r2\n\t" \ - "pop r1,r0\n\t" : : "a" (addr) \ + "pop a9,a8\n\t" \ + "pop r7,r6\n\t" \ + "pop r5,r4\n\t" \ + "pop r3,r2\n\t" \ + "pop r1,r0\n\t" : : "a" (addr) \ ); \ \ } @@ -249,7 +249,7 @@ thread->prev = (*list)->prev; thread->prev->next = thread; (*list)->prev = thread; - + /* Insert next thread->next = (*list)->next; thread->prev = *list; @@ -269,48 +269,48 @@ *list = NULL; return; } - + if (thread == *list) *list = thread->next; } - + /* Fix links to jump over the removed entry. */ thread->prev->next = thread->next; thread->next->prev = thread->prev; } -/* Compiler trick: Don't declare as static to prevent putting +/* Compiler trick: Don't declare as static to prevent putting * function in IRAM. */ void check_sleepers(void) { struct thread_entry *current, *next; - + /* Check sleeping threads. */ current = cores[CURRENT_CORE].sleeping; if (current == NULL) return ; - + for (;;) { next = current->next; - + if ((unsigned)current_tick >= GET_STATE_ARG(current->statearg)) { /* Sleep timeout has been reached so bring the thread * back to life again. */ remove_from_list(&cores[CURRENT_CORE].sleeping, current); add_to_list(&cores[CURRENT_CORE].running, current); - + /* If there is no more processes in the list, break the loop. */ if (cores[CURRENT_CORE].sleeping == NULL) break; - + current = next; continue; } - + current = next; - + /* Break the loop once we have walked through the list of all * sleeping processes. */ if (current == cores[CURRENT_CORE].sleeping) @@ -321,7 +321,7 @@ static inline void sleep_core(void) { static long last_tick = 0; - + for (;;) { if (last_tick != current_tick) @@ -329,7 +329,7 @@ check_sleepers(); last_tick = current_tick; } - + /* We must sleep until there is at least one process in the list * of running processes. */ if (cores[CURRENT_CORE].running != NULL) @@ -342,7 +342,7 @@ cpu_boosted = false; } #endif - + /* Enter sleep mode to reduce power usage, woken up on interrupt */ #ifdef CPU_COLDFIRE asm volatile ("stop #0x2000"); @@ -354,7 +354,7 @@ interrupts */ CPU_CTL = 0x80000000; #elif CONFIG_CPU == TCC730 - /* Sleep mode is triggered by the SYS instr on CalmRisc16. + /* Sleep mode is triggered by the SYS instr on CalmRisc16. * Unfortunately, the manual doesn't specify which arg to use. __asm__ volatile ("sys #0x0f"); 0x1f seems to trigger a reset; @@ -370,13 +370,13 @@ static int get_threadnum(struct thread_entry *thread) { int i; - + for (i = 0; i < MAXTHREADS; i++) { if (&cores[CURRENT_CORE].threads[i] == thread) return i; } - + return -1; } @@ -385,22 +385,22 @@ } #endif -/* Compiler trick: Don't declare as static to prevent putting +/* Compiler trick: Don't declare as static to prevent putting * function in IRAM. */ void change_thread_state(struct thread_entry **blocked_list) { struct thread_entry *old; - + /* Remove the thread from the list of running threads. */ old = cores[CURRENT_CORE].running; remove_from_list(&cores[CURRENT_CORE].running, old); - + /* And put the thread into a new list of inactive threads. */ if (GET_STATE(old->statearg) == STATE_BLOCKED) add_to_list(blocked_list, old); else add_to_list(&cores[CURRENT_CORE].sleeping, old); - + #ifdef HAVE_PRIORITY_SCHEDULING /* Reset priorities */ if (old->priority == highest_priority) @@ -418,11 +418,11 @@ profile_thread_stopped(get_threadnum(cores[CURRENT_CORE].running)); #endif unsigned int *stackptr; - + #ifdef SIMULATOR /* Do nothing */ #else - + /* Begin task switching by saving our current context so that we can * restore the state of the current thread later to the point prior * to this call. */ @@ -436,7 +436,7 @@ if(stackptr[0] != DEADBEEF) panicf("Stkov %s", cores[CURRENT_CORE].running->name); # endif - + /* Check if a thread state change has been requested. */ if (cores[CURRENT_CORE].running->statearg) { @@ -449,38 +449,38 @@ cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next; } } - + /* Go through the list of sleeping task to check if we need to wake up * any of them due to timeout. Also puts core into sleep state until * there is at least one running process again. */ sleep_core(); - + #ifdef HAVE_PRIORITY_SCHEDULING /* Select the new task based on priorities and the last time a process * got CPU time. */ for (;;) { int priority = cores[CURRENT_CORE].running->priority; - + if (priority < highest_priority) highest_priority = priority; - - if (priority == highest_priority || (current_tick + + if (priority == highest_priority || (current_tick - cores[CURRENT_CORE].running->last_run > priority * 8)) { break; } cores[CURRENT_CORE].running = cores[CURRENT_CORE].running->next; } - + /* Reset the value of thread's last running time to the current time. */ cores[CURRENT_CORE].running->last_run = current_tick; #endif - + #endif /* And finally give control to the next thread. */ load_context(&cores[CURRENT_CORE].running->context); - + #ifdef RB_PROFILE profile_thread_started(get_threadnum(cores[CURRENT_CORE].running)); #endif @@ -491,10 +491,10 @@ /* Set the thread's new state and timeout and finally force a task switch * so that scheduler removes thread from the list of running processes * and puts it in list of sleeping tasks. */ - cores[CURRENT_CORE].running->statearg = + cores[CURRENT_CORE].running->statearg = SET_STATE(STATE_SLEEPING, current_tick + ticks + 1); switch_thread(true, NULL); - + /* Clear all flags to indicate we are up and running again. */ cores[CURRENT_CORE].running->statearg = 0; } @@ -502,10 +502,10 @@ void block_thread(struct thread_entry **list, int timeout) { struct thread_entry *current; - + /* Get the entry for the current running thread. */ current = cores[CURRENT_CORE].running; - + /* At next task switch scheduler will immediately change the thread * state (and we also force the task switch to happen). */ if (timeout) @@ -516,15 +516,15 @@ if (*list) panicf("Blocking violation T->*B"); #endif - - current->statearg = + + current->statearg = SET_STATE(STATE_BLOCKED_W_TMO, current_tick + timeout); *list = current; /* Now force a task switch and block until we have been woken up * by another thread or timeout is reached. */ switch_thread(true, NULL); - + /* If timeout is reached, we must set list back to NULL here. */ *list = NULL; } @@ -535,14 +535,14 @@ if (*list && GET_STATE((*list)->statearg) == STATE_BLOCKED_W_TMO) panicf("Blocking violation B->*T"); #endif - + current->statearg = SET_STATE(STATE_BLOCKED, 0); - + /* Now force a task switch and block until we have been woken up * by another thread or timeout is reached. */ switch_thread(true, list); } - + /* Clear all flags to indicate we are up and running again. */ current->statearg = 0; } @@ -550,16 +550,16 @@ void wakeup_thread(struct thread_entry **list) { struct thread_entry *thread; - + /* Check if there is a blocked thread at all. */ if (*list == NULL) return ; - + /* Wake up the last thread first. */ thread = *list; - + /* Determine thread's current state. */ - switch (GET_STATE(thread->statearg)) + switch (GET_STATE(thread->statearg)) { case STATE_BLOCKED: /* Remove thread from the list of blocked threads and add it @@ -568,14 +568,14 @@ add_to_list(&cores[CURRENT_CORE].running, thread); thread->statearg = 0; break; - + case STATE_BLOCKED_W_TMO: /* Just remove the timeout to cause scheduler to immediately * wake up the thread. */ thread->statearg &= 0xC0000000; *list = NULL; break; - + default: /* Nothing to do. Thread has already been woken up * or it's state is not blocked or blocked with timeout. */ @@ -588,7 +588,7 @@ * Return ID if context area could be allocated, else -1. *--------------------------------------------------------------------------- */ -struct thread_entry* +struct thread_entry* create_thread(void (*function)(void), void* stack, int stack_size, const char *name IF_PRIO(, int priority)) { @@ -601,8 +601,8 @@ * Return ID if context area could be allocated, else -1. *--------------------------------------------------------------------------- */ -struct thread_entry* - create_thread_on_core(unsigned int core, void (*function)(void), +struct thread_entry* + create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size, const char *name IF_PRIO(, int priority)) { @@ -618,11 +618,11 @@ if (cores[core].threads[n].name == NULL) break; } - + if (n == MAXTHREADS) return NULL; - - + + /* Munge the stack to make it easy to spot stack overflows */ stacklen = stack_size / sizeof(int); stackptr = stack; @@ -642,7 +642,7 @@ highest_priority = 100; #endif add_to_list(&cores[core].running, thread); - + regs = &thread->context; #if defined(CPU_COLDFIRE) || (CONFIG_CPU == SH7034) || defined(CPU_ARM) /* Align stack to an even 32 bit boundary */ @@ -677,20 +677,20 @@ { if (thread == NULL) thread = cores[CURRENT_CORE].running; - + /* Free the entry by removing thread name. */ thread->name = NULL; #ifdef HAVE_PRIORITY_SCHEDULING highest_priority = 100; #endif - + if (thread == cores[CURRENT_CORE].running) { remove_from_list(&cores[CURRENT_CORE].running, thread); switch_thread(false, NULL); return ; } - + if (thread == cores[CURRENT_CORE].sleeping) remove_from_list(&cores[CURRENT_CORE].sleeping, thread); else @@ -701,16 +701,24 @@ int thread_set_priority(struct thread_entry *thread, int priority) { int old_priority; - + if (thread == NULL) thread = cores[CURRENT_CORE].running; - + old_priority = thread->priority; thread->priority = priority; highest_priority = 100; - + return old_priority; } + +int thread_get_priority(struct thread_entry *thread) +{ + if (thread == NULL) + thread = cores[CURRENT_CORE].running; + + return thread->priority; +} #endif void init_threads(void) @@ -730,7 +738,7 @@ cpu_boosted = false; #endif add_to_list(&cores[core].running, &cores[core].threads[0]); - + /* In multiple core setups, each core has a different stack. There is probably a much better way to do this. */ if (core == CPU) Index: firmware/drivers/tlv320.c =================================================================== RCS file: /cvsroot/rockbox/firmware/drivers/tlv320.c,v retrieving revision 1.9 diff -u -r1.9 tlv320.c --- firmware/drivers/tlv320.c 26 Sep 2006 18:57:31 -0000 1.9 +++ firmware/drivers/tlv320.c 16 Oct 2006 23:32:49 -0000 @@ -82,7 +82,7 @@ tlv320_write_reg(REG_DAP, 0x00); /* No deemphasis */ tlv320_write_reg(REG_DAIF, DAIF_IWL_16 | DAIF_FOR_I2S); tlv320_write_reg(REG_DIA, DIA_ACT); - tlv320_write_reg(REG_SRC, (1 << 5)); /* 44.1kHz */ + tlv320_set_frequency(-1); /* default */ /* All ON except ADC, MIC and LINE */ tlv320_write_reg(REG_PC, PC_ADC | PC_MIC | PC_LINE); } @@ -96,6 +96,35 @@ } /** + * Sets internal sample rate for DAC and ADC relative to MCLK + * Selection for frequency: + * Fs: tlv: with: + * 11025: 0 = MCLK/2 MCLK/2 SCLK, LRCK: Audio Clk / 16 + * 22050: 0 = MCLK/2 MCLK SCLK, LRCK: Audio Clk / 8 + * 44100: 1 = MCLK MCLK SCLK, LRCK: Audio Clk / 4 (default) + * 88200: 2 = MCLK*2 MCLK SCLK, LRCK: Audio Clk / 2 + */ +void tlv320_set_frequency(unsigned fsel) +{ + /* All rates available for 11.2896MHz besides 8.021 */ + unsigned char values_src[3] = + { + /* Fs: */ + (0x8 << 2) | SRC_CLKIN, /* 11025, 22050 */ + (0x8 << 2), /* 44100 */ + (0xf << 2), /* 88200 */ + }; + int level; + + if (fsel >= ARRAYLEN(values_src)) + fsel = 1; + + level = set_irq_level(HIGHEST_IRQ_LEVEL); + tlv320_write_reg(REG_SRC, values_src[fsel]); + set_irq_level(level); +} + +/** * Sets left and right headphone volume * * Left & Right: 48 .. 121 .. 127 => Volume -73dB (mute) .. +0 dB .. +6 dB @@ -135,19 +164,18 @@ if (type == AUDIO_GAIN_MIC) { unsigned value_aap = tlv320_regs[REG_AAP]; - + if (left) value_aap |= AAP_MICB; /* Enable mic boost (20dB) */ else value_aap &= ~AAP_MICB; - tlv320_write_reg(REG_AAP, value_aap); - + tlv320_write_reg(REG_AAP, value_aap); } else if (type == AUDIO_GAIN_LINEIN) { tlv320_write_reg(REG_LLIV, LLIV_LIV(left)); - tlv320_write_reg(REG_RLIV, RLIV_RIV(right)); + tlv320_write_reg(REG_RLIV, RLIV_RIV(right)); } } @@ -180,17 +208,19 @@ } /* Nice shutdown of TLV320 codec */ -void tlv320_close() +void tlv320_close(void) { + tlv320_mute(true); + sleep(HZ/8); + tlv320_write_reg(REG_PC, PC_OFF | PC_CLK | PC_OSC | PC_OUT | PC_DAC | PC_ADC | PC_MIC | PC_LINE); /* All OFF */ } void tlv320_enable_recording(bool source_mic) { - unsigned value_daif = tlv320_regs[REG_DAIF]; unsigned value_aap, value_pc; - + if (source_mic) { /* select MIC and enable mic boost (20 dB) */ @@ -205,20 +235,12 @@ tlv320_write_reg(REG_PC, value_pc); tlv320_write_reg(REG_AAP, value_aap); - - /* Enable MASTER mode (start sending I2S data to the CPU) */ - value_daif |= DAIF_MS; - tlv320_write_reg(REG_DAIF, value_daif); } -void tlv320_disable_recording() +void tlv320_disable_recording(void) { unsigned value_pc = tlv320_regs[REG_PC]; unsigned value_aap = tlv320_regs[REG_AAP]; - unsigned value_daif = tlv320_regs[REG_DAIF]; - - value_daif &= ~DAIF_MS; /* disable MASTER mode */ - tlv320_write_reg(REG_DAIF, value_daif); value_aap |= AAP_MICM; /* mute MIC */ tlv320_write_reg(REG_PC, value_aap); Index: firmware/drivers/uda1380.c =================================================================== RCS file: /cvsroot/rockbox/firmware/drivers/uda1380.c,v retrieving revision 1.31 diff -u -r1.31 uda1380.c --- firmware/drivers/uda1380.c 21 Jul 2006 08:42:27 -0000 1.31 +++ firmware/drivers/uda1380.c 16 Oct 2006 23:32:50 -0000 @@ -49,9 +49,9 @@ #define NUM_DEFAULT_REGS 13 unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] = { - REG_0, EN_DAC | EN_INT | EN_DEC | SYSCLK_256FS | WSPLL_25_50, + REG_0, EN_DAC | EN_INT | EN_DEC | ADC_CLK | DAC_CLK | WSPLL_25_50, REG_I2S, I2S_IFMT_IIS, - REG_PWR, PON_BIAS, + REG_PWR, PON_PLL | PON_BIAS, /* PON_HP & PON_DAC is enabled later */ REG_AMIX, AMIX_RIGHT(0x3f) | AMIX_LEFT(0x3f), /* 00=max, 3f=mute */ @@ -60,7 +60,7 @@ REG_MIX_VOL, MIX_VOL_CH_1(0) | MIX_VOL_CH_2(0xff), /* 00=max, ff=mute */ REG_EQ, EQ_MODE_MAX, - /* Bass and tremble = 0 dB */ + /* Bass and treble = 0 dB */ REG_MUTE, MUTE_MASTER | MUTE_CH2, /* Mute everything to start with */ REG_MIX_CTL, MIX_CTL_MIX, @@ -71,7 +71,7 @@ REG_AGC, 0 }; - + /* Returns 0 if register was written or -1 if write failed */ int uda1380_write_reg(unsigned char reg, unsigned short value) @@ -86,7 +86,7 @@ { DEBUGF("uda1380 error reg=0x%x", reg); return -1; - } + } uda1380_regs[reg] = value; @@ -192,6 +192,43 @@ #endif } +/** + * Sets frequency settings for DAC and ADC relative to MCLK + * + * Selection for frequency ranges: + * Fs: range: with: + * 11025: 0 = 6.25 to 12.5 SCLK, LRCK: Audio Clk / 16 + * 22050: 1 = 12.5 to 25 SCLK, LRCK: Audio Clk / 8 + * 44100: 2 = 25 to 50 SCLK, LRCK: Audio Clk / 4 (default) + * 88200: 3 = 50 to 100 SCLK, LRCK: Audio Clk / 2 + */ +void uda1380_set_frequency(unsigned fsel) +{ + static const unsigned short values_reg[4][2] = + { + /* Fs: */ + { 0, WSPLL_625_125 }, /* 11025 */ + { 0, WSPLL_125_25 }, /* 22050 */ + { MIX_CTL_SEL_NS, WSPLL_25_50 }, /* 44100 */ + { MIX_CTL_SEL_NS, WSPLL_50_100 }, /* 88200 */ + }; + + const unsigned short *ent; + + if (fsel >= ARRAYLEN(values_reg)) + fsel = 2; + + ent = values_reg[fsel]; + + /* Set WSPLL input frequency range */ + uda1380_regs[REG_0] &= ~0xf; + uda1380_write_reg(REG_0, uda1380_regs[REG_0] | ent[1]); + + /* Choose 3rd order or 5th order noise shaper */ + uda1380_regs[REG_MIX_CTL] &= ~MIX_CTL_SEL_NS; + uda1380_write_reg(REG_MIX_CTL, uda1380_regs[REG_MIX_CTL] | ent[0]); +} + /* Initialize UDA1380 codec with default register values (uda1380_defaults) */ int uda1380_init(void) { @@ -199,7 +236,7 @@ recgain_line = 0; uda1380_reset(); - + if (uda1380_set_regs() == -1) return -1; @@ -221,7 +258,7 @@ /** * Calling this function enables the UDA1380 to send * sound samples over the I2S bus, which is connected - * to the processor's IIS1 interface. + * to the processor's IIS1 interface. * * source_mic: true=record from microphone, false=record from line-in (or radio) */ @@ -232,46 +269,46 @@ if (source_mic) { /* VGA_GAIN: 0=0 dB, F=30dB */ + /* Output of left ADC is fed into right bitstream */ + uda1380_regs[REG_PWR] &= ~(PON_PGAR | PON_ADCR); uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_LNA | PON_ADCL); + uda1380_regs[REG_ADC] &= ~SKIP_DCFIL; uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] & VGA_GAIN_MASK) | SEL_LNA | SEL_MIC | EN_DCFIL); uda1380_write_reg(REG_PGA, 0); } else { /* PGA_GAIN: 0=0 dB, F=24dB */ + uda1380_regs[REG_PWR] &= ~(PON_LNA); uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] | PON_PGAL | PON_ADCL | PON_PGAR | PON_ADCR); uda1380_write_reg(REG_ADC, EN_DCFIL); - uda1380_write_reg(REG_PGA, (uda1380_regs[REG_PGA] & PGA_GAIN_MASK) - | PGA_GAINL(0) | PGA_GAINR(0)); + uda1380_write_reg(REG_PGA, 0); } sleep(HZ/8); - - uda1380_write_reg(REG_I2S, uda1380_regs[REG_I2S] | I2S_MODE_MASTER); - uda1380_write_reg(REG_MIX_CTL, MIX_MODE(1)); + uda1380_write_reg(REG_MIX_CTL, MIX_MODE(1)); } -/** +/** * Stop sending samples on the I2S bus */ void uda1380_disable_recording(void) { uda1380_write_reg(REG_PGA, MUTE_ADC); sleep(HZ/8); - + uda1380_write_reg(REG_I2S, I2S_IFMT_IIS); - uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR] & ~(PON_LNA | PON_ADCL - | PON_ADCR | PON_PGAL - | PON_PGAR)); + uda1380_regs[REG_PWR] &= ~(PON_LNA | PON_ADCL | PON_ADCR | PON_PGAL | PON_PGAR); + uda1380_write_reg(REG_PWR, uda1380_regs[REG_PWR]); uda1380_write_reg(REG_0, uda1380_regs[REG_0] & ~EN_ADC); uda1380_write_reg(REG_ADC, SKIP_DCFIL); } /** * Set recording gain and volume - * + * * type: params: ranges: * AUDIO_GAIN_MIC: left -128 .. 108 -> -64 .. 54 dB gain * AUDIO_GAIN_LINEIN left & right -128 .. 96 -> -64 .. 48 dB gain @@ -295,22 +332,22 @@ { uda1380_write_reg(REG_DEC_VOL, DEC_VOLL(left) | DEC_VOLR(left)); - uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] - & ~VGA_GAIN_MASK) + uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] + & ~VGA_GAIN_MASK) | VGA_GAIN(left_ag)); } else { - uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] - & ~VGA_GAIN_MASK) + uda1380_write_reg(REG_ADC, (uda1380_regs[REG_ADC] + & ~VGA_GAIN_MASK) | VGA_GAIN(left_ag)); - uda1380_write_reg(REG_DEC_VOL, DEC_VOLL(left) + uda1380_write_reg(REG_DEC_VOL, DEC_VOLL(left) | DEC_VOLR(left)); } recgain_mic = left; logf("Mic: %dA/%dD", left_ag, left); break; - + case AUDIO_GAIN_LINEIN: left_ag = MIN(MAX(0, left / 6), 8); left -= left_ag * 6; @@ -346,7 +383,7 @@ } else { - uda1380_write_reg(REG_PGA, (uda1380_regs[REG_PGA] + uda1380_write_reg(REG_PGA, (uda1380_regs[REG_PGA] & ~PGA_GAIN_MASK) | PGA_GAINL(left_ag) | PGA_GAINR(right_ag)); @@ -362,9 +399,9 @@ } -/** +/** * Enable or disable recording monitor (so one can listen to the recording) - * + * */ void uda1380_set_monitor(int enable) { @@ -373,20 +410,3 @@ else /* mute channel 2 */ uda1380_write_reg(REG_MUTE, uda1380_regs[REG_MUTE] | MUTE_CH2); } - -/* Change the order of the noise chaper, - 5th order is recommended above 32kHz */ -void uda1380_set_nsorder(int order) -{ - switch(order) - { - case 5: - uda1380_write_reg(REG_MIX_CTL, uda1380_regs[REG_MIX_CTL] - | MIX_CTL_SEL_NS); - break; - case 3: - default: - uda1380_write_reg(REG_MIX_CTL, uda1380_regs[REG_MIX_CTL] - & ~MIX_CTL_SEL_NS); - } -} Index: firmware/export/audio.h =================================================================== RCS file: /cvsroot/rockbox/firmware/export/audio.h,v retrieving revision 1.19 diff -u -r1.19 audio.h --- firmware/export/audio.h 12 Oct 2006 16:51:22 -0000 1.19 +++ firmware/export/audio.h 16 Oct 2006 23:32:50 -0000 @@ -31,9 +31,6 @@ #define AUDIO_STATUS_PRERECORD 8 #define AUDIO_STATUS_ERROR 16 -#define AUDIO_STATUS_STAYON_FLAGS \ - (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE | AUDIO_STATUS_RECORD | AUDIO_) - #define AUDIOERR_DISK_FULL 1 #define AUDIO_GAIN_LINEIN 0 @@ -99,8 +96,36 @@ void audio_resume_recording(void); void audio_new_file(const char *filename); +#if CONFIG_CODEC == SWCODEC +#include "pcm_sampr.h" +#ifdef HAVE_RECORDING +#include "pcm_record.h" +#include "id3.h" +#include "enc_base.h" +#endif + +#endif /* CONFIG_CODEC == SWCODEC */ + +/* channel modes */ +enum rec_channel_modes +{ + __CHN_MODE_START_INDEX = -1, + + CHN_MODE_STEREO, + CHN_MODE_MONO, + + CHN_NUM_MODES +}; + +#if CONFIG_CODEC == SWCODEC +/* channel mode capability bits */ +#define CHN_CAP_STEREO (1 << CHN_MODE_STEREO) +#define CHN_CAP_MONO (1 << CHN_MODE_MONO) +#define CHN_CAP_ALL (CHN_CAP_STEREO | CHN_CAP_MONO) +#endif /* CONFIG_CODEC == SWCODEC */ + /* audio sources */ -enum +enum audio_sources { AUDIO_SRC_PLAYBACK = -1, /* for audio playback (default) */ AUDIO_SRC_MIC, /* monitor mic */ @@ -123,30 +148,46 @@ AUDIO_SRC_MAX = AUDIO_NUM_SOURCES-1 }; -/* channel modes */ -enum +#ifdef HAVE_RECORDING +/* parameters for audio_set_recording_options */ +struct audio_recording_options { - CHN_MODE_MONO = 1, - CHN_MODE_STEREO, + int rec_source; + int rec_frequency; + int rec_channels; + int rec_prerecord_time; +#if CONFIG_CODEC == SWCODEC + bool rec_new_file_flush; + int rec_source_flags; /* for rec_set_source */ + struct encoder_config enc_config; +#else + int rec_quality; + bool rec_editable; +#endif }; -void audio_set_recording_options(int frequency, int quality, - int source, int channel_mode, - bool editable, int prerecord_time); + +void audio_set_recording_options(struct audio_recording_options *options); void audio_set_recording_gain(int left, int right, int type); unsigned long audio_recorded_time(void); unsigned long audio_num_recorded_bytes(void); -#if 0 -#ifdef HAVE_SPDIF_POWER -void audio_set_spdif_power_setting(bool on); -#endif -#endif -unsigned long audio_get_spdif_sample_rate(void); + #if CONFIG_CODEC == SWCODEC -/* audio encoder functions (defined in playback.c) */ -int audio_get_encoder_id(void); -void audio_load_encoder(int enc_id); +/** audio encoder functions **/ +/* playback.c */ +bool audio_load_encoder(int afmt); void audio_remove_encoder(void); #endif /* CONFIG_CODEC == SWCODEC */ +#endif /* HAVE_RECORDING */ + +#ifdef HAVE_SPDIF_IN +#ifdef HAVE_SPDIF_POWER +void audio_set_spdif_power_setting(bool on); +bool audio_get_spdif_power_setting(void); +#endif +/* returns index into rec_master_sampr_list */ +int audio_get_spdif_sample_rate(void); +void audio_spdif_set_monitor(bool monitor_spdif); +#endif /* HAVE_SPDIF_IN */ Index: firmware/export/config-h100.h =================================================================== RCS file: /cvsroot/rockbox/firmware/export/config-h100.h,v retrieving revision 1.84 diff -u -r1.84 config-h100.h --- firmware/export/config-h100.h 26 Sep 2006 20:46:17 -0000 1.84 +++ firmware/export/config-h100.h 16 Oct 2006 23:32:50 -0000 @@ -79,6 +79,12 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING 1 +/* define hardware samples rate caps mask */ +#define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) + +/* define the bitmask of recording sample rates */ +#define REC_SAMPR_CAPS (SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) + #define HAVE_AGC #ifndef SIMULATOR Index: firmware/export/config-h120.h =================================================================== RCS file: /cvsroot/rockbox/firmware/export/config-h120.h,v retrieving revision 1.46 diff -u -r1.46 config-h120.h --- firmware/export/config-h120.h 12 Oct 2006 20:22:16 -0000 1.46 +++ firmware/export/config-h120.h 16 Oct 2006 23:32:50 -0000 @@ -73,6 +73,12 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING 1 +/* define hardware samples rate caps mask */ +#define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) + +/* define the bitmask of recording sample rates */ +#define REC_SAMPR_CAPS (SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) + #define HAVE_AGC #define BATTERY_CAPACITY_DEFAULT 1300 /* default battery capacity */ Index: firmware/export/config-h300.h =================================================================== RCS file: /cvsroot/rockbox/firmware/export/config-h300.h,v retrieving revision 1.50 diff -u -r1.50 config-h300.h --- firmware/export/config-h300.h 26 Sep 2006 21:17:18 -0000 1.50 +++ firmware/export/config-h300.h 16 Oct 2006 23:32:50 -0000 @@ -68,6 +68,12 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING 1 +/* define hardware samples rate caps mask */ +#define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) + +/* define the bitmask of recording sample rates */ +#define REC_SAMPR_CAPS (SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) + #define HAVE_AGC #define BATTERY_CAPACITY_DEFAULT 1300 /* default battery capacity */ @@ -146,4 +152,3 @@ /* Define this for FM radio input available */ #define HAVE_FMRADIO_IN - Index: firmware/export/config-iaudiox5.h =================================================================== RCS file: /cvsroot/rockbox/firmware/export/config-iaudiox5.h,v retrieving revision 1.37 diff -u -r1.37 config-iaudiox5.h --- firmware/export/config-iaudiox5.h 26 Sep 2006 20:46:17 -0000 1.37 +++ firmware/export/config-iaudiox5.h 16 Oct 2006 23:32:50 -0000 @@ -9,6 +9,12 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING 1 +/* define the bitmask of hardware sample rates */ +#define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) + +/* define the bitmask of recording sample rates */ +#define REC_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | SAMPR_CAP_11) + /* define this if you have a bitmap LCD display */ #define HAVE_LCD_BITMAP 1 Index: firmware/export/enc_base.h =================================================================== RCS file: firmware/export/enc_base.h diff -N firmware/export/enc_base.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ firmware/export/enc_base.h 16 Oct 2006 23:32:50 -0000 @@ -0,0 +1,268 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Base declarations for working with software encoders + * + * Copyright (C) 2006 Michael Sevakis + * + * 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 ENC_BASE_H +#define ENC_BASE_H + +/** encoder config structures **/ + +/** mp3_enc.codec **/ +#define MP3_BITR_CAP_8 (1 << 0) +#define MP3_BITR_CAP_16 (1 << 1) +#define MP3_BITR_CAP_24 (1 << 2) +#define MP3_BITR_CAP_32 (1 << 3) +#define MP3_BITR_CAP_40 (1 << 4) +#define MP3_BITR_CAP_48 (1 << 5) +#define MP3_BITR_CAP_56 (1 << 6) +#define MP3_BITR_CAP_64 (1 << 7) +#define MP3_BITR_CAP_80 (1 << 8) +#define MP3_BITR_CAP_96 (1 << 9) +#define MP3_BITR_CAP_112 (1 << 10) +#define MP3_BITR_CAP_128 (1 << 11) +#define MP3_BITR_CAP_144 (1 << 12) +#define MP3_BITR_CAP_160 (1 << 13) +#define MP3_BITR_CAP_192 (1 << 14) +#define MP3_BITR_CAP_224 (1 << 15) +#define MP3_BITR_CAP_256 (1 << 16) +#define MP3_BITR_CAP_320 (1 << 17) +#define MP3_ENC_NUM_BITR 18 + +/* MPEG 1 */ +#define MPEG1_SAMPR_CAPS (SAMPR_CAP_32 | SAMPR_CAP_48 | SAMPR_CAP_44) +#define MPEG1_BITR_CAPS (MP3_BITR_CAP_32 | MP3_BITR_CAP_40 | MP3_BITR_CAP_48 | \ + MP3_BITR_CAP_56 | MP3_BITR_CAP_64 | MP3_BITR_CAP_80 | \ + MP3_BITR_CAP_96 | MP3_BITR_CAP_112 | MP3_BITR_CAP_128 | \ + MP3_BITR_CAP_160 | MP3_BITR_CAP_192 | MP3_BITR_CAP_224 | \ + MP3_BITR_CAP_256 | MP3_BITR_CAP_320) + +/* MPEG 2 */ +#define MPEG2_SAMPR_CAPS (SAMPR_CAP_22 | SAMPR_CAP_24 | SAMPR_CAP_16) +#define MPEG2_BITR_CAPS (MP3_BITR_CAP_8 | MP3_BITR_CAP_16 | MP3_BITR_CAP_24 | \ + MP3_BITR_CAP_32 | MP3_BITR_CAP_40 | MP3_BITR_CAP_48 | \ + MP3_BITR_CAP_56 | MP3_BITR_CAP_64 | MP3_BITR_CAP_80 | \ + MP3_BITR_CAP_96 | MP3_BITR_CAP_112 | MP3_BITR_CAP_128 | \ + MP3_BITR_CAP_144 | MP3_BITR_CAP_160) + +#if 0 +/* MPEG 2.5 */ +#define MPEG2_5_SAMPR_CAPS (SAMPR_CAP_8 | SAMPR_CAP_12 | SAMPR_CAP_11) +#define MPEG2_5_BITR_CAPS MPEG2_BITR_CAPS +#endif + +/* Assume 44100 is always available and therefore MPEG1 */ + +/* HAVE_MPEG* defines mainly apply to the bitrate menu */ +#if (REC_SAMPR_CAPS & MPEG2_SAMPR_CAPS) || defined (HAVE_SPDIF_IN) +#define HAVE_MPEG2_SAMPR +#endif + +#if 0 +#if (REC_SAMPR_CAPS & MPEG2_5_SAMPR_CAPS) || defined (HAVE_SPDIF_IN) +#define HAVE_MPEG2_5_SAMPR +#endif +#endif /* 0 */ + +#define MP3_ENC_SAMPR_CAPS (MPEG1_SAMPR_CAPS | MPEG2_SAMPR_CAPS) + +/* This number is count of full encoder set */ +#define MP3_ENC_NUM_SAMPR 6 + +extern const unsigned long mp3_enc_sampr[MP3_ENC_NUM_SAMPR]; +extern const unsigned long mp3_enc_bitr[MP3_ENC_NUM_BITR]; + +struct mp3_enc_config +{ + unsigned long bitrate; +}; + +#define MP3_ENC_BITRATE_CFG_DEFAULT 11 /* 128 */ +#define MP3_ENC_BITRATE_CFG_VALUE_LIST "8,16,24,32,40,48,56,64,80,96," \ + "112,128,144,160,192,224,256,320" + +/** wavpack_enc.codec **/ +#define WAVPACK_ENC_SAMPR_CAPS SAMPR_CAP_ALL + +struct wavpack_enc_config +{ +#if 0 + unsigned long sample_depth; +#endif +}; + +/** wav_enc.codec **/ +#define WAV_ENC_SAMPR_CAPS SAMPR_CAP_ALL + +struct wav_enc_config +{ +#if 0 + unsigned long sample_depth; +#endif +}; + +struct encoder_config +{ + union + { + int rec_format; /* REC_FORMAT_* value */ + int afmt; /* AFMT_* value */ + }; + + union + { + struct mp3_enc_config mp3_enc; + struct wavpack_enc_config wavpack_enc; + struct wav_enc_config wav_enc; + }; +}; + +/** Encoder chunk macros and definitions **/ +#define CHUNKF_START_FILE 0x0001 /* This chunk starts a new file */ +#define CHUNKF_END_FILE 0x0002 /* This chunk ends the current file */ +#define CHUNKF_PRERECORD 0x0010 /* This chunk is prerecord data, + a new file could start anytime */ +#define CHUNKF_ABORT 0x0020 /* Encoder should not finish this + chunk */ +#define CHUNKF_ERROR 0x80000000 /* An error has occured (passed to/ + from encoder) */ + +/* Header at the beginning of every encoder chunk */ +struct enc_chunk_hdr +{ + unsigned long flags; /* in/out: flags used by encoder and file + writing */ + size_t enc_size; /* out: amount of encoder data written to + chunk */ + unsigned long num_pcm; /* out: number of PCM samples eaten during + processing + (<= size of allocated buffer) */ + unsigned char *enc_data; /* out: pointer to enc_size_written bytes + of encoded audio data in chunk */ + /* Encoder defined data follows header. Can be audio data + any other + stuff the encoder needs to handle on a per chunk basis */ +}; + +/* Paranoia: be sure header size is multiple of four */ +#define ENC_CHUNK_HDR_SIZE \ + ALIGN_UP_P2(sizeof (struct enc_chunk_hdr), 2) +/* Skip the chunk header and return data */ +#define ENC_CHUNK_SKIP_HDR(t, hdr) \ + ((typeof (t))((char *)hdr + ENC_CHUNK_HDR_SIZE)) +/* Cast p to struct enc_chunk_hdr * */ +#define ENC_CHUNK_HDR(p) \ + ((struct enc_chunk_hdr *)(p)) + +enum enc_events +{ + /* File writing events - data points to enc_file_event_data */ + ENC_START_FILE = 0, /* a new file has been opened and no data has yet + been written */ + ENC_WRITE_CHUNK, /* write the current chunk to disk */ + ENC_END_FILE, /* current file about to be closed and all valid + data has been written */ + /* Encoder buffer events - data points to enc_buffer_event_data */ + ENC_REC_NEW_STREAM, /* Take steps to finish current stream and start + new */ +}; + +/** + * encoder can write extra data to the file such as headers or more encoded + * samples and must update sizes and samples accordingly. + */ +struct enc_file_event_data +{ + struct enc_chunk_hdr *chunk; /* Current chunk */ + size_t new_enc_size; /* New size of chunk */ + unsigned long new_num_pcm; /* New number of pcm in chunk */ + const char *filename; /* filename to open if ENC_START_FILE */ + int rec_file; /* Current file or < 0 if none */ + unsigned long num_pcm_samples; /* Current pcm sample count written to + file so far. */ +}; + +/** + * encoder may add some data to the end of the last and start of the next + * but must never yield here so any encoding done should be absolutely + * minimal. + */ +struct enc_buffer_event_data +{ + unsigned long flags; /* in: One or more of: + * CHUNKF_PRERECORD + * CHUNKF_END_FILE + * CHUNKF_START_FILE + */ + struct enc_chunk_hdr *pre_chunk; /* in: pointer to first prerecord + * chunk + */ + struct enc_chunk_hdr *chunk; /* in,out: chunk were split occurs - + * first chunk of start + */ +}; + +/** Callbacks called by encoder codec **/ + +/* parameters passed to encoder by enc_get_inputs */ +struct enc_inputs +{ + unsigned long sample_rate; /* out - pcm frequency */ + int num_channels; /* out - number of audio channels */ + struct encoder_config *config; /* out - encoder settings */ +}; + +void enc_get_inputs(struct enc_inputs *inputs); + +/* parameters pass from encoder to enc_set_parameters */ +struct enc_parameters +{ + /* IN parameters */ + int afmt; /* AFMT_* id - sanity checker */ + size_t chunk_size; /* max chunk size required */ + unsigned long enc_sample_rate; /* actual sample rate used by encoder + (for recorded time calculation) */ + size_t reserve_bytes; /* number of bytes to reserve immediately + following chunks */ + void (*events_callback)(enum enc_events event, + void *data); /* pointer to events callback */ + /* OUT parameters */ + unsigned char *enc_buffer; /* pointer to enc_buffer */ + size_t buf_chunk_size; /* size of chunks in enc_buffer */ + int num_chunks; /* number of chunks allotted to encoder */ + unsigned char *reserve_buffer; /* pointer to reserve_bytes bytes */ +}; + +/* set the encoder dimensions - called by encoder codec at initialization + and termination */ +void enc_set_parameters(struct enc_parameters *params); +/* returns pointer to next write chunk in circular buffer */ +struct enc_chunk_hdr * enc_get_chunk(void); +/* releases the current chunk into the available chunks */ +void enc_finish_chunk(void); +/* checks near empty state on pcm input buffer */ +int enc_pcm_buf_near_empty(void); + +#define PCM_MAX_FEED_SIZE 20000 /* max pcm size passed to encoder */ + +/* passes a pointer to next chunk of unprocessed wav data */ +unsigned char * enc_get_pcm_data(size_t size); +/* puts some pcm data back in the queue */ +size_t enc_unget_pcm_data(size_t size); + +#endif /* ENC_BASE_H */ Index: firmware/export/general.h =================================================================== RCS file: firmware/export/general.h diff -N firmware/export/general.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ firmware/export/general.h 16 Oct 2006 23:32:50 -0000 @@ -0,0 +1,38 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Michael Sevakis + * + * 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 GENERAL_H +#define GENERAL_H + +#include + +/* round a signed/unsigned 32bit value to the closest of a list of values */ +/* returns the index of the closest value */ +int round_value_to_list32(unsigned long value, + const unsigned long list[], + int count, + bool signd); + +int make_list_from_caps32(unsigned long src_mask, + const unsigned long *src_list, + unsigned long caps_mask, + unsigned long *caps_list); + + +#endif /* GENERAL_H */ Index: firmware/export/id3.h =================================================================== RCS file: /cvsroot/rockbox/firmware/export/id3.h,v retrieving revision 1.31 diff -u -r1.31 id3.h --- firmware/export/id3.h 25 Sep 2006 16:13:05 -0000 1.31 +++ firmware/export/id3.h 16 Oct 2006 23:32:51 -0000 @@ -31,6 +31,9 @@ AFMT_MPA_L2, /* MPEG Audio layer 2 */ AFMT_MPA_L3, /* MPEG Audio layer 3 */ + AFMT_AIFF, /* Audio Interchange File Format */ + +#if CONFIG_CODEC == SWCODEC AFMT_PCM_WAV, /* Uncompressed PCM in a WAV file */ AFMT_OGG_VORBIS, /* Ogg Vorbis */ AFMT_FLAC, /* FLAC */ @@ -40,54 +43,87 @@ AFMT_ALAC, /* Apple Lossless Audio Codec */ AFMT_AAC, /* Advanced Audio Coding (AAC) in M4A container */ AFMT_SHN, /* Shorten */ - AFMT_AIFF, /* Audio Interchange File Format */ AFMT_SID, /* SID File Format */ - AFMT_ADX, /* ADX */ + AFMT_ADX, /* ADX File Format */ +#endif - /* New formats must be added to the end of this list */ + /* Add new format above this line */ + /* Synchonize formats with arrays in id3.c */ AFMT_NUM_CODECS, -#if CONFIG_CODEC == SWCODEC +#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) /* masks to decompose parts */ CODEC_AFMT_MASK = 0x0fff, CODEC_TYPE_MASK = 0x7000, /* switch for specifying codec type when requesting a filename */ CODEC_TYPE_DECODER = (0 << 12), /* default */ - CODEC_TYPE_ENCODER = (1 << 12) -#endif + CODEC_TYPE_ENCODER = (1 << 12), + + AFMT_HAS_ENC = 0x01 +#endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */ }; #if CONFIG_CODEC == SWCODEC -#define AFMT_ENTRY(label, codec_fname, codec_enc_fname, enc_ext) \ - { label, codec_fname, codec_enc_fname, enc_ext } -#else -#define AFMT_ENTRY(label, codec_fname, codec_enc_fname, enc_ext) \ - { label } -#endif +#define CODEC_EXTENSION "codec" + +#ifdef HAVE_RECORDING +#define IF_RECORDING_(...) __VA_ARGS__ +#define IF_RECORDING +#define ENCODER_SUFFIX "_enc" +enum rec_format_indexes +{ + __REC_FORMAT_START_INDEX = -1, + + REC_FORMAT_MPA_L3, + REC_FORMAT_WAVPACK, + REC_FORMAT_PCM_WAV, + + REC_NUM_FORMATS, + + REC_FORMAT_DEFAULT = REC_FORMAT_MPA_L3, + REC_FORMAT_CFG_NUM_BITS = 2 +}; + +#define REC_FORMAT_CFG_VAL_LIST "mpa3,wvpk,wave" + +/* get REC_FORMAT_* corresponding AFMT_* */ +extern const int rec_format_afmt[REC_NUM_FORMATS]; +/* get AFMT_* corresponding REC_FORMAT_* */ +extern const int afmt_rec_format[AFMT_NUM_CODECS]; + +#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ + { label, root_fname, enc_root_fname, ext_list } +#else /* !HAVE_RECORDING */ +#define IF_RECORDING_(...) +#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ + { label, root_fname, ext_list } +#endif /* HAVE_RECORDING */ +#else /* !SWCODEC */ + +#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ + { label, ext_list } +#endif /* CONFIG_CODEC == SWCODEC */ /* record describing the audio format */ struct afmt_entry { + char label[8]; /* format label */ #if CONFIG_CODEC == SWCODEC - char label[8]; /* format label */ - char *codec_fn; /* filename of decoder codec */ - char *codec_enc_fn; /* filename of encoder codec */ - char *ext; /* default extension for file (enc only for now) */ -#else - char label[4]; + char *codec_root_fn; /* root codec filename (sans _enc and .codec) */ +#ifdef HAVE_RECORDING + char *codec_enc_root_fn; /* filename of encoder codec */ +#endif #endif + char *ext_list; /* double NULL terminated extension + list for type with the first as + the default for recording */ }; /* database of labels and codecs. add formats per above enum */ extern const struct afmt_entry audio_formats[AFMT_NUM_CODECS]; -#if CONFIG_CODEC == SWCODEC -/* recording quality to AFMT_* */ -extern const int rec_quality_info_afmt[9]; -#endif - struct mp3entry { char path[MAX_PATH]; char* title; Index: firmware/export/pcm_playback.h =================================================================== RCS file: /cvsroot/rockbox/firmware/export/pcm_playback.h,v retrieving revision 1.23 diff -u -r1.23 pcm_playback.h --- firmware/export/pcm_playback.h 7 Feb 2006 20:38:55 -0000 1.23 +++ firmware/export/pcm_playback.h 16 Oct 2006 23:32:51 -0000 @@ -20,7 +20,34 @@ #define PCM_PLAYBACK_H void pcm_init(void); + +#ifdef HAVE_RECORDING +enum pcm_monitor_sources +{ + /* set the source for audio monitoring + use -1 for default source */ + PCM_MONITOR_DEFAULT = -1, + PCM_MONITOR_PLAYBACK, + PCM_MONITOR_RECORDING, +#ifdef HAVE_SPDIF_IN + PCM_MONITOR_SPDIF, +#endif + PCM_NUM_MONITOR_SOURCES +}; +void pcm_set_monitor(int monitor); +#if defined(CPU_COLDFIRE) && !defined(IAUDIO_X5) +void pcm_enable_recording(bool record); +#else +static inline void pcm_enable_recording(bool record) + { (void)record; } +#endif +#endif /* HAVE_RECORDING */ +/* set the pcm frequency - use values in hw_sampr_list + * use -1 for the default frequency + */ void pcm_set_frequency(unsigned int frequency); +/* apply settings to hardware immediately */ +void pcm_apply_settings(bool reset); /* This is for playing "raw" PCM data */ void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size), Index: firmware/export/pcm_record.h =================================================================== RCS file: /cvsroot/rockbox/firmware/export/pcm_record.h,v retrieving revision 1.5 diff -u -r1.5 pcm_record.h --- firmware/export/pcm_record.h 28 Aug 2006 22:38:41 -0000 1.5 +++ firmware/export/pcm_record.h 16 Oct 2006 23:32:51 -0000 @@ -20,24 +20,18 @@ #ifndef PCM_RECORD_H #define PCM_RECORD_H -void enc_set_parameters(int chunk_size, int num_chunks, - int samp_per_chunk, char *head_ptr, int head_size, - int enc_id); -void enc_get_inputs(int *buffer_size, int *channels, int *quality); -unsigned int* enc_alloc_chunk(void); -void enc_free_chunk(void); -int enc_wavbuf_near_empty(void); -char* enc_get_wav_data(int size); -extern void (*enc_set_header_callback)(void *head_buffer, int head_size, - int num_pcm_samples, bool is_file_header); - +/** General functions **/ +void pcm_rec_error_clear(void); unsigned long pcm_rec_status(void); void pcm_rec_init(void); void pcm_rec_mux(int source); int pcm_rec_current_bitrate(void); +int pcm_rec_encoder_afmt(void); /* AFMT_* value, AFMT_UNKNOWN if none */ +int pcm_rec_rec_format(void); /* Format index or -1 otherwise */ +unsigned long pcm_rec_sample_rate(void); int pcm_get_num_unprocessed(void); void pcm_rec_get_peaks(int *left, int *right); -/* audio.h contains audio recording functions */ +/* audio.h contains audio_* recording functions */ -#endif +#endif /* PCM_RECORD_H */ Index: firmware/export/pcm_sampr.h =================================================================== RCS file: firmware/export/pcm_sampr.h diff -N firmware/export/pcm_sampr.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ firmware/export/pcm_sampr.h 16 Oct 2006 23:32:51 -0000 @@ -0,0 +1,310 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Michael Sevakis + * + * 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 PCM_SAMPR_H +#define PCM_SAMPR_H + +/* These must be macros for comparison with SAMPR_CAP_* flags by the + preprocessor. Add samplerate index in descending order renumbering + the ones later in the list if any */ +#define FREQ_96 0 +#define FREQ_88 1 +#define FREQ_64 2 +#define FREQ_48 3 +#define FREQ_44 4 +#define FREQ_32 5 +#define FREQ_24 6 +#define FREQ_22 7 +#define FREQ_16 8 +#define FREQ_12 9 +#define FREQ_11 10 +#define FREQ_8 11 +#define SAMPR_NUM_FREQ 12 + +/* sample rate values in HZ */ +#define SAMPR_96 96000 +#define SAMPR_88 88200 +#define SAMPR_64 64000 +#define SAMPR_48 48000 +#define SAMPR_44 44100 +#define SAMPR_32 32000 +#define SAMPR_24 24000 +#define SAMPR_22 22050 +#define SAMPR_16 16000 +#define SAMPR_12 12000 +#define SAMPR_11 11025 +#define SAMPR_8 8000 + +/* sample rate capability bits */ +#define SAMPR_CAP_96 (1 << FREQ_96) +#define SAMPR_CAP_88 (1 << FREQ_88) +#define SAMPR_CAP_64 (1 << FREQ_64) +#define SAMPR_CAP_48 (1 << FREQ_48) +#define SAMPR_CAP_44 (1 << FREQ_44) +#define SAMPR_CAP_32 (1 << FREQ_32) +#define SAMPR_CAP_24 (1 << FREQ_24) +#define SAMPR_CAP_22 (1 << FREQ_22) +#define SAMPR_CAP_16 (1 << FREQ_16) +#define SAMPR_CAP_12 (1 << FREQ_12) +#define SAMPR_CAP_11 (1 << FREQ_11) +#define SAMPR_CAP_8 (1 << FREQ_8) +#define SAMPR_CAP_ALL (SAMPR_CAP_96 | SAMPR_CAP_88 | SAMPR_CAP_64 | \ + SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) + +/* Master list of all "standard" rates supported. */ +extern const unsigned long audio_master_sampr_list[SAMPR_NUM_FREQ]; + +/** Hardware sample rates **/ + +/* Enumeration of supported frequencies where 0 is the highest rate + supported and REC_NUM_FREQUENCIES is the number available */ +enum hw_freq_indexes +{ + __HW_FREQ_START_INDEX = -1, /* Make sure first in list is 0 */ + +/* 96000 */ +#if (HW_SAMPR_CAPS & SAMPR_CAP_96) /* Macros and enums for each FREQ: */ + HW_FREQ_96, /* Index in enumeration */ +#define HW_HAVE_96 /* Defined if this FREQ is defined */ +#define HW_HAVE_96_(...) __VA_ARGS__ /* Output its parameters for this FREQ */ +#else +#define HW_HAVE_96_(...) /* Discards its parameters for this FREQ */ +#endif +/* 88200 */ +#if (HW_SAMPR_CAPS & SAMPR_CAP_88) + HW_FREQ_88, +#define HW_HAVE_88 +#define HW_HAVE_88_(...) __VA_ARGS__ +#else +#define HW_HAVE_88_(...) +#endif +/* 64000 */ +#if (HW_SAMPR_CAPS & SAMPR_CAP_64) + HW_FREQ_64, +#define HW_HAVE_64 +#define HW_HAVE_64_(...) __VA_ARGS__ +#else +#define HW_HAVE_64_(...) +#endif +/* 48000 */ +#if (HW_SAMPR_CAPS & SAMPR_CAP_48) + HW_FREQ_48, +#define HW_HAVE_48 +#define HW_HAVE_48_(...) __VA_ARGS__ +#else +#define HW_HAVE_48_(...) +#endif +/* 44100 */ + HW_FREQ_44, +#define HW_HAVE_44 +#define HW_HAVE_44_(...) __VA_ARGS__ +/* 32000 */ +#if (HW_SAMPR_CAPS & SAMPR_CAP_32) + HW_FREQ_32, +#define HW_HAVE_32 +#define HW_HAVE_32_(...) __VA_ARGS__ +#else +#define HW_HAVE_32_(...) +#endif +/* 24000 */ +#if (HW_SAMPR_CAPS & SAMPR_CAP_24) + HW_FREQ_24, +#define HW_HAVE_24 +#define HW_HAVE_24_(...) __VA_ARGS__ +#else +#define HW_HAVE_24_(...) +#endif +/* 22050 */ +#if (HW_SAMPR_CAPS & SAMPR_CAP_22) + HW_FREQ_22, +#define HW_HAVE_22 +#define HW_HAVE_22_(...) __VA_ARGS__ +#else +#define HW_HAVE_22_(...) +#endif +/* 16000 */ +#if (HW_SAMPR_CAPS & SAMPR_CAP_16) + HW_FREQ_16, +#define HW_HAVE_16 +#define HW_HAVE_16_(...) __VA_ARGS__ +#else +#define HW_HAVE_16_(...) +#endif +/* 12000 */ +#if (HW_SAMPR_CAPS & SAMPR_CAP_12) + HW_FREQ_12, +#define HW_HAVE_12 +#define HW_HAVE_12_(...) __VA_ARGS__ +#else +#define HW_HAVE_12_(...) +#endif +/* 11025 */ +#if (HW_SAMPR_CAPS & SAMPR_CAP_11) + HW_FREQ_11, +#define HW_HAVE_11 +#define HW_HAVE_11_(...) __VA_ARGS__ +#else +#define HW_HAVE_11_(...) +#endif +/* 8000 */ +#if (HW_SAMPR_CAPS & SAMPR_CAP_8 ) + HW_FREQ_8, +#define HW_HAVE_8 +#define HW_HAVE_8_(...) __VA_ARGS__ +#else +#define HW_HAVE_8_(...) +#endif + HW_NUM_FREQ, + HW_FREQ_DEFAULT = HW_FREQ_44, + HW_SAMPR_DEFAULT = SAMPR_44, +}; /* enum hw_freq_indexes */ + +/* list of hardware sample rates */ +extern const unsigned long hw_freq_sampr[HW_NUM_FREQ]; + +#ifdef HAVE_RECORDING +/* Enumeration of supported frequencies where 0 is the highest rate + supported and REC_NUM_FREQUENCIES is the number available */ +enum rec_freq_indexes +{ + __REC_FREQ_START_INDEX = -1, /* Make sure first in list is 0 */ + +/* 96000 */ +#if (REC_SAMPR_CAPS & SAMPR_CAP_96) /* Macros and enums for each FREQ: */ + REC_FREQ_96, /* Index in enumeration */ +#define REC_HAVE_96 /* Defined if this FREQ is defined */ +#define REC_HAVE_96_(...) __VA_ARGS__ /* Output its parameters for this FREQ */ +#else +#define REC_HAVE_96_(...) /* Discards its parameters for this FREQ */ +#endif +/* 88200 */ +#if (REC_SAMPR_CAPS & SAMPR_CAP_88) + REC_FREQ_88, +#define REC_HAVE_88 +#define REC_HAVE_88_(...) __VA_ARGS__ +#else +#define REC_HAVE_88_(...) +#endif +/* 64000 */ +#if (REC_SAMPR_CAPS & SAMPR_CAP_64) + REC_FREQ_64, +#define REC_HAVE_64 +#define REC_HAVE_64_(...) __VA_ARGS__ +#else +#define REC_HAVE_64_(...) +#endif +/* 48000 */ +#if (REC_SAMPR_CAPS & SAMPR_CAP_48) + REC_FREQ_48, +#define REC_HAVE_48 +#define REC_HAVE_48_(...) __VA_ARGS__ +#else +#define REC_HAVE_48_(...) +#endif +/* 44100 */ +#if (REC_SAMPR_CAPS & SAMPR_CAP_44) + REC_FREQ_44, +#define REC_HAVE_44 +#define REC_HAVE_44_(...) __VA_ARGS__ +#else +#define REC_HAVE_44_(...) +#endif +/* 32000 */ +#if (REC_SAMPR_CAPS & SAMPR_CAP_32) + REC_FREQ_32, +#define REC_HAVE_32 +#define REC_HAVE_32_(...) __VA_ARGS__ +#else +#define REC_HAVE_32_(...) +#endif +/* 24000 */ +#if (REC_SAMPR_CAPS & SAMPR_CAP_24) + REC_FREQ_24, +#define REC_HAVE_24 +#define REC_HAVE_24_(...) __VA_ARGS__ +#else +#define REC_HAVE_24_(...) +#endif +/* 22050 */ +#if (REC_SAMPR_CAPS & SAMPR_CAP_22) + REC_FREQ_22, +#define REC_HAVE_22 +#define REC_HAVE_22_(...) __VA_ARGS__ +#else +#define REC_HAVE_22_(...) +#endif +/* 16000 */ +#if (REC_SAMPR_CAPS & SAMPR_CAP_16) + REC_FREQ_16, +#define REC_HAVE_16 +#define REC_HAVE_16_(...) __VA_ARGS__ +#else +#define REC_HAVE_16_(...) +#endif +/* 12000 */ +#if (REC_SAMPR_CAPS & SAMPR_CAP_12) + REC_FREQ_12, +#define REC_HAVE_12 +#define REC_HAVE_12_(...) __VA_ARGS__ +#else +#define REC_HAVE_12_(...) +#endif +/* 11025 */ +#if (REC_SAMPR_CAPS & SAMPR_CAP_11) + REC_FREQ_11, +#define REC_HAVE_11 +#define REC_HAVE_11_(...) __VA_ARGS__ +#else +#define REC_HAVE_11_(...) +#endif +/* 8000 */ +#if (REC_SAMPR_CAPS & SAMPR_CAP_8 ) + REC_FREQ_8, +#define REC_HAVE_8 +#define REC_HAVE_8_(...) __VA_ARGS__ +#else +#define REC_HAVE_8_(...) +#endif + REC_NUM_FREQ, + /* This should always come out I reckon */ + REC_FREQ_DEFAULT = REC_FREQ_44, + /* Get the minimum bitcount needed to save the range of values */ + REC_FREQ_CFG_NUM_BITS = (REC_NUM_FREQ > 8 ? + 4 : (REC_NUM_FREQ > 4 ? + 3 : (REC_NUM_FREQ > 2 ? + 2 : 1 + ) + ) + ), +}; /* enum rec_freq_indexes */ + +#define REC_FREQ_CFG_VAL_LIST &REC_HAVE_96_(",96") REC_HAVE_88_(",88") \ + REC_HAVE_64_(",64") REC_HAVE_48_(",48") \ + REC_HAVE_44_(",44") REC_HAVE_32_(",32") \ + REC_HAVE_24_(",24") REC_HAVE_22_(",22") \ + REC_HAVE_16_(",16") REC_HAVE_12_(",12") \ + REC_HAVE_11_(",11") REC_HAVE_8_(",8")[1] + +/* List of recording supported sample rates (set or subset of master list) */ +extern const unsigned long rec_freq_sampr[REC_NUM_FREQ]; +#endif /* HAVE_RECORDING */ + +#endif /* PCM_SAMPR_H */ Index: firmware/export/system.h =================================================================== RCS file: /cvsroot/rockbox/firmware/export/system.h,v retrieving revision 1.61 diff -u -r1.61 system.h --- firmware/export/system.h 5 Oct 2006 10:23:18 -0000 1.61 +++ firmware/export/system.h 16 Oct 2006 23:32:51 -0000 @@ -111,6 +111,23 @@ #define MAX(a, b) (((a)>(b))?(a):(b)) #endif +/* return number of elements in array a */ +#define ARRAYLEN(a) (sizeof(a)/sizeof((a)[0])) + +/* return p incremented by specified number of bytes */ +#define SKIPBYTES(p, count) ((typeof (p))((char *)(p) + (count))) + +#define P2_M1(p2) ((1 << (p2))-1) + +/* align up or down to nearest 2^p2 */ +#define ALIGN_DOWN_P2(n, p2) ((n) & ~P2_M1(p2)) +#define ALIGN_UP_P2(n, p2) ALIGN_DOWN_P2((n) + P2_M1(p2),p2) + +/* align up or down to nearest integer multiple of a */ +#define ALIGN_DOWN(n, a) ((n)/(a)*(a)) +#define ALIGN_UP(n, a) ALIGN_DOWN((n)+((a)-1),a) + +/* live endianness conversion */ #ifdef ROCKBOX_LITTLE_ENDIAN #define letoh16(x) (x) #define letoh32(x) (x) @@ -120,6 +137,8 @@ #define betoh32(x) swap32(x) #define htobe16(x) swap16(x) #define htobe32(x) swap32(x) +#define swap_odd_even_be32(x) (x) +#define swap_odd_even_le32(x) swap_odd_even32(x) #else #define letoh16(x) swap16(x) #define letoh32(x) swap32(x) @@ -129,6 +148,37 @@ #define betoh32(x) (x) #define htobe16(x) (x) #define htobe32(x) (x) +#define swap_odd_even_be32(x) swap_odd_even32(x) +#define swap_odd_even_le32(x) (x) +#endif + +/* static endianness conversion */ +#define SWAP_16(x) ((typeof(x))(unsigned short)(((unsigned short)(x) >> 8) | \ + ((unsigned short)(x) << 8))) + +#define SWAP_32(x) ((typeof(x))(unsigned long)( ((unsigned long)(x) >> 24) | \ + (((unsigned long)(x) & 0xff0000ul) >> 8) | \ + (((unsigned long)(x) & 0xff00ul) << 8) | \ + ((unsigned long)(x) << 24))) + +#ifdef ROCKBOX_LITTLE_ENDIAN +#define LE_TO_H16(x) (x) +#define LE_TO_H32(x) (x) +#define H_TO_LE16(x) (x) +#define H_TO_LE32(x) (x) +#define BE_TO_H16(x) SWAP_16(x) +#define BE_TO_H32(x) SWAP_32(x) +#define H_TO_BE16(x) SWAP_16(x) +#define H_TO_BE32(x) SWAP_32(x) +#else +#define LE_TO_H16(x) SWAP_16(x) +#define LE_TO_H32(x) SWAP_32(x) +#define H_TO_LE16(x) SWAP_16(x) +#define H_TO_LE32(x) SWAP_32(x) +#define BE_TO_H16(x) (x) +#define BE_TO_H32(x) (x) +#define H_TO_BE16(x) (x) +#define H_TO_BE32(x) (x) #endif @@ -215,6 +265,25 @@ return m; } +#ifndef TARGET_TREE +#define DEFAULT_PLLCR_AUDIO_BITS 0x10c00000 +#elif defined(IAUDIO_X5) +#define DEFAULT_PLLCR_AUDIO_BITS 0x10400000 +#endif +void coldfire_set_pllcr_audio_bits(long bits); +#endif + +/* implement this in ASM for other CPUs please */ +#if !defined(CPU_COLDFIRE) || defined(SIMULATOR) +static inline unsigned long swap_odd_even32(unsigned long value) +{ + /* + result[31..24],[15.. 8] = value[23..16],[ 7.. 0] + result[23..16],[ 7.. 0] = value[31..24],[15.. 8] + */ + unsigned long t = value & 0xff00ff00; + return (t >> 8) | ((t ^ value) << 8); +} #endif #ifndef SIMULATOR @@ -284,6 +353,28 @@ return oldlevel; } +static inline unsigned long swap_odd_even32(unsigned long value) +{ + /* + result[31..24],[15.. 8] = value[23..16],[ 7.. 0] + result[23..16],[ 7.. 0] = value[31..24],[15.. 8] + */ + unsigned long mask = 0x00FF00FF; + + asm ( /* val = ABCD */ + "and.l %[val],%[mask] \n" /* mask = .B.D */ + "eor.l %[mask],%[val] \n" /* val = A.C. */ + "lsl.l #8,%[mask] \n" /* mask = B.D. */ + "lsr.l #8,%[val] \n" /* val = .A.C */ + "or.l %[mask],%[val] \n" /* val = BADC */ + : /* outputs */ + [val] "+d"(value), + [mask]"+d"(mask) + ); + + return value; +} + static inline unsigned short swap16(unsigned short value) /* result[15..8] = value[ 7..0]; @@ -444,8 +535,8 @@ { int result; __asm__ ("ld %0, 0\n\t" - "tstsr ie\n\t" - "incc %0" : "=r"(result)); + "tstsr ie\n\t" + "incc %0" : "=r"(result)); if (level > 0) __asm__ volatile ("clrsr ie"); else Index: firmware/export/thread.h =================================================================== RCS file: /cvsroot/rockbox/firmware/export/thread.h,v retrieving revision 1.17 diff -u -r1.17 thread.h --- firmware/export/thread.h 15 Oct 2006 11:57:52 -0000 1.17 +++ firmware/export/thread.h 16 Oct 2006 23:32:51 -0000 @@ -25,7 +25,7 @@ /* Priority scheduling (when enabled with HAVE_PRIORITY_SCHEDULING) works * by giving high priority threads more CPU time than less priority threads * when they need it. - * + * * If software playback codec pcm buffer is going down to critical, codec * can change it own priority to REALTIME to override user interface and * prevent playback skipping. @@ -39,7 +39,7 @@ #define PRIORITY_BACKGROUND 8 /* Normal application threads */ #if CONFIG_CODEC == SWCODEC -#define MAXTHREADS 15 +#define MAXTHREADS 15 #else #define MAXTHREADS 11 #endif @@ -126,7 +126,7 @@ const char *name IF_PRIO(, int priority)); struct thread_entry* - create_thread_on_core(unsigned int core, void (*function)(void), + create_thread_on_core(unsigned int core, void (*function)(void), void* stack, int stack_size, const char *name IF_PRIO(, int priority)); @@ -142,7 +142,10 @@ void sleep_thread(int ticks); void block_thread(struct thread_entry **thread, int timeout); void wakeup_thread(struct thread_entry **thread); -int thread_set_priority(struct thread_entry *thread, int priority); +#ifdef HAVE_PRIORITY_SCHEDULING +int thread_set_priority(struct thread_entry *thread, int priority); +int thread_get_priority(struct thread_entry *thread); +#endif void init_threads(void); int thread_stack_usage(const struct thread_entry *thread); int thread_get_status(const struct thread_entry *thread); Index: firmware/export/tlv320.h =================================================================== RCS file: /cvsroot/rockbox/firmware/export/tlv320.h,v retrieving revision 1.8 diff -u -r1.8 tlv320.h --- firmware/export/tlv320.h 26 Aug 2006 21:00:18 -0000 1.8 +++ firmware/export/tlv320.h 16 Oct 2006 23:32:51 -0000 @@ -24,6 +24,16 @@ extern void tlv320_init(void); extern void tlv320_reset(void); +/** + * Sets internal sample rate for DAC and ADC relative to MCLK + * Selection for frequency: + * Fs: tlv: with: + * 11025: 0 = MCLK/2 MCLK/2 SCLK, LRCK: Audio Clk / 16 + * 22050: 0 = MCLK/2 MCLK SCLK, LRCK: Audio Clk / 8 + * 44100: 1 = MCLK MCLK SCLK, LRCK: Audio Clk / 4 (default) + * 88200: 2 = MCLK*2 MCLK SCLK, LRCK: Audio Clk / 2 + */ +extern void tlv320_set_frequency(unsigned fsel); extern void tlv320_enable_output(bool enable); extern void tlv320_set_headphone_vol(int vol_l, int vol_r); extern void tlv320_set_recvol(int left, int right, int type); Index: firmware/export/uda1380.h =================================================================== RCS file: /cvsroot/rockbox/firmware/export/uda1380.h,v retrieving revision 1.11 diff -u -r1.11 uda1380.h --- firmware/export/uda1380.h 17 Dec 2005 11:01:51 -0000 1.11 +++ firmware/export/uda1380.h 16 Oct 2006 23:32:52 -0000 @@ -28,8 +28,17 @@ extern void uda1380_set_treble(int value); extern int uda1380_mute(int mute); extern void uda1380_close(void); -extern void uda1380_set_nsorder(int order); - +/** + * Sets frequency settings for DAC and ADC relative to MCLK + * + * Selection for frequency ranges: + * Fs: range: with: + * 11025: 0 = 6.25 to 12.5 SCLK, LRCK: Audio Clk / 16 + * 22050: 1 = 12.5 to 25 SCLK, LRCK: Audio Clk / 8 + * 44100: 2 = 25 to 50 SCLK, LRCK: Audio Clk / 4 (default) + * 88200: 3 = 50 to 100 SCLK, LRCK: Audio Clk / 2 + */ +extern void uda1380_set_frequency(unsigned fsel); extern void uda1380_enable_recording(bool source_mic); extern void uda1380_disable_recording(void); extern void uda1380_set_recvol(int left, int right, int type); @@ -60,7 +69,7 @@ /* REG_I2S: I2S settings */ -#define REG_I2S 0x01 +#define REG_I2S 0x01 #define I2S_IFMT_IIS (0 << 8) #define I2S_IFMT_LSB16 (1 << 8) #define I2S_IFMT_LSB18 (2 << 8) Index: firmware/target/coldfire/iaudio/x5/system-x5.c =================================================================== RCS file: /cvsroot/rockbox/firmware/target/coldfire/iaudio/x5/system-x5.c,v retrieving revision 1.3 diff -u -r1.3 system-x5.c --- firmware/target/coldfire/iaudio/x5/system-x5.c 30 Mar 2006 10:01:04 -0000 1.3 +++ firmware/target/coldfire/iaudio/x5/system-x5.c 16 Oct 2006 23:32:52 -0000 @@ -37,7 +37,7 @@ /* Refresh timer for bypass frequency */ PLLCR &= ~1; /* Bypass mode */ timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); - PLLCR = 0x13442045; + PLLCR = 0x03042045 | (PLLCR & 0x70C00000); CSCR0 = 0x00001180; /* Flash: 4 wait states */ CSCR1 = 0x00000980; /* LCD: 2 wait states */ while(!(PLLCR & 0x80000000)) {}; /* Wait until the PLL has locked. @@ -54,7 +54,7 @@ /* Refresh timer for bypass frequency */ PLLCR &= ~1; /* Bypass mode */ timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, false); - PLLCR = 0x16430045; + PLLCR = 0x06030045 | (PLLCR & 0x70C00000); CSCR0 = 0x00000580; /* Flash: 1 wait state */ CSCR1 = 0x00000180; /* LCD: 0 wait states */ while(!(PLLCR & 0x80000000)) {}; /* Wait until the PLL has locked. @@ -70,7 +70,8 @@ /* Refresh timer for bypass frequency */ PLLCR &= ~1; /* Bypass mode */ timers_adjust_prescale(CPUFREQ_DEFAULT_MULT, true); - PLLCR = 0x10400200; /* Power down PLL, but keep CLSEL and CRSEL */ + /* Power down PLL, but keep CLSEL and CRSEL */ + PLLCR = 0x00000200 | (PLLCR & 0x70C00000); CSCR0 = 0x00000180; /* Flash: 0 wait states */ CSCR1 = 0x00000180; /* LCD: 0 wait states */ DCR = (0x8000 | DEFAULT_REFRESH_TIMER); /* Refresh timer */ Index: uisimulator/sdl/lcd-charcell.c =================================================================== RCS file: /cvsroot/rockbox/uisimulator/sdl/lcd-charcell.c,v retrieving revision 1.5 diff -u -r1.5 lcd-charcell.c --- uisimulator/sdl/lcd-charcell.c 23 May 2006 10:00:11 -0000 1.5 +++ uisimulator/sdl/lcd-charcell.c 16 Oct 2006 23:32:53 -0000 @@ -181,7 +181,8 @@ int x, y; static unsigned char line[BMP_LINESIZE]; - create_numbered_filename(filename, "", "dump_", ".bmp", 4); + create_numbered_filename(filename, "", "dump_", ".bmp", 4, + IF_CNFN_NUM_(, NULL)); DEBUGF("screen_dump\n"); fd = sim_creat(filename, O_WRONLY);