diff --git a/apps/keymaps/keymap-fiiom3k.c b/apps/keymaps/keymap-fiiom3k.c index a97be0870d..337a2184cd 100644 --- a/apps/keymaps/keymap-fiiom3k.c +++ b/apps/keymaps/keymap-fiiom3k.c @@ -138,6 +138,16 @@ static const struct button_mapping button_context_settings[] = { LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) }; /* button_context_settings */ +static const struct button_mapping button_context_settings_rectrigger[] = { + {ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE}, + {ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE}, + {ACTION_SETTINGS_INCBIGSTEP, BUTTON_VOL_UP, BUTTON_NONE}, + {ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE}, + {ACTION_SETTINGS_DECREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE}, + {ACTION_SETTINGS_DECBIGSTEP, BUTTON_VOL_DOWN, BUTTON_NONE}, + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) +}; /* button_context_settings_rectrigger */ + static const struct button_mapping button_context_settings_eq[] = { {ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE}, {ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE}, @@ -203,6 +213,33 @@ static const struct button_mapping button_context_yesnoscreen[] = { LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) }; /* button_context_yesnoscreen */ +static const struct button_mapping button_context_recscreen[] = { + {ACTION_REC_PAUSE, BUTTON_SELECT, BUTTON_NONE}, + {ACTION_REC_PAUSE, BUTTON_PLAY, BUTTON_NONE}, + {ACTION_REC_NEWFILE, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT}, + {ACTION_REC_NEWFILE, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY}, + {ACTION_STD_MENU, BUTTON_MENU, BUTTON_NONE}, + {ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE}, + {ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE}, + {ACTION_STD_PREV, BUTTON_UP, BUTTON_NONE}, + {ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE}, + {ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE}, + {ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE}, + {ACTION_STD_PREV, BUTTON_SCROLL_BACK, BUTTON_NONE}, + {ACTION_STD_PREVREPEAT, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE}, + {ACTION_STD_NEXT, BUTTON_SCROLL_FWD, BUTTON_NONE}, + {ACTION_STD_NEXTREPEAT, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE}, + {ACTION_SETTINGS_INC, BUTTON_VOL_UP, BUTTON_NONE}, + {ACTION_SETTINGS_INCREPEAT, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE}, + {ACTION_SETTINGS_DEC, BUTTON_VOL_DOWN, BUTTON_NONE}, + {ACTION_SETTINGS_DECREPEAT, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE}, + {ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE}, + {ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE}, + {ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE}, + {ACTION_SETTINGS_DECREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE}, + LAST_ITEM_IN_LIST +}; /* button_context_recscreen */ + static const struct button_mapping button_context_keyboard[] = { {ACTION_KBD_UP, BUTTON_UP, BUTTON_NONE}, {ACTION_KBD_DOWN, BUTTON_DOWN, BUTTON_NONE}, @@ -315,8 +352,9 @@ const struct button_mapping* get_context_mapping(int context) return button_context_list; case CONTEXT_SETTINGS: case CONTEXT_SETTINGS_TIME: - case CONTEXT_SETTINGS_RECTRIGGER: return button_context_settings; + case CONTEXT_SETTINGS_RECTRIGGER: + return button_context_settings_rectrigger; case CONTEXT_SETTINGS_EQ: case CONTEXT_SETTINGS_COLOURCHOOSER: return button_context_settings_eq; @@ -326,6 +364,8 @@ const struct button_mapping* get_context_mapping(int context) return button_context_pitchscreen; case CONTEXT_YESNOSCREEN: return button_context_yesnoscreen; + case CONTEXT_RECSCREEN: + return button_context_recscreen; case CONTEXT_KEYBOARD: return button_context_keyboard; case CONTEXT_USB_HID: diff --git a/firmware/export/ak4376.h b/firmware/export/ak4376.h index 0ae156bc37..ad842b2b80 100644 --- a/firmware/export/ak4376.h +++ b/firmware/export/ak4376.h @@ -22,7 +22,9 @@ #ifndef __AK4376_H__ #define __AK4376_H__ -#define AUDIOHW_CAPS (FILTER_ROLL_OFF_CAP|POWER_MODE_CAP) +/* The target config must define this; defining it here would prevent + the target from supporting audio recording via an alternate codec. */ +/* #define AUDIOHW_CAPS (FILTER_ROLL_OFF_CAP|POWER_MODE_CAP) */ #define AUDIOHW_HAVE_SHORT2_ROLL_OFF #define AK4376_MIN_VOLUME (-890) diff --git a/firmware/export/config/fiiom3k.h b/firmware/export/config/fiiom3k.h index 45c2150208..ea97d52d76 100644 --- a/firmware/export/config/fiiom3k.h +++ b/firmware/export/config/fiiom3k.h @@ -55,11 +55,15 @@ /* Codec / audio hardware defines */ #define HW_SAMPR_CAPS SAMPR_CAP_ALL_192 +#define REC_SAMPR_CAPS (SAMPR_CAP_ALL_96 & ~SAMPR_CAP_64) +#define INPUT_SRC_CAPS SRC_CAP_MIC +#define AUDIOHW_CAPS (FILTER_ROLL_OFF_CAP|POWER_MODE_CAP|MIC_GAIN_CAP) +#define HAVE_RECORDING #define HAVE_AK4376 +#define HAVE_X1000_ICODEC_REC #define HAVE_SW_TONE_CONTROLS #define HAVE_SW_VOLUME_CONTROL - -/* TODO: Need to implement recording */ +#define DEFAULT_REC_MIC_GAIN 12 /* Button defines */ #define CONFIG_KEYPAD FIIO_M3K_PAD diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c index f7dced8f54..9374d23a81 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c @@ -7,7 +7,7 @@ * \/ \/ \/ \/ \/ * $Id$ * - * Copyright (C) 2021 Aidan MacDonald + * Copyright (C) 2021-2022 Aidan MacDonald * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,6 +20,7 @@ ****************************************************************************/ #include "audiohw.h" +#include "audio.h" #include "system.h" #include "pcm_sampr.h" #include "aic-x1000.h" @@ -27,6 +28,11 @@ #include "gpio-x1000.h" #include "logf.h" +static int cur_audio_source = AUDIO_SRC_PLAYBACK; +static int cur_vol_r = AK4376_MIN_VOLUME; +static int cur_vol_l = AK4376_MIN_VOLUME; +static int cur_recvol = 0; +static int cur_filter_roll_off = 0; static int cur_fsel = HW_FREQ_48; static int cur_power_mode = SOUND_HIGH_POWER; @@ -60,29 +66,138 @@ void audiohw_postinit(void) void audiohw_close(void) { - ak4376_close(); + if(cur_audio_source == AUDIO_SRC_PLAYBACK) + ak4376_close(); + else if(cur_audio_source == AUDIO_SRC_MIC) + x1000_icodec_close(); +} + +void audio_set_output_source(int source) +{ + /* this is a no-op */ + (void)source; +} + +void audio_input_mux(int source, unsigned flags) +{ + (void)flags; + + if(source == cur_audio_source) + return; + + /* close whatever codec is currently in use */ + audiohw_close(); + aic_enable_i2s_bit_clock(false); + + /* switch to new source */ + cur_audio_source = source; + + if(source == AUDIO_SRC_PLAYBACK) { + /* power on DAC */ + aic_set_external_codec(true); + aic_set_i2s_mode(AIC_I2S_MASTER_MODE); + ak4376_open(); + + /* apply the old settings */ + audiohw_set_volume(cur_vol_l, cur_vol_r); + audiohw_set_filter_roll_off(cur_filter_roll_off); + set_ak_freqmode(); + } else if(source == AUDIO_SRC_MIC) { + aic_set_external_codec(false); + aic_set_i2s_mode(AIC_I2S_SLAVE_MODE); + /* Note: Sampling frequency is irrelevant here */ + aic_set_i2s_clock(X1000_CLK_EXCLK, 48000, 0); + aic_enable_i2s_bit_clock(true); + + x1000_icodec_open(); + + /* configure the mic */ + x1000_icodec_mic1_enable(true); + x1000_icodec_mic1_bias_enable(true); + x1000_icodec_mic1_configure(JZCODEC_MIC1_DIFFERENTIAL | + JZCODEC_MIC1_BIAS_2_08V); + + /* configure the ADC */ + x1000_icodec_adc_mic_sel(JZCODEC_MIC_SEL_ANALOG); + x1000_icodec_adc_highpass_filter(true); + x1000_icodec_adc_frequency(cur_fsel); + x1000_icodec_adc_enable(true); + + /* configure the mixer to put mic input in both channels */ + x1000_icodec_mixer_enable(true); + x1000_icodec_write(JZCODEC_MIX2, 0x10); + + /* set gain and unmute */ + audiohw_set_recvol(cur_recvol, 0, AUDIO_GAIN_MIC); + x1000_icodec_adc_mute(false); + } else { + logf("bad audio input source: %d (flags: %x)", source, flags); + } } void audiohw_set_volume(int vol_l, int vol_r) { - ak4376_set_volume(vol_l, vol_r); + cur_vol_l = vol_l; + cur_vol_r = vol_r; + + if(cur_audio_source == AUDIO_SRC_PLAYBACK) + ak4376_set_volume(vol_l, vol_r); } void audiohw_set_filter_roll_off(int val) { - ak4376_set_filter_roll_off(val); + cur_filter_roll_off = val; + + if(cur_audio_source == AUDIO_SRC_PLAYBACK) + ak4376_set_filter_roll_off(val); } void audiohw_set_frequency(int fsel) { cur_fsel = fsel; - set_ak_freqmode(); + + if(cur_audio_source == AUDIO_SRC_PLAYBACK) + set_ak_freqmode(); + else + x1000_icodec_adc_frequency(fsel); } void audiohw_set_power_mode(int mode) { cur_power_mode = mode; - set_ak_freqmode(); + + if(cur_audio_source == AUDIO_SRC_PLAYBACK) + set_ak_freqmode(); +} + +static int round_step_up(int x, int step) +{ + int rem = x % step; + if(rem > 0) + rem -= step; + return x - rem; +} + +void audiohw_set_recvol(int left, int right, int type) +{ + (void)right; + + if(type == AUDIO_GAIN_MIC) { + cur_recvol = left; + + if(cur_audio_source == AUDIO_SRC_MIC) { + int mic_gain = round_step_up(left, X1000_ICODEC_MIC_GAIN_STEP); + mic_gain = MIN(mic_gain, X1000_ICODEC_MIC_GAIN_MAX); + mic_gain = MAX(mic_gain, X1000_ICODEC_MIC_GAIN_MIN); + + int adc_gain = left - mic_gain; + adc_gain = MIN(adc_gain, X1000_ICODEC_ADC_GAIN_MAX); + adc_gain = MAX(adc_gain, X1000_ICODEC_ADC_GAIN_MIN); + + x1000_icodec_adc_gain(adc_gain); + x1000_icodec_mic1_gain(mic_gain); + } + } } void ak4376_set_pdn_pin(int level) diff --git a/manual/platform/keymap-fiiom3k.tex b/manual/platform/keymap-fiiom3k.tex index ecf07bebd4..95c56f13ed 100644 --- a/manual/platform/keymap-fiiom3k.tex +++ b/manual/platform/keymap-fiiom3k.tex @@ -45,6 +45,18 @@ \newcommand{\ActionWpsAbSetBNextDir}{Long \ButtonDown} \newcommand{\ActionWpsAbReset}{Long \ButtonSelect} +%Button actions, recording context +\newcommand{\ActionRecPause}{\ButtonSelect{} or \ButtonPlay} +\newcommand{\ActionRecExit}{\ButtonBack{} or \ButtonPower} +\newcommand{\ActionRecNewfile}{Long \ButtonSelect{} or Long \ButtonPlay} +\newcommand{\ActionRecMenu}{\ButtonMenu} +\newcommand{\ActionRecPrev}{\ActionStdPrev} +\newcommand{\ActionRecPrevRepeat}{\ActionStdPrevRepeat} +\newcommand{\ActionRecNext}{\ActionStdNext} +\newcommand{\ActionRecNextRepeat}{\ActionStdNextRepeat} +\newcommand{\ActionRecSettingsInc}{\ButtonVolUp{} or \ButtonRight} +\newcommand{\ActionRecSettingsDec}{\ButtonVolDown{} or \ButtonLeft} + %Button actions, tree context \newcommand{\ActionTreeWps}{Long \ButtonBack} \newcommand{\ActionTreeStop}{Long \ButtonPlay}