Forgot to use cvs add on a few new files in the fresh checkout I used. woops.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11453 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
0f5cb94aa4
commit
5efee7c94a
9 changed files with 2060 additions and 0 deletions
432
apps/enc_config.c
Normal file
432
apps/enc_config.c
Normal file
|
@ -0,0 +1,432 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 <stdio.h>
|
||||
#include <sprintf.h>
|
||||
#include <string.h>
|
||||
#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 */
|
||||
|
||||
/* check if MPEG1 sample rates are available */
|
||||
if ((bitr >= 32 && bitr <= 128) || bitr >= 160)
|
||||
caps->samplerate_caps |= MPEG1_SAMPR_CAPS;
|
||||
|
||||
/* check if MPEG2 sample rates and mono are available */
|
||||
if (bitr <= 160)
|
||||
{
|
||||
caps->samplerate_caps |= MPEG2_SAMPR_CAPS;
|
||||
caps->channel_caps |= CHN_CAP_MONO;
|
||||
}
|
||||
|
||||
/* check if stereo is available */
|
||||
if (bitr >= 32)
|
||||
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[] =
|
||||
{
|
||||
/* Available in MPEG Version: */
|
||||
#ifdef HAVE_MPEG2_SAMPR
|
||||
#if 0
|
||||
/* this sounds awful no matter what */
|
||||
{ "8 kBit/s", TALK_ID(8, UNIT_KBIT) }, /* 2 */
|
||||
#endif
|
||||
/* mono only */
|
||||
{ "16 kBit/s", TALK_ID(16, UNIT_KBIT) }, /* 2 */
|
||||
{ "24 kBit/s", TALK_ID(24, UNIT_KBIT) }, /* 2 */
|
||||
#endif
|
||||
/* stereo/mono */
|
||||
{ "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 */
|
||||
#if 0
|
||||
/* oddball MPEG2-only rate stuck in the middle */
|
||||
{ "144 kBit/s", TALK_ID(144, UNIT_KBIT) }, /* 2 */
|
||||
#endif
|
||||
{ "160 kBit/s", TALK_ID(160, UNIT_KBIT) }, /* 1,2 */
|
||||
/* stereo only */
|
||||
{ "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 & ~(MP3_BITR_CAP_144 | MP3_BITR_CAP_8)),
|
||||
#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);
|
||||
index = round_value_to_list32(rate_list[index], mp3_enc_bitr,
|
||||
MP3_ENC_NUM_BITR, false);
|
||||
cfg->mp3_enc.bitrate = mp3_enc_bitr[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 */
|
||||
|
||||
/** wav_enc.codec **/
|
||||
/* wav_enc: show the configuration menu */
|
||||
#if 0
|
||||
static bool wav_enc_menu(struct encoder_config *cfg);
|
||||
#endif
|
||||
|
||||
/** wavpack_enc.codec **/
|
||||
/* wavpack_enc: show the configuration menu */
|
||||
#if 0
|
||||
static bool wavpack_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] =
|
||||
{
|
||||
/* mp3_enc.codec */
|
||||
[REC_FORMAT_MPA_L3] = {
|
||||
mp3_enc_get_caps,
|
||||
mp3_enc_default_config,
|
||||
mp3_enc_convert_config,
|
||||
mp3_enc_menu,
|
||||
},
|
||||
/* wav_enc.codec */
|
||||
[REC_FORMAT_PCM_WAV] = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
enc_no_config_menu,
|
||||
},
|
||||
/* wavpack_enc.codec */
|
||||
[REC_FORMAT_WAVPACK] = {
|
||||
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 */
|
73
apps/enc_config.h
Normal file
73
apps/enc_config.h
Normal file
|
@ -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 */
|
46
firmware/enc_base.c
Normal file
46
firmware/enc_base.c
Normal file
|
@ -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
|
||||
};
|
||||
|
||||
/** wav_enc.codec **/
|
||||
|
||||
/** wavpack_enc.codec **/
|
||||
|
||||
/** public functions **/
|
270
firmware/export/enc_base.h
Normal file
270
firmware/export/enc_base.h
Normal file
|
@ -0,0 +1,270 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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"
|
||||
|
||||
/** wav_enc.codec **/
|
||||
#define WAV_ENC_SAMPR_CAPS SAMPR_CAP_ALL
|
||||
|
||||
struct wav_enc_config
|
||||
{
|
||||
#if 0
|
||||
unsigned long sample_depth;
|
||||
#endif
|
||||
};
|
||||
|
||||
/** wavpack_enc.codec **/
|
||||
#define WAVPACK_ENC_SAMPR_CAPS SAMPR_CAP_ALL
|
||||
|
||||
struct wavpack_enc_config
|
||||
{
|
||||
#if 0
|
||||
unsigned long sample_depth;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct encoder_config
|
||||
{
|
||||
union
|
||||
{
|
||||
/* states which *_enc_config member is valid */
|
||||
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). Use the sign bit to
|
||||
check (long)flags < 0. */
|
||||
|
||||
/* 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 4-byte aligned */
|
||||
#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 when called 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 */
|
38
firmware/export/general.h
Normal file
38
firmware/export/general.h
Normal file
|
@ -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 <stdbool.h>
|
||||
|
||||
/* 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 */
|
310
firmware/export/pcm_sampr.h
Normal file
310
firmware/export/pcm_sampr.h
Normal file
|
@ -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 */
|
77
firmware/general.c
Normal file
77
firmware/general.c
Normal file
|
@ -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 <limits.h>
|
||||
#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 */
|
76
firmware/pcm_sampr.c
Normal file
76
firmware/pcm_sampr.c
Normal file
|
@ -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 */
|
738
firmware/target/coldfire/pcm-coldfire.c
Normal file
738
firmware/target/coldfire/pcm-coldfire.c
Normal file
|
@ -0,0 +1,738 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 <stdlib.h>
|
||||
#include "system.h"
|
||||
#include "kernel.h"
|
||||
#include "logf.h"
|
||||
#include "audio.h"
|
||||
#if defined(HAVE_UDA1380)
|
||||
#include "uda1380.h"
|
||||
#elif defined(HAVE_TLV320)
|
||||
#include "tlv320.h"
|
||||
#endif
|
||||
|
||||
/* Avoid further #ifdef's for some codec functions */
|
||||
#if defined(HAVE_UDA1380)
|
||||
#define ac_init uda1380_init
|
||||
#define ac_mute uda1380_mute
|
||||
#define ac_set_frequency uda1380_set_frequency
|
||||
#elif defined(HAVE_TLV320)
|
||||
#define ac_init tlv320_init
|
||||
#define ac_mute tlv320_mute
|
||||
#define ac_set_frequency tlv320_set_frequency
|
||||
#endif
|
||||
|
||||
/** Semi-private shared symbols **/
|
||||
|
||||
/* the registered callback function to ask for more pcm data */
|
||||
extern pcm_more_callback_type pcm_callback_for_more;
|
||||
extern bool pcm_playing;
|
||||
extern bool pcm_paused;
|
||||
|
||||
/* the registered callback function for when more data is available */
|
||||
extern pcm_more_callback_type pcm_callback_more_ready;
|
||||
extern bool pcm_recording;
|
||||
|
||||
/* peaks */
|
||||
static int play_peak_left, play_peak_right;
|
||||
static unsigned long *rec_peak_addr;
|
||||
static int rec_peak_left, rec_peak_right;
|
||||
|
||||
#define IIS_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
|
||||
(pcm_txsrc_select[pcm_monitor+1] << 8) | \
|
||||
(4 << 2) ) /* 64 bit clocks / word clock */
|
||||
#define IIS_RESET 0x800
|
||||
|
||||
#ifdef IAUDIO_X5
|
||||
#define SET_IIS_CONFIG(x) IIS1CONFIG = (x);
|
||||
#define IIS_CONFIG IIS1CONFIG
|
||||
#define PLLCR_SET_AUDIO_BITS_DEFPARM \
|
||||
((freq_ent[FPARM_CLSEL] << 28) | (1 << 22))
|
||||
#else
|
||||
#define SET_IIS_CONFIG(x) IIS2CONFIG = (x);
|
||||
#define IIS_CONFIG IIS2CONFIG
|
||||
#define PLLCR_SET_AUDIO_BITS_DEFPARM \
|
||||
((freq_ent[FPARM_CLSEL] << 28) | (3 << 22))
|
||||
|
||||
#ifdef HAVE_SPDIF_OUT
|
||||
#define EBU_DEFPARM ((7 << 12) | (3 << 8) | (1 << 5) | (5 << 2))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** Sample rates **/
|
||||
#define FPARM_CLOCKSEL 0
|
||||
#define FPARM_CLSEL 1
|
||||
#define FPARM_FSEL 2
|
||||
#if CONFIG_CPU == MCF5249 && defined(HAVE_UDA1380)
|
||||
static const unsigned char pcm_freq_parms[HW_NUM_FREQ][3] =
|
||||
{
|
||||
[HW_FREQ_88] = { 0x0c, 0x01, 0x03 },
|
||||
[HW_FREQ_44] = { 0x06, 0x01, 0x02 },
|
||||
[HW_FREQ_22] = { 0x04, 0x02, 0x01 },
|
||||
[HW_FREQ_11] = { 0x02, 0x02, 0x00 },
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CONFIG_CPU == MCF5250 && defined(HAVE_TLV320)
|
||||
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];
|
||||
|
||||
/* 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];
|
||||
} /* pcm_set_frequency */
|
||||
|
||||
/** monitoring/source selection **/
|
||||
static int pcm_monitor = AUDIO_SRC_PLAYBACK;
|
||||
|
||||
static const unsigned char pcm_txsrc_select[AUDIO_NUM_SOURCES+1] =
|
||||
{
|
||||
[AUDIO_SRC_PLAYBACK+1] = 3, /* PDOR3 */
|
||||
[AUDIO_SRC_MIC+1] = 4, /* IIS1 RcvData */
|
||||
[AUDIO_SRC_LINEIN+1] = 4, /* IIS1 RcvData */
|
||||
#ifdef HAVE_FMRADIO_IN
|
||||
[AUDIO_SRC_FMRADIO+1] = 4, /* IIS1 RcvData */
|
||||
#endif
|
||||
#ifdef HAVE_SPDIF_IN
|
||||
[AUDIO_SRC_SPDIF+1] = 7, /* EBU1 RcvData */
|
||||
#endif
|
||||
};
|
||||
|
||||
static const unsigned short pcm_dataincontrol[AUDIO_NUM_SOURCES+1] =
|
||||
{
|
||||
[AUDIO_SRC_PLAYBACK+1] = 0x0200, /* Reset PDIR2 data flow */
|
||||
[AUDIO_SRC_MIC+1] = 0xc020, /* Int. when 6 samples in FIFO,
|
||||
PDIR2 src = ebu1RcvData */
|
||||
[AUDIO_SRC_LINEIN+1] = 0xc020, /* Int. when 6 samples in FIFO,
|
||||
PDIR2 src = ebu1RcvData */
|
||||
#ifdef HAVE_FMRADIO_IN
|
||||
[AUDIO_SRC_FMRADIO+1] = 0xc020, /* Int. when 6 samples in FIFO,
|
||||
PDIR2 src = ebu1RcvData */
|
||||
#endif
|
||||
#ifdef HAVE_SPDIF_IN
|
||||
[AUDIO_SRC_SPDIF+1] = 0xc038, /* Int. when 6 samples in FIFO,
|
||||
PDIR2 src = ebu1RcvData */
|
||||
#endif
|
||||
};
|
||||
|
||||
static int pcm_rec_src = AUDIO_SRC_PLAYBACK;
|
||||
|
||||
void pcm_set_monitor(int monitor)
|
||||
{
|
||||
if ((unsigned)monitor >= AUDIO_NUM_SOURCES)
|
||||
monitor = AUDIO_SRC_PLAYBACK;
|
||||
pcm_monitor = monitor;
|
||||
} /* pcm_set_monitor */
|
||||
|
||||
void pcm_set_rec_source(int source)
|
||||
{
|
||||
if ((unsigned)source >= AUDIO_NUM_SOURCES)
|
||||
source = AUDIO_SRC_PLAYBACK;
|
||||
pcm_rec_src = source;
|
||||
} /* pcm_set_rec_source */
|
||||
|
||||
/* apply audio settings */
|
||||
void pcm_apply_settings(bool reset)
|
||||
{
|
||||
static int last_pcm_freq = HW_SAMPR_DEFAULT;
|
||||
#if 0
|
||||
static int last_pcm_monitor = AUDIO_SRC_PLAYBACK;
|
||||
#endif
|
||||
static int last_pcm_rec_src = AUDIO_SRC_PLAYBACK;
|
||||
|
||||
/* 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 != AUDIO_SRC_PLAYBACK))
|
||||
{
|
||||
/* Not playback - reset first */
|
||||
SET_IIS_CONFIG(IIS_RESET);
|
||||
reset = false;
|
||||
}
|
||||
|
||||
if (pcm_rec_src != last_pcm_rec_src)
|
||||
{
|
||||
last_pcm_rec_src = pcm_rec_src;
|
||||
DATAINCONTROL = pcm_dataincontrol[pcm_rec_src+1];
|
||||
}
|
||||
|
||||
if (pcm_freq != last_pcm_freq)
|
||||
{
|
||||
last_pcm_freq = pcm_freq;
|
||||
ac_set_frequency(freq_ent[FPARM_FSEL]);
|
||||
coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
|
||||
}
|
||||
|
||||
SET_IIS_CONFIG(IIS_DEFPARM | (reset ? IIS_RESET : 0));
|
||||
} /* pcm_apply_settings */
|
||||
|
||||
/** DMA **/
|
||||
|
||||
/****************************************************************************
|
||||
** Playback DMA transfer
|
||||
**/
|
||||
|
||||
/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
|
||||
void pcm_play_dma_start(const void *addr, size_t size)
|
||||
{
|
||||
logf("pcm_play_dma_start");
|
||||
|
||||
addr = (void *)((unsigned long)addr & ~3); /* Align data */
|
||||
size &= ~3; /* Size must be multiple of 4 */
|
||||
|
||||
pcm_playing = true;
|
||||
|
||||
/* Reset the audio FIFO */
|
||||
#ifdef HAVE_SPDIF_OUT
|
||||
EBU1CONFIG = IIS_RESET | EBU_DEFPARM;
|
||||
#endif
|
||||
|
||||
/* Set up DMA transfer */
|
||||
SAR0 = (unsigned long)addr; /* Source address */
|
||||
DAR0 = (unsigned long)&PDOR3; /* Destination address */
|
||||
BCR0 = size; /* Bytes to transfer */
|
||||
|
||||
/* Enable the FIFO and force one write to it */
|
||||
pcm_apply_settings(false);
|
||||
|
||||
/* Also send the audio to S/PDIF */
|
||||
#ifdef HAVE_SPDIF_OUT
|
||||
EBU1CONFIG = EBU_DEFPARM;
|
||||
#endif
|
||||
|
||||
DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA |
|
||||
DMA_SINC | DMA_SSIZE(3) | DMA_START;
|
||||
} /* pcm_play_dma_start */
|
||||
|
||||
/* Stops the DMA transfer and interrupt */
|
||||
void pcm_play_dma_stop(void)
|
||||
{
|
||||
logf("pcm_play_dma_stop");
|
||||
|
||||
pcm_playing = false;
|
||||
|
||||
DCR0 = 0;
|
||||
DSR0 = 1;
|
||||
|
||||
/* Reset the FIFO */
|
||||
pcm_apply_settings(false);
|
||||
|
||||
#ifdef HAVE_SPDIF_OUT
|
||||
EBU1CONFIG = IIS_RESET | EBU_DEFPARM;
|
||||
#endif
|
||||
} /* pcm_play_dma_stop */
|
||||
|
||||
void pcm_init(void)
|
||||
{
|
||||
logf("pcm_init");
|
||||
|
||||
pcm_playing = false;
|
||||
pcm_paused = false;
|
||||
pcm_callback_for_more = NULL;
|
||||
|
||||
MPARK = 0x81; /* PARK[1,0]=10 + BCR24BIT */
|
||||
DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
|
||||
DMAROUTE = (DMAROUTE & 0xffffff00) | DMA0_REQ_AUDIO_1;
|
||||
DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
|
||||
|
||||
/* Reset the audio FIFO */
|
||||
SET_IIS_CONFIG(IIS_RESET);
|
||||
|
||||
pcm_set_frequency(-1);
|
||||
pcm_set_monitor(-1);
|
||||
|
||||
/* Prevent pops (resets DAC to zero point) */
|
||||
SET_IIS_CONFIG(IIS_DEFPARM | IIS_RESET);
|
||||
|
||||
/* Initialize default register values. */
|
||||
ac_init();
|
||||
|
||||
#if defined(HAVE_UDA1380)
|
||||
/* Sleep a while so the power can stabilize (especially a long
|
||||
delay is needed for the line out connector). */
|
||||
sleep(HZ);
|
||||
/* Power on FSDAC and HP amp. */
|
||||
uda1380_enable_output(true);
|
||||
#elif defined(HAVE_TLV320)
|
||||
sleep(HZ/4);
|
||||
#endif
|
||||
|
||||
/* UDA1380: Unmute the master channel
|
||||
(DAC should be at zero point now). */
|
||||
ac_mute(false);
|
||||
|
||||
/* Call pcm_play_dma_stop to initialize everything. */
|
||||
pcm_play_dma_stop();
|
||||
|
||||
/* Enable interrupt at level 7, priority 0 */
|
||||
ICR6 = (7 << 2);
|
||||
IMR &= ~(1 << 14); /* bit 14 is DMA0 */
|
||||
} /* pcm_init */
|
||||
|
||||
size_t pcm_get_bytes_waiting(void)
|
||||
{
|
||||
return BCR0 & 0xffffff;
|
||||
} /* pcm_get_bytes_waiting */
|
||||
|
||||
/* DMA0 Interrupt is called when the DMA has finished transfering a chunk
|
||||
from the caller's buffer */
|
||||
void DMA0(void) __attribute__ ((interrupt_handler, section(".icode")));
|
||||
void DMA0(void)
|
||||
{
|
||||
int res = DSR0;
|
||||
|
||||
DSR0 = 1; /* Clear interrupt */
|
||||
DCR0 &= ~DMA_EEXT;
|
||||
|
||||
/* Stop on error */
|
||||
if ((res & 0x70) == 0)
|
||||
{
|
||||
pcm_more_callback_type get_more = pcm_callback_for_more;
|
||||
unsigned char *next_start;
|
||||
size_t next_size = 0;
|
||||
|
||||
if (get_more)
|
||||
get_more(&next_start, &next_size);
|
||||
|
||||
if (next_size > 0)
|
||||
{
|
||||
SAR0 = (unsigned long)next_start; /* Source address */
|
||||
BCR0 = next_size; /* Bytes to transfer */
|
||||
DCR0 |= DMA_EEXT;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Finished playing */
|
||||
#if 0
|
||||
/* int. logfs can trash the display */
|
||||
logf("DMA0 No Data:0x%04x", res);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logf("DMA Error:0x%04x", res);
|
||||
}
|
||||
|
||||
pcm_play_dma_stop();
|
||||
} /* DMA0 */
|
||||
|
||||
/****************************************************************************
|
||||
** Recording DMA transfer
|
||||
**/
|
||||
void pcm_rec_dma_start(const void *addr, size_t size)
|
||||
{
|
||||
logf("pcm_rec_dma_start");
|
||||
|
||||
addr = (void *)((unsigned long)addr & ~3); /* Align data */
|
||||
size &= ~3; /* Size must be multiple of 4 */
|
||||
|
||||
pcm_recording = true;
|
||||
|
||||
DAR1 = (unsigned long)addr; /* Destination address */
|
||||
SAR1 = (unsigned long)&PDIR2; /* Source address */
|
||||
BCR1 = size; /* Bytes to transfer */
|
||||
|
||||
rec_peak_addr = (unsigned long *)addr;
|
||||
|
||||
pcm_apply_settings(false);
|
||||
|
||||
/* Start the DMA transfer.. */
|
||||
#ifdef HAVE_SPDIF_IN
|
||||
INTERRUPTCLEAR = 0x03c00000;
|
||||
#endif
|
||||
|
||||
DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_DINC |
|
||||
DMA_DSIZE(3) | DMA_START;
|
||||
} /* pcm_dma_start */
|
||||
|
||||
void pcm_rec_dma_stop(void)
|
||||
{
|
||||
logf("pcm_rec_dma_stop");
|
||||
|
||||
pcm_recording = false;
|
||||
|
||||
DCR1 = 0;
|
||||
DSR1 = 1; /* Clear interrupt */
|
||||
} /* pcm_dma_stop */
|
||||
|
||||
void pcm_init_recording(void)
|
||||
{
|
||||
logf("pcm_init_recording");
|
||||
|
||||
pcm_recording = false;
|
||||
pcm_callback_more_ready = NULL;
|
||||
|
||||
AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */
|
||||
|
||||
DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */
|
||||
DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
|
||||
DMAROUTE = (DMAROUTE & 0xffff00ff) | DMA1_REQ_AUDIO_2;
|
||||
|
||||
#ifdef HAVE_SPDIF_IN
|
||||
/* PHASECONFIG setup: gain = 3*2^13, source = EBUIN */
|
||||
PHASECONFIG = (6 << 3) | (4 << 0);
|
||||
#endif
|
||||
|
||||
pcm_rec_dma_stop();
|
||||
|
||||
ICR7 = (7 << 2); /* Enable interrupt at level 7, priority 0 */
|
||||
IMR &= ~(1 << 15); /* bit 15 is DMA1 */
|
||||
} /* pcm_init_recording */
|
||||
|
||||
void pcm_close_recording(void)
|
||||
{
|
||||
logf("pcm_close_recording");
|
||||
|
||||
pcm_rec_dma_stop();
|
||||
|
||||
DMAROUTE &= 0xffff00ff;
|
||||
ICR7 = 0x00; /* Disable interrupt */
|
||||
IMR |= (1 << 15); /* bit 15 is DMA1 */
|
||||
} /* pcm_close_recording */
|
||||
|
||||
/* DMA1 Interrupt is called when the DMA has finished transfering a chunk
|
||||
into the caller's buffer */
|
||||
void DMA1(void) __attribute__ ((interrupt_handler, section(".icode")));
|
||||
void DMA1(void)
|
||||
{
|
||||
int res = DSR1;
|
||||
pcm_more_callback_type more_ready;
|
||||
unsigned char *next_start;
|
||||
ssize_t next_size = 0; /* passing <> 0 is indicates
|
||||
an error condition */
|
||||
|
||||
DSR1 = 1; /* Clear interrupt */
|
||||
DCR1 &= ~DMA_EEXT;
|
||||
|
||||
if (res & 0x70)
|
||||
{
|
||||
next_size = DMA_REC_ERROR_DMA;
|
||||
logf("DMA1 err: 0x%x", res);
|
||||
}
|
||||
#ifdef HAVE_SPDIF_IN
|
||||
else if (pcm_rec_src == AUDIO_SRC_SPDIF &&
|
||||
(INTERRUPTSTAT & 0x01c00000)) /* valnogood, symbolerr, parityerr */
|
||||
{
|
||||
INTERRUPTCLEAR = 0x03c00000;
|
||||
next_size = DMA_REC_ERROR_SPDIF;
|
||||
logf("spdif err");
|
||||
}
|
||||
#endif
|
||||
|
||||
more_ready = pcm_callback_more_ready;
|
||||
|
||||
if (more_ready)
|
||||
more_ready(&next_start, &next_size);
|
||||
|
||||
if (next_size > 0)
|
||||
{
|
||||
/* Start peaking at dest */
|
||||
rec_peak_addr = (unsigned long *)next_start;
|
||||
DAR1 = (unsigned long)next_start; /* Destination address */
|
||||
BCR1 = (unsigned long)next_size; /* Bytes to transfer */
|
||||
DCR1 |= DMA_EEXT;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
/* int. logfs can trash the display */
|
||||
logf("DMA1 No Data:0x%04x", res);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Finished recording */
|
||||
pcm_rec_dma_stop();
|
||||
} /* DMA1 */
|
||||
|
||||
void pcm_mute(bool mute)
|
||||
{
|
||||
ac_mute(mute);
|
||||
if (mute)
|
||||
sleep(HZ/16);
|
||||
} /* pcm_mute */
|
||||
|
||||
void pcm_play_pause_pause(void)
|
||||
{
|
||||
/* Disable DMA peripheral request. */
|
||||
DCR0 &= ~DMA_EEXT;
|
||||
pcm_apply_settings(true);
|
||||
#ifdef HAVE_SPDIF_OUT
|
||||
EBU1CONFIG = EBU_DEFPARM;
|
||||
#endif
|
||||
} /* pcm_play_pause_pause */
|
||||
|
||||
void pcm_play_pause_unpause(void)
|
||||
{
|
||||
/* Enable the FIFO and force one write to it */
|
||||
pcm_apply_settings(false);
|
||||
#ifdef HAVE_SPDIF_OUT
|
||||
EBU1CONFIG = EBU_DEFPARM;
|
||||
#endif
|
||||
DCR0 |= DMA_EEXT | DMA_START;
|
||||
} /* pcm_play_pause_unpause */
|
||||
|
||||
/**
|
||||
* Return playback peaks - Peaks ahead in the DMA buffer based upon the
|
||||
* calling period to attempt to compensate for
|
||||
* delay.
|
||||
*/
|
||||
void pcm_calculate_peaks(int *left, int *right)
|
||||
{
|
||||
unsigned long samples;
|
||||
unsigned long *addr, *end;
|
||||
long peak_p, peak_n;
|
||||
int level;
|
||||
|
||||
static unsigned long last_peak_tick = 0;
|
||||
static unsigned long frame_period = 0;
|
||||
|
||||
/* Throttled peak ahead based on calling period */
|
||||
unsigned long period = current_tick - last_peak_tick;
|
||||
|
||||
/* Keep reasonable limits on period */
|
||||
if (period < 1)
|
||||
period = 1;
|
||||
else if (period > HZ/5)
|
||||
period = HZ/5;
|
||||
|
||||
frame_period = (3*frame_period + period) >> 2;
|
||||
|
||||
last_peak_tick = current_tick;
|
||||
|
||||
if (!pcm_playing || pcm_paused)
|
||||
{
|
||||
play_peak_left = play_peak_right = 0;
|
||||
goto peak_done;
|
||||
}
|
||||
|
||||
/* prevent interrupt from setting up next transfer and
|
||||
be sure SAR0 and BCR0 refer to current transfer */
|
||||
level = set_irq_level(HIGHEST_IRQ_LEVEL);
|
||||
|
||||
addr = (long *)(SAR0 & ~3);
|
||||
samples = (BCR0 & 0xffffff) >> 2;
|
||||
|
||||
set_irq_level(level);
|
||||
|
||||
samples = MIN(frame_period*pcm_freq/HZ, samples);
|
||||
end = addr + samples;
|
||||
peak_p = peak_n = 0;
|
||||
|
||||
if (left && right)
|
||||
{
|
||||
if (samples > 0)
|
||||
{
|
||||
long peak_rp = 0, peak_rn = 0;
|
||||
|
||||
do
|
||||
{
|
||||
long value = *addr;
|
||||
long ch;
|
||||
|
||||
ch = value >> 16;
|
||||
if (ch > peak_p) peak_p = ch;
|
||||
else if (ch < peak_n) peak_n = ch;
|
||||
|
||||
ch = (short)value;
|
||||
if (ch > peak_rp) peak_rp = ch;
|
||||
else if (ch < peak_rn) peak_rn = ch;
|
||||
|
||||
addr += 4;
|
||||
}
|
||||
while (addr < end);
|
||||
|
||||
play_peak_left = MAX(peak_p, -peak_n);
|
||||
play_peak_right = MAX(peak_rp, -peak_rn);
|
||||
}
|
||||
}
|
||||
else if (left || right)
|
||||
{
|
||||
if (samples > 0)
|
||||
{
|
||||
if (left)
|
||||
{
|
||||
/* Put left channel in low word */
|
||||
addr = (long *)((short *)addr - 1);
|
||||
end = (long *)((short *)end - 1);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
long value = *(short *)addr;
|
||||
|
||||
if (value > peak_p) peak_p = value;
|
||||
else if (value < peak_n) peak_n = value;
|
||||
|
||||
addr += 4;
|
||||
}
|
||||
while (addr < end);
|
||||
|
||||
if (left)
|
||||
play_peak_left = MAX(peak_p, -peak_n);
|
||||
else
|
||||
play_peak_right = MAX(peak_p, -peak_n);
|
||||
}
|
||||
}
|
||||
|
||||
peak_done:
|
||||
if (left)
|
||||
*left = play_peak_left;
|
||||
|
||||
if (right)
|
||||
*right = play_peak_right;
|
||||
} /* pcm_calculate_peaks */
|
||||
|
||||
/**
|
||||
* Return recording peaks - Looks at every 4th sample from last peak up to
|
||||
* current write position.
|
||||
*/
|
||||
void pcm_calculate_rec_peaks(int *left, int *right)
|
||||
{
|
||||
unsigned long *pkaddr, *addr, *end;
|
||||
long peak_lp, peak_ln; /* L +,- */
|
||||
long peak_rp, peak_rn; /* R +,- */
|
||||
int level;
|
||||
|
||||
if (!pcm_recording)
|
||||
{
|
||||
rec_peak_left = rec_peak_right = 0;
|
||||
goto peak_done;
|
||||
}
|
||||
|
||||
/* read these atomically or each value may not refer to the
|
||||
same data transfer */
|
||||
level = set_irq_level(HIGHEST_IRQ_LEVEL);
|
||||
|
||||
pkaddr = rec_peak_addr;
|
||||
addr = pkaddr;
|
||||
end = (unsigned long *)(DAR1 & ~3);
|
||||
|
||||
set_irq_level(level);
|
||||
|
||||
if (addr < end)
|
||||
{
|
||||
peak_lp = peak_ln =
|
||||
peak_rp = peak_rn = 0;
|
||||
|
||||
/* peak one sample per line */
|
||||
do
|
||||
{
|
||||
long value = *addr;
|
||||
long ch;
|
||||
|
||||
ch = value >> 16;
|
||||
if (ch < peak_ln)
|
||||
peak_ln = ch;
|
||||
else if (ch > peak_lp)
|
||||
peak_lp = ch;
|
||||
|
||||
ch = (short)value;
|
||||
if (ch > peak_rp)
|
||||
peak_rp = ch;
|
||||
else if (ch < peak_rn)
|
||||
peak_rn = ch;
|
||||
|
||||
addr += 4;
|
||||
}
|
||||
while (addr < end);
|
||||
|
||||
/* only update rec_peak_addr if a DMA interrupt hasn't already
|
||||
done so */
|
||||
level = set_irq_level(HIGHEST_IRQ_LEVEL);
|
||||
|
||||
if (pkaddr == rec_peak_addr)
|
||||
rec_peak_addr = end;
|
||||
|
||||
set_irq_level(level);
|
||||
|
||||
/* save peaks */
|
||||
rec_peak_left = MAX(peak_lp, -peak_ln);
|
||||
rec_peak_right = MAX(peak_rp, -peak_rn);
|
||||
}
|
||||
|
||||
peak_done:
|
||||
if (left)
|
||||
*left = rec_peak_left;
|
||||
|
||||
if (right)
|
||||
*right = rec_peak_right;
|
||||
} /* pcm_calculate_rec_peaks */
|
||||
|
||||
/**
|
||||
* Select VINL & VINR source: 0=Line-in, 1=FM Radio
|
||||
*/
|
||||
/* All use GPIO */
|
||||
#if defined(IAUDIO_X5)
|
||||
#define REC_MUX_BIT (1 << 29)
|
||||
#define REC_MUX_SET_LINE() or_l(REC_MUX_BIT, &GPIO_OUT)
|
||||
#define REC_MUX_SET_FM() and_l(~REC_MUX_BIT, &GPIO_OUT)
|
||||
#else
|
||||
#if defined(IRIVER_H100_SERIES)
|
||||
#define REC_MUX_BIT (1 << 23)
|
||||
#elif defined(IRIVER_H300_SERIES)
|
||||
#define REC_MUX_BIT (1 << 30)
|
||||
#endif
|
||||
#define REC_MUX_SET_LINE() and_l(~REC_MUX_BIT, &GPIO_OUT)
|
||||
#define REC_MUX_SET_FM() or_l(REC_MUX_BIT, &GPIO_OUT)
|
||||
#endif
|
||||
|
||||
void pcm_rec_mux(int source)
|
||||
{
|
||||
if (source == 0)
|
||||
REC_MUX_SET_LINE(); /* Line In */
|
||||
else
|
||||
REC_MUX_SET_FM(); /* FM radio */
|
||||
|
||||
or_l(REC_MUX_BIT, &GPIO_ENABLE);
|
||||
or_l(REC_MUX_BIT, &GPIO_FUNCTION);
|
||||
} /* pcm_rec_mux */
|
Loading…
Reference in a new issue