summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2022-01-11 13:58:41 +0000
committerAidan MacDonald <amachronic@protonmail.com>2022-01-29 19:28:03 +0000
commitc1f1d9140407757fab16c418eed09f5517c649d7 (patch)
treeee75be10480d454ea8a8cbd38cb51d29b7019433
parentbc5a6385949c9f0a17173f3512aa9a6db9175803 (diff)
downloadrockbox-c1f1d9140407757fab16c418eed09f5517c649d7.tar.gz
rockbox-c1f1d9140407757fab16c418eed09f5517c649d7.zip
FiiO M3K: audio recording
Recording works now, although I'm sure there will be a few things that need fine-tuning. A major issue is that writing to the SD card creates noticable interference, which happens on the original firmware too but seems worse under Rockbox. (Since Rockbox waits until RAM fills up before writing data, the interference will only be heard on >50 MiB recordings.) Change-Id: I5561dd9668c3bdd34e92f34ef50848aef8c0b7eb
-rw-r--r--apps/keymaps/keymap-fiiom3k.c42
-rw-r--r--firmware/export/ak4376.h4
-rw-r--r--firmware/export/config/fiiom3k.h8
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c127
-rw-r--r--manual/platform/keymap-fiiom3k.tex12
5 files changed, 183 insertions, 10 deletions
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[] = {
138 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) 138 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
139}; /* button_context_settings */ 139}; /* button_context_settings */
140 140
141static const struct button_mapping button_context_settings_rectrigger[] = {
142 {ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE},
143 {ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
144 {ACTION_SETTINGS_INCBIGSTEP, BUTTON_VOL_UP, BUTTON_NONE},
145 {ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE},
146 {ACTION_SETTINGS_DECREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
147 {ACTION_SETTINGS_DECBIGSTEP, BUTTON_VOL_DOWN, BUTTON_NONE},
148 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
149}; /* button_context_settings_rectrigger */
150
141static const struct button_mapping button_context_settings_eq[] = { 151static const struct button_mapping button_context_settings_eq[] = {
142 {ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE}, 152 {ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE},
143 {ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE}, 153 {ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
@@ -203,6 +213,33 @@ static const struct button_mapping button_context_yesnoscreen[] = {
203 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) 213 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
204}; /* button_context_yesnoscreen */ 214}; /* button_context_yesnoscreen */
205 215
216static const struct button_mapping button_context_recscreen[] = {
217 {ACTION_REC_PAUSE, BUTTON_SELECT, BUTTON_NONE},
218 {ACTION_REC_PAUSE, BUTTON_PLAY, BUTTON_NONE},
219 {ACTION_REC_NEWFILE, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT},
220 {ACTION_REC_NEWFILE, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY},
221 {ACTION_STD_MENU, BUTTON_MENU, BUTTON_NONE},
222 {ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE},
223 {ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE},
224 {ACTION_STD_PREV, BUTTON_UP, BUTTON_NONE},
225 {ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE},
226 {ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE},
227 {ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE},
228 {ACTION_STD_PREV, BUTTON_SCROLL_BACK, BUTTON_NONE},
229 {ACTION_STD_PREVREPEAT, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE},
230 {ACTION_STD_NEXT, BUTTON_SCROLL_FWD, BUTTON_NONE},
231 {ACTION_STD_NEXTREPEAT, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE},
232 {ACTION_SETTINGS_INC, BUTTON_VOL_UP, BUTTON_NONE},
233 {ACTION_SETTINGS_INCREPEAT, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE},
234 {ACTION_SETTINGS_DEC, BUTTON_VOL_DOWN, BUTTON_NONE},
235 {ACTION_SETTINGS_DECREPEAT, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE},
236 {ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE},
237 {ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
238 {ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE},
239 {ACTION_SETTINGS_DECREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
240 LAST_ITEM_IN_LIST
241}; /* button_context_recscreen */
242
206static const struct button_mapping button_context_keyboard[] = { 243static const struct button_mapping button_context_keyboard[] = {
207 {ACTION_KBD_UP, BUTTON_UP, BUTTON_NONE}, 244 {ACTION_KBD_UP, BUTTON_UP, BUTTON_NONE},
208 {ACTION_KBD_DOWN, BUTTON_DOWN, BUTTON_NONE}, 245 {ACTION_KBD_DOWN, BUTTON_DOWN, BUTTON_NONE},
@@ -315,8 +352,9 @@ const struct button_mapping* get_context_mapping(int context)
315 return button_context_list; 352 return button_context_list;
316 case CONTEXT_SETTINGS: 353 case CONTEXT_SETTINGS:
317 case CONTEXT_SETTINGS_TIME: 354 case CONTEXT_SETTINGS_TIME:
318 case CONTEXT_SETTINGS_RECTRIGGER:
319 return button_context_settings; 355 return button_context_settings;
356 case CONTEXT_SETTINGS_RECTRIGGER:
357 return button_context_settings_rectrigger;
320 case CONTEXT_SETTINGS_EQ: 358 case CONTEXT_SETTINGS_EQ:
321 case CONTEXT_SETTINGS_COLOURCHOOSER: 359 case CONTEXT_SETTINGS_COLOURCHOOSER:
322 return button_context_settings_eq; 360 return button_context_settings_eq;
@@ -326,6 +364,8 @@ const struct button_mapping* get_context_mapping(int context)
326 return button_context_pitchscreen; 364 return button_context_pitchscreen;
327 case CONTEXT_YESNOSCREEN: 365 case CONTEXT_YESNOSCREEN:
328 return button_context_yesnoscreen; 366 return button_context_yesnoscreen;
367 case CONTEXT_RECSCREEN:
368 return button_context_recscreen;
329 case CONTEXT_KEYBOARD: 369 case CONTEXT_KEYBOARD:
330 return button_context_keyboard; 370 return button_context_keyboard;
331 case CONTEXT_USB_HID: 371 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 @@
22#ifndef __AK4376_H__ 22#ifndef __AK4376_H__
23#define __AK4376_H__ 23#define __AK4376_H__
24 24
25#define AUDIOHW_CAPS (FILTER_ROLL_OFF_CAP|POWER_MODE_CAP) 25/* The target config must define this; defining it here would prevent
26 the target from supporting audio recording via an alternate codec. */
27/* #define AUDIOHW_CAPS (FILTER_ROLL_OFF_CAP|POWER_MODE_CAP) */
26#define AUDIOHW_HAVE_SHORT2_ROLL_OFF 28#define AUDIOHW_HAVE_SHORT2_ROLL_OFF
27 29
28#define AK4376_MIN_VOLUME (-890) 30#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 @@
55 55
56/* Codec / audio hardware defines */ 56/* Codec / audio hardware defines */
57#define HW_SAMPR_CAPS SAMPR_CAP_ALL_192 57#define HW_SAMPR_CAPS SAMPR_CAP_ALL_192
58#define REC_SAMPR_CAPS (SAMPR_CAP_ALL_96 & ~SAMPR_CAP_64)
59#define INPUT_SRC_CAPS SRC_CAP_MIC
60#define AUDIOHW_CAPS (FILTER_ROLL_OFF_CAP|POWER_MODE_CAP|MIC_GAIN_CAP)
61#define HAVE_RECORDING
58#define HAVE_AK4376 62#define HAVE_AK4376
63#define HAVE_X1000_ICODEC_REC
59#define HAVE_SW_TONE_CONTROLS 64#define HAVE_SW_TONE_CONTROLS
60#define HAVE_SW_VOLUME_CONTROL 65#define HAVE_SW_VOLUME_CONTROL
61 66#define DEFAULT_REC_MIC_GAIN 12
62/* TODO: Need to implement recording */
63 67
64/* Button defines */ 68/* Button defines */
65#define CONFIG_KEYPAD FIIO_M3K_PAD 69#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 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2021 Aidan MacDonald 10 * Copyright (C) 2021-2022 Aidan MacDonald
11 * 11 *
12 * This program is free software; you can redistribute it and/or 12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 13 * modify it under the terms of the GNU General Public License
@@ -20,6 +20,7 @@
20 ****************************************************************************/ 20 ****************************************************************************/
21 21
22#include "audiohw.h" 22#include "audiohw.h"
23#include "audio.h"
23#include "system.h" 24#include "system.h"
24#include "pcm_sampr.h" 25#include "pcm_sampr.h"
25#include "aic-x1000.h" 26#include "aic-x1000.h"
@@ -27,6 +28,11 @@
27#include "gpio-x1000.h" 28#include "gpio-x1000.h"
28#include "logf.h" 29#include "logf.h"
29 30
31static int cur_audio_source = AUDIO_SRC_PLAYBACK;
32static int cur_vol_r = AK4376_MIN_VOLUME;
33static int cur_vol_l = AK4376_MIN_VOLUME;
34static int cur_recvol = 0;
35static int cur_filter_roll_off = 0;
30static int cur_fsel = HW_FREQ_48; 36static int cur_fsel = HW_FREQ_48;
31static int cur_power_mode = SOUND_HIGH_POWER; 37static int cur_power_mode = SOUND_HIGH_POWER;
32 38
@@ -60,29 +66,138 @@ void audiohw_postinit(void)
60 66
61void audiohw_close(void) 67void audiohw_close(void)
62{ 68{
63 ak4376_close(); 69 if(cur_audio_source == AUDIO_SRC_PLAYBACK)
70 ak4376_close();
71 else if(cur_audio_source == AUDIO_SRC_MIC)
72 x1000_icodec_close();
73}
74
75void audio_set_output_source(int source)
76{
77 /* this is a no-op */
78 (void)source;
79}
80
81void audio_input_mux(int source, unsigned flags)
82{
83 (void)flags;
84
85 if(source == cur_audio_source)
86 return;
87
88 /* close whatever codec is currently in use */
89 audiohw_close();
90 aic_enable_i2s_bit_clock(false);
91
92 /* switch to new source */
93 cur_audio_source = source;
94
95 if(source == AUDIO_SRC_PLAYBACK) {
96 /* power on DAC */
97 aic_set_external_codec(true);
98 aic_set_i2s_mode(AIC_I2S_MASTER_MODE);
99 ak4376_open();
100
101 /* apply the old settings */
102 audiohw_set_volume(cur_vol_l, cur_vol_r);
103 audiohw_set_filter_roll_off(cur_filter_roll_off);
104 set_ak_freqmode();
105 } else if(source == AUDIO_SRC_MIC) {
106 aic_set_external_codec(false);
107 aic_set_i2s_mode(AIC_I2S_SLAVE_MODE);
108 /* Note: Sampling frequency is irrelevant here */
109 aic_set_i2s_clock(X1000_CLK_EXCLK, 48000, 0);
110 aic_enable_i2s_bit_clock(true);
111
112 x1000_icodec_open();
113
114 /* configure the mic */
115 x1000_icodec_mic1_enable(true);
116 x1000_icodec_mic1_bias_enable(true);
117 x1000_icodec_mic1_configure(JZCODEC_MIC1_DIFFERENTIAL |
118 JZCODEC_MIC1_BIAS_2_08V);
119
120 /* configure the ADC */
121 x1000_icodec_adc_mic_sel(JZCODEC_MIC_SEL_ANALOG);
122 x1000_icodec_adc_highpass_filter(true);
123 x1000_icodec_adc_frequency(cur_fsel);
124 x1000_icodec_adc_enable(true);
125
126 /* configure the mixer to put mic input in both channels */
127 x1000_icodec_mixer_enable(true);
128 x1000_icodec_write(JZCODEC_MIX2, 0x10);
129
130 /* set gain and unmute */
131 audiohw_set_recvol(cur_recvol, 0, AUDIO_GAIN_MIC);
132 x1000_icodec_adc_mute(false);
133 } else {
134 logf("bad audio input source: %d (flags: %x)", source, flags);
135 }
64} 136}
65 137
66void audiohw_set_volume(int vol_l, int vol_r) 138void audiohw_set_volume(int vol_l, int vol_r)
67{ 139{
68 ak4376_set_volume(vol_l, vol_r); 140 cur_vol_l = vol_l;
141 cur_vol_r = vol_r;
142
143 if(cur_audio_source == AUDIO_SRC_PLAYBACK)
144 ak4376_set_volume(vol_l, vol_r);
69} 145}
70 146
71void audiohw_set_filter_roll_off(int val) 147void audiohw_set_filter_roll_off(int val)
72{ 148{
73 ak4376_set_filter_roll_off(val); 149 cur_filter_roll_off = val;
150
151 if(cur_audio_source == AUDIO_SRC_PLAYBACK)
152 ak4376_set_filter_roll_off(val);
74} 153}
75 154
76void audiohw_set_frequency(int fsel) 155void audiohw_set_frequency(int fsel)
77{ 156{
78 cur_fsel = fsel; 157 cur_fsel = fsel;
79 set_ak_freqmode(); 158
159 if(cur_audio_source == AUDIO_SRC_PLAYBACK)
160 set_ak_freqmode();
161 else
162 x1000_icodec_adc_frequency(fsel);
80} 163}
81 164
82void audiohw_set_power_mode(int mode) 165void audiohw_set_power_mode(int mode)
83{ 166{
84 cur_power_mode = mode; 167 cur_power_mode = mode;
85 set_ak_freqmode(); 168
169 if(cur_audio_source == AUDIO_SRC_PLAYBACK)
170 set_ak_freqmode();
171}
172
173static int round_step_up(int x, int step)
174{
175 int rem = x % step;
176 if(rem > 0)
177 rem -= step;
178 return x - rem;
179}
180
181void audiohw_set_recvol(int left, int right, int type)
182{
183 (void)right;
184
185 if(type == AUDIO_GAIN_MIC) {
186 cur_recvol = left;
187
188 if(cur_audio_source == AUDIO_SRC_MIC) {
189 int mic_gain = round_step_up(left, X1000_ICODEC_MIC_GAIN_STEP);
190 mic_gain = MIN(mic_gain, X1000_ICODEC_MIC_GAIN_MAX);
191 mic_gain = MAX(mic_gain, X1000_ICODEC_MIC_GAIN_MIN);
192
193 int adc_gain = left - mic_gain;
194 adc_gain = MIN(adc_gain, X1000_ICODEC_ADC_GAIN_MAX);
195 adc_gain = MAX(adc_gain, X1000_ICODEC_ADC_GAIN_MIN);
196
197 x1000_icodec_adc_gain(adc_gain);
198 x1000_icodec_mic1_gain(mic_gain);
199 }
200 }
86} 201}
87 202
88void ak4376_set_pdn_pin(int level) 203void 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 @@
45\newcommand{\ActionWpsAbSetBNextDir}{Long \ButtonDown} 45\newcommand{\ActionWpsAbSetBNextDir}{Long \ButtonDown}
46\newcommand{\ActionWpsAbReset}{Long \ButtonSelect} 46\newcommand{\ActionWpsAbReset}{Long \ButtonSelect}
47 47
48%Button actions, recording context
49\newcommand{\ActionRecPause}{\ButtonSelect{} or \ButtonPlay}
50\newcommand{\ActionRecExit}{\ButtonBack{} or \ButtonPower}
51\newcommand{\ActionRecNewfile}{Long \ButtonSelect{} or Long \ButtonPlay}
52\newcommand{\ActionRecMenu}{\ButtonMenu}
53\newcommand{\ActionRecPrev}{\ActionStdPrev}
54\newcommand{\ActionRecPrevRepeat}{\ActionStdPrevRepeat}
55\newcommand{\ActionRecNext}{\ActionStdNext}
56\newcommand{\ActionRecNextRepeat}{\ActionStdNextRepeat}
57\newcommand{\ActionRecSettingsInc}{\ButtonVolUp{} or \ButtonRight}
58\newcommand{\ActionRecSettingsDec}{\ButtonVolDown{} or \ButtonLeft}
59
48%Button actions, tree context 60%Button actions, tree context
49\newcommand{\ActionTreeWps}{Long \ButtonBack} 61\newcommand{\ActionTreeWps}{Long \ButtonBack}
50\newcommand{\ActionTreeStop}{Long \ButtonPlay} 62\newcommand{\ActionTreeStop}{Long \ButtonPlay}