FS#6096. Recording on PortalPlayer targets (H10, iPod Video, iPod 4g, iPod Color, iPod Nano).
* Fix failed compile of enc_config.c when HAVE_MPEG2_SAMPR is not defined. * Fix bug in AIFF encoder header creation on little endian targets. * Add recording screen keymaps for H10 and iPod. * Move pcm_playback PP specific code to target tree. * Add recording code to wmcodec drivers. * Add pcm_record code. Some problems still remain: * Playback doesn't work after recording until Rockbox is restarted. * Gain control not implemented. * Only 16-bit/44KHz for now. The hardware should be capable of up to 24-bit/96KHz. * Line-in recording not tested on H10. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11794 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
440353a9aa
commit
df0dc2262e
|
@ -59,7 +59,7 @@ struct aiff_header aiff_header =
|
|||
H_TO_BE32(18), /* comm_size */
|
||||
0, /* num_channels (*) */
|
||||
0, /* num_sample_frames (*) */
|
||||
H_TO_BE32(PCM_DEPTH_BITS), /* sample_size */
|
||||
H_TO_BE16(PCM_DEPTH_BITS), /* sample_size */
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* sample_rate (*) */
|
||||
{ 'S', 'S', 'N', 'D' }, /* ssnd_id */
|
||||
0, /* ssnd_size (*) */
|
||||
|
|
|
@ -159,9 +159,9 @@ static bool mp3_enc_bitrate(struct encoder_config *cfg)
|
|||
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)),
|
||||
| (MPEG2_BITR_CAPS & ~(MP3_BITR_CAP_144 | MP3_BITR_CAP_8))
|
||||
#endif
|
||||
rate_list);
|
||||
, rate_list);
|
||||
|
||||
int index = round_value_to_list32(cfg->mp3_enc.bitrate, rate_list,
|
||||
n_rates, false);
|
||||
|
|
|
@ -298,6 +298,12 @@ static const struct button_mapping button_context_bmark[] = {
|
|||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD),
|
||||
}; /* button_context_bmark */
|
||||
|
||||
const struct button_mapping button_context_recscreen[] = {
|
||||
{ ACTION_REC_PAUSE, BUTTON_PLAY, BUTTON_NONE },
|
||||
|
||||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS)
|
||||
}; /* button_context_recscreen */
|
||||
|
||||
static const struct button_mapping* get_context_mapping_remote( int context )
|
||||
{
|
||||
context ^= CONTEXT_REMOTE;
|
||||
|
@ -325,6 +331,8 @@ static const struct button_mapping* get_context_mapping_remote( int context )
|
|||
return remote_button_context_quickscreen;
|
||||
case CONTEXT_PITCHSCREEN:
|
||||
return remote_button_context_pitchscreen;
|
||||
case CONTEXT_RECSCREEN:
|
||||
return button_context_recscreen;
|
||||
|
||||
default:
|
||||
return remote_button_context_standard;
|
||||
|
@ -374,6 +382,8 @@ const struct button_mapping* get_context_mapping(int context)
|
|||
return button_context_pitchscreen;
|
||||
case CONTEXT_KEYBOARD:
|
||||
return button_context_keyboard;
|
||||
case CONTEXT_RECSCREEN:
|
||||
return button_context_recscreen;
|
||||
|
||||
default:
|
||||
return button_context_standard;
|
||||
|
|
|
@ -166,6 +166,12 @@ static const struct button_mapping button_context_keyboard[] = {
|
|||
LAST_ITEM_IN_LIST
|
||||
}; /* button_context_keyboard */
|
||||
|
||||
const struct button_mapping button_context_recscreen[] = {
|
||||
{ ACTION_REC_PAUSE, BUTTON_PLAY, BUTTON_NONE },
|
||||
|
||||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS)
|
||||
}; /* button_context_recscreen */
|
||||
|
||||
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
|
||||
const struct button_mapping* get_context_mapping(int context)
|
||||
{
|
||||
|
@ -202,6 +208,8 @@ const struct button_mapping* get_context_mapping(int context)
|
|||
return button_context_pitchscreen;
|
||||
case CONTEXT_KEYBOARD:
|
||||
return button_context_keyboard;
|
||||
case CONTEXT_RECSCREEN:
|
||||
return button_context_recscreen;
|
||||
default:
|
||||
return button_context_standard;
|
||||
}
|
||||
|
|
|
@ -78,6 +78,9 @@
|
|||
#endif
|
||||
#if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) && !defined(SIMULATOR)
|
||||
#include "pcm_record.h"
|
||||
#endif
|
||||
|
||||
#ifdef BUTTON_REC
|
||||
#define SETTINGS_RESET BUTTON_REC
|
||||
#endif
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ const char rec_base_directory[] = REC_BASE_DIR;
|
|||
#include "eq_menu.h"
|
||||
#endif
|
||||
|
||||
#define CONFIG_BLOCK_VERSION 56
|
||||
#define CONFIG_BLOCK_VERSION 57
|
||||
#define CONFIG_BLOCK_SIZE 512
|
||||
#define RTC_BLOCK_SIZE 44
|
||||
|
||||
|
@ -521,13 +521,26 @@ static const struct bit_entry hd_bits[] =
|
|||
#if CONFIG_CODEC == SWCODEC
|
||||
#ifdef HAVE_UDA1380
|
||||
{8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
|
||||
#endif
|
||||
#ifdef HAVE_TLV320
|
||||
/* TLV320 only has no mic boost or 20db mic boost */
|
||||
{1, S_O(rec_mic_gain), 0 /* 0 dB */, "rec mic gain", NULL }, /* 0db or 20db */
|
||||
#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 */
|
||||
#elif defined(HAVE_TLV320)
|
||||
/* TLV320 only has no mic boost or 20db mic boost */
|
||||
{1, S_O(rec_mic_gain), 0 /* 0 dB */, "rec mic gain", NULL }, /* 0db or 20db */
|
||||
{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 */
|
||||
#elif defined(HAVE_WM8975)
|
||||
{8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
|
||||
{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 */
|
||||
#elif defined(HAVE_WM8758)
|
||||
{8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
|
||||
{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 */
|
||||
#elif defined(HAVE_WM8731)
|
||||
{8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
|
||||
{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 */
|
||||
#endif
|
||||
{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,
|
||||
|
|
|
@ -262,6 +262,8 @@ drivers/i2c-pnx0101.c
|
|||
/* no i2c driver yet */
|
||||
#endif
|
||||
#if defined(CPU_PP)
|
||||
target/arm/pcm-pp.c
|
||||
target/arm/audio-pp.c
|
||||
target/arm/crt0-pp.S
|
||||
#elif defined(CPU_ARM)
|
||||
target/arm/crt0.S
|
||||
|
|
|
@ -220,12 +220,73 @@ void audiohw_set_sample_rate(int sampling_control)
|
|||
|
||||
void audiohw_enable_recording(bool source_mic)
|
||||
{
|
||||
(void)source_mic;
|
||||
static int line_level = 0x17;
|
||||
static int mic_boost = true;
|
||||
codec_set_active(0x0);
|
||||
|
||||
/* set BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0
|
||||
* LRP=0 IWL=00(16 bit) FORMAT=10(I2S format) */
|
||||
wmcodec_write(AINTFCE, 0x42);
|
||||
|
||||
wmcodec_write(LOUTVOL, 0x0); /* headphone mute left */
|
||||
wmcodec_write(ROUTVOL, 0x0); /* headphone mute right */
|
||||
|
||||
|
||||
if(source_mic){
|
||||
wmcodec_write(LINVOL, 0x80); /* line in mute left */
|
||||
wmcodec_write(RINVOL, 0x80); /* line in mute right */
|
||||
|
||||
|
||||
if (mic_boost) {
|
||||
wmcodec_write(AAPCTRL, 0x5); /* INSEL=mic, MIC_BOOST=enable */
|
||||
} else {
|
||||
wmcodec_write(AAPCTRL, 0x4); /* INSEL=mic */
|
||||
}
|
||||
} else {
|
||||
if (line_level == 0) {
|
||||
wmcodec_write(LINVOL, 0x80);
|
||||
wmcodec_write(RINVOL, 0x80);
|
||||
} else {
|
||||
wmcodec_write(LINVOL, line_level);
|
||||
wmcodec_write(RINVOL, line_level);
|
||||
}
|
||||
wmcodec_write(AAPCTRL, 0xa); /* BY PASS, mute mic, INSEL=line in */
|
||||
}
|
||||
|
||||
/* disable ADC high pass filter, mute dac */
|
||||
wmcodec_write(DACCTRL, 0x9);
|
||||
|
||||
/* power on (PWR_OFF=0) */
|
||||
if(source_mic){
|
||||
/* CLKOUTPD OSCPD OUTPD DACPD LINEINPD */
|
||||
wmcodec_write(PWRMGMT, 0x79);
|
||||
} else {
|
||||
wmcodec_write(PWRMGMT, 0x7a); /* MICPD */
|
||||
}
|
||||
|
||||
codec_set_active(0x1);
|
||||
}
|
||||
|
||||
void audiohw_disable_recording(void)
|
||||
{
|
||||
|
||||
/* set DACMU=1 DEEMPH=0 */
|
||||
wmcodec_write(DACCTRL, 0x8);
|
||||
|
||||
/* ACTIVE=0 */
|
||||
codec_set_active(0x0);
|
||||
|
||||
/* line in mute left & right*/
|
||||
wmcodec_write(LINVOL, 0x80);
|
||||
wmcodec_write(RINVOL, 0x80);
|
||||
|
||||
/* set DACSEL=0, MUTEMIC=1 */
|
||||
wmcodec_write(AAPCTRL, 0x2);
|
||||
|
||||
/* set POWEROFF=0 OUTPD=0 DACPD=1 */
|
||||
wmcodec_write(PWRMGMT, 0x6f);
|
||||
|
||||
/* set POWEROFF=1 OUTPD=1 DACPD=1 */
|
||||
wmcodec_write(PWRMGMT, 0xff);
|
||||
}
|
||||
|
||||
void audiohw_set_recvol(int left, int right, int type)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Driver for WM8758 audio codec
|
||||
* Driver for WM8758 audio codec - based on datasheet for WM8983
|
||||
*
|
||||
* Based on code from the ipodlinux project - http://ipodlinux.org/
|
||||
* Adapted for Rockbox in December 2005
|
||||
|
@ -142,30 +142,11 @@ int audiohw_set_mixer_vol(int channel1, int channel2)
|
|||
void audiohw_set_bass(int value)
|
||||
{
|
||||
(void)value;
|
||||
#if 0
|
||||
/* Not yet implemented - this is the wm8975 code*/
|
||||
int regvalues[]={11, 10, 10, 9, 8, 8, 0xf , 6, 6, 5, 4, 4, 3, 2, 1, 0};
|
||||
|
||||
if ((value >= -6) && (value <= 9)) {
|
||||
/* We use linear bass control with 130Hz cutoff */
|
||||
wmcodec_write(BASSCTRL, regvalues[value+6]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void audiohw_set_treble(int value)
|
||||
{
|
||||
(void)value;
|
||||
#if 0
|
||||
/* Not yet implemented - this is the wm8975 code*/
|
||||
int regvalues[]={11, 10, 10, 9, 8, 8, 0xf , 6, 6, 5, 4, 4, 3, 2, 1, 0};
|
||||
|
||||
if ((value >= -6) && (value <= 9)) {
|
||||
/* We use a 8Khz cutoff */
|
||||
wmcodec_write(TREBCTRL, regvalues[value+6]);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int audiohw_mute(int mute)
|
||||
|
@ -224,11 +205,60 @@ void audiohw_set_sample_rate(int sampling_control)
|
|||
|
||||
void audiohw_enable_recording(bool source_mic)
|
||||
{
|
||||
(void)source_mic;
|
||||
(void)source_mic; /* We only have a line-in (I think) */
|
||||
|
||||
/* reset the I2S controller into known state */
|
||||
i2s_reset();
|
||||
|
||||
wmcodec_write(RESET, 0x1ff); /*Reset*/
|
||||
|
||||
wmcodec_write(PWRMGMT1, 0x2b);
|
||||
wmcodec_write(PWRMGMT2, 0x18f); /* Enable ADC - 0x0c enables left/right PGA input, and 0x03 turns on power to the ADCs */
|
||||
wmcodec_write(PWRMGMT3, 0x6f);
|
||||
|
||||
wmcodec_write(AINTFCE, 0x10);
|
||||
wmcodec_write(CLKCTRL, 0x49);
|
||||
|
||||
wmcodec_write(OUTCTRL, 1);
|
||||
|
||||
/* The iPod can handle multiple frequencies, but fix at 44.1KHz
|
||||
for now */
|
||||
wmcodec_set_sample_rate(WM8758_44100HZ);
|
||||
|
||||
wmcodec_write(INCTRL,0x44); /* Connect L2 and R2 inputs */
|
||||
|
||||
/* Set L2/R2_2BOOSTVOL to 0db (bits 4-6) */
|
||||
/* 000 = disabled
|
||||
001 = -12dB
|
||||
010 = -9dB
|
||||
011 = -6dB
|
||||
100 = -3dB
|
||||
101 = 0dB
|
||||
110 = 3dB
|
||||
111 = 6dB
|
||||
*/
|
||||
wmcodec_write(LADCBOOST,0x50);
|
||||
wmcodec_write(RADCBOOST,0x50);
|
||||
|
||||
/* Set L/R input PGA Volume to 0db */
|
||||
// wm8758_write(LINPGAVOL,0x3f);
|
||||
// wm8758_write(RINPGAVOL,0x13f);
|
||||
|
||||
/* Enable monitoring */
|
||||
wmcodec_write(LOUTMIX,0x17); /* Enable output mixer - BYPL2LMIX @ 0db*/
|
||||
wmcodec_write(ROUTMIX,0x17); /* Enable output mixer - BYPR2RMIX @ 0db*/
|
||||
|
||||
wmcodec_mute(0);
|
||||
}
|
||||
|
||||
void audiohw_disable_recording(void) {
|
||||
wmcodec_mute(1);
|
||||
|
||||
wmcodec_write(PWRMGMT3, 0x0);
|
||||
|
||||
wmcodec_write(PWRMGMT1, 0x0);
|
||||
|
||||
wmcodec_write(PWRMGMT2, 0x40);
|
||||
}
|
||||
|
||||
void audiohw_set_recvol(int left, int right, int type) {
|
||||
|
|
|
@ -224,13 +224,80 @@ void audiohw_set_sample_rate(int sampling_control) {
|
|||
|
||||
}
|
||||
|
||||
void audiohw_enable_recording(bool source_mic) {
|
||||
void audiohw_enable_recording(bool source_mic)
|
||||
{
|
||||
(void)source_mic;
|
||||
|
||||
(void)source_mic;
|
||||
/* reset the I2S controller into known state */
|
||||
i2s_reset();
|
||||
|
||||
/*
|
||||
* 1. Switch on power supplies.
|
||||
* By default the WM8750L is in Standby Mode, the DAC is
|
||||
* digitally muted and the Audio Interface, Line outputs
|
||||
* and Headphone outputs are all OFF (DACMU = 1 Power
|
||||
* Management registers 1 and 2 are all zeros).
|
||||
*/
|
||||
wmcodec_write(0x0f, 0x1ff);
|
||||
wmcodec_write(0x0f, 0x000);
|
||||
|
||||
/* 2. Enable Vmid and VREF. */
|
||||
wmcodec_write(0x19, 0xc0); /*Pwr Mgmt(1)*/
|
||||
|
||||
/* 3. Enable ADCs as required. */
|
||||
wmcodec_write(0x19, 0xcc); /*Pwr Mgmt(1)*/
|
||||
wmcodec_write(0x1a, 0x180); /*Pwr Mgmt(2)*/
|
||||
|
||||
/* 4. Enable line and / or headphone output buffers as required. */
|
||||
wmcodec_write(0x19, 0xfc); /*Pwr Mgmt(1)*/
|
||||
|
||||
/* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */
|
||||
/* IWL=00(16 bit) FORMAT=10(I2S format) */
|
||||
wmcodec_write(0x07, 0x42);
|
||||
|
||||
/* The iPod can handle multiple frequencies, but fix at 44.1KHz for now */
|
||||
wmcodec_set_sample_rate(WM8975_44100HZ);
|
||||
|
||||
/* unmute inputs */
|
||||
wmcodec_write(0x00, 0x17); /* LINVOL (def 0dB) */
|
||||
wmcodec_write(0x01, 0x117); /* RINVOL (def 0dB) */
|
||||
|
||||
wmcodec_write(0x15, 0x1d7); /* LADCVOL max vol x was ff */
|
||||
wmcodec_write(0x16, 0x1d7); /* RADCVOL max vol x was ff */
|
||||
|
||||
if (source_mic) {
|
||||
/* VSEL=10(def) DATSEL=10 (use right ADC only) */
|
||||
wmcodec_write(0x17, 0xc8); /* Additional control(1) */
|
||||
|
||||
/* VROI=1 (sets output resistance to 40kohms) */
|
||||
wmcodec_write(0x1b, 0x40); /* Additional control(3) */
|
||||
|
||||
/* LINSEL=1 (LINPUT2) LMICBOOST=10 (20dB boost) */
|
||||
wmcodec_write(0x20, 0x60); /* ADCL signal path */
|
||||
wmcodec_write(0x21, 0x60); /* ADCR signal path */
|
||||
} else {
|
||||
/* VSEL=10(def) DATSEL=00 (left->left, right->right) */
|
||||
wmcodec_write(0x17, 0xc0); /* Additional control(1) */
|
||||
|
||||
/* VROI=1 (sets output resistance to 40kohms) */
|
||||
wmcodec_write(0x1b, 0x40); /* Additional control(3) */
|
||||
|
||||
/* LINSEL=0 (LINPUT1) LMICBOOST=00 (bypass boost) */
|
||||
wmcodec_write(0x20, 0x00); /* ADCL signal path */
|
||||
/* RINSEL=0 (RINPUT1) RMICBOOST=00 (bypass boost) */
|
||||
wmcodec_write(0x21, 0x00); /* ADCR signal path */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void audiohw_disable_recording(void) {
|
||||
/* 1. Set DACMU = 1 to soft-mute the audio DACs. */
|
||||
wmcodec_write(0x05, 0x8);
|
||||
|
||||
/* 2. Disable all output buffers. */
|
||||
wmcodec_write(0x1a, 0x0); /*Pwr Mgmt(2)*/
|
||||
|
||||
/* 3. Switch off the power supplies. */
|
||||
wmcodec_write(0x19, 0x0); /*Pwr Mgmt(1)*/
|
||||
}
|
||||
|
||||
void audiohw_set_recvol(int left, int right, int type) {
|
||||
|
|
|
@ -8,7 +8,13 @@
|
|||
#define MODEL_NUMBER 13
|
||||
|
||||
/* define this if you have recording possibility */
|
||||
/*#define HAVE_RECORDING 1*/ /* TODO: add support for this */
|
||||
#define HAVE_RECORDING 1
|
||||
|
||||
/* define the bitmask of hardware sample rates */
|
||||
#define HW_SAMPR_CAPS (SAMPR_CAP_44)
|
||||
|
||||
/* define the bitmask of recording sample rates */
|
||||
#define REC_SAMPR_CAPS (SAMPR_CAP_44)
|
||||
|
||||
/* define this if you have a bitmap LCD display */
|
||||
#define HAVE_LCD_BITMAP 1
|
||||
|
|
|
@ -8,7 +8,13 @@
|
|||
#define MODEL_NUMBER 14
|
||||
|
||||
/* define this if you have recording possibility */
|
||||
/*#define HAVE_RECORDING 1*/ /* TODO: add support for this */
|
||||
#define HAVE_RECORDING 1
|
||||
|
||||
/* define the bitmask of hardware sample rates */
|
||||
#define HW_SAMPR_CAPS (SAMPR_CAP_44)
|
||||
|
||||
/* define the bitmask of recording sample rates */
|
||||
#define REC_SAMPR_CAPS (SAMPR_CAP_44)
|
||||
|
||||
/* define this if you have a bitmap LCD display */
|
||||
#define HAVE_LCD_BITMAP 1
|
||||
|
|
|
@ -9,7 +9,13 @@
|
|||
#define MODEL_NUMBER 8
|
||||
|
||||
/* define this if you have recording possibility */
|
||||
/*#define HAVE_RECORDING 1*/
|
||||
#define HAVE_RECORDING 1
|
||||
|
||||
/* define the bitmask of hardware sample rates */
|
||||
#define HW_SAMPR_CAPS (SAMPR_CAP_44)
|
||||
|
||||
/* define the bitmask of recording sample rates */
|
||||
#define REC_SAMPR_CAPS (SAMPR_CAP_44)
|
||||
|
||||
/* define this if you have a bitmap LCD display */
|
||||
#define HAVE_LCD_BITMAP 1
|
||||
|
|
|
@ -9,7 +9,13 @@
|
|||
#define MODEL_NUMBER 3
|
||||
|
||||
/* define this if you have recording possibility */
|
||||
/*#define HAVE_RECORDING 1*/
|
||||
#define HAVE_RECORDING 1
|
||||
|
||||
/* define the bitmask of hardware sample rates */
|
||||
#define HW_SAMPR_CAPS (SAMPR_CAP_44)
|
||||
|
||||
/* define the bitmask of recording sample rates */
|
||||
#define REC_SAMPR_CAPS (SAMPR_CAP_44)
|
||||
|
||||
/* define this if you have a bitmap LCD display */
|
||||
#define HAVE_LCD_BITMAP 1
|
||||
|
|
|
@ -9,7 +9,13 @@
|
|||
#define MODEL_NUMBER 4
|
||||
|
||||
/* define this if you have recording possibility */
|
||||
/*#define HAVE_RECORDING 1*/
|
||||
#define HAVE_RECORDING 1
|
||||
|
||||
/* define the bitmask of hardware sample rates */
|
||||
#define HW_SAMPR_CAPS (SAMPR_CAP_44)
|
||||
|
||||
/* define the bitmask of recording sample rates */
|
||||
#define REC_SAMPR_CAPS (SAMPR_CAP_44)
|
||||
|
||||
/* define this if you have a bitmap LCD display */
|
||||
#define HAVE_LCD_BITMAP 1
|
||||
|
|
|
@ -9,7 +9,13 @@
|
|||
#define MODEL_NUMBER 5
|
||||
|
||||
/* define this if you have recording possibility */
|
||||
/*#define HAVE_RECORDING 1*/
|
||||
#define HAVE_RECORDING 1
|
||||
|
||||
/* define the bitmask of hardware sample rates */
|
||||
#define HW_SAMPR_CAPS (SAMPR_CAP_44)
|
||||
|
||||
/* define the bitmask of recording sample rates */
|
||||
#define REC_SAMPR_CAPS (SAMPR_CAP_44)
|
||||
|
||||
/* define this if you have a bitmap LCD display */
|
||||
#define HAVE_LCD_BITMAP 1
|
||||
|
|
|
@ -48,7 +48,8 @@ enum {
|
|||
SOUND_MDB_ENABLE,
|
||||
SOUND_SUPERBASS,
|
||||
#endif
|
||||
#if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) || defined(HAVE_TLV320)
|
||||
#if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) || defined(HAVE_TLV320)\
|
||||
|| defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8731)
|
||||
SOUND_LEFT_GAIN,
|
||||
SOUND_RIGHT_GAIN,
|
||||
SOUND_MIC_GAIN,
|
||||
|
|
|
@ -314,8 +314,11 @@ static inline int set_irq_level(int level)
|
|||
return (cpsr >> 7) & 1;
|
||||
}
|
||||
|
||||
static inline void enable_fiq(void)
|
||||
static inline void enable_fiq(void(*fiq_handler)(void))
|
||||
{
|
||||
/* Install the FIQ handler */
|
||||
*((unsigned int*)(15*4)) = (unsigned int)fiq_handler;
|
||||
|
||||
/* Clear FIQ disable bit */
|
||||
asm volatile (
|
||||
"mrs r0, cpsr \n"\
|
||||
|
|
|
@ -49,6 +49,7 @@ extern void audiohw_set_monitor(int enable);
|
|||
#define RINVOL 0x01
|
||||
#define LOUTVOL 0x02
|
||||
#define ROUTVOL 0x03
|
||||
#define AAPCTRL 0x04 /* Analog audio path control */
|
||||
#define DACCTRL 0x05
|
||||
#define PWRMGMT 0x06
|
||||
#define AINTFCE 0x07
|
||||
|
|
|
@ -55,6 +55,11 @@ extern void audiohw_set_equalizer_band(int band, int freq, int bw, int gain);
|
|||
#define CLKCTRL 0x06
|
||||
#define SRATECTRL 0x07
|
||||
#define DACCTRL 0x0a
|
||||
#define INCTRL 0x2c
|
||||
#define LINPGAVOL 0x2d
|
||||
#define RINPGAVOL 0x2e
|
||||
#define LADCBOOST 0x2f
|
||||
#define RADCBOOST 0x30
|
||||
#define OUTCTRL 0x31
|
||||
#define LOUTMIX 0x32
|
||||
#define ROUTMIX 0x33
|
||||
|
|
|
@ -98,326 +98,6 @@ size_t pcm_get_bytes_waiting(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
|
||||
|| defined(HAVE_WM8731) || defined(HAVE_WM8721) \
|
||||
|| defined(HAVE_PP5024_CODEC)
|
||||
|
||||
/* We need to unify this code with the uda1380 code as much as possible, but
|
||||
we will keep it separate during early development.
|
||||
*/
|
||||
|
||||
#if CONFIG_CPU == PP5020
|
||||
#define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x3f0000) >> 16)
|
||||
#elif CONFIG_CPU == PP5002
|
||||
#define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x7800000) >> 23)
|
||||
#elif CONFIG_CPU == PP5024
|
||||
#define FIFO_FREE_COUNT 4 /* TODO: make this sensible */
|
||||
#endif
|
||||
|
||||
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. */
|
||||
unsigned short* p IBSS_ATTR;
|
||||
size_t p_size IBSS_ATTR;
|
||||
|
||||
void pcm_play_dma_start(const void *addr, size_t size)
|
||||
{
|
||||
p=(unsigned short*)addr;
|
||||
p_size=size;
|
||||
|
||||
pcm_playing = true;
|
||||
|
||||
#if CONFIG_CPU == PP5020
|
||||
/* setup I2S interrupt for FIQ */
|
||||
outl(inl(0x6000402c) | I2S_MASK, 0x6000402c);
|
||||
outl(I2S_MASK, 0x60004024);
|
||||
#elif CONFIG_CPU == PP5024
|
||||
#else
|
||||
/* setup I2S interrupt for FIQ */
|
||||
outl(inl(0xcf00102c) | DMA_OUT_MASK, 0xcf00102c);
|
||||
outl(DMA_OUT_MASK, 0xcf001024);
|
||||
#endif
|
||||
|
||||
/* Clear the FIQ disable bit in cpsr_c */
|
||||
enable_fiq();
|
||||
|
||||
/* Enable playback FIFO */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x20000000;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISCONFIG |= 0x4;
|
||||
#endif
|
||||
|
||||
/* Fill the FIFO - we assume there are enough bytes in the pcm buffer to
|
||||
fill the 32-byte FIFO. */
|
||||
while (p_size > 0) {
|
||||
if (FIFO_FREE_COUNT < 2) {
|
||||
/* Enable interrupt */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x2;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISFIFO_CFG |= (1<<9);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
p_size-=4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Stops the DMA transfer and interrupt */
|
||||
void pcm_play_dma_stop(void)
|
||||
{
|
||||
pcm_playing = false;
|
||||
|
||||
#if CONFIG_CPU == PP5020
|
||||
|
||||
/* Disable playback FIFO */
|
||||
IISCONFIG &= ~0x20000000;
|
||||
|
||||
/* Disable the interrupt */
|
||||
IISCONFIG &= ~0x2;
|
||||
|
||||
#elif CONFIG_CPU == PP5002
|
||||
|
||||
/* Disable playback FIFO */
|
||||
IISCONFIG &= ~0x4;
|
||||
|
||||
/* Disable the interrupt */
|
||||
IISFIFO_CFG &= ~(1<<9);
|
||||
#endif
|
||||
|
||||
disable_fiq();
|
||||
}
|
||||
|
||||
void pcm_play_pause_pause(void)
|
||||
{
|
||||
#if CONFIG_CPU == PP5020
|
||||
/* Disable the interrupt */
|
||||
IISCONFIG &= ~0x2;
|
||||
/* Disable playback FIFO */
|
||||
IISCONFIG &= ~0x20000000;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
/* Disable the interrupt */
|
||||
IISFIFO_CFG &= ~(1<<9);
|
||||
/* Disable playback FIFO */
|
||||
IISCONFIG &= ~0x4;
|
||||
#endif
|
||||
disable_fiq();
|
||||
}
|
||||
|
||||
void pcm_play_pause_unpause(void)
|
||||
{
|
||||
/* Enable the FIFO and fill it */
|
||||
|
||||
enable_fiq();
|
||||
|
||||
/* Enable playback FIFO */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x20000000;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISCONFIG |= 0x4;
|
||||
#endif
|
||||
|
||||
/* Fill the FIFO - we assume there are enough bytes in the
|
||||
pcm buffer to fill the 32-byte FIFO. */
|
||||
while (p_size > 0) {
|
||||
if (FIFO_FREE_COUNT < 2) {
|
||||
/* Enable interrupt */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x2;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISFIFO_CFG |= (1<<9);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
p_size-=4;
|
||||
}
|
||||
}
|
||||
|
||||
void pcm_set_frequency(unsigned int frequency)
|
||||
{
|
||||
(void)frequency;
|
||||
pcm_freq = HW_SAMPR_DEFAULT;
|
||||
}
|
||||
|
||||
size_t pcm_get_bytes_waiting(void)
|
||||
{
|
||||
return p_size;
|
||||
}
|
||||
|
||||
/* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode
|
||||
has registers r8-r14 banked, and so does not need to be saved. This routine
|
||||
uses only these registers, and so will never touch the stack unless it
|
||||
actually needs to do so when calling pcm_callback_for_more. C version is
|
||||
still included below for reference.
|
||||
*/
|
||||
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002
|
||||
void fiq(void) ICODE_ATTR __attribute__((naked));
|
||||
void fiq(void)
|
||||
{
|
||||
/* r12 contains IISCONFIG address (set in crt0.S to minimise code in actual
|
||||
* FIQ handler. r11 contains address of p (also set in crt0.S). Most other
|
||||
* addresses we need are generated by using offsets with these two.
|
||||
* r12 + 0x40 is IISFIFO_WR, and r12 + 0x0c is IISFIFO_CFG.
|
||||
* r8 and r9 contains local copies of p_size and p respectively.
|
||||
* r10 is a working register.
|
||||
*/
|
||||
asm volatile (
|
||||
#if CONFIG_CPU == PP5002
|
||||
"ldr r10, =0xcf001040 \n\t" /* Some magic from iPodLinux */
|
||||
"ldr r10, [r10] \n\t"
|
||||
"ldr r10, [r12, #0x1c]\n\t"
|
||||
"bic r10, r10, #0x200 \n\t" /* clear interrupt */
|
||||
"str r10, [r12, #0x1c]\n\t"
|
||||
#else
|
||||
"ldr r10, [r12] \n\t"
|
||||
"bic r10, r10, #0x2 \n\t" /* clear interrupt */
|
||||
"str r10, [r12] \n\t"
|
||||
#endif
|
||||
"ldr r8, [r11, #4] \n\t" /* r8 = p_size */
|
||||
"ldr r9, [r11] \n\t" /* r9 = p */
|
||||
".loop: \n\t"
|
||||
"cmp r8, #0 \n\t" /* is p_size 0? */
|
||||
"beq .more_data \n\t" /* if so, ask pcmbuf for more data */
|
||||
".fifo_loop: \n\t"
|
||||
#if CONFIG_CPU == PP5002
|
||||
"ldr r10, [r12, #0x1c]\n\t" /* read IISFIFO_CFG to check FIFO status */
|
||||
"and r10, r10, #0x7800000\n\t"
|
||||
"cmp r10, #0x800000 \n\t"
|
||||
#else
|
||||
"ldr r10, [r12, #0x0c]\n\t" /* read IISFIFO_CFG to check FIFO status */
|
||||
"and r10, r10, #0x3f0000\n\t"
|
||||
"cmp r10, #0x10000 \n\t"
|
||||
#endif
|
||||
"bls .fifo_full \n\t" /* FIFO full, exit */
|
||||
"ldr r10, [r9], #4 \n\t" /* load two samples */
|
||||
"mov r10, r10, ror #16\n\t" /* put left sample at the top bits */
|
||||
"str r10, [r12, #0x40]\n\t" /* write top sample, lower sample ignored */
|
||||
"mov r10, r10, lsl #16\n\t" /* shift lower sample up */
|
||||
"str r10, [r12, #0x40]\n\t" /* then write it */
|
||||
"subs r8, r8, #4 \n\t" /* check if we have more samples */
|
||||
"bne .fifo_loop \n\t" /* yes, continue */
|
||||
".more_data: \n\t"
|
||||
"stmdb sp!, { r0-r3, r12, lr}\n\t" /* stack scratch regs and lr */
|
||||
"mov r0, r11 \n\t" /* r0 = &p */
|
||||
"add r1, r11, #4 \n\t" /* r1 = &p_size */
|
||||
"str r9, [r0] \n\t" /* save internal copies of variables back */
|
||||
"str r8, [r1] \n\t"
|
||||
"ldr r2, =pcm_callback_for_more\n\t"
|
||||
"ldr r2, [r2] \n\t" /* get callback address */
|
||||
"cmp r2, #0 \n\t" /* check for null pointer */
|
||||
"movne lr, pc \n\t" /* call pcm_callback_for_more */
|
||||
"bxne r2 \n\t"
|
||||
"ldmia sp!, { r0-r3, r12, lr}\n\t"
|
||||
"ldr r8, [r11, #4] \n\t" /* reload p_size and p */
|
||||
"ldr r9, [r11] \n\t"
|
||||
"cmp r8, #0 \n\t" /* did we actually get more data? */
|
||||
"bne .loop \n\t" /* yes, continue to try feeding FIFO */
|
||||
".dma_stop: \n\t" /* no more data, do dma_stop() and exit */
|
||||
"ldr r10, =pcm_playing\n\t"
|
||||
"strb r8, [r10] \n\t" /* pcm_playing = false (r8=0, look above) */
|
||||
"ldr r10, [r12] \n\t"
|
||||
#if CONFIG_CPU == PP5002
|
||||
"bic r10, r10, #0x4\n\t" /* disable playback FIFO */
|
||||
"str r10, [r12] \n\t"
|
||||
"ldr r10, [r12, #0x1c] \n\t"
|
||||
"bic r10, r10, #0x200 \n\t" /* clear interrupt */
|
||||
"str r10, [r12, #0x1c] \n\t"
|
||||
#else
|
||||
"bic r10, r10, #0x20000002\n\t" /* disable playback FIFO and IRQ */
|
||||
"str r10, [r12] \n\t"
|
||||
#endif
|
||||
"mrs r10, cpsr \n\t"
|
||||
"orr r10, r10, #0x40 \n\t" /* disable FIQ */
|
||||
"msr cpsr_c, r10 \n\t"
|
||||
".exit: \n\t"
|
||||
"str r8, [r11, #4] \n\t"
|
||||
"str r9, [r11] \n\t"
|
||||
"subs pc, lr, #4 \n\t" /* FIQ specific return sequence */
|
||||
".fifo_full: \n\t" /* enable IRQ and exit */
|
||||
#if CONFIG_CPU == PP5002
|
||||
"ldr r10, [r12, #0x1c]\n\t"
|
||||
"orr r10, r10, #0x200 \n\t" /* set interrupt */
|
||||
"str r10, [r12, #0x1c]\n\t"
|
||||
#else
|
||||
"ldr r10, [r12] \n\t"
|
||||
"orr r10, r10, #0x2 \n\t" /* set interrupt */
|
||||
"str r10, [r12] \n\t"
|
||||
#endif
|
||||
"b .exit \n\t"
|
||||
);
|
||||
}
|
||||
#else /* !(CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002) */
|
||||
void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ")));
|
||||
void fiq(void)
|
||||
{
|
||||
/* Clear interrupt */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG &= ~0x2;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
inl(0xcf001040);
|
||||
IISFIFO_CFG &= ~(1<<9);
|
||||
#endif
|
||||
|
||||
do {
|
||||
while (p_size) {
|
||||
if (FIFO_FREE_COUNT < 2) {
|
||||
/* Enable interrupt */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x2;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISFIFO_CFG |= (1<<9);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
p_size-=4;
|
||||
}
|
||||
|
||||
/* p is empty, get some more data */
|
||||
if (pcm_callback_for_more) {
|
||||
pcm_callback_for_more((unsigned char**)&p,&p_size);
|
||||
}
|
||||
} while (p_size);
|
||||
|
||||
/* No more data, so disable the FIFO/FIQ */
|
||||
pcm_play_dma_stop();
|
||||
}
|
||||
#endif /* CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 */
|
||||
|
||||
#ifdef HAVE_PP5024_CODEC
|
||||
void pcm_init(void)
|
||||
{
|
||||
}
|
||||
#else
|
||||
void pcm_init(void)
|
||||
{
|
||||
pcm_playing = false;
|
||||
pcm_paused = false;
|
||||
pcm_callback_for_more = NULL;
|
||||
|
||||
/* Initialize default register values. */
|
||||
audiohw_init();
|
||||
|
||||
/* Power on */
|
||||
audiohw_enable_output(true);
|
||||
|
||||
/* Unmute the master channel (DAC should be at zero point now). */
|
||||
audiohw_mute(false);
|
||||
|
||||
/* Call pcm_play_dma_stop to initialize everything. */
|
||||
pcm_play_dma_stop();
|
||||
}
|
||||
#endif /* HAVE_PP5024_CODEC */
|
||||
#elif (CONFIG_CPU == PNX0101)
|
||||
|
||||
#define DMA_BUF_SAMPLES 0x100
|
||||
|
@ -608,7 +288,7 @@ void pcm_mute(bool mute)
|
|||
if (mute)
|
||||
sleep(HZ/16);
|
||||
}
|
||||
|
||||
#if !defined(CPU_PP)
|
||||
/*
|
||||
* This function goes directly into the DMA buffer to calculate the left and
|
||||
* right peak values. To avoid missing peaks it tries to look forward two full
|
||||
|
@ -632,9 +312,7 @@ void pcm_calculate_peaks(int *left, int *right)
|
|||
short *addr;
|
||||
short *end;
|
||||
{
|
||||
#if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
|
||||
|| defined(HAVE_WM8731) || defined(HAVE_WM8721) \
|
||||
|| (CONFIG_CPU == PNX0101) || defined(HAVE_PP5024_CODEC)
|
||||
#if CONFIG_CPU == PNX0101
|
||||
size_t samples = p_size / 4;
|
||||
addr = p;
|
||||
#endif
|
||||
|
@ -690,7 +368,7 @@ void pcm_calculate_peaks(int *left, int *right)
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* CPU_COLDFIRE */
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -112,7 +112,19 @@ static const struct sound_settings_info sound_settings_table[] = {
|
|||
[SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 31, 23, NULL},
|
||||
[SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 31, 23, NULL},
|
||||
[SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 1, 1, NULL},
|
||||
#endif
|
||||
#elif defined(HAVE_WM8975)
|
||||
[SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL},
|
||||
[SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL},
|
||||
[SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16, NULL},
|
||||
#elif defined(HAVE_WM8758)
|
||||
[SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL},
|
||||
[SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL},
|
||||
[SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16, NULL},
|
||||
#elif defined(HAVE_WM8731)
|
||||
[SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL},
|
||||
[SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL},
|
||||
[SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16, NULL},
|
||||
#endif
|
||||
};
|
||||
|
||||
const char *sound_unit(int setting)
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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 "system.h"
|
||||
#include "cpu.h"
|
||||
#include "audio.h"
|
||||
#include "sound.h"
|
||||
|
||||
void audio_set_output_source(int source)
|
||||
{
|
||||
if ((unsigned)source >= AUDIO_NUM_SOURCES)
|
||||
source = AUDIO_SRC_PLAYBACK;
|
||||
} /* audio_set_output_source */
|
||||
|
||||
void audio_set_source(int source, unsigned flags)
|
||||
{
|
||||
/* Prevent pops from unneeded switching */
|
||||
static int last_source = AUDIO_SRC_PLAYBACK;
|
||||
bool recording = flags & SRCF_RECORDING;
|
||||
static bool last_recording = false;
|
||||
|
||||
switch (source)
|
||||
{
|
||||
default: /* playback - no recording */
|
||||
source = AUDIO_SRC_PLAYBACK;
|
||||
case AUDIO_SRC_PLAYBACK:
|
||||
if (source != last_source)
|
||||
{
|
||||
audiohw_disable_recording();
|
||||
audiohw_set_monitor(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case AUDIO_SRC_MIC: /* recording only */
|
||||
if (source != last_source)
|
||||
{
|
||||
audiohw_enable_recording(true); /* source mic */
|
||||
audiohw_set_monitor(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case AUDIO_SRC_LINEIN: /* recording only */
|
||||
if (source != last_source)
|
||||
{
|
||||
audiohw_enable_recording(false); /* source line */
|
||||
audiohw_set_monitor(false);
|
||||
}
|
||||
break;
|
||||
#ifdef CONFIG_TUNER
|
||||
case AUDIO_SRC_FMRADIO: /* recording and playback */
|
||||
if (!recording)
|
||||
audiohw_set_recvol(0, 0, AUDIO_GAIN_LINEIN);
|
||||
|
||||
if (source == last_source && recording == last_recording)
|
||||
break;
|
||||
|
||||
last_recording = recording;
|
||||
|
||||
/* I2S recording and playback */
|
||||
audiohw_enable_recording(false); /* source line */
|
||||
audiohw_set_monitor(!recording);
|
||||
break;
|
||||
#endif
|
||||
} /* end switch */
|
||||
|
||||
last_source = source;
|
||||
} /* audio_set_source */
|
||||
|
||||
|
|
@ -0,0 +1,578 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* 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_WM8975)
|
||||
#include "wm8975.h"
|
||||
#elif defined(HAVE_WM8758)
|
||||
#include "wm8758.h"
|
||||
#elif defined(HAVE_WM8731)
|
||||
#include "wm8731l.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* peaks */
|
||||
static int play_peak_left, play_peak_right;
|
||||
static unsigned long *rec_peak_addr;
|
||||
static int rec_peak_left, rec_peak_right;
|
||||
|
||||
/** DMA **/
|
||||
#if CONFIG_CPU == PP5020
|
||||
#define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x3f000000) >> 24)
|
||||
#elif CONFIG_CPU == PP5002
|
||||
#define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x7800000) >> 23)
|
||||
#elif CONFIG_CPU == PP5024
|
||||
#define FIFO_FREE_COUNT 4 /* TODO: make this sensible */
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
** Playback DMA transfer
|
||||
**/
|
||||
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. */
|
||||
unsigned short* p IBSS_ATTR;
|
||||
size_t p_size IBSS_ATTR;
|
||||
|
||||
/* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode
|
||||
has registers r8-r14 banked, and so does not need to be saved. This routine
|
||||
uses only these registers, and so will never touch the stack unless it
|
||||
actually needs to do so when calling pcm_callback_for_more. C version is
|
||||
still included below for reference.
|
||||
*/
|
||||
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002
|
||||
void fiq(void) ICODE_ATTR __attribute__((naked));
|
||||
void fiq(void)
|
||||
{
|
||||
/* r12 contains IISCONFIG address (set in crt0.S to minimise code in actual
|
||||
* FIQ handler. r11 contains address of p (also set in crt0.S). Most other
|
||||
* addresses we need are generated by using offsets with these two.
|
||||
* r12 + 0x40 is IISFIFO_WR, and r12 + 0x0c is IISFIFO_CFG.
|
||||
* r8 and r9 contains local copies of p_size and p respectively.
|
||||
* r10 is a working register.
|
||||
*/
|
||||
asm volatile (
|
||||
#if CONFIG_CPU == PP5002
|
||||
"ldr r10, =0xcf001040 \n\t" /* Some magic from iPodLinux */
|
||||
"ldr r10, [r10] \n\t"
|
||||
"ldr r10, [r12, #0x1c]\n\t"
|
||||
"bic r10, r10, #0x200 \n\t" /* clear interrupt */
|
||||
"str r10, [r12, #0x1c]\n\t"
|
||||
#else
|
||||
"ldr r10, [r12] \n\t"
|
||||
"bic r10, r10, #0x2 \n\t" /* clear interrupt */
|
||||
"str r10, [r12] \n\t"
|
||||
#endif
|
||||
"ldr r8, [r11, #4] \n\t" /* r8 = p_size */
|
||||
"ldr r9, [r11] \n\t" /* r9 = p */
|
||||
".loop: \n\t"
|
||||
"cmp r8, #0 \n\t" /* is p_size 0? */
|
||||
"beq .more_data \n\t" /* if so, ask pcmbuf for more data */
|
||||
".fifo_loop: \n\t"
|
||||
#if CONFIG_CPU == PP5002
|
||||
"ldr r10, [r12, #0x1c]\n\t" /* read IISFIFO_CFG to check FIFO status */
|
||||
"and r10, r10, #0x7800000\n\t"
|
||||
"cmp r10, #0x800000 \n\t"
|
||||
#else
|
||||
"ldr r10, [r12, #0x0c]\n\t" /* read IISFIFO_CFG to check FIFO status */
|
||||
"and r10, r10, #0x3f0000\n\t"
|
||||
"cmp r10, #0x10000 \n\t"
|
||||
#endif
|
||||
"bls .fifo_full \n\t" /* FIFO full, exit */
|
||||
"ldr r10, [r9], #4 \n\t" /* load two samples */
|
||||
"mov r10, r10, ror #16\n\t" /* put left sample at the top bits */
|
||||
"str r10, [r12, #0x40]\n\t" /* write top sample, lower sample ignored */
|
||||
"mov r10, r10, lsl #16\n\t" /* shift lower sample up */
|
||||
"str r10, [r12, #0x40]\n\t" /* then write it */
|
||||
"subs r8, r8, #4 \n\t" /* check if we have more samples */
|
||||
"bne .fifo_loop \n\t" /* yes, continue */
|
||||
".more_data: \n\t"
|
||||
"stmdb sp!, { r0-r3, r12, lr}\n\t" /* stack scratch regs and lr */
|
||||
"mov r0, r11 \n\t" /* r0 = &p */
|
||||
"add r1, r11, #4 \n\t" /* r1 = &p_size */
|
||||
"str r9, [r0] \n\t" /* save internal copies of variables back */
|
||||
"str r8, [r1] \n\t"
|
||||
"ldr r2, =pcm_callback_for_more\n\t"
|
||||
"ldr r2, [r2] \n\t" /* get callback address */
|
||||
"cmp r2, #0 \n\t" /* check for null pointer */
|
||||
"movne lr, pc \n\t" /* call pcm_callback_for_more */
|
||||
"bxne r2 \n\t"
|
||||
"ldmia sp!, { r0-r3, r12, lr}\n\t"
|
||||
"ldr r8, [r11, #4] \n\t" /* reload p_size and p */
|
||||
"ldr r9, [r11] \n\t"
|
||||
"cmp r8, #0 \n\t" /* did we actually get more data? */
|
||||
"bne .loop \n\t" /* yes, continue to try feeding FIFO */
|
||||
".dma_stop: \n\t" /* no more data, do dma_stop() and exit */
|
||||
"ldr r10, =pcm_playing\n\t"
|
||||
"strb r8, [r10] \n\t" /* pcm_playing = false (r8=0, look above) */
|
||||
"ldr r10, [r12] \n\t"
|
||||
#if CONFIG_CPU == PP5002
|
||||
"bic r10, r10, #0x4\n\t" /* disable playback FIFO */
|
||||
"str r10, [r12] \n\t"
|
||||
"ldr r10, [r12, #0x1c] \n\t"
|
||||
"bic r10, r10, #0x200 \n\t" /* clear interrupt */
|
||||
"str r10, [r12, #0x1c] \n\t"
|
||||
#else
|
||||
"bic r10, r10, #0x20000002\n\t" /* disable playback FIFO and IRQ */
|
||||
"str r10, [r12] \n\t"
|
||||
#endif
|
||||
"mrs r10, cpsr \n\t"
|
||||
"orr r10, r10, #0x40 \n\t" /* disable FIQ */
|
||||
"msr cpsr_c, r10 \n\t"
|
||||
".exit: \n\t"
|
||||
"str r8, [r11, #4] \n\t"
|
||||
"str r9, [r11] \n\t"
|
||||
"subs pc, lr, #4 \n\t" /* FIQ specific return sequence */
|
||||
".fifo_full: \n\t" /* enable IRQ and exit */
|
||||
#if CONFIG_CPU == PP5002
|
||||
"ldr r10, [r12, #0x1c]\n\t"
|
||||
"orr r10, r10, #0x200 \n\t" /* set interrupt */
|
||||
"str r10, [r12, #0x1c]\n\t"
|
||||
#else
|
||||
"ldr r10, [r12] \n\t"
|
||||
"orr r10, r10, #0x2 \n\t" /* set interrupt */
|
||||
"str r10, [r12] \n\t"
|
||||
#endif
|
||||
"b .exit \n\t"
|
||||
);
|
||||
}
|
||||
#else /* !(CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002) */
|
||||
void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ")));
|
||||
void fiq(void)
|
||||
{
|
||||
/* Clear interrupt */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG &= ~0x2;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
inl(0xcf001040);
|
||||
IISFIFO_CFG &= ~(1<<9);
|
||||
#endif
|
||||
|
||||
do {
|
||||
while (p_size) {
|
||||
if (FIFO_FREE_COUNT < 2) {
|
||||
/* Enable interrupt */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x2;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISFIFO_CFG |= (1<<9);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
p_size-=4;
|
||||
}
|
||||
|
||||
/* p is empty, get some more data */
|
||||
if (pcm_callback_for_more) {
|
||||
pcm_callback_for_more((unsigned char**)&p,&p_size);
|
||||
}
|
||||
} while (p_size);
|
||||
|
||||
/* No more data, so disable the FIFO/FIQ */
|
||||
pcm_play_dma_stop();
|
||||
}
|
||||
#endif /* CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 */
|
||||
|
||||
void pcm_play_dma_start(const void *addr, size_t size)
|
||||
{
|
||||
p=(unsigned short*)addr;
|
||||
p_size=size;
|
||||
|
||||
pcm_playing = true;
|
||||
|
||||
#if CONFIG_CPU == PP5020
|
||||
/* setup I2S interrupt for FIQ */
|
||||
outl(inl(0x6000402c) | I2S_MASK, 0x6000402c);
|
||||
outl(I2S_MASK, 0x60004024);
|
||||
#elif CONFIG_CPU == PP5024
|
||||
#else
|
||||
/* setup I2S interrupt for FIQ */
|
||||
outl(inl(0xcf00102c) | DMA_OUT_MASK, 0xcf00102c);
|
||||
outl(DMA_OUT_MASK, 0xcf001024);
|
||||
#endif
|
||||
|
||||
/* Clear the FIQ disable bit in cpsr_c */
|
||||
enable_fiq(fiq);
|
||||
|
||||
/* Enable playback FIFO */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x20000000;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISCONFIG |= 0x4;
|
||||
#endif
|
||||
|
||||
/* Fill the FIFO - we assume there are enough bytes in the pcm buffer to
|
||||
fill the 32-byte FIFO. */
|
||||
while (p_size > 0) {
|
||||
if (FIFO_FREE_COUNT < 2) {
|
||||
/* Enable interrupt */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x2;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISFIFO_CFG |= (1<<9);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
p_size-=4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Stops the DMA transfer and interrupt */
|
||||
void pcm_play_dma_stop(void)
|
||||
{
|
||||
pcm_playing = false;
|
||||
|
||||
#if CONFIG_CPU == PP5020
|
||||
|
||||
/* Disable playback FIFO */
|
||||
IISCONFIG &= ~0x20000000;
|
||||
|
||||
/* Disable the interrupt */
|
||||
IISCONFIG &= ~0x2;
|
||||
|
||||
#elif CONFIG_CPU == PP5002
|
||||
|
||||
/* Disable playback FIFO */
|
||||
IISCONFIG &= ~0x4;
|
||||
|
||||
/* Disable the interrupt */
|
||||
IISFIFO_CFG &= ~(1<<9);
|
||||
#endif
|
||||
|
||||
disable_fiq();
|
||||
}
|
||||
|
||||
void pcm_play_pause_pause(void)
|
||||
{
|
||||
#if CONFIG_CPU == PP5020
|
||||
/* Disable the interrupt */
|
||||
IISCONFIG &= ~0x2;
|
||||
/* Disable playback FIFO */
|
||||
IISCONFIG &= ~0x20000000;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
/* Disable the interrupt */
|
||||
IISFIFO_CFG &= ~(1<<9);
|
||||
/* Disable playback FIFO */
|
||||
IISCONFIG &= ~0x4;
|
||||
#endif
|
||||
disable_fiq();
|
||||
}
|
||||
|
||||
void pcm_play_pause_unpause(void)
|
||||
{
|
||||
/* Enable the FIFO and fill it */
|
||||
|
||||
enable_fiq(fiq);
|
||||
|
||||
/* Enable playback FIFO */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x20000000;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISCONFIG |= 0x4;
|
||||
#endif
|
||||
|
||||
/* Fill the FIFO - we assume there are enough bytes in the
|
||||
pcm buffer to fill the 32-byte FIFO. */
|
||||
while (p_size > 0) {
|
||||
if (FIFO_FREE_COUNT < 2) {
|
||||
/* Enable interrupt */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x2;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISFIFO_CFG |= (1<<9);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
p_size-=4;
|
||||
}
|
||||
}
|
||||
|
||||
void pcm_set_frequency(unsigned int frequency)
|
||||
{
|
||||
(void)frequency;
|
||||
pcm_freq = HW_SAMPR_DEFAULT;
|
||||
}
|
||||
|
||||
size_t pcm_get_bytes_waiting(void)
|
||||
{
|
||||
return p_size;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PP5024_CODEC
|
||||
void pcm_init(void)
|
||||
{
|
||||
}
|
||||
#else
|
||||
void pcm_init(void)
|
||||
{
|
||||
pcm_playing = false;
|
||||
pcm_paused = false;
|
||||
pcm_callback_for_more = NULL;
|
||||
|
||||
/* Initialize default register values. */
|
||||
audiohw_init();
|
||||
|
||||
/* Power on */
|
||||
audiohw_enable_output(true);
|
||||
|
||||
/* Unmute the master channel (DAC should be at zero point now). */
|
||||
audiohw_mute(false);
|
||||
|
||||
/* Call pcm_play_dma_stop to initialize everything. */
|
||||
pcm_play_dma_stop();
|
||||
}
|
||||
#endif /* HAVE_PP5024_CODEC */
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
** Recording DMA transfer
|
||||
**/
|
||||
static short peak_l, peak_r IBSS_ATTR;
|
||||
|
||||
void fiq_record(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ")));
|
||||
void fiq_record(void)
|
||||
{
|
||||
short value;
|
||||
pcm_more_callback_type2 more_ready;
|
||||
int status = 0;
|
||||
|
||||
/* Clear interrupt */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG &= ~0x01;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
/* TODO */
|
||||
#endif
|
||||
|
||||
while (p_size > 0) {
|
||||
if (FIFO_FREE_COUNT < 2) {
|
||||
/* enable interrupt */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x01;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
/* TODO */
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
value = (unsigned short)(IISFIFO_RD >> 16);
|
||||
if (value > peak_l) peak_l = value;
|
||||
else if (-value > peak_l) peak_l = -value;
|
||||
*(p++) = value;
|
||||
|
||||
value = (unsigned short)(IISFIFO_RD >> 16);
|
||||
if (value > peak_r) peak_r = value;
|
||||
else if (-value > peak_r) peak_r = -value;
|
||||
*(p++) = value;
|
||||
|
||||
p_size -= 4;
|
||||
|
||||
/* If we have filled the current chunk, start a new one */
|
||||
if (p_size == 0) {
|
||||
rec_peak_left = peak_l;
|
||||
rec_peak_right = peak_r;
|
||||
peak_l = peak_r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
more_ready = pcm_callback_more_ready;
|
||||
|
||||
if (more_ready != NULL && more_ready(status) >= 0)
|
||||
return;
|
||||
|
||||
/* Finished recording */
|
||||
pcm_rec_dma_stop();
|
||||
}
|
||||
|
||||
/* Continue transferring data in */
|
||||
void pcm_record_more(void *start, size_t size)
|
||||
{
|
||||
rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */
|
||||
p = start;
|
||||
p_size = size; /* Bytes to transfer */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x01;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
/* TODO */
|
||||
#endif
|
||||
}
|
||||
|
||||
void pcm_rec_dma_stop(void)
|
||||
{
|
||||
logf("pcm_rec_dma_stop");
|
||||
|
||||
/* disable fifo */
|
||||
IISCONFIG &= ~0x10000000;
|
||||
|
||||
disable_fiq();
|
||||
|
||||
pcm_recording = false;
|
||||
}
|
||||
|
||||
void pcm_rec_dma_start(void *addr, size_t size)
|
||||
{
|
||||
logf("pcm_rec_dma_start");
|
||||
|
||||
pcm_recording = true;
|
||||
|
||||
peak_l = peak_r = 0;
|
||||
p_size = size;
|
||||
p = addr;
|
||||
|
||||
/* setup FIQ */
|
||||
outl(inl(0x6000402c) | I2S_MASK, 0x6000402c);
|
||||
outl(I2S_MASK, 0x60004024);
|
||||
|
||||
/* interrupt on full fifo */
|
||||
outl(inl(0x70002800) | 0x1, 0x70002800);
|
||||
|
||||
/* enable record fifo */
|
||||
outl(inl(0x70002800) | 0x10000000, 0x70002800);
|
||||
|
||||
enable_fiq(fiq_record);
|
||||
}
|
||||
|
||||
void pcm_close_recording(void)
|
||||
{
|
||||
logf("pcm_close_recording");
|
||||
|
||||
pcm_rec_dma_stop();
|
||||
|
||||
#if (CONFIG_CPU == PP5020)
|
||||
disable_fiq();
|
||||
|
||||
/* disable fifo */
|
||||
IISCONFIG &= ~0x10000000;
|
||||
|
||||
/* Clear interrupt */
|
||||
IISCONFIG &= ~0x01;
|
||||
#endif
|
||||
} /* pcm_close_recording */
|
||||
|
||||
void pcm_init_recording(void)
|
||||
{
|
||||
logf("pcm_init_recording");
|
||||
|
||||
pcm_recording = false;
|
||||
pcm_callback_more_ready = NULL;
|
||||
|
||||
#if (CONFIG_CPU == PP5020)
|
||||
#if defined(IPOD_COLOR) || defined (IPOD_4G)
|
||||
/* The usual magic from IPL - I'm guessing this configures the headphone
|
||||
socket to be input or output - in this case, input. */
|
||||
GPIOI_OUTPUT_VAL &= ~0x40;
|
||||
GPIOA_OUTPUT_VAL &= ~0x4;
|
||||
#endif
|
||||
/* Setup the recording FIQ handler */
|
||||
*((unsigned int*)(15*4)) = (unsigned int)&fiq_record;
|
||||
#endif
|
||||
|
||||
pcm_rec_dma_stop();
|
||||
} /* pcm_init */
|
||||
|
||||
void pcm_calculate_rec_peaks(int *left, int *right)
|
||||
{
|
||||
*left = rec_peak_left;
|
||||
*right = rec_peak_right;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function goes directly into the DMA buffer to calculate the left and
|
||||
* right peak values. To avoid missing peaks it tries to look forward two full
|
||||
* peek periods (2/HZ sec, 100% overlap), although it's always possible that
|
||||
* the entire period will not be visible. To reduce CPU load it only looks at
|
||||
* every third sample, and this can be reduced even further if needed (even
|
||||
* every tenth sample would still be pretty accurate).
|
||||
*/
|
||||
|
||||
/* Check for a peak every PEAK_STRIDE samples */
|
||||
#define PEAK_STRIDE 3
|
||||
/* Up to 1/50th of a second of audio for peak calculation */
|
||||
/* This should use NATIVE_FREQUENCY, or eventually an adjustable freq. value */
|
||||
#define PEAK_SAMPLES (44100/50)
|
||||
void pcm_calculate_peaks(int *left, int *right)
|
||||
{
|
||||
short *addr;
|
||||
short *end;
|
||||
{
|
||||
size_t samples = p_size / 4;
|
||||
addr = p;
|
||||
|
||||
if (samples > PEAK_SAMPLES)
|
||||
samples = PEAK_SAMPLES - (PEAK_STRIDE - 1);
|
||||
else
|
||||
samples -= MIN(PEAK_STRIDE - 1, samples);
|
||||
|
||||
end = &addr[samples * 2];
|
||||
}
|
||||
|
||||
if (left && right) {
|
||||
int left_peak = 0, right_peak = 0;
|
||||
|
||||
while (addr < end) {
|
||||
int value;
|
||||
if ((value = addr [0]) > left_peak)
|
||||
left_peak = value;
|
||||
else if (-value > left_peak)
|
||||
left_peak = -value;
|
||||
|
||||
if ((value = addr [PEAK_STRIDE | 1]) > right_peak)
|
||||
right_peak = value;
|
||||
else if (-value > right_peak)
|
||||
right_peak = -value;
|
||||
|
||||
addr = &addr[PEAK_STRIDE * 2];
|
||||
}
|
||||
|
||||
*left = left_peak;
|
||||
*right = right_peak;
|
||||
}
|
||||
else if (left || right) {
|
||||
int peak_value = 0, value;
|
||||
|
||||
if (right)
|
||||
addr += (PEAK_STRIDE | 1);
|
||||
|
||||
while (addr < end) {
|
||||
if ((value = addr [0]) > peak_value)
|
||||
peak_value = value;
|
||||
else if (-value > peak_value)
|
||||
peak_value = -value;
|
||||
|
||||
addr += PEAK_STRIDE * 2;
|
||||
}
|
||||
|
||||
if (left)
|
||||
*left = peak_value;
|
||||
else
|
||||
*right = peak_value;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue